From 82c9feccc10d4953fad7a2350d7b076eff7b0604 Mon Sep 17 00:00:00 2001 From: Mayank Chopra Date: Fri, 2 Nov 2012 15:25:37 +0530 Subject: [PATCH] weritos los13 final --- .../devicetree/bindings/arm/msm/msm_bus.txt | 34 - Makefile | 76 +- arch/Kconfig | 7 + arch/arm/Kconfig | 2 +- arch/arm/configs/jsr_i6_defconfig | 3524 +++++++ arch/arm/configs/msm8960-perf_defconfig | 2 +- arch/arm/configs/msm8960_defconfig | 2 +- arch/arm/configs/normandy_defconfig | 108 +- arch/arm/configs/weritos_defconfig | 3484 +++++++ ...\320\272\320\276\320\277\320\270\321\217)" | 3482 +++++++ arch/arm/include/asm.zip | Bin 0 -> 236089 bytes arch/arm/include/asm/device.h | 4 + arch/arm/include/asm/hw_breakpoint.h | 11 +- arch/arm/kernel/hw_breakpoint.c | 236 +- arch/arm/mach-msm/Kconfig | 108 +- arch/arm/mach-msm/Makefile | 15 +- arch/arm/mach-msm/audio-7627a-devices.c | 1 - arch/arm/mach-msm/board-8064.c | 16 +- arch/arm/mach-msm/board-8930.c | 16 +- arch/arm/mach-msm/board-8960.c | 16 +- arch/arm/mach-msm/board-msm7627a_i6-display.c | 535 ++ arch/arm/mach-msm/board-msm7x27.c | 1 - arch/arm/mach-msm/board-msm7x27a.c | 178 +- arch/arm/mach-msm/board-msm7x27a_i6.c | 1191 +++ arch/arm/mach-msm/board-msm7x27a_i6.cd | 1237 +++ arch/arm/mach-msm/board-qrd7627a.c | 161 +- arch/arm/mach-msm/board-qrd7627a_i6.c | 1232 +++ arch/arm/mach-msm/bricked_hotplug.c | 892 ++ arch/arm/mach-msm/devices-iommu.c | 8 +- arch/arm/mach-msm/devices-msm7x27.c | 2 +- arch/arm/mach-msm/devices-msm7x27a.c | 12 +- arch/arm/mach-msm/devices.h | 6 + arch/arm/mach-msm/dma.c | 304 +- arch/arm/mach-msm/include/mach/gpio.h | 3 + arch/arm/mach-msm/include/mach/memory.h | 18 + arch/arm/mach-msm/include/mach/msm_bus.h | 5 +- arch/arm/mach-msm/include/mach/msm_fb.h | 4 +- arch/arm/mach-msm/include/mach/msm_memtypes.h | 4 +- arch/arm/mach-msm/intelli_plug.c | 606 ++ arch/arm/mach-msm/memory.c | 12 - arch/arm/mach-msm/msm_bus/Makefile | 2 +- arch/arm/mach-msm/msm_bus/msm_bus_arb.c | 57 +- arch/arm/mach-msm/msm_bus/msm_bus_bimc.c | 4 +- arch/arm/mach-msm/msm_bus/msm_bus_core.h | 35 +- arch/arm/mach-msm/msm_bus/msm_bus_dbg.c | 4 +- arch/arm/mach-msm/msm_bus/msm_bus_fabric.c | 20 +- arch/arm/mach-msm/msm_bus/msm_bus_noc.c | 4 +- arch/arm/mach-msm/msm_bus/msm_bus_of.c | 150 - arch/arm/mach-msm/msm_bus/msm_bus_rpm.c | 38 +- arch/arm/mach-msm/msm_dcvs_scm.c | 20 +- arch/arm/mach-msm/msm_rq_stats.c | 2 +- arch/arm/mach-msm/qdsp5/Makefile | 1 + arch/arm/mach-msm/qdsp5/adsp.c | 4 +- arch/arm/mach-msm/qdsp5/adsp.h | 2 +- arch/arm/mach-msm/qdsp5/adsp_driver.c | 5 +- .../mach-msm/qdsp5/adsp_video_verify_cmd.c | 2 +- arch/arm/mach-msm/qdsp5/audio_aac.c | 12 +- arch/arm/mach-msm/qdsp5/audio_aac_in.c | 11 +- arch/arm/mach-msm/qdsp5/audio_ac3.c | 13 +- arch/arm/mach-msm/qdsp5/audio_acdb.c | 20 - arch/arm/mach-msm/qdsp5/audio_amrnb.c | 13 +- arch/arm/mach-msm/qdsp5/audio_amrnb_in.c | 10 +- arch/arm/mach-msm/qdsp5/audio_amrwb.c | 11 +- arch/arm/mach-msm/qdsp5/audio_evrc.c | 11 +- arch/arm/mach-msm/qdsp5/audio_evrc_in.c | 15 +- arch/arm/mach-msm/qdsp5/audio_lpa.c | 4 +- arch/arm/mach-msm/qdsp5/audio_mp3.c | 15 +- arch/arm/mach-msm/qdsp5/audio_pcm.c | 8 +- arch/arm/mach-msm/qdsp5/audio_pcm_in.c | 6 +- arch/arm/mach-msm/qdsp5/audio_qcelp.c | 13 +- arch/arm/mach-msm/qdsp5/audio_qcelp_in.c | 14 +- arch/arm/mach-msm/qdsp5/audio_wma.c | 13 +- arch/arm/mach-msm/qdsp5/audio_wmapro.c | 13 +- arch/arm/mach-msm/rpcrouter_sdio_xprt.c | 655 ++ arch/arm/mach-msm/sdio_al.c | 4365 +++++++++ arch/arm/mach-msm/sdio_al_dloader.c | 2541 +++++ arch/arm/mach-msm/sdio_al_private.h | 267 + arch/arm/mach-msm/sdio_al_test.c | 6500 +++++++++++++ arch/arm/mach-msm/sdio_cmux.c | 885 ++ arch/arm/mach-msm/sdio_ctl.c | 575 ++ arch/arm/mach-msm/sdio_dmux.c | 925 ++ arch/arm/mach-msm/sdio_smem.c | 175 + arch/arm/mach-msm/sdio_tty.c | 824 ++ arch/arm/mm/dma-mapping.c | 2 +- arch/arm/mm/dma-mapping.cd | 989 ++ arch/arm/mm/mm.h | 3 + block/Kconfig.iosched | 175 +- block/Makefile | 10 +- block/bfq-cgroup.c | 908 ++ block/bfq-ioc.c | 36 + block/bfq-iosched.c | 4207 +++++++++ block/bfq-sched.c | 1180 +++ block/bfq.h | 806 ++ block/fiops-iosched.c | 229 +- block/row-iosched.c | 790 ++ block/sio-iosched.c | 399 + block/sioplus-iosched.c | 409 + block/vr-iosched.c | 434 + block/zen-iosched.c | 277 + drivers/base/genlock.c | 63 +- drivers/base/sync.c | 278 +- drivers/block/Kconfig | 2 + drivers/block/Makefile | 2 + drivers/{staging => block}/zram/Kconfig | 41 +- drivers/block/zram/Makefile | 5 + drivers/block/zram/zcomp.c | 353 + drivers/block/zram/zcomp.h | 68 + drivers/block/zram/zcomp_lz4.c | 47 + drivers/block/zram/zcomp_lz4.h | 17 + drivers/block/zram/zcomp_lzo.c | 47 + drivers/block/zram/zcomp_lzo.h | 17 + drivers/{staging => block}/zram/zram_drv.c | 570 +- drivers/{staging => block}/zram/zram_drv.h | 71 +- drivers/bluetooth/Kconfig | 7 + drivers/bluetooth/ath3k.c | 74 - drivers/bluetooth/bluesleep.c | 981 +- drivers/bluetooth/bluetooth-power.c | 2 +- drivers/bluetooth/btusb.c | 71 +- drivers/bluetooth/btwilink.c | 5 +- drivers/bluetooth/hci_h4.c | 2 +- drivers/bluetooth/hci_ibs.c | 4 +- drivers/bluetooth/hci_ldisc.c | 55 +- drivers/bluetooth/hci_smd.c | 2 +- drivers/bluetooth/hci_uart.h | 4 +- drivers/bluetooth/hci_vhci.c | 2 +- drivers/cpufreq/Kconfig | 269 +- drivers/cpufreq/Makefile | 18 +- drivers/cpufreq/cpufreq_adaptive.c | 947 ++ drivers/cpufreq/cpufreq_alucard.c | 599 ++ drivers/cpufreq/cpufreq_gov_msm.c | 184 +- drivers/cpufreq/cpufreq_hyper.c | 898 ++ drivers/cpufreq/cpufreq_intelliactive.c | 1544 ++++ drivers/cpufreq/cpufreq_intellidemand.c | 2469 +++++ drivers/cpufreq/cpufreq_intellimm.c | 1664 ++++ drivers/cpufreq/cpufreq_interactivex.c | 405 + drivers/cpufreq/cpufreq_lionheart.c | 545 ++ drivers/cpufreq/cpufreq_ondemandx.c | 830 ++ drivers/cpufreq/cpufreq_smartass2.c | 868 ++ drivers/cpufreq/cpufreq_smartassH3.c | 981 ++ drivers/crypto/msm/qce.c | 148 +- drivers/crypto/msm/qcedev.c | 246 +- drivers/gpu/ion/ion.c | 376 +- drivers/gpu/ion/ion_carveout_heap.c | 103 +- drivers/gpu/ion/ion_cma_heap.c | 23 +- drivers/gpu/ion/ion_cp_heap.c | 243 +- drivers/gpu/ion/ion_heap.c | 5 +- drivers/gpu/ion/ion_iommu_heap.c | 268 +- drivers/gpu/ion/ion_priv.h | 6 +- drivers/gpu/ion/ion_system_heap.c | 41 +- drivers/gpu/ion/msm/ion_cp_common.h | 2 +- drivers/gpu/ion/msm/msm_ion.c | 470 +- drivers/gpu/msm/Kconfig | 98 + drivers/gpu/msm/Makefile | 2 - drivers/gpu/msm/a2xx_reg.h | 26 +- drivers/gpu/msm/a3xx_reg.h | 172 +- drivers/gpu/msm/adreno.c | 1297 ++- drivers/gpu/msm/adreno.h | 157 +- drivers/gpu/msm/adreno_a2xx.c | 131 +- drivers/gpu/msm/adreno_a2xx_snapshot.c | 37 + drivers/gpu/msm/adreno_a3xx.c | 623 +- drivers/gpu/msm/adreno_a3xx_snapshot.c | 101 +- drivers/gpu/msm/adreno_debugfs.c | 41 +- drivers/gpu/msm/adreno_debugfs.h | 46 + drivers/gpu/msm/adreno_dispatch.c | 1415 +++ drivers/gpu/msm/adreno_drawctxt.c | 30 +- drivers/gpu/msm/adreno_drawctxt.h | 14 +- drivers/gpu/msm/adreno_postmortem.c | 6 +- drivers/gpu/msm/adreno_postmortem.h | 21 + drivers/gpu/msm/adreno_ringbuffer.c | 299 +- drivers/gpu/msm/adreno_ringbuffer.h | 5 +- drivers/gpu/msm/adreno_snapshot.c | 206 +- drivers/gpu/msm/adreno_trace.c | 18 + drivers/gpu/msm/adreno_trace.h | 169 + drivers/gpu/msm/kgsl.c | 1787 +++- drivers/gpu/msm/kgsl.h | 51 +- drivers/gpu/msm/kgsl_cffdump.c | 37 +- drivers/gpu/msm/kgsl_cffdump.h | 6 +- drivers/gpu/msm/kgsl_debugfs.c | 146 +- drivers/gpu/msm/kgsl_debugfs.h | 4 +- drivers/gpu/msm/kgsl_device.h | 224 +- drivers/gpu/msm/kgsl_drm.c | 1 - drivers/gpu/msm/kgsl_events.c | 308 +- drivers/gpu/msm/kgsl_gpummu.c | 2 +- drivers/gpu/msm/kgsl_iommu.c | 707 +- drivers/gpu/msm/kgsl_iommu.h | 36 +- drivers/gpu/msm/kgsl_mmu.c | 375 +- drivers/gpu/msm/kgsl_mmu.h | 98 +- drivers/gpu/msm/kgsl_pwrctrl.c | 350 +- drivers/gpu/msm/kgsl_pwrctrl.h | 11 +- drivers/gpu/msm/kgsl_pwrscale.c | 3 +- drivers/gpu/msm/kgsl_pwrscale_trustzone.c | 10 +- drivers/gpu/msm/kgsl_sharedmem.c | 166 +- drivers/gpu/msm/kgsl_sharedmem.h | 127 +- drivers/gpu/msm/kgsl_snapshot.c | 92 +- drivers/gpu/msm/kgsl_snapshot.h | 12 + drivers/gpu/msm/kgsl_sync.c | 84 +- drivers/gpu/msm/kgsl_sync.h | 2 + drivers/gpu/msm/kgsl_trace.h | 151 +- drivers/gpu/msm/z180.c | 96 +- drivers/gpu/msm/z180.h | 6 +- drivers/gpu/msm/z180_postmortem.c | 2 + .../dvb/mpq/demux/mpq_dmx_plugin_common.h | 2 +- .../media/video/msm/actuators/msm_actuator.c | 39 +- .../video/msm/gemini/msm_gemini_platform.c | 7 - drivers/media/video/msm/msm_camera.c | 25 +- drivers/media/video/msm/msm_isp.c | 1 - drivers/media/video/msm/msm_mctl.c | 2 - drivers/media/video/msm/msm_mctl_buf.c | 2 - drivers/media/video/msm/msm_mctl_pp.c | 2 - drivers/media/video/msm/msm_mem.c | 39 +- drivers/media/video/msm/msm_v4l2_video.c | 60 +- drivers/media/video/msm/msm_v4l2_video.h | 4 +- drivers/media/video/msm/msm_vfe7x.c | 1 - drivers/media/video/msm/msm_vfe7x27a.c | 1 - drivers/media/video/msm/msm_vfe7x27a_v4l2.c | 1 - drivers/media/video/msm/msm_vfe_stats_buf.c | 42 +- drivers/media/video/msm/wfd/wfd-ioctl.c | 2 - drivers/media/video/videobuf-msm-mem.c | 57 - drivers/media/video/videobuf2-msm-mem.c | 35 +- drivers/misc/qseecom.c | 2 +- drivers/mtd/devices/msm_nand.c | 8 - drivers/net/ethernet/msm/msm_rmnet.c | 27 +- drivers/net/wireless/ath/Kconfig | 2 +- drivers/net/wireless/ath/Makefile | 11 +- drivers/net/wireless/ath/ath.h | 0 drivers/net/wireless/ath/ath5k/ahb.c | 32 +- drivers/net/wireless/ath/ath5k/ani.c | 99 +- drivers/net/wireless/ath/ath5k/ani.h | 32 +- drivers/net/wireless/ath/ath5k/ath5k.h | 576 +- drivers/net/wireless/ath/ath5k/attach.c | 16 +- drivers/net/wireless/ath/ath5k/base.c | 292 +- drivers/net/wireless/ath/ath5k/caps.c | 27 +- drivers/net/wireless/ath/ath5k/debug.c | 23 +- drivers/net/wireless/ath/ath5k/desc.c | 217 +- drivers/net/wireless/ath/ath5k/desc.h | 124 +- drivers/net/wireless/ath/ath5k/dma.c | 370 +- drivers/net/wireless/ath/ath5k/gpio.c | 81 +- drivers/net/wireless/ath/ath5k/initvals.c | 75 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 37 +- drivers/net/wireless/ath/ath5k/pci.c | 10 +- drivers/net/wireless/ath/ath5k/pcu.c | 222 +- drivers/net/wireless/ath/ath5k/phy.c | 835 +- drivers/net/wireless/ath/ath5k/qcu.c | 151 +- drivers/net/wireless/ath/ath5k/reg.h | 27 +- drivers/net/wireless/ath/ath5k/reset.c | 244 +- drivers/net/wireless/ath/ath5k/rfbuffer.h | 59 +- drivers/net/wireless/ath/ath5k/rfgain.h | 22 +- drivers/net/wireless/ath/ath5k/trace.h | 5 +- drivers/net/wireless/ath/ath6kl/Kconfig | 14 + drivers/net/wireless/ath/ath6kl/Makefile | 51 +- drivers/net/wireless/ath/ath6kl/ath.h | 284 + drivers/net/wireless/ath/ath6kl/bmi.c | 6 +- drivers/net/wireless/ath/ath6kl/bmi.h | 23 - drivers/net/wireless/ath/ath6kl/btc.h | 76 + drivers/net/wireless/ath/ath6kl/cfg80211.c | 1469 ++- drivers/net/wireless/ath/ath6kl/cfg80211.h | 18 +- .../net/wireless/ath/ath6kl/cfg80211_btcoex.c | 65 + .../net/wireless/ath/ath6kl/cfg80211_btcoex.h | 18 + drivers/net/wireless/ath/ath6kl/common.h | 4 + drivers/net/wireless/ath/ath6kl/core.c | 299 - drivers/net/wireless/ath/ath6kl/core.h | 245 +- drivers/net/wireless/ath/ath6kl/debug.c | 228 +- drivers/net/wireless/ath/ath6kl/debug.h | 38 +- drivers/net/wireless/ath/ath6kl/debugfs_pri.c | 238 + drivers/net/wireless/ath/ath6kl/debugfs_pri.h | 35 + drivers/net/wireless/ath/ath6kl/hif-ops.h | 4 + drivers/net/wireless/ath/ath6kl/hif.c | 106 +- drivers/net/wireless/ath/ath6kl/hif.h | 5 +- drivers/net/wireless/ath/ath6kl/htc.c | 193 +- drivers/net/wireless/ath/ath6kl/htc.h | 16 +- drivers/net/wireless/ath/ath6kl/init.c | 651 +- drivers/net/wireless/ath/ath6kl/main.c | 420 +- drivers/net/wireless/ath/ath6kl/platform.c | 206 + drivers/net/wireless/ath/ath6kl/pm.c | 238 + drivers/net/wireless/ath/ath6kl/pm.h | 24 + drivers/net/wireless/ath/ath6kl/recovery.c | 151 + drivers/net/wireless/ath/ath6kl/regd.c | 85 + drivers/net/wireless/ath/ath6kl/regd.h | 13 + drivers/net/wireless/ath/ath6kl/regd_ath.h | 263 + drivers/net/wireless/ath/ath6kl/regd_common.h | 478 + drivers/net/wireless/ath/ath6kl/sdio.c | 96 +- drivers/net/wireless/ath/ath6kl/softmac.c | 248 + drivers/net/wireless/ath/ath6kl/target.h | 1 + drivers/net/wireless/ath/ath6kl/testmode.c | 33 + drivers/net/wireless/ath/ath6kl/txrx.c | 155 +- drivers/net/wireless/ath/ath6kl/usb.c | 9 +- drivers/net/wireless/ath/ath6kl/wmi.c | 706 +- drivers/net/wireless/ath/ath6kl/wmi.h | 220 +- drivers/net/wireless/ath/ath6kl/wmi_btcoex.c | 127 + drivers/net/wireless/ath/ath6kl/wmi_btcoex.h | 32 + drivers/net/wireless/ath/ath6kl/wmiconfig.c | 88 + drivers/net/wireless/ath/ath6kl/wmiconfig.h | 25 + drivers/net/wireless/ath/ath9k/Kconfig | 38 - drivers/net/wireless/ath/ath9k/Makefile | 11 +- drivers/net/wireless/ath/ath9k/ani.c | 35 +- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 90 +- .../net/wireless/ath/ath9k/ar9001_initvals.h | 270 + drivers/net/wireless/ath/ath9k/ar9002_calib.c | 136 +- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 166 +- .../net/wireless/ath/ath9k/ar9002_initvals.h | 104 + drivers/net/wireless/ath/ath9k/ar9002_mac.c | 15 +- drivers/net/wireless/ath/ath9k/ar9002_phy.h | 2 - .../wireless/ath/ath9k/ar9003_2p2_initvals.h | 302 + drivers/net/wireless/ath/ath9k/ar9003_calib.c | 121 +- .../net/wireless/ath/ath9k/ar9003_eeprom.c | 87 +- .../net/wireless/ath/ath9k/ar9003_eeprom.h | 0 drivers/net/wireless/ath/ath9k/ar9003_hw.c | 113 +- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 70 +- drivers/net/wireless/ath/ath9k/ar9003_mac.h | 5 +- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 19 +- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 86 +- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 26 +- drivers/net/wireless/ath/ath9k/ar9003_rtt.c | 1 - .../wireless/ath/ath9k/ar9462_1p0_initvals.h | 1833 ++++ .../wireless/ath/ath9k/ar9462_2p0_initvals.h | 507 +- .../wireless/ath/ath9k/ar9580_1p0_initvals.h | 0 drivers/net/wireless/ath/ath9k/ath9k.h | 75 +- drivers/net/wireless/ath/ath9k/beacon.c | 60 +- drivers/net/wireless/ath/ath9k/btcoex.c | 67 +- drivers/net/wireless/ath/ath9k/btcoex.h | 33 +- drivers/net/wireless/ath/ath9k/calib.c | 26 +- drivers/net/wireless/ath/ath9k/calib.h | 1 + drivers/net/wireless/ath/ath9k/common.h | 0 drivers/net/wireless/ath/ath9k/debug.c | 440 +- drivers/net/wireless/ath/ath9k/debug.h | 29 +- drivers/net/wireless/ath/ath9k/eeprom.c | 3 +- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 29 +- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 22 +- drivers/net/wireless/ath/ath9k/eeprom_def.c | 36 +- drivers/net/wireless/ath/ath9k/gpio.c | 125 +- drivers/net/wireless/ath/ath9k/hif_usb.c | 158 +- drivers/net/wireless/ath/ath9k/hif_usb.h | 3 +- drivers/net/wireless/ath/ath9k/htc.h | 21 +- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 51 +- .../net/wireless/ath/ath9k/htc_drv_debug.c | 26 +- drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | 73 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 53 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 118 +- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 13 +- drivers/net/wireless/ath/ath9k/htc_hst.c | 5 +- drivers/net/wireless/ath/ath9k/hw-ops.h | 11 +- drivers/net/wireless/ath/ath9k/hw.c | 359 +- drivers/net/wireless/ath/ath9k/hw.h | 107 +- drivers/net/wireless/ath/ath9k/init.c | 94 +- drivers/net/wireless/ath/ath9k/mac.c | 109 +- drivers/net/wireless/ath/ath9k/mac.h | 4 +- drivers/net/wireless/ath/ath9k/main.c | 415 +- drivers/net/wireless/ath/ath9k/mci.c | 364 +- drivers/net/wireless/ath/ath9k/mci.h | 23 +- drivers/net/wireless/ath/ath9k/pci.c | 68 +- drivers/net/wireless/ath/ath9k/rc.c | 43 +- drivers/net/wireless/ath/ath9k/rc.h | 2 + drivers/net/wireless/ath/ath9k/recv.c | 131 +- drivers/net/wireless/ath/ath9k/reg.h | 312 +- drivers/net/wireless/ath/ath9k/wmi.c | 8 +- drivers/net/wireless/ath/ath9k/xmit.c | 469 +- drivers/net/wireless/ath/carl9170/carl9170.h | 2 +- drivers/net/wireless/ath/carl9170/debug.c | 9 +- drivers/net/wireless/ath/carl9170/fw.c | 130 +- drivers/net/wireless/ath/carl9170/mac.c | 35 - drivers/net/wireless/ath/carl9170/main.c | 50 +- drivers/net/wireless/ath/carl9170/phy.c | 36 +- drivers/net/wireless/ath/carl9170/tx.c | 15 +- drivers/net/wireless/ath/carl9170/usb.c | 13 +- drivers/net/wireless/ath/key.c | 0 drivers/power/msm_battery.c | 6 +- drivers/staging/Kconfig | 10 +- drivers/staging/Makefile | 3 - drivers/staging/android/binder.c | 173 +- drivers/staging/android/binder_trace.h | 327 + drivers/staging/qcache/Kconfig | 8 - drivers/staging/qcache/Makefile | 3 - drivers/staging/qcache/fmem.c | 344 - drivers/staging/qcache/qcache-main.c | 1358 --- drivers/staging/qcache/tmem.c | 833 -- drivers/staging/qcache/tmem.h | 212 - drivers/staging/zcache/Kconfig | 3 +- drivers/staging/zcache/tmem.c | 65 +- drivers/staging/zcache/zcache-main.c | 214 +- drivers/staging/zram/Makefile | 3 - drivers/staging/zram/zram.txt | 77 - drivers/staging/zsmalloc/Kconfig | 24 - drivers/staging/zsmalloc/Makefile | 3 - drivers/tty/serial/msm_serial_hs.c | 8 +- drivers/video/msm.zip | Bin 0 -> 3844017 bytes drivers/video/msm/external_common.c | 233 +- drivers/video/msm/external_common.h | 32 +- drivers/video/msm/hdmi_msm.c | 1057 ++- drivers/video/msm/hdmi_msm.h | 8 +- drivers/video/msm/lcdc.c | 6 +- drivers/video/msm/lvds.c | 15 +- drivers/video/msm/mdp.c | 515 +- drivers/video/msm/mdp.h | 43 +- drivers/video/msm/mdp4.h | 152 +- drivers/video/msm/mdp4_dtv.c | 58 +- drivers/video/msm/mdp4_overlay.c | 1107 ++- drivers/video/msm/mdp4_overlay.c.save | 3709 ++++++++ drivers/video/msm/mdp4_overlay_atv.c | 2 + drivers/video/msm/mdp4_overlay_dsi_cmd.c | 252 +- drivers/video/msm/mdp4_overlay_dsi_video.c | 195 +- drivers/video/msm/mdp4_overlay_dtv.c | 384 +- drivers/video/msm/mdp4_overlay_lcdc.c | 67 +- drivers/video/msm/mdp4_overlay_mddi.c | 1362 +-- drivers/video/msm/mdp4_overlay_writeback.c | 549 +- drivers/video/msm/mdp4_util.c | 786 +- drivers/video/msm/mdp4_wfd_writeback.c | 15 + drivers/video/msm/mdp_cursor.c | 65 +- drivers/video/msm/mdp_debugfs.c | 232 +- drivers/video/msm/mdp_dma.c | 0 drivers/video/msm/mdp_dma_dsi_video.c | 42 +- drivers/video/msm/mdp_dma_lcdc.c | 40 +- drivers/video/msm/mdp_hw_init.c | 16 +- drivers/video/msm/mdp_ppp.c | 84 +- drivers/video/msm/mipi_byd_otm9608a_wg451v.c | 0 ..._wvga (\320\272\320\276\320\277\320\270.c" | 1183 +++ .../video/msm/mipi_div4_nt35510_cmd_wvga.c | 0 drivers/video/msm/mipi_dsi.c | 41 +- drivers/video/msm/mipi_dsi.h | 7 +- drivers/video/msm/mipi_dsi_host.c | 146 +- drivers/video/msm/mipi_hx8389b_video_qhd_pt.c | 0 drivers/video/msm/mipi_novatek.c | 87 +- drivers/video/msm/mipi_novatek_cmd_qhd_pt.c | 2 +- drivers/video/msm/mipi_nt35516_e808t.c | 0 drivers/video/msm/mipi_otm9605a.c | 0 .../video/msm/mipi_yassy_otm9608a_wg451v.c | 0 drivers/video/msm/msm_dss_io_7x27a.c | 0 drivers/video/msm/msm_fb.c | 967 +- drivers/video/msm/msm_fb.c- | 4643 ++++++++++ drivers/video/msm/msm_fb.h | 36 +- drivers/video/msm/msm_fb_bl.c | 0 drivers/video/msm/msm_fb_panel.c | 22 + drivers/video/msm/msm_fb_panel.h | 25 +- .../video/msm/vidc/1080p/ddl/vcd_ddl_helper.c | 4 +- .../video/msm/vidc/1080p/ddl/vcd_ddl_utils.c | 2 +- .../1080p/resource_tracker/vcd_res_tracker.c | 2 +- .../1080p/resource_tracker/vcd_res_tracker.h | 2 +- .../video/msm/vidc/720p/ddl/vcd_ddl_utils.c | 3 +- .../720p/resource_tracker/vcd_res_tracker.c | 6 +- .../720p/resource_tracker/vcd_res_tracker.h | 2 +- drivers/video/msm/vidc/common/dec/vdec.c | 40 +- drivers/video/msm/vidc/common/enc/venc.c | 1 - .../video/msm/vidc/common/enc/venc_internal.c | 69 +- .../video/msm/vidc/common/init/vidc_init.c | 34 +- drivers/video/msm/vidc/common/vcd/vcd_core.h | 2 +- drivers/video/msm/vidc/common/vcd/vcd_sub.c | 3 +- include/asm-generic/vmlinux.lds.h | 5 + include/compat/linux/ath9k_platform.h | 37 + include/compat/linux/atomic.h | 46 + include/compat/linux/average.h | 5 + include/compat/linux/bcma/bcma.h | 277 + .../linux/bcma/bcma_driver_chipcommon.h | 390 + include/compat/linux/bcma/bcma_driver_mips.h | 51 + include/compat/linux/bcma/bcma_driver_pci.h | 91 + include/compat/linux/bcma/bcma_regs.h | 59 + include/compat/linux/bcma/bcma_soc.h | 16 + include/compat/linux/bitops.h | 211 + include/compat/linux/compat-2.6.14.h | 13 + include/compat/linux/compat-2.6.18.h | 13 + include/compat/linux/compat-2.6.19.h | 24 + include/compat/linux/compat-2.6.20.h | 21 + include/compat/linux/compat-2.6.21.h | 18 + include/compat/linux/compat-2.6.22.h | 104 + include/compat/linux/compat-2.6.23.h | 136 + include/compat/linux/compat-2.6.24.h | 247 + include/compat/linux/compat-2.6.25.h | 193 + include/compat/linux/compat-2.6.26.h | 455 + include/compat/linux/compat-2.6.27.h | 261 + include/compat/linux/compat-2.6.28.h | 264 + include/compat/linux/compat-2.6.29.h | 350 + include/compat/linux/compat-2.6.30.h | 47 + include/compat/linux/compat-2.6.31.h | 221 + include/compat/linux/compat-2.6.32.h | 129 + include/compat/linux/compat-2.6.33.h | 172 + include/compat/linux/compat-2.6.34.h | 309 + include/compat/linux/compat-2.6.35.h | 48 + include/compat/linux/compat-2.6.36.h | 172 + include/compat/linux/compat-2.6.37.h | 140 + include/compat/linux/compat-2.6.38.h | 95 + include/compat/linux/compat-2.6.39.h | 169 + include/compat/linux/compat-2.6.h | 44 + include/compat/linux/compat-3.0.h | 130 + include/compat/linux/compat-3.1.h | 49 + include/compat/linux/compat-3.2.h | 81 + include/compat/linux/compat-3.3.h | 56 + include/compat/linux/compat-3.4.h | 80 + include/compat/linux/compat-3.5.h | 13 + include/compat/linux/compat_autoconf.h | 37 + include/compat/linux/cordic.h | 48 + include/compat/linux/crc8.h | 101 + include/compat/linux/eeprom_93cx6.h | 74 + include/compat/linux/export.h | 12 + include/compat/linux/ieee80211.h | 1852 ++++ include/compat/linux/kfifo.h | 857 ++ include/compat/linux/math64.h | 10 + include/compat/linux/nl80211.h | 2963 ++++++ include/compat/linux/of.h | 16 + include/compat/linux/pci-aspm.h | 5 + include/compat/linux/pci_ids.h | 2879 ++++++ include/compat/linux/pm_qos.h | 12 + include/compat/linux/pm_qos_params.h | 36 + include/compat/linux/pm_runtime.h | 14 + include/compat/linux/printk.h | 12 + include/compat/linux/rfkill.h | 32 + include/compat/linux/rfkill_backport.h | 359 + include/compat/linux/semaphore.h | 12 + include/compat/linux/spi/libertas_spi.h | 29 + include/compat/linux/ssb/ssb.h | 538 ++ .../compat/linux/ssb/ssb_driver_chipcommon.h | 665 ++ include/compat/linux/ssb/ssb_driver_extif.h | 214 + include/compat/linux/ssb/ssb_driver_gige.h | 179 + include/compat/linux/ssb/ssb_driver_mips.h | 46 + include/compat/linux/ssb/ssb_driver_pci.h | 130 + include/compat/linux/ssb/ssb_embedded.h | 18 + include/compat/linux/ssb/ssb_regs.h | 543 ++ include/compat/linux/tracepoint.h | 10 + include/compat/linux/unaligned/access_ok.h | 67 + include/compat/linux/unaligned/be_byteshift.h | 70 + include/compat/linux/unaligned/be_memmove.h | 36 + include/compat/linux/unaligned/be_struct.h | 36 + include/compat/linux/unaligned/generic.h | 68 + include/compat/linux/unaligned/le_byteshift.h | 70 + include/compat/linux/unaligned/le_memmove.h | 36 + include/compat/linux/unaligned/le_struct.h | 36 + include/compat/linux/unaligned/memmove.h | 45 + .../compat/linux/unaligned/packed_struct.h | 46 + include/compat/linux/usb/rndis_host.h | 272 + include/compat/linux/usb/usbnet.h | 231 + include/compat/linux/wireless.h | 1162 +++ include/compat/linux/wl12xx.h | 78 + include/compat/net/bluetooth/bluetooth.h | 276 + include/compat/net/bluetooth/hci.h | 1334 +++ include/compat/net/bluetooth/hci_core.h | 988 ++ include/compat/net/bluetooth/l2cap.h | 814 ++ include/compat/net/bluetooth/mgmt.h | 324 + include/compat/net/bluetooth/rfcomm.h | 372 + include/compat/net/bluetooth/smp.h | 140 + include/compat/net/cfg80211-wext.h | 55 + include/compat/net/cfg80211.h | 3479 +++++++ include/compat/net/ieee80211_radiotap.h | 283 + include/compat/net/lib80211.h | 124 + include/compat/net/mac80211.h | 3686 ++++++++ include/compat/net/net_namespace.h | 10 + include/compat/net/regulatory.h | 116 + include/linux/Kbuild | 1 - include/linux/audit.h | 6 +- include/linux/cpu.h | 49 +- include/linux/cpufreq.h | 115 +- include/linux/dma-attrs.h | 2 + include/linux/elevator.h | 9 + include/linux/fib_rules.h | 2 + include/linux/freezer.h | 2 +- include/linux/frontswap.h | 129 + include/linux/genlock.h | 1 + include/linux/ion.h | 297 +- include/linux/lsm_audit.h | 7 + include/linux/msm_ion.h | 315 +- include/linux/msm_mdp.h | 298 +- include/linux/rtnetlink.h | 2 + include/linux/sched.h | 12 +- include/linux/security.h | 41 +- include/linux/swap.h | 5 + include/linux/swapfile.h | 13 + include/linux/sync.h | 24 +- include/linux/writeback.h | 6 + .../zsmalloc => include/linux}/zsmalloc.h | 10 +- include/net/bluetooth/amp.h | 7 +- include/net/bluetooth/bluetooth.h | 3 +- include/net/bluetooth/hci.h | 20 +- include/net/bluetooth/hci_core.h | 60 +- include/net/bluetooth/l2cap.h | 15 +- include/net/bluetooth/mgmt.h | 2 + include/net/bluetooth/sco.h | 4 +- include/net/fib_rules.h | 6 +- include/net/flow.h | 9 +- include/net/ip.h | 1 + include/net/route.h | 6 +- include/trace/binder_trace.h | 327 + include/trace/events/sync.h | 125 + kernel/cpu.c | 44 +- kernel/sched/core.c | 76 +- kernel/sched/fair.c | 4 + kernel/sched/rt.c | 20 +- kernel/sched/sched.h | 68 + kernel/sysctl.c | 3 +- mm/Kconfig | 43 +- mm/Makefile | 2 + mm/frontswap.c | 370 + mm/page-writeback.c | 171 +- mm/swapfile.c | 84 +- .../zsmalloc/zsmalloc-main.c => mm/zsmalloc.c | 107 +- net/Makefile | 2 +- net/bluetooth/af_bluetooth.c | 6 +- net/bluetooth/amp.c | 43 +- net/bluetooth/bnep/core.c | 3 - net/bluetooth/bnep/netdev.c | 3 - net/bluetooth/hci_conn.c | 326 +- net/bluetooth/hci_core.c | 74 +- net/bluetooth/hci_event.c | 242 +- net/bluetooth/hci_sock.c | 32 +- net/bluetooth/hidp/core.c | 71 +- net/bluetooth/l2cap.c | 4747 ++++++++++ net/bluetooth/l2cap_core.c | 679 +- net/bluetooth/l2cap_sock.c | 120 +- net/bluetooth/lib.c | 2 +- net/bluetooth/mgmt.c | 566 +- net/bluetooth/rfcomm/sock.c | 2 + net/bluetooth/rfcomm/tty.c | 2 +- net/bluetooth/sco.c | 28 +- net/bluetooth/smp.c | 54 +- net/core/fib_rules.c | 59 +- net/ipv4/fib_frontend.c | 1 + net/ipv4/inet_connection_sock.c | 6 +- net/ipv4/ip_output.c | 3 +- net/ipv4/ping.c | 3 +- net/ipv4/raw.c | 4 +- net/ipv4/route.c | 12 + net/ipv4/syncookies.c | 3 +- net/ipv4/udp.c | 3 +- net/ipv4/xfrm4_policy.c | 1 + net/ipv6/af_inet6.c | 1 + net/ipv6/datagram.c | 1 + net/ipv6/inet6_connection_sock.c | 2 + net/ipv6/raw.c | 1 + net/ipv6/route.c | 6 + net/ipv6/syncookies.c | 1 + net/ipv6/tcp_ipv6.c | 3 + net/ipv6/udp.c | 1 + net/wireless_ath/Makefile | 23 + net/wireless_ath/Makefile.bk | 18 + net/wireless_ath/chan.c | 135 + net/wireless_ath/core.c | 1104 +++ net/wireless_ath/core.h | 468 + net/wireless_ath/db.txt | 697 ++ net/wireless_ath/debugfs.c | 121 + net/wireless_ath/debugfs.h | 11 + net/wireless_ath/ethtool.c | 78 + net/wireless_ath/ethtool.h | 6 + net/wireless_ath/genregdb.awk | 119 + net/wireless_ath/ibss.c | 527 ++ net/wireless_ath/lib80211.c | 289 + net/wireless_ath/lib80211_crypt_ccmp.c | 491 + net/wireless_ath/lib80211_crypt_tkip.c | 780 ++ net/wireless_ath/lib80211_crypt_wep.c | 290 + net/wireless_ath/mesh.c | 165 + net/wireless_ath/mlme.c | 1191 +++ net/wireless_ath/nl80211.c | 8154 +++++++++++++++++ net/wireless_ath/nl80211.h | 139 + net/wireless_ath/radiotap.c | 358 + net/wireless_ath/reg.c | 2299 +++++ net/wireless_ath/reg.h | 87 + net/wireless_ath/regdb.h | 7 + net/wireless_ath/scan.c | 1352 +++ net/wireless_ath/sme.c | 1041 +++ net/wireless_ath/sysfs.c | 157 + net/wireless_ath/sysfs.h | 9 + net/wireless_ath/util.c | 1219 +++ net/wireless_ath/wext-compat.c | 1531 ++++ net/wireless_ath/wext-compat.h | 57 + net/wireless_ath/wext-core.c | 1123 +++ net/wireless_ath/wext-priv.c | 249 + net/wireless_ath/wext-proc.c | 159 + net/wireless_ath/wext-sme.c | 408 + net/wireless_ath/wext-spy.c | 232 + scripts/mkcompile_h | 4 +- security/Kconfig | 0 security/Makefile | 0 security/apparmor/.gitignore | 0 security/apparmor/Kconfig | 0 security/apparmor/Makefile | 0 security/apparmor/apparmorfs.c | 0 security/apparmor/audit.c | 0 security/apparmor/capability.c | 0 security/apparmor/context.c | 0 security/apparmor/domain.c | 0 security/apparmor/file.c | 0 security/apparmor/include/apparmor.h | 1 - security/apparmor/include/apparmorfs.h | 0 security/apparmor/include/audit.h | 0 security/apparmor/include/capability.h | 0 security/apparmor/include/context.h | 0 security/apparmor/include/domain.h | 0 security/apparmor/include/file.h | 0 security/apparmor/include/ipc.h | 0 security/apparmor/include/match.h | 0 security/apparmor/include/path.h | 0 security/apparmor/include/policy.h | 0 security/apparmor/include/policy_unpack.h | 0 security/apparmor/include/procattr.h | 0 security/apparmor/include/resource.h | 0 security/apparmor/include/sid.h | 0 security/apparmor/ipc.c | 0 security/apparmor/lib.c | 31 - security/apparmor/lsm.c | 0 security/apparmor/match.c | 0 security/apparmor/path.c | 0 security/apparmor/policy.c | 0 security/apparmor/policy_unpack.c | 0 security/apparmor/procattr.c | 0 security/apparmor/resource.c | 0 security/apparmor/sid.c | 0 security/capability.c | 28 +- security/commoncap.c | 0 security/device_cgroup.c | 0 security/inode.c | 0 security/integrity/Kconfig | 0 security/integrity/Makefile | 0 security/integrity/digsig.c | 0 security/integrity/evm/Kconfig | 0 security/integrity/evm/Makefile | 0 security/integrity/evm/evm.h | 0 security/integrity/evm/evm_crypto.c | 0 security/integrity/evm/evm_main.c | 0 security/integrity/evm/evm_posix_acl.c | 0 security/integrity/evm/evm_secfs.c | 0 security/integrity/iint.c | 0 security/integrity/ima/Kconfig | 0 security/integrity/ima/Makefile | 0 security/integrity/ima/ima.h | 0 security/integrity/ima/ima_api.c | 0 security/integrity/ima/ima_audit.c | 0 security/integrity/ima/ima_crypto.c | 0 security/integrity/ima/ima_fs.c | 0 security/integrity/ima/ima_init.c | 0 security/integrity/ima/ima_main.c | 0 security/integrity/ima/ima_policy.c | 0 security/integrity/ima/ima_queue.c | 0 security/integrity/integrity.h | 0 security/keys/Makefile | 0 security/keys/compat.c | 3 + security/keys/encrypted-keys/Makefile | 0 .../keys/encrypted-keys/ecryptfs_format.c | 0 .../keys/encrypted-keys/ecryptfs_format.h | 0 security/keys/encrypted-keys/encrypted.c | 2 + security/keys/encrypted-keys/encrypted.h | 0 .../keys/encrypted-keys/masterkey_trusted.c | 0 security/keys/gc.c | 98 +- security/keys/internal.h | 15 +- security/keys/key.c | 22 + security/keys/keyctl.c | 34 + security/keys/keyring.c | 120 +- security/keys/permission.c | 15 +- security/keys/proc.c | 3 +- security/keys/process_keys.c | 0 security/keys/request_key.c | 0 security/keys/request_key_auth.c | 0 security/keys/sysctl.c | 0 security/keys/trusted.c | 5 +- security/keys/trusted.h | 0 security/keys/user_defined.c | 5 +- security/lsm_audit.c | 15 + security/min_addr.c | 0 security/security.c | 24 +- security/selinux/.gitignore | 0 security/selinux/Kconfig | 7 + security/selinux/Makefile | 0 security/selinux/avc.c | 438 +- security/selinux/exports.c | 0 security/selinux/hooks.c | 132 +- security/selinux/include/audit.h | 0 security/selinux/include/avc.h | 5 + security/selinux/include/avc_ss.h | 0 security/selinux/include/classmap.h | 5 +- security/selinux/include/conditional.h | 0 .../selinux/include/initial_sid_to_string.h | 0 security/selinux/include/netif.h | 0 security/selinux/include/netlabel.h | 0 security/selinux/include/netnode.h | 0 security/selinux/include/netport.h | 0 security/selinux/include/objsec.h | 1 - security/selinux/include/security.h | 37 +- security/selinux/include/xfrm.h | 0 security/selinux/netif.c | 0 security/selinux/netlabel.c | 0 security/selinux/netlink.c | 0 security/selinux/netnode.c | 0 security/selinux/netport.c | 0 security/selinux/nlmsgtab.c | 2 + security/selinux/selinuxfs.c | 7 + security/selinux/ss/avtab.c | 94 +- security/selinux/ss/avtab.h | 25 +- security/selinux/ss/conditional.c | 32 +- security/selinux/ss/conditional.h | 6 +- security/selinux/ss/constraint.h | 1 + security/selinux/ss/context.h | 20 + security/selinux/ss/ebitmap.c | 0 security/selinux/ss/ebitmap.h | 0 security/selinux/ss/hashtab.c | 0 security/selinux/ss/hashtab.h | 0 security/selinux/ss/mls.c | 24 + security/selinux/ss/mls.h | 0 security/selinux/ss/mls_types.h | 0 security/selinux/ss/policydb.c | 145 +- security/selinux/ss/policydb.h | 25 + security/selinux/ss/services.c | 249 +- security/selinux/ss/services.h | 6 + security/selinux/ss/sidtab.c | 0 security/selinux/ss/sidtab.h | 0 security/selinux/ss/status.c | 0 security/selinux/ss/symtab.c | 0 security/selinux/ss/symtab.h | 0 security/selinux/xfrm.c | 0 security/smack/Kconfig | 0 security/smack/Makefile | 0 security/smack/smack.h | 0 security/smack/smack_access.c | 0 security/smack/smack_lsm.c | 4 +- security/smack/smackfs.c | 0 security/tomoyo/.gitignore | 0 security/tomoyo/Kconfig | 0 security/tomoyo/Makefile | 0 security/tomoyo/audit.c | 0 security/tomoyo/common.c | 0 security/tomoyo/common.h | 2 +- security/tomoyo/condition.c | 0 security/tomoyo/domain.c | 0 security/tomoyo/environ.c | 0 security/tomoyo/file.c | 0 security/tomoyo/gc.c | 0 security/tomoyo/group.c | 0 security/tomoyo/load_policy.c | 0 security/tomoyo/memory.c | 0 security/tomoyo/mount.c | 5 +- security/tomoyo/network.c | 0 security/tomoyo/realpath.c | 0 security/tomoyo/securityfs_if.c | 0 security/tomoyo/tomoyo.c | 4 +- security/tomoyo/util.c | 0 security/yama/Kconfig | 0 security/yama/Makefile | 0 security/yama/yama_lsm.c | 0 weritos_defconfig | 3484 +++++++ 831 files changed, 166143 insertions(+), 20788 deletions(-) delete mode 100644 Documentation/devicetree/bindings/arm/msm/msm_bus.txt create mode 100644 arch/arm/configs/jsr_i6_defconfig create mode 100644 arch/arm/configs/weritos_defconfig create mode 100644 "arch/arm/configs/weritos_defconfig (\320\272\320\276\320\277\320\270\321\217)" create mode 100644 arch/arm/include/asm.zip create mode 100644 arch/arm/mach-msm/board-msm7627a_i6-display.c create mode 100644 arch/arm/mach-msm/board-msm7x27a_i6.c create mode 100644 arch/arm/mach-msm/board-msm7x27a_i6.cd create mode 100644 arch/arm/mach-msm/board-qrd7627a_i6.c create mode 100644 arch/arm/mach-msm/bricked_hotplug.c create mode 100644 arch/arm/mach-msm/intelli_plug.c delete mode 100644 arch/arm/mach-msm/msm_bus/msm_bus_of.c create mode 100644 arch/arm/mach-msm/rpcrouter_sdio_xprt.c create mode 100644 arch/arm/mach-msm/sdio_al.c create mode 100644 arch/arm/mach-msm/sdio_al_dloader.c create mode 100644 arch/arm/mach-msm/sdio_al_private.h create mode 100644 arch/arm/mach-msm/sdio_al_test.c create mode 100644 arch/arm/mach-msm/sdio_cmux.c create mode 100644 arch/arm/mach-msm/sdio_ctl.c create mode 100644 arch/arm/mach-msm/sdio_dmux.c create mode 100644 arch/arm/mach-msm/sdio_smem.c create mode 100644 arch/arm/mach-msm/sdio_tty.c create mode 100644 arch/arm/mm/dma-mapping.cd create mode 100644 block/bfq-cgroup.c create mode 100644 block/bfq-ioc.c create mode 100644 block/bfq-iosched.c create mode 100644 block/bfq-sched.c create mode 100644 block/bfq.h create mode 100644 block/row-iosched.c create mode 100755 block/sio-iosched.c create mode 100644 block/sioplus-iosched.c create mode 100644 block/vr-iosched.c create mode 100644 block/zen-iosched.c rename drivers/{staging => block}/zram/Kconfig (58%) create mode 100644 drivers/block/zram/Makefile create mode 100644 drivers/block/zram/zcomp.c create mode 100644 drivers/block/zram/zcomp.h create mode 100644 drivers/block/zram/zcomp_lz4.c create mode 100644 drivers/block/zram/zcomp_lz4.h create mode 100644 drivers/block/zram/zcomp_lzo.c create mode 100644 drivers/block/zram/zcomp_lzo.h rename drivers/{staging => block}/zram/zram_drv.c (66%) rename drivers/{staging => block}/zram/zram_drv.h (61%) create mode 100644 drivers/cpufreq/cpufreq_adaptive.c create mode 100644 drivers/cpufreq/cpufreq_alucard.c create mode 100644 drivers/cpufreq/cpufreq_hyper.c create mode 100644 drivers/cpufreq/cpufreq_intelliactive.c create mode 100644 drivers/cpufreq/cpufreq_intellidemand.c create mode 100644 drivers/cpufreq/cpufreq_intellimm.c create mode 100644 drivers/cpufreq/cpufreq_interactivex.c create mode 100755 drivers/cpufreq/cpufreq_lionheart.c create mode 100644 drivers/cpufreq/cpufreq_ondemandx.c create mode 100644 drivers/cpufreq/cpufreq_smartass2.c create mode 100644 drivers/cpufreq/cpufreq_smartassH3.c create mode 100644 drivers/gpu/msm/Kconfig create mode 100644 drivers/gpu/msm/adreno_debugfs.h create mode 100644 drivers/gpu/msm/adreno_dispatch.c create mode 100644 drivers/gpu/msm/adreno_postmortem.h mode change 100644 => 100755 drivers/gpu/msm/adreno_ringbuffer.c create mode 100644 drivers/gpu/msm/adreno_trace.c create mode 100644 drivers/gpu/msm/adreno_trace.h mode change 100755 => 100644 drivers/gpu/msm/kgsl_sharedmem.c mode change 100644 => 100755 drivers/net/wireless/ath/ath.h mode change 100644 => 100755 drivers/net/wireless/ath/ath5k/base.c mode change 100644 => 100755 drivers/net/wireless/ath/ath5k/mac80211-ops.c create mode 100644 drivers/net/wireless/ath/ath6kl/ath.h create mode 100644 drivers/net/wireless/ath/ath6kl/btc.h create mode 100644 drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.c create mode 100644 drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.h delete mode 100644 drivers/net/wireless/ath/ath6kl/core.c create mode 100644 drivers/net/wireless/ath/ath6kl/debugfs_pri.c create mode 100644 drivers/net/wireless/ath/ath6kl/debugfs_pri.h create mode 100644 drivers/net/wireless/ath/ath6kl/platform.c create mode 100644 drivers/net/wireless/ath/ath6kl/pm.c create mode 100644 drivers/net/wireless/ath/ath6kl/pm.h create mode 100644 drivers/net/wireless/ath/ath6kl/recovery.c create mode 100644 drivers/net/wireless/ath/ath6kl/regd.c create mode 100644 drivers/net/wireless/ath/ath6kl/regd.h create mode 100644 drivers/net/wireless/ath/ath6kl/regd_ath.h create mode 100644 drivers/net/wireless/ath/ath6kl/regd_common.h create mode 100644 drivers/net/wireless/ath/ath6kl/softmac.c create mode 100644 drivers/net/wireless/ath/ath6kl/wmi_btcoex.c create mode 100644 drivers/net/wireless/ath/ath6kl/wmi_btcoex.h create mode 100644 drivers/net/wireless/ath/ath6kl/wmiconfig.c create mode 100644 drivers/net/wireless/ath/ath6kl/wmiconfig.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/Kconfig mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/ar9002_mac.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/ar9003_calib.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/ar9003_eeprom.h create mode 100644 drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/ath9k.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/beacon.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/calib.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/common.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/htc_drv_init.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/htc_drv_main.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/htc_hst.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/init.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/main.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/pci.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/rc.h mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/recv.c mode change 100644 => 100755 drivers/net/wireless/ath/ath9k/xmit.c mode change 100644 => 100755 drivers/net/wireless/ath/key.c create mode 100644 drivers/staging/android/binder_trace.h delete mode 100644 drivers/staging/qcache/Kconfig delete mode 100644 drivers/staging/qcache/Makefile delete mode 100644 drivers/staging/qcache/fmem.c delete mode 100644 drivers/staging/qcache/qcache-main.c delete mode 100644 drivers/staging/qcache/tmem.c delete mode 100644 drivers/staging/qcache/tmem.h delete mode 100644 drivers/staging/zram/Makefile delete mode 100644 drivers/staging/zram/zram.txt delete mode 100644 drivers/staging/zsmalloc/Kconfig delete mode 100644 drivers/staging/zsmalloc/Makefile create mode 100644 drivers/video/msm.zip create mode 100644 drivers/video/msm/mdp4_overlay.c.save mode change 100644 => 100755 drivers/video/msm/mdp_dma.c mode change 100644 => 100755 drivers/video/msm/mipi_byd_otm9608a_wg451v.c create mode 100755 "drivers/video/msm/mipi_div4_nt35510_cmd_wvga (\320\272\320\276\320\277\320\270.c" mode change 100644 => 100755 drivers/video/msm/mipi_div4_nt35510_cmd_wvga.c mode change 100644 => 100755 drivers/video/msm/mipi_hx8389b_video_qhd_pt.c mode change 100644 => 100755 drivers/video/msm/mipi_nt35516_e808t.c mode change 100644 => 100755 drivers/video/msm/mipi_otm9605a.c mode change 100644 => 100755 drivers/video/msm/mipi_yassy_otm9608a_wg451v.c mode change 100644 => 100755 drivers/video/msm/msm_dss_io_7x27a.c create mode 100644 drivers/video/msm/msm_fb.c- mode change 100644 => 100755 drivers/video/msm/msm_fb_bl.c mode change 100644 => 100755 drivers/video/msm/msm_fb_panel.h create mode 100644 include/compat/linux/ath9k_platform.h create mode 100644 include/compat/linux/atomic.h create mode 100644 include/compat/linux/average.h create mode 100644 include/compat/linux/bcma/bcma.h create mode 100644 include/compat/linux/bcma/bcma_driver_chipcommon.h create mode 100644 include/compat/linux/bcma/bcma_driver_mips.h create mode 100644 include/compat/linux/bcma/bcma_driver_pci.h create mode 100644 include/compat/linux/bcma/bcma_regs.h create mode 100644 include/compat/linux/bcma/bcma_soc.h create mode 100644 include/compat/linux/bitops.h create mode 100644 include/compat/linux/compat-2.6.14.h create mode 100644 include/compat/linux/compat-2.6.18.h create mode 100644 include/compat/linux/compat-2.6.19.h create mode 100644 include/compat/linux/compat-2.6.20.h create mode 100644 include/compat/linux/compat-2.6.21.h create mode 100644 include/compat/linux/compat-2.6.22.h create mode 100644 include/compat/linux/compat-2.6.23.h create mode 100644 include/compat/linux/compat-2.6.24.h create mode 100644 include/compat/linux/compat-2.6.25.h create mode 100644 include/compat/linux/compat-2.6.26.h create mode 100644 include/compat/linux/compat-2.6.27.h create mode 100644 include/compat/linux/compat-2.6.28.h create mode 100644 include/compat/linux/compat-2.6.29.h create mode 100644 include/compat/linux/compat-2.6.30.h create mode 100644 include/compat/linux/compat-2.6.31.h create mode 100644 include/compat/linux/compat-2.6.32.h create mode 100644 include/compat/linux/compat-2.6.33.h create mode 100644 include/compat/linux/compat-2.6.34.h create mode 100644 include/compat/linux/compat-2.6.35.h create mode 100644 include/compat/linux/compat-2.6.36.h create mode 100644 include/compat/linux/compat-2.6.37.h create mode 100644 include/compat/linux/compat-2.6.38.h create mode 100644 include/compat/linux/compat-2.6.39.h create mode 100644 include/compat/linux/compat-2.6.h create mode 100644 include/compat/linux/compat-3.0.h create mode 100644 include/compat/linux/compat-3.1.h create mode 100644 include/compat/linux/compat-3.2.h create mode 100644 include/compat/linux/compat-3.3.h create mode 100644 include/compat/linux/compat-3.4.h create mode 100644 include/compat/linux/compat-3.5.h create mode 100644 include/compat/linux/compat_autoconf.h create mode 100644 include/compat/linux/cordic.h create mode 100644 include/compat/linux/crc8.h create mode 100644 include/compat/linux/eeprom_93cx6.h create mode 100644 include/compat/linux/export.h create mode 100644 include/compat/linux/ieee80211.h create mode 100644 include/compat/linux/kfifo.h create mode 100644 include/compat/linux/math64.h create mode 100644 include/compat/linux/nl80211.h create mode 100644 include/compat/linux/of.h create mode 100644 include/compat/linux/pci-aspm.h create mode 100644 include/compat/linux/pci_ids.h create mode 100644 include/compat/linux/pm_qos.h create mode 100644 include/compat/linux/pm_qos_params.h create mode 100644 include/compat/linux/pm_runtime.h create mode 100644 include/compat/linux/printk.h create mode 100644 include/compat/linux/rfkill.h create mode 100644 include/compat/linux/rfkill_backport.h create mode 100644 include/compat/linux/semaphore.h create mode 100644 include/compat/linux/spi/libertas_spi.h create mode 100644 include/compat/linux/ssb/ssb.h create mode 100644 include/compat/linux/ssb/ssb_driver_chipcommon.h create mode 100644 include/compat/linux/ssb/ssb_driver_extif.h create mode 100644 include/compat/linux/ssb/ssb_driver_gige.h create mode 100644 include/compat/linux/ssb/ssb_driver_mips.h create mode 100644 include/compat/linux/ssb/ssb_driver_pci.h create mode 100644 include/compat/linux/ssb/ssb_embedded.h create mode 100644 include/compat/linux/ssb/ssb_regs.h create mode 100644 include/compat/linux/tracepoint.h create mode 100644 include/compat/linux/unaligned/access_ok.h create mode 100644 include/compat/linux/unaligned/be_byteshift.h create mode 100644 include/compat/linux/unaligned/be_memmove.h create mode 100644 include/compat/linux/unaligned/be_struct.h create mode 100644 include/compat/linux/unaligned/generic.h create mode 100644 include/compat/linux/unaligned/le_byteshift.h create mode 100644 include/compat/linux/unaligned/le_memmove.h create mode 100644 include/compat/linux/unaligned/le_struct.h create mode 100644 include/compat/linux/unaligned/memmove.h create mode 100644 include/compat/linux/unaligned/packed_struct.h create mode 100644 include/compat/linux/usb/rndis_host.h create mode 100644 include/compat/linux/usb/usbnet.h create mode 100644 include/compat/linux/wireless.h create mode 100644 include/compat/linux/wl12xx.h create mode 100644 include/compat/net/bluetooth/bluetooth.h create mode 100644 include/compat/net/bluetooth/hci.h create mode 100644 include/compat/net/bluetooth/hci_core.h create mode 100644 include/compat/net/bluetooth/l2cap.h create mode 100644 include/compat/net/bluetooth/mgmt.h create mode 100644 include/compat/net/bluetooth/rfcomm.h create mode 100644 include/compat/net/bluetooth/smp.h create mode 100644 include/compat/net/cfg80211-wext.h create mode 100644 include/compat/net/cfg80211.h create mode 100644 include/compat/net/ieee80211_radiotap.h create mode 100644 include/compat/net/lib80211.h create mode 100644 include/compat/net/mac80211.h create mode 100644 include/compat/net/net_namespace.h create mode 100644 include/compat/net/regulatory.h create mode 100644 include/linux/frontswap.h create mode 100644 include/linux/swapfile.h rename {drivers/staging/zsmalloc => include/linux}/zsmalloc.h (77%) create mode 100644 include/trace/binder_trace.h create mode 100644 include/trace/events/sync.h create mode 100644 mm/frontswap.c rename drivers/staging/zsmalloc/zsmalloc-main.c => mm/zsmalloc.c (88%) mode change 100644 => 100755 net/bluetooth/af_bluetooth.c mode change 100644 => 100755 net/bluetooth/hci_core.c mode change 100644 => 100755 net/bluetooth/hci_sock.c create mode 100644 net/bluetooth/l2cap.c mode change 100644 => 100755 net/bluetooth/rfcomm/sock.c create mode 100644 net/wireless_ath/Makefile create mode 100644 net/wireless_ath/Makefile.bk create mode 100644 net/wireless_ath/chan.c create mode 100644 net/wireless_ath/core.c create mode 100644 net/wireless_ath/core.h create mode 100644 net/wireless_ath/db.txt create mode 100644 net/wireless_ath/debugfs.c create mode 100644 net/wireless_ath/debugfs.h create mode 100644 net/wireless_ath/ethtool.c create mode 100644 net/wireless_ath/ethtool.h create mode 100644 net/wireless_ath/genregdb.awk create mode 100644 net/wireless_ath/ibss.c create mode 100644 net/wireless_ath/lib80211.c create mode 100644 net/wireless_ath/lib80211_crypt_ccmp.c create mode 100644 net/wireless_ath/lib80211_crypt_tkip.c create mode 100644 net/wireless_ath/lib80211_crypt_wep.c create mode 100644 net/wireless_ath/mesh.c create mode 100644 net/wireless_ath/mlme.c create mode 100644 net/wireless_ath/nl80211.c create mode 100644 net/wireless_ath/nl80211.h create mode 100644 net/wireless_ath/radiotap.c create mode 100644 net/wireless_ath/reg.c create mode 100644 net/wireless_ath/reg.h create mode 100644 net/wireless_ath/regdb.h create mode 100644 net/wireless_ath/scan.c create mode 100644 net/wireless_ath/sme.c create mode 100644 net/wireless_ath/sysfs.c create mode 100644 net/wireless_ath/sysfs.h create mode 100644 net/wireless_ath/util.c create mode 100644 net/wireless_ath/wext-compat.c create mode 100644 net/wireless_ath/wext-compat.h create mode 100644 net/wireless_ath/wext-core.c create mode 100644 net/wireless_ath/wext-priv.c create mode 100644 net/wireless_ath/wext-proc.c create mode 100644 net/wireless_ath/wext-sme.c create mode 100644 net/wireless_ath/wext-spy.c mode change 100755 => 100644 security/Kconfig mode change 100755 => 100644 security/Makefile mode change 100755 => 100644 security/apparmor/.gitignore mode change 100755 => 100644 security/apparmor/Kconfig mode change 100755 => 100644 security/apparmor/Makefile mode change 100755 => 100644 security/apparmor/apparmorfs.c mode change 100755 => 100644 security/apparmor/audit.c mode change 100755 => 100644 security/apparmor/capability.c mode change 100755 => 100644 security/apparmor/context.c mode change 100755 => 100644 security/apparmor/domain.c mode change 100755 => 100644 security/apparmor/file.c mode change 100755 => 100644 security/apparmor/include/apparmor.h mode change 100755 => 100644 security/apparmor/include/apparmorfs.h mode change 100755 => 100644 security/apparmor/include/audit.h mode change 100755 => 100644 security/apparmor/include/capability.h mode change 100755 => 100644 security/apparmor/include/context.h mode change 100755 => 100644 security/apparmor/include/domain.h mode change 100755 => 100644 security/apparmor/include/file.h mode change 100755 => 100644 security/apparmor/include/ipc.h mode change 100755 => 100644 security/apparmor/include/match.h mode change 100755 => 100644 security/apparmor/include/path.h mode change 100755 => 100644 security/apparmor/include/policy.h mode change 100755 => 100644 security/apparmor/include/policy_unpack.h mode change 100755 => 100644 security/apparmor/include/procattr.h mode change 100755 => 100644 security/apparmor/include/resource.h mode change 100755 => 100644 security/apparmor/include/sid.h mode change 100755 => 100644 security/apparmor/ipc.c mode change 100755 => 100644 security/apparmor/lib.c mode change 100755 => 100644 security/apparmor/lsm.c mode change 100755 => 100644 security/apparmor/match.c mode change 100755 => 100644 security/apparmor/path.c mode change 100755 => 100644 security/apparmor/policy.c mode change 100755 => 100644 security/apparmor/policy_unpack.c mode change 100755 => 100644 security/apparmor/procattr.c mode change 100755 => 100644 security/apparmor/resource.c mode change 100755 => 100644 security/apparmor/sid.c mode change 100755 => 100644 security/capability.c mode change 100755 => 100644 security/commoncap.c mode change 100755 => 100644 security/device_cgroup.c mode change 100755 => 100644 security/inode.c mode change 100755 => 100644 security/integrity/Kconfig mode change 100755 => 100644 security/integrity/Makefile mode change 100755 => 100644 security/integrity/digsig.c mode change 100755 => 100644 security/integrity/evm/Kconfig mode change 100755 => 100644 security/integrity/evm/Makefile mode change 100755 => 100644 security/integrity/evm/evm.h mode change 100755 => 100644 security/integrity/evm/evm_crypto.c mode change 100755 => 100644 security/integrity/evm/evm_main.c mode change 100755 => 100644 security/integrity/evm/evm_posix_acl.c mode change 100755 => 100644 security/integrity/evm/evm_secfs.c mode change 100755 => 100644 security/integrity/iint.c mode change 100755 => 100644 security/integrity/ima/Kconfig mode change 100755 => 100644 security/integrity/ima/Makefile mode change 100755 => 100644 security/integrity/ima/ima.h mode change 100755 => 100644 security/integrity/ima/ima_api.c mode change 100755 => 100644 security/integrity/ima/ima_audit.c mode change 100755 => 100644 security/integrity/ima/ima_crypto.c mode change 100755 => 100644 security/integrity/ima/ima_fs.c mode change 100755 => 100644 security/integrity/ima/ima_init.c mode change 100755 => 100644 security/integrity/ima/ima_main.c mode change 100755 => 100644 security/integrity/ima/ima_policy.c mode change 100755 => 100644 security/integrity/ima/ima_queue.c mode change 100755 => 100644 security/integrity/integrity.h mode change 100755 => 100644 security/keys/Makefile mode change 100755 => 100644 security/keys/compat.c mode change 100755 => 100644 security/keys/encrypted-keys/Makefile mode change 100755 => 100644 security/keys/encrypted-keys/ecryptfs_format.c mode change 100755 => 100644 security/keys/encrypted-keys/ecryptfs_format.h mode change 100755 => 100644 security/keys/encrypted-keys/encrypted.c mode change 100755 => 100644 security/keys/encrypted-keys/encrypted.h mode change 100755 => 100644 security/keys/encrypted-keys/masterkey_trusted.c mode change 100755 => 100644 security/keys/gc.c mode change 100755 => 100644 security/keys/internal.h mode change 100755 => 100644 security/keys/key.c mode change 100755 => 100644 security/keys/keyctl.c mode change 100755 => 100644 security/keys/keyring.c mode change 100755 => 100644 security/keys/permission.c mode change 100755 => 100644 security/keys/proc.c mode change 100755 => 100644 security/keys/process_keys.c mode change 100755 => 100644 security/keys/request_key.c mode change 100755 => 100644 security/keys/request_key_auth.c mode change 100755 => 100644 security/keys/sysctl.c mode change 100755 => 100644 security/keys/trusted.c mode change 100755 => 100644 security/keys/trusted.h mode change 100755 => 100644 security/keys/user_defined.c mode change 100755 => 100644 security/lsm_audit.c mode change 100755 => 100644 security/min_addr.c mode change 100755 => 100644 security/security.c mode change 100755 => 100644 security/selinux/.gitignore mode change 100755 => 100644 security/selinux/Kconfig mode change 100755 => 100644 security/selinux/Makefile mode change 100755 => 100644 security/selinux/avc.c mode change 100755 => 100644 security/selinux/exports.c mode change 100755 => 100644 security/selinux/hooks.c mode change 100755 => 100644 security/selinux/include/audit.h mode change 100755 => 100644 security/selinux/include/avc.h mode change 100755 => 100644 security/selinux/include/avc_ss.h mode change 100755 => 100644 security/selinux/include/classmap.h mode change 100755 => 100644 security/selinux/include/conditional.h mode change 100755 => 100644 security/selinux/include/initial_sid_to_string.h mode change 100755 => 100644 security/selinux/include/netif.h mode change 100755 => 100644 security/selinux/include/netlabel.h mode change 100755 => 100644 security/selinux/include/netnode.h mode change 100755 => 100644 security/selinux/include/netport.h mode change 100755 => 100644 security/selinux/include/objsec.h mode change 100755 => 100644 security/selinux/include/security.h mode change 100755 => 100644 security/selinux/include/xfrm.h mode change 100755 => 100644 security/selinux/netif.c mode change 100755 => 100644 security/selinux/netlabel.c mode change 100755 => 100644 security/selinux/netlink.c mode change 100755 => 100644 security/selinux/netnode.c mode change 100755 => 100644 security/selinux/netport.c mode change 100755 => 100644 security/selinux/selinuxfs.c mode change 100755 => 100644 security/selinux/ss/avtab.c mode change 100755 => 100644 security/selinux/ss/avtab.h mode change 100755 => 100644 security/selinux/ss/conditional.c mode change 100755 => 100644 security/selinux/ss/conditional.h mode change 100755 => 100644 security/selinux/ss/constraint.h mode change 100755 => 100644 security/selinux/ss/context.h mode change 100755 => 100644 security/selinux/ss/ebitmap.c mode change 100755 => 100644 security/selinux/ss/ebitmap.h mode change 100755 => 100644 security/selinux/ss/hashtab.c mode change 100755 => 100644 security/selinux/ss/hashtab.h mode change 100755 => 100644 security/selinux/ss/mls.c mode change 100755 => 100644 security/selinux/ss/mls.h mode change 100755 => 100644 security/selinux/ss/mls_types.h mode change 100755 => 100644 security/selinux/ss/policydb.c mode change 100755 => 100644 security/selinux/ss/policydb.h mode change 100755 => 100644 security/selinux/ss/services.c mode change 100755 => 100644 security/selinux/ss/services.h mode change 100755 => 100644 security/selinux/ss/sidtab.c mode change 100755 => 100644 security/selinux/ss/sidtab.h mode change 100755 => 100644 security/selinux/ss/status.c mode change 100755 => 100644 security/selinux/ss/symtab.c mode change 100755 => 100644 security/selinux/ss/symtab.h mode change 100755 => 100644 security/selinux/xfrm.c mode change 100755 => 100644 security/smack/Kconfig mode change 100755 => 100644 security/smack/Makefile mode change 100755 => 100644 security/smack/smack.h mode change 100755 => 100644 security/smack/smack_access.c mode change 100755 => 100644 security/smack/smack_lsm.c mode change 100755 => 100644 security/smack/smackfs.c mode change 100755 => 100644 security/tomoyo/.gitignore mode change 100755 => 100644 security/tomoyo/Kconfig mode change 100755 => 100644 security/tomoyo/Makefile mode change 100755 => 100644 security/tomoyo/audit.c mode change 100755 => 100644 security/tomoyo/common.c mode change 100755 => 100644 security/tomoyo/common.h mode change 100755 => 100644 security/tomoyo/condition.c mode change 100755 => 100644 security/tomoyo/domain.c mode change 100755 => 100644 security/tomoyo/environ.c mode change 100755 => 100644 security/tomoyo/file.c mode change 100755 => 100644 security/tomoyo/gc.c mode change 100755 => 100644 security/tomoyo/group.c mode change 100755 => 100644 security/tomoyo/load_policy.c mode change 100755 => 100644 security/tomoyo/memory.c mode change 100755 => 100644 security/tomoyo/mount.c mode change 100755 => 100644 security/tomoyo/network.c mode change 100755 => 100644 security/tomoyo/realpath.c mode change 100755 => 100644 security/tomoyo/securityfs_if.c mode change 100755 => 100644 security/tomoyo/tomoyo.c mode change 100755 => 100644 security/tomoyo/util.c mode change 100755 => 100644 security/yama/Kconfig mode change 100755 => 100644 security/yama/Makefile mode change 100755 => 100644 security/yama/yama_lsm.c create mode 100644 weritos_defconfig diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt deleted file mode 100644 index 1ec3081e..00000000 --- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt +++ /dev/null @@ -1,34 +0,0 @@ -MSM Bus Scaling Driver - -The msm bus scaling driver provides the ability to configure -bus performance parameters across the entire chip-set. -Various clients use MSM scaling APIs to request bandwidth -between multiple master-slave pairs. The bus driver then finds -the optimal path between the master and the slave, and aggregates -the bandwidth and clock requests for all master-slave pairs on -that path, and programs hardware accordingly. - -The device-tree data required for bus-scaling can be embedded within -the clients' device nodes. The clients can register with the bus driver -using the following properties: - -- qcom,msm_bus,name: String representing the client-name -- qcom,msm_bus,num_cases: Total number of usecases -- qcom,msm_bus,active_only: Context flag for requests in active or - dual (active & sleep) contex -- qcom,msm_bus,num_paths: Total number of master-slave pairs -- qcom,msm_bus,vectors: Arrays of unsigned integers representing: - master-id, slave-id, arbitrated bandwidth, - instantaneous bandwidth - -Example: - - qcom,msm_bus,name = "client-name"; - qcom,msm_bus,num_cases = <3>; - qcom,msm_bus,active_only = <0>; - qcom,msm_bus,num_paths = <2>; - qcom,msm_bus,vectors = - <22 512 0 0>, <26 512 0 0>, - <22 512 320000 320000000>, <26 512 3200000 320000000>, - <22 512 160000 160000000>, <26 512 1600000 160000000>; - diff --git a/Makefile b/Makefile index de570d00..09a1f8e2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 4 SUBLEVEL = 110 -EXTRAVERSION = --ThE-ShAdOw-v1.1-- +EXTRAVERSION = NAME = Saber-toothed Squirrel # *DOCUMENTATION* @@ -162,7 +162,7 @@ export srctree objtree VPATH # SUBARCH tells the usermode build what the underlying arch is. That is set # first, and if a usermode build is happening, the "ARCH=um" on the command # line overrides the setting of ARCH below. If a native build is happening, -# then ARCH is assigned, getting whatever value it gets normally, and +# then ARCH is assigned, getting whatever value it gets normally, and # SUBARCH is subsequently ignored. SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ @@ -171,6 +171,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ ) +SUBARCH := arm + # Cross compiling and selecting different set of gcc/bin-utils # --------------------------------------------------------------------------- # @@ -192,7 +194,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ # Default value for CROSS_COMPILE is not to prefix executables # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile export KBUILD_BUILDHOST := $(SUBARCH) -ARCH ?= arm +ARCH ?=arm CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) # Architecture as present in compile.h @@ -243,10 +245,10 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) -HOSTCC = ccache gcc -HOSTCXX = ccache g++ -HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O3 -fomit-frame-pointer -HOSTCXXFLAGS = -O3 +HOSTCC = gcc +HOSTCXX = g++ +HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCXXFLAGS = -O2 # Decide whether to build built-in, modular, or both. # Normally, just do built-in. @@ -289,7 +291,7 @@ export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD # cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< # # If $(quiet) is empty, the whole command will be printed. -# If it is set to "quiet_", only the short version will be printed. +# If it is set to "quiet_", only the short version will be printed. # If it is set to "silent_", nothing will be printed at all, since # the variable $(silent_cmd_cc_o_c) doesn't exist. # @@ -330,7 +332,7 @@ include $(srctree)/scripts/Kbuild.include AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld -REAL_CC = ccache $(CROSS_COMPILE)gcc +REAL_CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm @@ -347,24 +349,17 @@ CHECK = sparse # Use the wrapper for the compiler. This wrapper scans for new # warnings and causes the build to stop upon encountering them. -CC = $(srctree)/scripts/gcc-wrapper.py $(REAL_CC) - -CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ - -Wbitwise -Wno-return-void $(CF) +CC = $(srctree)/scripts/gcc-wrapper.py $(REAL_CC) -LIN_FLAG = -mfloat-abi=soft -munaligned-access -marm -march=armv7-a -mtune=cortex-a5 -mfpu=neon-vfpv4 -mvectorize-with-neon-quad \ - -ffloat-store -ffast-math -foptimize-sibling-calls -fcrossjumping -fgcse-lm -fgcse-sm -fgcse-las -fsched-spec-load \ - -fforce-addr -fsingle-precision-constant -funsafe-math-optimizations -ftree-vectorize -funswitch-loops -fno-toplevel-reorder \ - -fuse-linker-plugin -fpredictive-commoning -fgraphite -fgraphite-identity -ftree-loop-linear -floop-interchange -floop-strip-mine \ - -floop-block -fsanitize=leak -fopenmp -lgomp -lgcc -pipe +CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ + -Wbitwise -Wno-return-void $(CF) +CFLAGS_MODULE = +AFLAGS_MODULE = +LDFLAGS_MODULE = +CFLAGS_KERNEL = +AFLAGS_KERNEL = +CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -MODFLAGS = -DMODULE $(LIN_FLAG) -CFLAGS_MODULE = $(MODFLAGS) -fno-pic -AFLAGS_MODULE = $(MODFLAGS) -fno-pic -LDFLAGS_MODULE = -CFLAGS_KERNEL = $(LIN_FLAG) -AFLAGS_KERNEL = $(LIN_FLAG) -CFLAGS_GCOV = -fprofile-arcs -ftest-coverage # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option @@ -375,22 +370,16 @@ LINUXINCLUDE := -I$(srctree)/arch/$(hdr-arch)/include \ KBUILD_CPPFLAGS := -D__KERNEL__ -# -# Optimizations -# -CFLAGS_A5 = -mtune=cortex-a5 -marm -march=armv7-a -mfpu=neon-vfpv4 -funsafe-math-optimizations -ftree-vectorize -CFLAGS_MODULO = -fmodulo-sched -fmodulo-sched-allow-regmoves -KERNEL_MODS = $(CFLAGS_A5) $(CFLAGS_MODULO) - KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ + -Wno-array-bounds \ + -Wno-maybe-uninitialized \ + -Wno-unused-value \ + -Wno-sequence-point \ + -Wno-address \ -fno-strict-aliasing -fno-common \ -Werror-implicit-function-declaration \ -Wno-format-security \ - -fno-delete-null-pointer-checks \ - -mno-unaligned-access \ - -Wno-sizeof-pointer-memaccess \ - $(KERNEL_MODS) - + -fno-delete-null-pointer-checks KBUILD_AFLAGS_KERNEL := KBUILD_CFLAGS_KERNEL := KBUILD_AFLAGS := -D__ASSEMBLY__ @@ -583,7 +572,7 @@ all: vmlinux ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += -Os else -KBUILD_CFLAGS += -O3 +KBUILD_CFLAGS += -O2 endif include $(srctree)/arch/$(SRCARCH)/Makefile @@ -592,9 +581,6 @@ ifneq ($(CONFIG_FRAME_WARN),0) KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN}) endif -# Tell gcc to never replace conditional load with a non-conditional one -KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) - # Force gcc to behave correct even for buggy distributions ifndef CONFIG_CC_STACKPROTECTOR KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) @@ -617,8 +603,6 @@ KBUILD_CFLAGS += -fomit-frame-pointer endif endif -KBUILD_CFLAGS += $(call cc-option, -fno-var-tracking-assignments) - ifdef CONFIG_DEBUG_INFO KBUILD_CFLAGS += -g KBUILD_AFLAGS += -gdwarf-2 @@ -878,7 +862,7 @@ endef # First command is ':' to allow us to use + in front of this rule cmd_ksym_ld = $(cmd_vmlinux__) define rule_ksym_ld - : + : +$(call cmd,vmlinux_version) $(call cmd,vmlinux__) $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd @@ -957,7 +941,7 @@ modpost-init := $(filter-out init/built-in.o, $(vmlinux-init)) vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE $(call if_changed_rule,vmlinux-modpost) -# The actual objects are generated when descending, +# The actual objects are generated when descending, # make sure no implicit rule kicks in $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; @@ -1547,7 +1531,7 @@ endif $(build)=$(build-dir) $(@:.ko=.o) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost -# FIXME Should go into a make.lib or something +# FIXME Should go into a make.lib or something # =========================================================================== quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN $(wildcard $(rm-dirs))) diff --git a/arch/Kconfig b/arch/Kconfig index 0a3ffe46..0d887601 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -169,6 +169,13 @@ config HAVE_HW_BREAKPOINT bool depends on PERF_EVENTS +config HAVE_HW_BRKPT_RESERVED_RW_ACCESS + bool + depends on HAVE_HW_BREAKPOINT + help + Some of the hardware might not have r/w access beyond a certain number + of breakpoint register access. + config HAVE_MIXED_BREAKPOINTS_REGS bool depends on HAVE_HW_BREAKPOINT diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 71494c87..e1d7bb1c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -28,7 +28,7 @@ config ARM select HAVE_PERF_EVENTS select PERF_USE_VMALLOC select HAVE_REGS_AND_STACK_ACCESS_API - select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) + #select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) select HAVE_C_RECORDMCOUNT select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_SHOW diff --git a/arch/arm/configs/jsr_i6_defconfig b/arch/arm/configs/jsr_i6_defconfig new file mode 100644 index 00000000..ada8750c --- /dev/null +++ b/arch/arm/configs/jsr_i6_defconfig @@ -0,0 +1,3524 @@ +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +## CONFIG_GENERIC_LOCKBREAK=y +## CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARM_TICKET_LOCKS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +## CONFIG_FIQ=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x00200000 +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-Chil360-MM" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +CONFIG_AUDIT=y +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=21 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_TIMER_SLACK=y +CONFIG_CGROUP_DYNAMIC_TIMER_SLACK=y +CONFIG_CGROUP_DEVICE=y +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=3 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_PERF_COUNTERS is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +## CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +## CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_BFQ=y +CONFIG_CGROUP_BFQIO=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_FIOPS=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_SIO=y +CONFIG_IOSCHED_SIOPLUS=y +# CONFIG_IOSCHED_TEST is not set +CONFIG_IOSCHED_VR=y +CONFIG_IOSCHED_ZEN=y +# CONFIG_DEFAULT_BFQ is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_FIOPS is not set +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set +# CONFIG_DEFAULT_SIOPLUS is not set +# CONFIG_DEFAULT_VR is not set +# CONFIG_DEFAULT_ZEN is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +CONFIG_ARCH_MSM7X27=y +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +# CONFIG_ARCH_MSM8960 is not set +# CONFIG_ARCH_MSM8930 is not set +# CONFIG_ARCH_APQ8064 is not set +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +CONFIG_ARCH_MSM8625=y +# CONFIG_ARCH_MSM9625 is not set +# CONFIG_MSM_SOC_REV_NONE is not set +CONFIG_MSM_SOC_REV_A=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +CONFIG_ARCH_MSM_CORTEX_A5=y +CONFIG_ARCH_MSM7X27A=y +CONFIG_MSM_VIC=y +# CONFIG_MSM_RPM is not set +# CONFIG_MSM_RPM_SMD is not set +# CONFIG_MSM_MPM is not set + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM7X27_SURF is not set +# CONFIG_MACH_MSM7X27_FFA is not set +CONFIG_MACH_MSM7X27A_RUMI3=y +CONFIG_MACH_MSM7X27A_SURF=y +CONFIG_MACH_MSM7X27A_FFA=y +# CONFIG_JSR_D9 is not set +# CONFIG_JSR_D9C is not set +CONFIG_MACH_MSM7X27A_I6=y +CONFIG_JSR_KERNEL=y +CONFIG_JSR_I6=y +# CONFIG_JSR_I6C is not set +# CONFIG_JSR_I6C_SMARTFREN is not set +# CONFIG_JSR_I3DC_SMARTFREN is not set +# CONFIG_JSR_I3DC is not set +# CONFIG_JSR_I3D is not set +CONFIG_MACH_MSM7625A_SURF=y +CONFIG_MACH_MSM7625A_FFA=y +CONFIG_MACH_MSM7627A_QRD1=y +CONFIG_MACH_MSM7627A_QRD3=y +CONFIG_MACH_MSM7627A_EVB=y +CONFIG_MACH_MSM8625_RUMI3=y +CONFIG_MACH_MSM8625_SURF=y +CONFIG_MACH_MSM8625_FFA=y +CONFIG_MACH_MSM8625_EVB=y +CONFIG_MACH_MSM8625_EVT=y +CONFIG_MACH_MSM7X27A_QRD5A=y +CONFIG_MACH_MSM8625_QRD7=y +CONFIG_MACH_MSM8625_QRD5=y +CONFIG_MACH_MSM8625Q_SKUD=y +CONFIG_MACH_MSM8625Q_SKUE=y +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +# CONFIG_MSM7X00A_USE_GP_TIMER is not set +CONFIG_MSM7X00A_USE_DG_TIMER=y +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +# CONFIG_CPU_HAS_L2_PMU is not set +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +# CONFIG_MSM_FIQ_SUPPORT is not set +# CONFIG_MSM_SERIAL_DEBUGGER is not set +CONFIG_MSM_PROC_COMM=y +CONFIG_MSM_SMD=y +## CONFIG_MSM_AMSS_ENHANCE_DEBUG=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +## CONFIG_MSM_FUSE_INFO_DEBUG=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_FAST_BOOT=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +# CONFIG_MSM_RESET_MODEM is not set +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +# CONFIG_MSM_SMD_NMEA is not set +CONFIG_MSM_SMD_TTY=y +# CONFIG_MSM_SMD_QMI is not set +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ONCRPCROUTER=y +# CONFIG_MSM_IPC_ROUTER is not set +## CONFIG_MSM_ONCRPCROUTER_DEBUG=y +# CONFIG_MSM_RPC_LOOPBACK_XPRT is not set +# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set +CONFIG_MSM_RPCSERVER_WATCHDOG=y +# CONFIG_MSM_RPC_WATCHDOG is not set +CONFIG_MSM_RPC_PING=y +CONFIG_MSM_RPC_PROC_COMM_TEST=y +CONFIG_MSM_RPC_OEM_RAPI=y +CONFIG_MSM_RPCSERVER_HANDSET=y +CONFIG_MSM_RMT_STORAGE_CLIENT=y +# CONFIG_MSM_RMT_STORAGE_CLIENT_STATS is not set +CONFIG_MSM_DALRPC=y +CONFIG_MSM_DALRPC_TEST=m +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_MSM_ADSP=y +CONFIG_ADSP_RPC_VER=0x30002 +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_MSM_ADSP_REPORT_EVENTS=y +CONFIG_RTAC=y +CONFIG_MSM7X27A_AUDIO=y +CONFIG_MSM_PROC_COMM_REGULATOR=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=y +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_AUDIO_AAC_PLUS=y +CONFIG_AUDIO_ENHANCED_AAC_PLUS=y +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +# CONFIG_MSM_PIL is not set +# CONFIG_MSM_SCM is not set +# CONFIG_MSM_TZ_LOG is not set +# CONFIG_MSM_DIRECT_SCLK_ACCESS is not set +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_MODEM_RESTART=y +CONFIG_MSM_PM2=y +CONFIG_MSM_EVENT_TIMER=y +# CONFIG_MSM_BUS_SCALING is not set +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_JTAG is not set +CONFIG_MSM_SLEEP_STATS_DEVICE=y +## CONFIG_MSM_RUN_QUEUE_STATS=y +## CONFIG_MSM_SM_EVENT=y +## CONFIG_MSM_SM_EVENT_LOG=m +## CONFIG_UNCACHED_BUF=y +## CONFIG_MSM_SLEEP_MONITOR=m +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_MSM_PINTEST=y +# CONFIG_MSM_FAKE_BATTERY is not set +# CONFIG_MSM_QDSP6_APR is not set +# CONFIG_MSM_QDSP6_CODECS is not set +# CONFIG_MSM_QDSP6V2_CODECS is not set +# CONFIG_MSM_AUDIO_QDSP6 is not set +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +CONFIG_MSM_RPC_VIBRATOR=y +CONFIG_PM8XXX_RPC_VIBRATOR=y +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +# CONFIG_MSM_L2_SPM is not set +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +## CONFIG_MSM_CPR=y +CONFIG_MSM_VP_REGULATOR=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +# CONFIG_MSM_8X60_FUSION_GPIO_GLITCH is not set +## CONFIG_MSM_FIQ=y + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +# CONFIG_CACHE_PL310_ERP is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARCH_HAS_BARRIERS=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set +CONFIG_ARM_GIC=y +## CONFIG_GIC_SECURE=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +## CONFIG_OABI_COMPAT=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0xC800000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=2 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +## CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +CONFIG_FRONTSWAP=y +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set +## CONFIG_DYNAMIC_PAGE_WRITEBACK=y +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ARCH_POPULATES_NODE_MAP is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ASSWAX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_BADASS is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_DANCEDANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_LIONHEART is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_LULZACTIVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMANDX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASSH3 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTMAX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_WHEATLEY is not set +CONFIG_CPU_FREQ_GOV_ADAPTIVE=y +# CONFIG_CPU_FREQ_GOV_ASSWAX is not set +CONFIG_CPU_FREQ_GOV_BADASS=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_DANCEDANCE=y +CONFIG_CPU_FREQ_GOV_HYPER=y +CONFIG_CPU_FREQ_GOV_INTELLIDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_LIONHEART=y +CONFIG_CPU_FREQ_GOV_LULZACTIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_ONDEMANDX=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_SMARTASS2 is not set +# CONFIG_CPU_FREQ_GOV_SMARTASSH3 is not set +CONFIG_CPU_FREQ_GOV_SMARTMAX=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_WHEATLEY=y +CONFIG_CPU_FREQ_VDD_LEVELS=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_CPU_IDLE is not set +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +## CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +CONFIG_CPU_PM=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=y +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +CONFIG_TCP_CONG_VEGAS=y +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +CONFIG_TCP_CONG_VENO=y +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_VENO is not set +CONFIG_DEFAULT_WESTWOOD=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="westwood" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_NF_NAT_SIP=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_SECURITY=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCISMD is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_IBS=y +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +CONFIG_BT_MSM_SLEEP=y +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_MSM_BT_POWER=y +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +# CONFIG_CFG80211 is not set +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +# CONFIG_CFG80211_WEXT is not set +# CONFIG_WIRELESS_EXT_SYSFS is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +CONFIG_SW_SYNC_USER=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_PERCENTAGE=5 +# CONFIG_CMA_SIZE_SEL_MBYTES is not set +CONFIG_CMA_SIZE_SEL_PERCENTAGE=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +## CONFIG_MTD_TESTS=m +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +CONFIG_MTD_LAZYECCSTATS=y + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_MSM_NAND=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +## CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +# CONFIG_TSIF is not set +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_QSEECOM is not set +# CONFIG_QFP_FUSE is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set +# CONFIG_MPU_SENSORS_TIMERIRQ is not set +# CONFIG_INV_SENSORS is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851_MLL is not set +CONFIG_MSM_RMNET=y +# CONFIG_MSM_RMNET_DEBUG is not set +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +CONFIG_LIBRA_SDIOIF=m +# CONFIG_ATH6K_LEGACY_EXT is not set +# CONFIG_ATH_COMMON is not set +# CONFIG_BCMDHD is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +## CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y +CONFIG_SYNA_MULTI_TOUCH=y +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_HIMAX is not set +# CONFIG_TOUCHSCREEN_WINPOWER is not set +CONFIG_TOUCHSCREEN_ELAN_KTF2K=y +CONFIG_TS_FT5306=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_INPUT_LTR502 is not set +# CONFIG_BOSCH_BMA250 is not set +# CONFIG_AVAGO_APDS990X is not set +# CONFIG_INPUT_ISL29028 is not set +# CONFIG_INPUT_LIS3DH is not set +# CONFIG_INPUT_LTR558_D9 is not set +# CONFIG_INPUT_LTR558_D9C is not set +CONFIG_INPUT_LTR558_I6=y +# CONFIG_INPUT_LTR558_I6C is not set +# CONFIG_INPUT_LTR558_I6C_SMARTFREN is not set +CONFIG_INPUT_YAS_ACCELEROMETER=y +CONFIG_INPUT_YAS_ACCELEROMETER_POSITION=4 +CONFIG_INPUT_YAS_MAGNETOMETER=y +CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=7 +CONFIG_INPUT_YAS_ORIENTATION=y +CONFIG_MXC_MMA8452=y +CONFIG_MXC_MMA_POSITION=7 + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +## CONFIG_VT=y +## CONFIG_CONSOLE_TRANSLATIONS=y +## CONFIG_VT_CONSOLE=y +## CONFIG_VT_CONSOLE_SLEEP=y +## CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_MSM=y +CONFIG_I2C_MSMv2=y +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_SENSORS_BMA250 is not set +# CONFIG_SENSORS_BMM050 is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_SLIMBUS is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +CONFIG_GPIO_MSM_V1=y +# CONFIG_GPIO_MSM_V2 is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_GPIO_PM8XXX_RPC is not set +CONFIG_GPIO_SLEEP=y +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +CONFIG_BATTERY_MSM=y +CONFIG_MSM_BATTERY_CHG_LEGACY=y +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_EARLYSUSPEND is not set +# CONFIG_BATTERY_MSM_FAKE is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_CHARGER_SMB347 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_MSM_ADC=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +CONFIG_MARIMBA_CORE=y +# CONFIG_MARIMBA_CODEC is not set +# CONFIG_TIMPANI_CODEC is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +CONFIG_MEDIA_TUNER_CUSTOMISE=y + +# +# Customize TV tuners +# +# CONFIG_MEDIA_TUNER_SIMPLE is not set +# CONFIG_MEDIA_TUNER_TDA8290 is not set +# CONFIG_MEDIA_TUNER_TDA827X is not set +# CONFIG_MEDIA_TUNER_TDA18271 is not set +# CONFIG_MEDIA_TUNER_TDA9887 is not set +# CONFIG_MEDIA_TUNER_TEA5761 is not set +# CONFIG_MEDIA_TUNER_TEA5767 is not set +# CONFIG_MEDIA_TUNER_MT20XX is not set +# CONFIG_MEDIA_TUNER_MT2060 is not set +# CONFIG_MEDIA_TUNER_MT2063 is not set +# CONFIG_MEDIA_TUNER_MT2266 is not set +# CONFIG_MEDIA_TUNER_MT2131 is not set +# CONFIG_MEDIA_TUNER_QT1010 is not set +# CONFIG_MEDIA_TUNER_XC2028 is not set +# CONFIG_MEDIA_TUNER_XC5000 is not set +# CONFIG_MEDIA_TUNER_XC4000 is not set +# CONFIG_MEDIA_TUNER_MXL5005S is not set +# CONFIG_MEDIA_TUNER_MXL5007T is not set +# CONFIG_MEDIA_TUNER_MC44S803 is not set +# CONFIG_MEDIA_TUNER_MAX2165 is not set +# CONFIG_MEDIA_TUNER_TDA18218 is not set +# CONFIG_MEDIA_TUNER_TDA18212 is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_AK881X is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_S5K6AA is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_AS3645A is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +# CONFIG_OV5647 is not set +# CONFIG_OV5647_TRULY_CM6868 is not set +# CONFIG_OV5648_TRULY_CM8352 is not set +# CONFIG_WEBCAM_OV7692_QRD is not set +CONFIG_GC0339=y +# CONFIG_MT9M114 is not set +CONFIG_OV2675=y +# CONFIG_WEBCAM_OV9726 is not set +# CONFIG_MT9E013 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +# CONFIG_AR0543 is not set +# CONFIG_MSM_CAMERA_FLASH_SC628A is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_IMX072 is not set +# CONFIG_OV2720 is not set +# CONFIG_OV8825 is not set +CONFIG_OV5647_TRULY_CM8312=y +CONFIG_OV8825_TRULY_CM8313=y +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y +# CONFIG_OV7692 is not set +# CONFIG_OV7695 is not set +# CONFIG_OV7695_RAW is not set +# CONFIG_GC2235 is not set +# CONFIG_GC2235_GCDF130477 is not set +# CONFIG_OV5648_TRULY_CM7500 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +# CONFIG_RADIO_WL128X is not set +CONFIG_RADIO_TAVARUA=y +# CONFIG_RADIO_IRIS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +# CONFIG_KGSL_PER_PROCESS_PAGE_TABLE is not set +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LOGO is not set +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +CONFIG_FB_MSM_MDP30=y +CONFIG_FB_MSM_MDP303=y +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +# CONFIG_FB_MSM_LCDC is not set +# CONFIG_FB_MSM_LVDS is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set + +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set + +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL is not set + +## CONFIG_FB_MSM_MIPI_DSI_TOSHIBA=y +## CONFIG_FB_MSM_MIPI_DSI_RENESAS=y +## CONFIG_FB_MSM_MIPI_DSI_TRULY=y +## CONFIG_FB_MSM_MIPI_DSI_SIMULATOR=y +## CONFIG_FB_MSM_MIPI_DSI_NOVATEK=y +## CONFIG_FB_MSM_MIPI_DSI_NT35510=y +## CONFIG_FB_MSM_MIPI_DSI_HX8389B=y +## CONFIG_FB_MSM_MIPI_DSI_ORISE=y +## CONFIG_FB_MSM_MIPI_DSI_NT35516=y +CONFIG_FB_MSM_MIPI_DSI_NT35516_SHARP=y +## CONFIG_FB_MSM_MIPI_DSI_TRULY_OTM8018B=y +## CONFIG_FB_MSM_MIPI_DSI_SUCCESS_NT35512=y +## CONFIG_FB_MSM_MIPI_DSI_RS69324_HITACHI=y +CONFIG_FB_MSM_MIPI_DSI_NT35516_NOVATEK=y +## CONFIG_FB_MSM_MIPI_DSI_NT35516_TRULY=y + +## CONFIG_FB_MSM_MIPI_DSI_TC358764_DSI2LVDS=y + +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 is not set +# CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set + +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set + +## CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT=y +## CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT=y +## CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA=y +## CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT=y +## CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT=y +## CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT=y +## CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT=y +## CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT=y +## CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT=y +## CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT=y +## CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT=y +## CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT=y +## CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT=y +## CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_VIDEO_SHARP_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_CMD_SHARP_QHD_PT=y +## CONFIG_FB_MSM_MIPI_TRULY_OTM8018B_VIDEO_WVGA_PT=y +## CONFIG_FB_MSM_MIPI_SUCCESS_NT35512_VIDEO_WVGA_PT=y +## CONFIG_FB_MSM_MIPI_RS69324_VIDEO_HITACHI_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_VIDEO_NOVATEK_QHD_PT=y +## CONFIG_FB_MSM_MIPI_NT35516_VIDEO_TRULY_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_CMD_NOVATEK_QHD_PT=y +## CONFIG_FB_MSM_MIPI_NT35516_CMD_TRULY_QHD_PT=y + +## CONFIG_FB_MSM_MIPI_CHIMEI_WXGA=y +## CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA=y +## CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT=y +## CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO=y + +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set + +CONFIG_FB_MSM_MIPI_JSR_PANEL_DETECT=y +# CONFIG_FB_MSM_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set + +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set + +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_SHARP_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_SHARP_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_OTM8018B_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SUCCESS_NT35512_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RS69324_VIDEO_HITACHI_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_NOVATEK_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_NOVATEK_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_TRULY_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_TRULY_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set + +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_EXT_INTERFACE_COMMON is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +## CONFIG_FB_DYNAMIC_GAMMA=y +## CONFIG_FB_AUTO_CABC=y +CONFIG_FB_MSM_ALIGN_BUFFER=y +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set + +# +# Console display driver support +# +## CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_MSM_DAI_SOC=y +CONFIG_SND_MSM_SOC_MSM7K=y +CONFIG_SND_MSM_SOC=y +# CONFIG_SND_SOC_QDSP6 is not set +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +CONFIG_UHID=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LOGITECH is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_SUPPORT_NON_STANDARD_WALL_CHARGER=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_OXU210HP_HCD is not set +CONFIG_USB_EHCI_MSM_72K=y +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_CI13XXX_MSM is not set +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +CONFIG_USB_MSM_72K=y +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL" +CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40" +# CONFIG_USB_ANDROID_RMNET_CTRL_SMD is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_MSM_OTG_72K=y +# CONFIG_MSM_OTG_ENABLE_A_WAIT_BCON_TIMEOUT is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_JSR_WIFI_SDCC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +CONFIG_MMC_TEST=m +CONFIG_MMC_BLOCK_TEST=m + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +# CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC2_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +# CONFIG_MMC_MSM_SDC4_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_MSM_PDM=y +CONFIG_LEDS_PMIC_MPP=y +CONFIG_LEDS_MSM_TRICOLOR=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +CONFIG_LEDS_TRICOLOR_FLAHSLIGHT=y +# CONFIG_LEDS_PMIC8029 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_TRIGGERS is not set + +# +# LED Triggers +# +CONFIG_SWITCH=y +CONFIG_SWITCH_GPIO=y +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_MSM=y +CONFIG_RTC_SECURE_TIME_SUPPORT=y +# CONFIG_RTC_DRV_MSM7X00A is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +## CONFIG_QCACHE=y +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +# CONFIG_PERSISTENT_TRACER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +# CONFIG_ANDROID_TIMED_GPIO is not set +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_MSM_QDSS is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +## CONFIG_EXT2_FS=y +## CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +## CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +## CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +## CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_YAFFS_FS=y +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_9BYTE_TAGS is not set +# CONFIG_YAFFS_DOES_ECC is not set +CONFIG_YAFFS_YAFFS2=y +CONFIG_YAFFS_AUTO_YAFFS2=y +CONFIG_YAFFS_DISABLE_TAGS_ECC=y +# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set +# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set +# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set +# CONFIG_YAFFS_DISABLE_BACKGROUND is not set +CONFIG_YAFFS_XATTR=y +# CONFIG_JFFS2_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_F2FS_FS=y +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +CONFIG_F2FS_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +CONFIG_DYNAMIC_FSYNC=y + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +## CONFIG_PRINTK_RTC_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=9 +## CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +## CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +## CONFIG_LOCKUP_DETECTOR=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +## CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +## CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +## CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +## CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +## CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +## CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +## CONFIG_DEBUG_LIST=y +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_RING_BUFFER_ALLOW_SWAP=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_KPROBE_EVENT=y +# CONFIG_RING_BUFFER_BENCHMARK is not set +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +CONFIG_SUPPORT_SYSTEMTAP=y +# CONFIG_SRECORDER_MSM is not set +# CONFIG_SRECORDER_POWERCOLLAPS is not set +# CONFIG_DEVICE_CHECK is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=32768 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_ABLK_HELPER=y +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_SHA512_ARM_NEON is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_QCRYPTO is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_QCEDEV is not set +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set + +# +# Misc +# +CONFIG_ENABLE_VMALLOC_SAVING=y +# CONFIG_NO_VM_RECLAIM is not set +CONFIG_INTELLI_PLUG=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig index 8c01b21e..6ab36c3a 100644 --- a/arch/arm/configs/msm8960-perf_defconfig +++ b/arch/arm/configs/msm8960-perf_defconfig @@ -59,7 +59,7 @@ CONFIG_MACH_MPQ8064_CDP=y CONFIG_MACH_MPQ8064_HRD=y CONFIG_MACH_MPQ8064_DTV=y # CONFIG_MSM_STACKED_MEMORY is not set -CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y +CONFIG_KERNEL_PMEM_EBI_REGION=y # CONFIG_MSM_FIQ_SUPPORT is not set # CONFIG_MSM_PROC_COMM is not set CONFIG_MSM_SMD=y diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig index 5bc5f225..482f9f44 100644 --- a/arch/arm/configs/msm8960_defconfig +++ b/arch/arm/configs/msm8960_defconfig @@ -58,7 +58,7 @@ CONFIG_MACH_MPQ8064_CDP=y CONFIG_MACH_MPQ8064_HRD=y CONFIG_MACH_MPQ8064_DTV=y # CONFIG_MSM_STACKED_MEMORY is not set -CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y +CONFIG_KERNEL_PMEM_EBI_REGION=y # CONFIG_MSM_FIQ_SUPPORT is not set # CONFIG_MSM_PROC_COMM is not set CONFIG_MSM_SMD=y diff --git a/arch/arm/configs/normandy_defconfig b/arch/arm/configs/normandy_defconfig index 36bfd385..c0be83e4 100644 --- a/arch/arm/configs/normandy_defconfig +++ b/arch/arm/configs/normandy_defconfig @@ -42,7 +42,7 @@ CONFIG_IRQ_WORK=y CONFIG_EXPERIMENTAL=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_CROSS_COMPILE="" -CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)-perf" +CONFIG_LOCALVERSION="-WERITOS-MM" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y @@ -60,7 +60,7 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_FHANDLE is not set # CONFIG_TASKSTATS is not set -# CONFIG_AUDIT is not set +CONFIG_AUDIT=y CONFIG_HAVE_GENERIC_HARDIRQS=y # @@ -460,6 +460,7 @@ CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 CONFIG_MSM_GPIOMUX=y CONFIG_MSM_MODEM_RESTART=y CONFIG_MSM_PM2=y +CONFIG_MSM_EVENT_TIMER=y # CONFIG_MSM_BUS_SCALING is not set # CONFIG_MSM_WATCHDOG_V2 is not set # CONFIG_MSM_JTAG is not set @@ -806,7 +807,7 @@ CONFIG_IPV6_SUBTREES=y # CONFIG_IPV6_MROUTE is not set CONFIG_ANDROID_PARANOID_NETWORK=y CONFIG_NET_ACTIVITY_STATS=y -# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETWORK_SECMARK=y # CONFIG_NETWORK_PHY_TIMESTAMPING is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -821,6 +822,7 @@ CONFIG_NETFILTER_NETLINK_QUEUE=y CONFIG_NETFILTER_NETLINK_LOG=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_PROCFS=y CONFIG_NF_CONNTRACK_EVENTS=y # CONFIG_NF_CONNTRACK_TIMEOUT is not set @@ -854,23 +856,26 @@ CONFIG_NETFILTER_XT_CONNMARK=y # # Xtables targets # +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set # CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y # CONFIG_NETFILTER_XT_TARGET_CT is not set # CONFIG_NETFILTER_XT_TARGET_DSCP is not set # CONFIG_NETFILTER_XT_TARGET_HL is not set # CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y -CONFIG_NETFILTER_XT_TARGET_NFLOG=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set # CONFIG_NETFILTER_XT_TARGET_RATEEST is not set # CONFIG_NETFILTER_XT_TARGET_TEE is not set -CONFIG_NETFILTER_XT_TARGET_TPROXY=y -CONFIG_NETFILTER_XT_TARGET_TRACE=y -# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y # CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set # @@ -935,7 +940,7 @@ CONFIG_IP_NF_MATCH_ECN=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set # CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_NF_NAT=y CONFIG_NF_NAT_NEEDED=y @@ -958,6 +963,7 @@ CONFIG_IP_NF_MANGLE=y # CONFIG_IP_NF_TARGET_ECN is not set # CONFIG_IP_NF_TARGET_TTL is not set CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y @@ -966,7 +972,7 @@ CONFIG_IP_NF_ARP_MANGLE=y # IPv6: Netfilter Configuration # CONFIG_NF_DEFRAG_IPV6=y -CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_NF_CONNTRACK_IPV6 is not set # CONFIG_IP6_NF_QUEUE is not set CONFIG_IP6_NF_IPTABLES=y # CONFIG_IP6_NF_MATCH_AH is not set @@ -981,16 +987,17 @@ CONFIG_IP6_NF_IPTABLES=y # CONFIG_IP6_NF_TARGET_HL is not set CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_SECURITY=y # CONFIG_IP_DCCP is not set # CONFIG_IP_SCTP is not set # CONFIG_RDS is not set # CONFIG_TIPC is not set # CONFIG_ATM is not set CONFIG_L2TP=y -# CONFIG_L2TP_DEBUGFS is not set +CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y CONFIG_L2TP_IP=y CONFIG_L2TP_ETH=y @@ -998,10 +1005,8 @@ CONFIG_L2TP_ETH=y # CONFIG_NET_DSA is not set # CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set -CONFIG_LLC=y # CONFIG_LLC2 is not set -CONFIG_IPX=y -CONFIG_IPX_INTERN=y +# CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set @@ -1170,8 +1175,10 @@ CONFIG_DMA_SHARED_BUFFER=y CONFIG_GENLOCK=y CONFIG_GENLOCK_MISCDEVICE=y CONFIG_SYNC=y -# CONFIG_SW_SYNC is not set -# CONFIG_CMA is not set +CONFIG_SW_SYNC=y +CONFIG_SW_SYNC_USER=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set # CONFIG_CONNECTOR is not set # CONFIG_MTD is not set # CONFIG_PARPORT is not set @@ -1200,7 +1207,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 # # CONFIG_SENSORS_LIS3LV02D is not set # CONFIG_AD525X_DPOT is not set -CONFIG_ANDROID_PMEM=y +## CONFIG_ANDROID_PMEM=y # CONFIG_ATMEL_PWM is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set @@ -1979,19 +1986,33 @@ CONFIG_VIDEO_MEDIA=y # CONFIG_RC_CORE is not set # CONFIG_MEDIA_ATTACH is not set CONFIG_MEDIA_TUNER=y -# CONFIG_MEDIA_TUNER_CUSTOMISE is not set -CONFIG_MEDIA_TUNER_SIMPLE=y -CONFIG_MEDIA_TUNER_TDA8290=y -CONFIG_MEDIA_TUNER_TDA827X=y -CONFIG_MEDIA_TUNER_TDA18271=y -CONFIG_MEDIA_TUNER_TDA9887=y -CONFIG_MEDIA_TUNER_TEA5761=y -CONFIG_MEDIA_TUNER_TEA5767=y -CONFIG_MEDIA_TUNER_MT20XX=y -CONFIG_MEDIA_TUNER_XC2028=y -CONFIG_MEDIA_TUNER_XC5000=y -CONFIG_MEDIA_TUNER_XC4000=y -CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_MEDIA_TUNER_CUSTOMISE=y + +# +# Customize TV tuners +# +# CONFIG_MEDIA_TUNER_SIMPLE is not set +# CONFIG_MEDIA_TUNER_TDA8290 is not set +# CONFIG_MEDIA_TUNER_TDA827X is not set +# CONFIG_MEDIA_TUNER_TDA18271 is not set +# CONFIG_MEDIA_TUNER_TDA9887 is not set +# CONFIG_MEDIA_TUNER_TEA5761 is not set +# CONFIG_MEDIA_TUNER_TEA5767 is not set +# CONFIG_MEDIA_TUNER_MT20XX is not set +# CONFIG_MEDIA_TUNER_MT2060 is not set +# CONFIG_MEDIA_TUNER_MT2063 is not set +# CONFIG_MEDIA_TUNER_MT2266 is not set +# CONFIG_MEDIA_TUNER_MT2131 is not set +# CONFIG_MEDIA_TUNER_QT1010 is not set +# CONFIG_MEDIA_TUNER_XC2028 is not set +# CONFIG_MEDIA_TUNER_XC5000 is not set +# CONFIG_MEDIA_TUNER_XC4000 is not set +# CONFIG_MEDIA_TUNER_MXL5005S is not set +# CONFIG_MEDIA_TUNER_MXL5007T is not set +# CONFIG_MEDIA_TUNER_MC44S803 is not set +# CONFIG_MEDIA_TUNER_MAX2165 is not set +# CONFIG_MEDIA_TUNER_TDA18218 is not set +# CONFIG_MEDIA_TUNER_TDA18212 is not set CONFIG_VIDEO_V4L2=y CONFIG_VIDEOBUF2_CORE=y CONFIG_VIDEOBUF2_MEMOPS=y @@ -2245,9 +2266,8 @@ CONFIG_MSM_KGSL=y # CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set # CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set # CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set -CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +# CONFIG_KGSL_PER_PROCESS_PAGE_TABLE is not set CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 -CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24 CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES=y # CONFIG_VGASTATE is not set @@ -3221,10 +3241,26 @@ CONFIG_DEBUG_USER=y # # CONFIG_KEYS is not set # CONFIG_SECURITY_DMESG_RESTRICT is not set -# CONFIG_SECURITY is not set +CONFIG_SECURITY=y # CONFIG_SECURITYFS is not set -CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_DEFAULT_SECURITY="" +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=32768 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" CONFIG_CRYPTO=y # @@ -3355,6 +3391,8 @@ CONFIG_CRC32_SLICEBY8=y # CONFIG_CRC7 is not set CONFIG_LIBCRC32C=y # CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_LZO_COMPRESS=y diff --git a/arch/arm/configs/weritos_defconfig b/arch/arm/configs/weritos_defconfig new file mode 100644 index 00000000..1c065c25 --- /dev/null +++ b/arch/arm/configs/weritos_defconfig @@ -0,0 +1,3484 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.110 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_LOCKBREAK=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x00200000 +CONFIG_GENERIC_BUG=y +# CONFIG_ARCH_RANDOM is not set +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-WERITOS-KK-CAF" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_MEM_RES_CTLR=y +# CONFIG_CGROUP_MEM_RES_CTLR_SWAP is not set +# CONFIG_CGROUP_MEM_RES_CTLR_KMEM is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_MM_OWNER=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +# CONFIG_OPTIMIZE_INLINING is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_PERF_COUNTERS is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_LOAD_ATH6KL is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_BFQ=y +# CONFIG_CGROUP_BFQIO is not set +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_FIOPS=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_SIO=y +CONFIG_IOSCHED_SIOPLUS=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_VR=y +CONFIG_IOSCHED_ZEN=y +# CONFIG_DEFAULT_BFQ is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_FIOPS is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_ROW=y +# CONFIG_DEFAULT_SIO is not set +# CONFIG_DEFAULT_SIOPLUS is not set +# CONFIG_DEFAULT_VR is not set +# CONFIG_DEFAULT_ZEN is not set +CONFIG_DEFAULT_IOSCHED="row" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +CONFIG_ARCH_MSM7X27=y +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +# CONFIG_ARCH_MSM8960 is not set +# CONFIG_ARCH_MSM8930 is not set +# CONFIG_ARCH_APQ8064 is not set +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +CONFIG_ARCH_MSM8625=y +# CONFIG_ARCH_MSM9625 is not set +# CONFIG_ARCH_MSM8910 is not set +# CONFIG_MSM_SOC_REV_NONE is not set +CONFIG_MSM_SOC_REV_A=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +CONFIG_ARCH_MSM_CORTEX_A5=y +CONFIG_ARCH_MSM7X27A=y +CONFIG_MSM_VIC=y +# CONFIG_MSM_RPM is not set +# CONFIG_MSM_RPM_SMD is not set +# CONFIG_MSM_MPM is not set + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM7X27_SURF is not set +# CONFIG_MACH_MSM7X27_FFA is not set +CONFIG_MACH_MSM7X27A_RUMI3=y +CONFIG_MACH_MSM7X27A_SURF=y +CONFIG_MACH_MSM7X27A_FFA=y +CONFIG_WERITOS_KERNEL=y +CONFIG_MACH_MSM7625A_SURF=y +CONFIG_MACH_MSM7625A_FFA=y +CONFIG_MACH_MSM7627A_QRD1=y +CONFIG_MACH_MSM7627A_QRD3=y +CONFIG_MACH_MSM7627A_EVB=y +CONFIG_MACH_MSM8625_RUMI3=y +CONFIG_MACH_MSM8625_SURF=y +CONFIG_MACH_MSM8625_FFA=y +CONFIG_MACH_MSM8625_EVB=y +CONFIG_MACH_MSM7X27A_QRD5A=y +CONFIG_MACH_MSM8625_QRD7=y +CONFIG_MACH_MSM8625_QRD5=y +CONFIG_MACH_MSM8625Q_EVBD=y +CONFIG_MACH_MSM8625Q_SKUD=y +CONFIG_MACH_MSM8625Q_SKUE=y +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +# CONFIG_MSM7X00A_USE_GP_TIMER is not set +CONFIG_MSM7X00A_USE_DG_TIMER=y +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +CONFIG_MSM_FIQ_SUPPORT=y +# CONFIG_MSM_SERIAL_DEBUGGER is not set +CONFIG_MSM_PROC_COMM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_AMSS_ENHANCE_DEBUG=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_FUSE_INFO_DEBUG=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_FAST_BOOT=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +# CONFIG_MSM_RESET_MODEM is not set +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +# CONFIG_MSM_SMD_NMEA is not set +CONFIG_MSM_SMD_TTY=y +# CONFIG_MSM_SMD_QMI is not set +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ONCRPCROUTER=y +CONFIG_MSM_IPC_ROUTER=y +# CONFIG_MSM_IPC_ROUTER_SMD_XPRT is not set +CONFIG_MSM_ONCRPCROUTER_DEBUG=y +# CONFIG_MSM_RPC_LOOPBACK_XPRT is not set +# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set +CONFIG_MSM_RPCSERVER_WATCHDOG=y +# CONFIG_MSM_RPC_WATCHDOG is not set +CONFIG_MSM_RPC_PING=y +CONFIG_MSM_RPC_PROC_COMM_TEST=y +CONFIG_MSM_RPC_OEM_RAPI=y +CONFIG_MSM_RPCSERVER_HANDSET=y +CONFIG_MSM_RMT_STORAGE_CLIENT=y +# CONFIG_MSM_RMT_STORAGE_CLIENT_STATS is not set +CONFIG_MSM_DALRPC=y +CONFIG_MSM_DALRPC_TEST=m +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_MSM_ADSP=y +CONFIG_ADSP_RPC_VER=0x30002 +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_MSM_ADSP_REPORT_EVENTS=y +CONFIG_RTAC=y +CONFIG_MSM7X27A_AUDIO=y +CONFIG_MSM_PROC_COMM_REGULATOR=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=y +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_AUDIO_AAC_PLUS=y +CONFIG_AUDIO_ENHANCED_AAC_PLUS=y +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +# CONFIG_MSM_PIL is not set +# CONFIG_MSM_SCM is not set +# CONFIG_MSM_TZ_LOG is not set +# CONFIG_MSM_DIRECT_SCLK_ACCESS is not set +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_MODEM_RESTART=y +CONFIG_MSM_PM2=y +CONFIG_MSM_EVENT_TIMER=y +# CONFIG_MSM_BUS_SCALING is not set +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_JTAG is not set +CONFIG_MSM_SLEEP_STATS_DEVICE=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SM_EVENT=y +CONFIG_MSM_SM_EVENT_LOG=m +CONFIG_UNCACHED_BUF=y +CONFIG_MSM_SLEEP_MONITOR=m +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_MSM_PINTEST=y +# CONFIG_MSM_FAKE_BATTERY is not set +# CONFIG_MSM_QDSP6_APR is not set +# CONFIG_MSM_QDSP6_CODECS is not set +# CONFIG_MSM_QDSP6V2_CODECS is not set +# CONFIG_MSM_AUDIO_QDSP6 is not set +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +CONFIG_MSM_RPC_VIBRATOR=y +CONFIG_PM8XXX_RPC_VIBRATOR=y +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +# CONFIG_MSM_L2_SPM is not set +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CPR=y +CONFIG_MSM_VP_REGULATOR=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +# CONFIG_MSM_8X60_FUSION_GPIO_GLITCH is not set +CONFIG_MSM_FIQ=y +CONFIG_MSM_PBUS=y +CONFIG_HAS_MACH_MEMUTILS=y +# CONFIG_MSM_OVERCLOCK_GPU is not set +# CONFIG_INTELLI_PLUG is not set +# CONFIG_BRICKED_HOTPLUG is not set + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +# CONFIG_CACHE_PL310_ERP is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARCH_HAS_BARRIERS=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set +CONFIG_ARM_GIC=y +CONFIG_GIC_SECURE=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=300 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0xC800000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=999999 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_DYNAMIC_PAGE_WRITEBACK is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ARCH_POPULATES_NODE_MAP is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASSH3 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIACTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIMM is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_STOCKDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_YANKDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_LIONHEART is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMANDX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVEX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SMARTASS2=y +# CONFIG_CPU_FREQ_GOV_SMARTASSH3 is not set +# CONFIG_CPU_FREQ_GOV_INTELLIACTIVE is not set +# CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set +# CONFIG_CPU_FREQ_GOV_INTELLIMM is not set +# CONFIG_CPU_FREQ_GOV_STOCKDEMAND is not set +# CONFIG_CPU_FREQ_GOV_YANKDEMAND is not set +# CONFIG_CPU_FREQ_GOV_INTELLIDEMAND is not set +CONFIG_CPU_FREQ_GOV_LIONHEART=y +# CONFIG_CPU_FREQ_GOV_HYPER is not set +# CONFIG_CPU_FREQ_GOV_ONDEMANDX is not set +# CONFIG_CPU_FREQ_GOV_INTERACTIVEX is not set +CONFIG_CPU_FREQ_GOV_ALUCARD=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_CPU_IDLE is not set +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_CAN_PM_TRACE=y +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=y +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +CONFIG_TCP_CONG_VEGAS=y +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +CONFIG_TCP_CONG_VENO=y +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_VENO is not set +CONFIG_DEFAULT_WESTWOOD=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="westwood" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_NF_NAT_SIP=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_SECURITY=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCISMD is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_IBS=y +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +CONFIG_BT_MSM_SLEEP=y +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_MSM_BT_POWER=y +CONFIG_HUAWEI_BT_WCN2243=y +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +# CONFIG_WIRELESS_EXT_SYSFS is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +CONFIG_SW_SYNC_USER=y +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +CONFIG_APANIC_MMC=y +CONFIG_APANIC_PLABEL="kpanic" +# CONFIG_TSIF is not set +CONFIG_GLANCEVIEW=y +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_QSEECOM is not set +# CONFIG_QFP_FUSE is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851_MLL is not set +CONFIG_MSM_RMNET=y +# CONFIG_MSM_RMNET_DEBUG is not set +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +CONFIG_LIBRA_SDIOIF=m +# CONFIG_ATH6K_LEGACY_EXT is not set +CONFIG_ATH_COMMON=m +# CONFIG_ATH_DEBUG is not set +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +# CONFIG_WIFI_MAC_FROM_NV is not set +# CONFIG_ATH6KL_USB is not set +# CONFIG_ATH6KL_DEBUG is not set +# CONFIG_ATH6KL_REGDOMAIN is not set +# CONFIG_BCMDHD is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_FOCAL is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y +CONFIG_SYNA_MULTI_TOUCH=y +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +CONFIG_TOUCHSCREEN_FT6306=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_INPUT_LTR502 is not set +# CONFIG_INPUT_LTR558 is not set +# CONFIG_BOSCH_BMA250 is not set +# CONFIG_AVAGO_APDS990X is not set +# CONFIG_INPUT_ISL29028 is not set +# CONFIG_INPUT_LIS3DH is not set +# CONFIG_SENSORS_TMD2771X is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_SLIMBUS is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +CONFIG_GPIO_MSM_V1=y +# CONFIG_GPIO_MSM_V2 is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +CONFIG_BATTERY_MSM=y +# CONFIG_BATTERY_MSM_DEBUG is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_EARLYSUSPEND is not set +# CONFIG_BATTERY_MSM_FAKE is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_FORCE_FAST_CHARGE is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_MSM_ADC=y +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_LTR559=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +CONFIG_MARIMBA_CORE=y +# CONFIG_MARIMBA_CODEC is not set +# CONFIG_TIMPANI_CODEC is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_FAN53555=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +CONFIG_REGULATOR_ONSEMI_NCP6335D=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_TUNER is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_AK881X is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_S5K6AA is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_AS3645A is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +CONFIG_S5K5CA=y +CONFIG_S5K5CA_DARLING=y +# CONFIG_HI351_SUNNY_Q3H01B is not set +# CONFIG_OV5647 is not set +# CONFIG_OV5647_TRULY_CM6868 is not set +# CONFIG_OV5648_TRULY_CM8352 is not set +# CONFIG_WEBCAM_OV7692_QRD is not set +# CONFIG_MT9M114 is not set +# CONFIG_WEBCAM_OV9726 is not set +# CONFIG_MT9E013 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +# CONFIG_AR0543 is not set +# CONFIG_A8140 is not set +# CONFIG_S5K3H2_SUNNY_Q8S02E is not set +CONFIG_AR0542=y +# CONFIG_MSM_CAMERA_FLASH_SC628A is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_IMX072 is not set +# CONFIG_OV2720 is not set +CONFIG_OV8825=y +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_OV7695 is not set +# CONFIG_OV7695_RAW is not set +# CONFIG_MT9V115 is not set +# CONFIG_OV5647_DALING_OVBD631AC is not set +# CONFIG_OV5647_PARTRON_CM500 is not set +# CONFIG_OV5647_HQ_O9B5_DG806T is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +# CONFIG_RADIO_WL128X is not set +CONFIG_RADIO_TAVARUA=y +# CONFIG_RADIO_IRIS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +# CONFIG_KGSL_PER_PROCESS_PAGE_TABLE is not set +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MIPI_OTM9608A_PT=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LOGO is not set +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +CONFIG_FB_MSM_MDP30=y +CONFIG_FB_MSM_MDP303=y +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +CONFIG_FB_MSM_LCDC=y +# CONFIG_FB_MSM_LVDS is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +CONFIG_FB_MSM_LCDC_PANEL=y +CONFIG_FB_MSM_MIPI_DSI_TOSHIBA=y +CONFIG_FB_MSM_MIPI_DSI_RENESAS=y +CONFIG_FB_MSM_MIPI_DSI_TRULY=y +CONFIG_FB_MSM_MIPI_DSI_SIMULATOR=y +CONFIG_FB_MSM_MIPI_DSI_NOVATEK=y +CONFIG_FB_MSM_MIPI_DSI_NT35510=y +CONFIG_FB_MSM_MIPI_DSI_HX8389B=y +CONFIG_FB_MSM_MIPI_DSI_HX8392A=y +CONFIG_FB_MSM_MIPI_DSI_OTM9605A=y +CONFIG_FB_MSM_MIPI_DSI_ORISE=y +CONFIG_FB_MSM_MIPI_DSI_NT35516=y +CONFIG_FB_MSM_MIPI_DSI_NT35590=y +CONFIG_FB_MSM_MIPI_DSI_TC358764_DSI2LVDS=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335=y +CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL=y +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT=y +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA=y +CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT=y +CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT=y +CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT=y +CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT=y +CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT=y +CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT=y +CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_HX8392A_VIDEO_720P_PT=y +CONFIG_FB_MSM_MIPI_OTM9605A_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35590_CMD_720P_PT=y +CONFIG_FB_MSM_MIPI_NT35590_VIDEO_720P_PT=y +# CONFIG_FB_MSM_MIPI_DIV4_WVGA_NT35510_PANEL is not set +CONFIG_FB_MSM_MIPI_CHIMEI_WXGA=y +CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA=y +CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +CONFIG_FB_MSM_MIPI_PANEL_DETECT=y +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_HX8392A_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_OTM9605A_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35590_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35590_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_EXT_INTERFACE_COMMON is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_MSM_DAI_SOC=y +CONFIG_SND_MSM_SOC_MSM7K=y +CONFIG_SND_MSM_SOC=y +# CONFIG_SND_SOC_QDSP6 is not set +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +# CONFIG_HOLTEK_FF is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LEDS is not set +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +CONFIG_HID_WIIMOTE=y +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_SUPPORT_NON_STANDARD_WALL_CHARGER=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_OXU210HP_HCD is not set +CONFIG_USB_EHCI_MSM_72K=y +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_CI13XXX_MSM is not set +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +CONFIG_USB_MSM_72K=y +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL" +CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40" +# CONFIG_USB_ANDROID_RMNET_CTRL_SMD is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +CONFIG_USB_OTG_WAKELOCK=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_MSM_OTG_72K=y +# CONFIG_MSM_OTG_ENABLE_A_WAIT_BCON_TIMEOUT is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +CONFIG_MMC_TEST=m +CONFIG_MMC_BLOCK_TEST=m + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_RAW=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +# CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC2_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +# CONFIG_MMC_MSM_SDC4_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_MSM_PDM=y +CONFIG_LEDS_PMIC_MPP=y +CONFIG_LEDS_MSM_TRICOLOR=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +CONFIG_LEDS_TRICOLOR_FLAHSLIGHT=y +# CONFIG_LEDS_PMIC8029 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_TRIGGERS is not set + +# +# LED Triggers +# +CONFIG_SWITCH=y +CONFIG_SWITCH_GPIO=y +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_MSM=y +CONFIG_RTC_SECURE_TIME_SUPPORT=y +# CONFIG_RTC_DRV_MSM7X00A is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +# CONFIG_SNAPPY_COMPRESS is not set +# CONFIG_SNAPPY_DECOMPRESS is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_ZCACHE is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +# CONFIG_ANDROID_LOGGER_SYSFS is not set +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_MSM_QDSS is not set + +# +# NVBK share memory +# +CONFIG_NVBK_SHARE_MEM=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DYNAMIC_FSYNC is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_PRINTK_RTC_TIME=y +CONFIG_PRINTK_CPU_ID=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_KPROBE_EVENT=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=32768 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_FORCE_PERMISSIVE=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA1_ARM is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_QCRYPTO is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_QCEDEV is not set +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set diff --git "a/arch/arm/configs/weritos_defconfig (\320\272\320\276\320\277\320\270\321\217)" "b/arch/arm/configs/weritos_defconfig (\320\272\320\276\320\277\320\270\321\217)" new file mode 100644 index 00000000..c7c05881 --- /dev/null +++ "b/arch/arm/configs/weritos_defconfig (\320\272\320\276\320\277\320\270\321\217)" @@ -0,0 +1,3482 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.110 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_LOCKBREAK=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x00200000 +CONFIG_GENERIC_BUG=y +# CONFIG_ARCH_RANDOM is not set +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-WERITOS-MM" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_MEM_RES_CTLR=y +CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y +CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y +# CONFIG_CGROUP_MEM_RES_CTLR_KMEM is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_MM_OWNER=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +# CONFIG_OPTIMIZE_INLINING is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_PERF_COUNTERS is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_LOAD_ATH6KL is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_BFQ=y +# CONFIG_CGROUP_BFQIO is not set +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_FIOPS=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_SIO=y +CONFIG_IOSCHED_SIOPLUS=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_VR=y +CONFIG_IOSCHED_ZEN=y +# CONFIG_DEFAULT_BFQ is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_FIOPS is not set +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set +# CONFIG_DEFAULT_SIOPLUS is not set +# CONFIG_DEFAULT_VR is not set +# CONFIG_DEFAULT_ZEN is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +CONFIG_ARCH_MSM7X27=y +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +# CONFIG_ARCH_MSM8960 is not set +# CONFIG_ARCH_MSM8930 is not set +# CONFIG_ARCH_APQ8064 is not set +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +CONFIG_ARCH_MSM8625=y +# CONFIG_ARCH_MSM9625 is not set +# CONFIG_ARCH_MSM8910 is not set +# CONFIG_MSM_SOC_REV_NONE is not set +CONFIG_MSM_SOC_REV_A=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +CONFIG_ARCH_MSM_CORTEX_A5=y +CONFIG_ARCH_MSM7X27A=y +CONFIG_MSM_VIC=y +# CONFIG_MSM_RPM is not set +# CONFIG_MSM_RPM_SMD is not set +# CONFIG_MSM_MPM is not set + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM7X27_SURF is not set +# CONFIG_MACH_MSM7X27_FFA is not set +CONFIG_MACH_MSM7X27A_RUMI3=y +CONFIG_MACH_MSM7X27A_SURF=y +CONFIG_MACH_MSM7X27A_FFA=y +CONFIG_WERITOS_KERNEL=y +CONFIG_MACH_MSM7625A_SURF=y +CONFIG_MACH_MSM7625A_FFA=y +CONFIG_MACH_MSM7627A_QRD1=y +CONFIG_MACH_MSM7627A_QRD3=y +CONFIG_MACH_MSM7627A_EVB=y +CONFIG_MACH_MSM8625_RUMI3=y +CONFIG_MACH_MSM8625_SURF=y +CONFIG_MACH_MSM8625_FFA=y +CONFIG_MACH_MSM8625_EVB=y +CONFIG_MACH_MSM7X27A_QRD5A=y +CONFIG_MACH_MSM8625_QRD7=y +CONFIG_MACH_MSM8625_QRD5=y +CONFIG_MACH_MSM8625Q_EVBD=y +CONFIG_MACH_MSM8625Q_SKUD=y +CONFIG_MACH_MSM8625Q_SKUE=y +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +# CONFIG_MSM7X00A_USE_GP_TIMER is not set +CONFIG_MSM7X00A_USE_DG_TIMER=y +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +CONFIG_MSM_FIQ_SUPPORT=y +# CONFIG_MSM_SERIAL_DEBUGGER is not set +CONFIG_MSM_PROC_COMM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_AMSS_ENHANCE_DEBUG=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_FUSE_INFO_DEBUG=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_FAST_BOOT=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +# CONFIG_MSM_RESET_MODEM is not set +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +# CONFIG_MSM_SMD_NMEA is not set +CONFIG_MSM_SMD_TTY=y +# CONFIG_MSM_SMD_QMI is not set +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ONCRPCROUTER=y +CONFIG_MSM_IPC_ROUTER=y +# CONFIG_MSM_IPC_ROUTER_SMD_XPRT is not set +CONFIG_MSM_ONCRPCROUTER_DEBUG=y +# CONFIG_MSM_RPC_LOOPBACK_XPRT is not set +# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set +CONFIG_MSM_RPCSERVER_WATCHDOG=y +# CONFIG_MSM_RPC_WATCHDOG is not set +CONFIG_MSM_RPC_PING=y +CONFIG_MSM_RPC_PROC_COMM_TEST=y +CONFIG_MSM_RPC_OEM_RAPI=y +CONFIG_MSM_RPCSERVER_HANDSET=y +CONFIG_MSM_RMT_STORAGE_CLIENT=y +# CONFIG_MSM_RMT_STORAGE_CLIENT_STATS is not set +CONFIG_MSM_DALRPC=y +CONFIG_MSM_DALRPC_TEST=m +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_MSM_ADSP=y +CONFIG_ADSP_RPC_VER=0x30002 +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_MSM_ADSP_REPORT_EVENTS=y +CONFIG_RTAC=y +CONFIG_MSM7X27A_AUDIO=y +CONFIG_MSM_PROC_COMM_REGULATOR=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=y +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_AUDIO_AAC_PLUS=y +CONFIG_AUDIO_ENHANCED_AAC_PLUS=y +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +# CONFIG_MSM_PIL is not set +# CONFIG_MSM_SCM is not set +# CONFIG_MSM_TZ_LOG is not set +# CONFIG_MSM_DIRECT_SCLK_ACCESS is not set +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_MODEM_RESTART=y +CONFIG_MSM_PM2=y +CONFIG_MSM_EVENT_TIMER=y +# CONFIG_MSM_BUS_SCALING is not set +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_JTAG is not set +CONFIG_MSM_SLEEP_STATS_DEVICE=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SM_EVENT=y +CONFIG_MSM_SM_EVENT_LOG=m +CONFIG_UNCACHED_BUF=y +CONFIG_MSM_SLEEP_MONITOR=m +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_MSM_PINTEST=y +# CONFIG_MSM_FAKE_BATTERY is not set +# CONFIG_MSM_QDSP6_APR is not set +# CONFIG_MSM_QDSP6_CODECS is not set +# CONFIG_MSM_QDSP6V2_CODECS is not set +# CONFIG_MSM_AUDIO_QDSP6 is not set +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +CONFIG_MSM_RPC_VIBRATOR=y +CONFIG_PM8XXX_RPC_VIBRATOR=y +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +# CONFIG_MSM_L2_SPM is not set +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CPR=y +CONFIG_MSM_VP_REGULATOR=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +# CONFIG_MSM_8X60_FUSION_GPIO_GLITCH is not set +CONFIG_MSM_FIQ=y +CONFIG_MSM_PBUS=y +CONFIG_HAS_MACH_MEMUTILS=y +# CONFIG_MSM_OVERCLOCK_GPU is not set +# CONFIG_INTELLI_PLUG is not set +CONFIG_BRICKED_HOTPLUG=y + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +# CONFIG_CACHE_PL310_ERP is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARCH_HAS_BARRIERS=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set +CONFIG_ARM_GIC=y +CONFIG_GIC_SECURE=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=300 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0xC800000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=999999 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_DYNAMIC_PAGE_WRITEBACK is not set +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ARCH_POPULATES_NODE_MAP is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASSH3 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIACTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIMM is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_STOCKDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_YANKDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_LIONHEART is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMANDX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVEX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SMARTASS2=y +CONFIG_CPU_FREQ_GOV_SMARTASSH3=y +# CONFIG_CPU_FREQ_GOV_INTELLIACTIVE is not set +CONFIG_CPU_FREQ_GOV_ADAPTIVE=y +CONFIG_CPU_FREQ_GOV_INTELLIMM=y +# CONFIG_CPU_FREQ_GOV_STOCKDEMAND is not set +# CONFIG_CPU_FREQ_GOV_YANKDEMAND is not set +CONFIG_CPU_FREQ_GOV_INTELLIDEMAND=y +CONFIG_CPU_FREQ_GOV_LIONHEART=y +CONFIG_CPU_FREQ_GOV_HYPER=y +CONFIG_CPU_FREQ_GOV_ONDEMANDX=y +CONFIG_CPU_FREQ_GOV_INTERACTIVEX=y +CONFIG_CPU_FREQ_GOV_ALUCARD=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_CPU_IDLE is not set +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +# CONFIG_KERNEL_MODE_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_CAN_PM_TRACE=y +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=y +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +CONFIG_TCP_CONG_VEGAS=y +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +CONFIG_TCP_CONG_VENO=y +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_VENO is not set +CONFIG_DEFAULT_WESTWOOD=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="westwood" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_NF_NAT_SIP=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_SECURITY=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCISMD is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_IBS=y +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +CONFIG_BT_MSM_SLEEP=y +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_MSM_BT_POWER=y +CONFIG_HUAWEI_BT_WCN2243=y +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +# CONFIG_WIRELESS_EXT_SYSFS is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +CONFIG_SW_SYNC_USER=y +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +CONFIG_APANIC_MMC=y +CONFIG_APANIC_PLABEL="kpanic" +# CONFIG_TSIF is not set +CONFIG_GLANCEVIEW=y +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_QSEECOM is not set +# CONFIG_QFP_FUSE is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851_MLL is not set +CONFIG_MSM_RMNET=y +# CONFIG_MSM_RMNET_DEBUG is not set +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +CONFIG_LIBRA_SDIOIF=m +# CONFIG_ATH6K_LEGACY_EXT is not set +CONFIG_ATH_COMMON=m +# CONFIG_ATH_DEBUG is not set +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +# CONFIG_WIFI_MAC_FROM_NV is not set +# CONFIG_ATH6KL_USB is not set +# CONFIG_ATH6KL_DEBUG is not set +# CONFIG_ATH6KL_REGDOMAIN is not set +# CONFIG_BCMDHD is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_FOCAL is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y +CONFIG_SYNA_MULTI_TOUCH=y +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +CONFIG_TOUCHSCREEN_FT6306=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_INPUT_LTR502 is not set +# CONFIG_INPUT_LTR558 is not set +# CONFIG_BOSCH_BMA250 is not set +# CONFIG_AVAGO_APDS990X is not set +# CONFIG_INPUT_ISL29028 is not set +# CONFIG_INPUT_LIS3DH is not set +# CONFIG_SENSORS_TMD2771X is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_SLIMBUS is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +CONFIG_GPIO_MSM_V1=y +# CONFIG_GPIO_MSM_V2 is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +CONFIG_BATTERY_MSM=y +# CONFIG_BATTERY_MSM_DEBUG is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_EARLYSUSPEND is not set +# CONFIG_BATTERY_MSM_FAKE is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_FORCE_FAST_CHARGE is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_MSM_ADC=y +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_LTR559=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +CONFIG_MARIMBA_CORE=y +# CONFIG_MARIMBA_CODEC is not set +# CONFIG_TIMPANI_CODEC is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_FAN53555=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +CONFIG_REGULATOR_ONSEMI_NCP6335D=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_TUNER is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_AK881X is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_S5K6AA is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_AS3645A is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +CONFIG_S5K5CA=y +CONFIG_S5K5CA_DARLING=y +# CONFIG_HI351_SUNNY_Q3H01B is not set +# CONFIG_OV5647 is not set +# CONFIG_OV5647_TRULY_CM6868 is not set +# CONFIG_OV5648_TRULY_CM8352 is not set +# CONFIG_WEBCAM_OV7692_QRD is not set +# CONFIG_MT9M114 is not set +# CONFIG_WEBCAM_OV9726 is not set +# CONFIG_MT9E013 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +# CONFIG_AR0543 is not set +# CONFIG_A8140 is not set +# CONFIG_S5K3H2_SUNNY_Q8S02E is not set +CONFIG_AR0542=y +# CONFIG_MSM_CAMERA_FLASH_SC628A is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_IMX072 is not set +# CONFIG_OV2720 is not set +CONFIG_OV8825=y +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_OV7695 is not set +# CONFIG_OV7695_RAW is not set +# CONFIG_MT9V115 is not set +# CONFIG_OV5647_DALING_OVBD631AC is not set +# CONFIG_OV5647_PARTRON_CM500 is not set +# CONFIG_OV5647_HQ_O9B5_DG806T is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +# CONFIG_RADIO_WL128X is not set +CONFIG_RADIO_TAVARUA=y +# CONFIG_RADIO_IRIS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +# CONFIG_KGSL_PER_PROCESS_PAGE_TABLE is not set +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MIPI_OTM9608A_PT=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LOGO is not set +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +CONFIG_FB_MSM_MDP30=y +CONFIG_FB_MSM_MDP303=y +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +CONFIG_FB_MSM_LCDC=y +# CONFIG_FB_MSM_LVDS is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +CONFIG_FB_MSM_LCDC_PANEL=y +CONFIG_FB_MSM_MIPI_DSI_TOSHIBA=y +CONFIG_FB_MSM_MIPI_DSI_RENESAS=y +CONFIG_FB_MSM_MIPI_DSI_TRULY=y +CONFIG_FB_MSM_MIPI_DSI_SIMULATOR=y +CONFIG_FB_MSM_MIPI_DSI_NOVATEK=y +CONFIG_FB_MSM_MIPI_DSI_NT35510=y +CONFIG_FB_MSM_MIPI_DSI_HX8389B=y +CONFIG_FB_MSM_MIPI_DSI_HX8392A=y +CONFIG_FB_MSM_MIPI_DSI_OTM9605A=y +CONFIG_FB_MSM_MIPI_DSI_ORISE=y +CONFIG_FB_MSM_MIPI_DSI_NT35516=y +CONFIG_FB_MSM_MIPI_DSI_NT35590=y +CONFIG_FB_MSM_MIPI_DSI_TC358764_DSI2LVDS=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335=y +CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL=y +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT=y +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA=y +CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT=y +CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT=y +CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT=y +CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT=y +CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT=y +CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT=y +CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_HX8392A_VIDEO_720P_PT=y +CONFIG_FB_MSM_MIPI_OTM9605A_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35590_CMD_720P_PT=y +CONFIG_FB_MSM_MIPI_NT35590_VIDEO_720P_PT=y +# CONFIG_FB_MSM_MIPI_DIV4_WVGA_NT35510_PANEL is not set +CONFIG_FB_MSM_MIPI_CHIMEI_WXGA=y +CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA=y +CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +CONFIG_FB_MSM_MIPI_PANEL_DETECT=y +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_HX8392A_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_OTM9605A_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35590_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35590_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_EXT_INTERFACE_COMMON is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_MSM_DAI_SOC=y +CONFIG_SND_MSM_SOC_MSM7K=y +CONFIG_SND_MSM_SOC=y +# CONFIG_SND_SOC_QDSP6 is not set +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +# CONFIG_HOLTEK_FF is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LEDS is not set +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +CONFIG_HID_WIIMOTE=y +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_SUPPORT_NON_STANDARD_WALL_CHARGER=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_OXU210HP_HCD is not set +CONFIG_USB_EHCI_MSM_72K=y +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_CI13XXX_MSM is not set +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +CONFIG_USB_MSM_72K=y +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL" +CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40" +# CONFIG_USB_ANDROID_RMNET_CTRL_SMD is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +CONFIG_USB_OTG_WAKELOCK=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_MSM_OTG_72K=y +# CONFIG_MSM_OTG_ENABLE_A_WAIT_BCON_TIMEOUT is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +CONFIG_MMC_TEST=m +CONFIG_MMC_BLOCK_TEST=m + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_RAW=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +# CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC2_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +# CONFIG_MMC_MSM_SDC4_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_MSM_PDM=y +CONFIG_LEDS_PMIC_MPP=y +CONFIG_LEDS_MSM_TRICOLOR=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +CONFIG_LEDS_TRICOLOR_FLAHSLIGHT=y +# CONFIG_LEDS_PMIC8029 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_TRIGGERS is not set + +# +# LED Triggers +# +CONFIG_SWITCH=y +CONFIG_SWITCH_GPIO=y +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_MSM=y +CONFIG_RTC_SECURE_TIME_SUPPORT=y +# CONFIG_RTC_DRV_MSM7X00A is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +# CONFIG_SNAPPY_COMPRESS is not set +# CONFIG_SNAPPY_DECOMPRESS is not set +CONFIG_ZRAM=y +# CONFIG_ZRAM_DEBUG is not set +CONFIG_ZRAM_LZO=y +# CONFIG_ZRAM_SNAPPY is not set +# CONFIG_ZCACHE is not set +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +# CONFIG_ANDROID_LOGGER_SYSFS is not set +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_MSM_QDSS is not set + +# +# NVBK share memory +# +CONFIG_NVBK_SHARE_MEM=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DYNAMIC_FSYNC is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_PRINTK_RTC_TIME=y +CONFIG_PRINTK_CPU_ID=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_KPROBE_EVENT=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=32768 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_FORCE_PERMISSIVE=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA1_ARM is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_QCRYPTO is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_QCEDEV is not set +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set diff --git a/arch/arm/include/asm.zip b/arch/arm/include/asm.zip new file mode 100644 index 0000000000000000000000000000000000000000..9ee4794a2e20189ceb35463591a28e35a3b0a903 GIT binary patch literal 236089 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 a@Yw%Hrw8$shGr1_lV}FoZ+pR7MDu^hic?Pj literal 0 HcmV?d00001 diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h index 7aa36800..b69c0d32 100644 --- a/arch/arm/include/asm/device.h +++ b/arch/arm/include/asm/device.h @@ -7,12 +7,16 @@ #define ASMARM_DEVICE_H struct dev_archdata { + struct dma_map_ops *dma_ops; #ifdef CONFIG_DMABOUNCE struct dmabounce_device_info *dmabounce; #endif #ifdef CONFIG_IOMMU_API void *iommu; /* private IOMMU data */ #endif +#ifdef CONFIG_ARM_DMA_USE_IOMMU + struct dma_iommu_mapping *mapping; +#endif }; struct omap_device; diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h index eef55ea9..c190bc99 100644 --- a/arch/arm/include/asm/hw_breakpoint.h +++ b/arch/arm/include/asm/hw_breakpoint.h @@ -85,9 +85,6 @@ static inline void decode_ctrl_reg(u32 reg, #define ARM_DSCR_HDBGEN (1 << 14) #define ARM_DSCR_MDBGEN (1 << 15) -/* OSLSR os lock model bits */ -#define ARM_OSLSR_OSLM0 (1 << 0) - /* opcode2 numbers for the co-processor instructions. */ #define ARM_OP2_BVR 4 #define ARM_OP2_BCR 5 @@ -101,12 +98,12 @@ static inline void decode_ctrl_reg(u32 reg, #define ARM_BASE_WCR 112 /* Accessor macros for the debug registers. */ -#define ARM_DBG_READ(N, M, OP2, VAL) do {\ - asm volatile("mrc p14, 0, %0, " #N "," #M ", " #OP2 : "=r" (VAL));\ +#define ARM_DBG_READ(M, OP2, VAL) do {\ + asm volatile("mrc p14, 0, %0, c0," #M ", " #OP2 : "=r" (VAL));\ } while (0) -#define ARM_DBG_WRITE(N, M, OP2, VAL) do {\ - asm volatile("mcr p14, 0, %0, " #N "," #M ", " #OP2 : : "r" (VAL));\ +#define ARM_DBG_WRITE(M, OP2, VAL) do {\ + asm volatile("mcr p14, 0, %0, c0," #M ", " #OP2 : : "r" (VAL));\ } while (0) struct notifier_block; diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 9e17f7ac..b12032b5 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -50,20 +49,17 @@ static int core_num_wrps; /* Debug architecture version. */ static u8 debug_arch; -/* Does debug architecture support OS Save and Restore? */ -static bool has_ossr; - /* Maximum supported watchpoint length. */ static u8 max_watchpoint_len; -#define READ_WB_REG_CASE(OP2, M, VAL) \ - case ((OP2 << 4) + M): \ - ARM_DBG_READ(c0, c ## M, OP2, VAL); \ +#define READ_WB_REG_CASE(OP2, M, VAL) \ + case ((OP2 << 4) + M): \ + ARM_DBG_READ(c ## M, OP2, VAL); \ break -#define WRITE_WB_REG_CASE(OP2, M, VAL) \ - case ((OP2 << 4) + M): \ - ARM_DBG_WRITE(c0, c ## M, OP2, VAL); \ +#define WRITE_WB_REG_CASE(OP2, M, VAL) \ + case ((OP2 << 4) + M): \ + ARM_DBG_WRITE(c ## M, OP2, VAL);\ break #define GEN_READ_WB_REG_CASES(OP2, VAL) \ @@ -140,12 +136,12 @@ static u8 get_debug_arch(void) /* Do we implement the extended CPUID interface? */ if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { - pr_warn_once("CPUID feature registers not supported. " - "Assuming v6 debug is present.\n"); + pr_warning("CPUID feature registers not supported. " + "Assuming v6 debug is present.\n"); return ARM_DEBUG_ARCH_V6; } - ARM_DBG_READ(c0, c0, 0, didr); + ARM_DBG_READ(c0, 0, didr); return (didr >> 16) & 0xf; } @@ -173,7 +169,7 @@ static int debug_exception_updates_fsr(void) static int get_num_wrp_resources(void) { u32 didr; - ARM_DBG_READ(c0, c0, 0, didr); + ARM_DBG_READ(c0, 0, didr); return ((didr >> 28) & 0xf) + 1; } @@ -181,7 +177,7 @@ static int get_num_wrp_resources(void) static int get_num_brp_resources(void) { u32 didr; - ARM_DBG_READ(c0, c0, 0, didr); + ARM_DBG_READ(c0, 0, didr); return ((didr >> 24) & 0xf) + 1; } @@ -232,17 +228,19 @@ static int get_num_brps(void) * be put into halting debug mode at any time by an external debugger * but there is nothing we can do to prevent that. */ -static int monitor_mode_enabled(void) -{ - u32 dscr; - ARM_DBG_READ(c0, c1, 0, dscr); - return !!(dscr & ARM_DSCR_MDBGEN); -} - static int enable_monitor_mode(void) { u32 dscr; - ARM_DBG_READ(c0, c1, 0, dscr); + int ret = 0; + + ARM_DBG_READ(c1, 0, dscr); + + /* Ensure that halting mode is disabled. */ + if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, + "halting debug mode enabled. Unable to access hardware resources.\n")) { + ret = -EPERM; + goto out; + } /* If monitor mode is already enabled, just return. */ if (dscr & ARM_DSCR_MDBGEN) @@ -252,27 +250,24 @@ static int enable_monitor_mode(void) switch (get_debug_arch()) { case ARM_DEBUG_ARCH_V6: case ARM_DEBUG_ARCH_V6_1: - ARM_DBG_WRITE(c0, c1, 0, (dscr | ARM_DSCR_MDBGEN)); + ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN)); break; case ARM_DEBUG_ARCH_V7_ECP14: case ARM_DEBUG_ARCH_V7_1: - ARM_DBG_WRITE(c0, c2, 2, (dscr | ARM_DSCR_MDBGEN)); - isb(); + ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN)); break; default: - return -ENODEV; + ret = -ENODEV; + goto out; } /* Check that the write made it through. */ - ARM_DBG_READ(c0, c1, 0, dscr); - if (!(dscr & ARM_DSCR_MDBGEN)) { - pr_warn_once("Failed to enable monitor mode on CPU %d.\n", - smp_processor_id()); - return -EPERM; - } + ARM_DBG_READ(c1, 0, dscr); + if (!(dscr & ARM_DSCR_MDBGEN)) + ret = -EPERM; out: - return 0; + return ret; } int hw_breakpoint_slots(int type) @@ -333,9 +328,14 @@ int arch_install_hw_breakpoint(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); struct perf_event **slot, **slots; - int i, max_slots, ctrl_base, val_base; + int i, max_slots, ctrl_base, val_base, ret = 0; u32 addr, ctrl; + /* Ensure that we are in monitor mode and halting mode is disabled. */ + ret = enable_monitor_mode(); + if (ret) + goto out; + addr = info->address; ctrl = encode_ctrl_reg(info->ctrl) | 0x1; @@ -362,9 +362,9 @@ int arch_install_hw_breakpoint(struct perf_event *bp) } } - if (i == max_slots) { - pr_warning("Can't find any breakpoint slot\n"); - return -EBUSY; + if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) { + ret = -EBUSY; + goto out; } /* Override the breakpoint data with the step data. */ @@ -383,7 +383,9 @@ int arch_install_hw_breakpoint(struct perf_event *bp) /* Setup the control register. */ write_wb_reg(ctrl_base + i, ctrl); - return 0; + +out: + return ret; } void arch_uninstall_hw_breakpoint(struct perf_event *bp) @@ -414,10 +416,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) } } - if (i == max_slots) { - pr_warning("Can't find any breakpoint slot\n"); + if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) return; - } /* Ensure that we disable the mismatch breakpoint. */ if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE && @@ -596,10 +596,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) int ret = 0; u32 offset, alignment_mask = 0x3; - /* Ensure that we are in monitor debug mode. */ - if (!monitor_mode_enabled()) - return -ENODEV; - /* Build the arch_hw_breakpoint. */ ret = arch_build_bp_info(bp); if (ret) @@ -614,14 +610,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) /* Aligned */ break; case 1: + /* Allow single byte watchpoint. */ + if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) + break; case 2: /* Allow halfword watchpoints and breakpoints. */ if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) break; - case 3: - /* Allow single byte watchpoint. */ - if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) - break; default: ret = -EINVAL; goto out; @@ -862,7 +857,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, local_irq_enable(); /* We only handle watchpoints and hardware breakpoints. */ - ARM_DBG_READ(c0, c1, 0, dscr); + ARM_DBG_READ(c1, 0, dscr); /* Perform perf callbacks. */ switch (ARM_DSCR_MOE(dscr)) { @@ -883,6 +878,18 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, return ret; } +static void reset_brps_reserved_reg(int n) +{ + int i; + + /* we must also reset any reserved registers. */ + for (i = 0; i < n; ++i) { + write_wb_reg(ARM_BASE_BCR + i, 0UL); + write_wb_reg(ARM_BASE_BVR + i, 0UL); + } + +} + /* * One-time initialisation. */ @@ -907,27 +914,10 @@ static struct undef_hook debug_reg_hook = { .fn = debug_reg_trap, }; -/* Does this core support OS Save and Restore? */ -static bool core_has_os_save_restore(void) -{ - u32 oslsr; - - switch (get_debug_arch()) { - case ARM_DEBUG_ARCH_V7_1: - return true; - case ARM_DEBUG_ARCH_V7_ECP14: - ARM_DBG_READ(c1, c1, 4, oslsr); - if (oslsr & ARM_OSLSR_OSLM0) - return true; - default: - return false; - } -} - static void reset_ctrl_regs(void *unused) { int i, raw_num_brps, err = 0, cpu = smp_processor_id(); - u32 val; + u32 dbg_power; /* * v7 debug contains save and restore registers so that debug state @@ -940,89 +930,67 @@ static void reset_ctrl_regs(void *unused) switch (debug_arch) { case ARM_DEBUG_ARCH_V6: case ARM_DEBUG_ARCH_V6_1: - /* ARMv6 cores clear the registers out of reset. */ - goto out_mdbgen; + /* ARMv6 cores just need to reset the registers. */ + goto reset_regs; case ARM_DEBUG_ARCH_V7_ECP14: /* * Ensure sticky power-down is clear (i.e. debug logic is * powered up). */ - ARM_DBG_READ(c1, c5, 4, val); - if ((val & 0x1) == 0) + asm volatile("mrc p14, 0, %0, c1, c5, 4" : "=r" (dbg_power)); + if ((dbg_power & 0x1) == 0) err = -EPERM; - - if (!has_ossr) - goto clear_vcr; break; case ARM_DEBUG_ARCH_V7_1: /* * Ensure the OS double lock is clear. */ - ARM_DBG_READ(c1, c3, 4, val); - if ((val & 0x1) == 1) + asm volatile("mrc p14, 0, %0, c1, c3, 4" : "=r" (dbg_power)); + if ((dbg_power & 0x1) == 1) err = -EPERM; break; } if (err) { - pr_warn_once("CPU %d debug is powered down!\n", cpu); + pr_warning("CPU %d debug is powered down!\n", cpu); cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu)); return; } /* - * Unconditionally clear the OS lock by writing a value + * Unconditionally clear the lock by writing a value * other than 0xC5ACCE55 to the access register. */ - ARM_DBG_WRITE(c1, c0, 4, 0); + asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0)); isb(); /* * Clear any configured vector-catch events before * enabling monitor mode. */ -clear_vcr: - ARM_DBG_WRITE(c0, c7, 0, 0); + asm volatile("mcr p14, 0, %0, c0, c7, 0" : : "r" (0)); isb(); - if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { - pr_warn_once("CPU %d failed to disable vector catch\n", cpu); +reset_regs: + if (enable_monitor_mode()) return; - } - /* - * The control/value register pairs are UNKNOWN out of reset so - * clear them to avoid spurious debug events. - */ - raw_num_brps = get_num_brp_resources(); - for (i = 0; i < raw_num_brps; ++i) { - write_wb_reg(ARM_BASE_BCR + i, 0UL); - write_wb_reg(ARM_BASE_BVR + i, 0UL); - } +#ifdef CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS + reset_brps_reserved_reg(core_num_brps); +#else + reset_brps_reserved_reg(core_num_brps + core_num_reserved_brps); +#endif for (i = 0; i < core_num_wrps; ++i) { write_wb_reg(ARM_BASE_WCR + i, 0UL); write_wb_reg(ARM_BASE_WVR + i, 0UL); } - - if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { - pr_warn_once("CPU %d failed to clear debug register pairs\n", cpu); - return; - } - - /* - * Have a crack at enabling monitor mode. We don't actually need - * it yet, but reporting an error early is useful if it fails. - */ -out_mdbgen: - if (enable_monitor_mode()) - cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu)); } static int dbg_reset_notify(struct notifier_block *self, unsigned long action, void *cpu) { - if ((action & ~CPU_TASKS_FROZEN) == CPU_ONLINE) + if (action == CPU_ONLINE) smp_call_function_single((int)cpu, reset_ctrl_regs, NULL, 1); return NOTIFY_OK; @@ -1032,32 +1000,10 @@ static struct notifier_block dbg_reset_nb = { .notifier_call = dbg_reset_notify, }; -#ifdef CONFIG_CPU_PM -static int dbg_cpu_pm_notify(struct notifier_block *self, unsigned long action, - void *v) -{ - if (action == CPU_PM_EXIT) - reset_ctrl_regs(NULL); - - return NOTIFY_OK; -} - -static struct notifier_block dbg_cpu_pm_nb = { - .notifier_call = dbg_cpu_pm_notify, -}; - -static void __init pm_init(void) -{ - cpu_pm_register_notifier(&dbg_cpu_pm_nb); -} -#else -static inline void pm_init(void) -{ -} -#endif - static int __init arch_hw_breakpoint_init(void) { + u32 dscr; + debug_arch = get_debug_arch(); if (!debug_arch_supported()) { @@ -1065,8 +1011,6 @@ static int __init arch_hw_breakpoint_init(void) return 0; } - has_ossr = core_has_os_save_restore(); - /* Determine how many BRPs/WRPs are available. */ core_num_brps = get_num_brps(); core_num_wrps = get_num_wrps(); @@ -1094,10 +1038,17 @@ static int __init arch_hw_breakpoint_init(void) core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " : "", core_num_wrps); - /* Work out the maximum supported watchpoint length. */ - max_watchpoint_len = get_max_wp_len(); - pr_info("maximum watchpoint size is %u bytes.\n", - max_watchpoint_len); + ARM_DBG_READ(c1, 0, dscr); + if (dscr & ARM_DSCR_HDBGEN) { + max_watchpoint_len = 4; + pr_warning("halting debug mode enabled. Assuming maximum watchpoint size of %u bytes.\n", + max_watchpoint_len); + } else { + /* Work out the maximum supported watchpoint length. */ + max_watchpoint_len = get_max_wp_len(); + pr_info("maximum watchpoint size is %u bytes.\n", + max_watchpoint_len); + } /* Register debug fault handler. */ hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, @@ -1105,11 +1056,8 @@ static int __init arch_hw_breakpoint_init(void) hook_ifault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT, "breakpoint debug exception"); - /* Register hotplug and PM notifiers. */ - __register_cpu_notifier(&dbg_reset_nb); - - cpu_notifier_register_done(); - pm_init(); + /* Register hotplug notifier. */ + register_cpu_notifier(&dbg_reset_nb); return 0; } arch_initcall(arch_hw_breakpoint_init); diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 2cdc5462..40a4bb1b 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -409,6 +409,7 @@ config ARCH_MSM_KRAITMP select HAVE_ARCH_HAS_CURRENT_TIMER select MSM_JTAG if MSM_QDSS bool + select HAVE_HW_BRKPT_RESERVED_RW_ACCESS config ARCH_MSM_CORTEXMP select MSM_SMP @@ -419,6 +420,7 @@ config MSM_KRAIT_WFE_FIXUP config ARCH_MSM_CORTEX_A5 bool + select HAVE_HW_BRKPT_RESERVED_RW_ACCESS config ARCH_MSM7X27A bool @@ -532,6 +534,12 @@ config MACH_MSM7X27A_FFA help Support for the Qualcomm MSM7x27A FFA. +config WERITOS_KERNEL + depends on ARCH_MSM7X27A + bool "Kernel weritos" + help + Support for the Weritos Kernel + config MACH_MSM7625A_SURF depends on ARCH_MSM7X27A depends on !MSM_STACKED_MEMORY @@ -983,20 +991,17 @@ config PHYS_OFFSET default "0x40200000" if ARCH_MSM8X60 default "0x10000000" -config KERNEL_MSM_CONTIG_MEM_REGION - bool "Enable in-kernel contiguous memory region" +config KERNEL_PMEM_EBI_REGION + bool "Enable in-kernel PMEM region for EBI" default y if ARCH_MSM8X60 - depends on ANDROID_PMEM && (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974) + depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974) help - Enable the in-kernel contiguous memory allocator. Sets up a - region of physically contiguous memory. This memory is - reserved during initialization, and can be used - generically. + Enable the in-kernel PMEM allocator to use EBI memory. config KERNEL_PMEM_SMI_REGION bool "Enable in-kernel PMEM region for SMI" default y if ARCH_MSM8X60 - depends on (ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM) + depends on ((ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM)) help Enable the in-kernel PMEM allocator to use SMI memory. @@ -1350,6 +1355,20 @@ config MSM_PCIE Enables the PCIe functionality by configures PCIe core on MSM chipset and by enabling the ARM PCI framework extension. +config MSM_RPC_SDIO_XPRT + depends on MSM_SDIO_AL + default y + bool "MSM SDIO XPRT Layer" + help + SDIO Transport Layer for RPC Rouer + +config MSM_RPC_SDIO_DEBUG + depends on MSM_RPC_SDIO_XPRT + default y + bool "MSM SDIO XPRT debug support" + help + Support for debugging SDIO XPRT + config MSM_FUSE_INFO_DEBUG default y bool "MSM FUSE debug support" @@ -1370,6 +1389,21 @@ config MSM_FAST_BOOT help Enable the fast power on support in MSM platform. +config MSM_SDIO_AL + depends on ((ARCH_MSM7X30 || MACH_MSM8X60_FUSN_FFA || MACH_TYPE_MSM8X60_FUSION) && HAS_WAKELOCK) + default y + tristate "SDIO-Abstraction-Layer" + help + Support MSM<->MDM Communication over SDIO bus. + MDM SDIO-Client should have pipes support. + +config MSM_SDIO_DMUX + bool "SDIO Data Mux Driver" + depends on MSM_SDIO_AL + default n + help + Support Muxed Data Channels over SDIO interface. + config MSM_BAM_DMUX bool "BAM Data Mux Driver" depends on SPS @@ -1429,6 +1463,16 @@ config MSM_SMD_NMEA If in doubt, say yes. +config MSM_SDIO_TTY + bool "SDIO TTY Driver" + depends on MSM_SDIO_AL + default n + help + Provides a TTY driver SDIO TTY + This driver can be used by user space + applications for passing data through the + SDIO interface. + config MSM_SMD_TTY bool "SMD TTY Driver" depends on MSM_SMD @@ -1456,6 +1500,13 @@ config MSM_SMD_PKT If in doubt, say yes. +config MSM_SDIO_CMUX + bool "SDIO CMUX Driver" + depends on MSM_SDIO_AL + default n + help + Provides a Muxed port interface over SDIO QMI + config MSM_DSPS bool "Sensors DSPS driver" depends on (MSM_PIL && (ARCH_MSM8X60 || ARCH_MSM8960)) @@ -1468,6 +1519,13 @@ config MSM_DSPS The number of clocks and their name may vary between targets. It also triggers the PIL to load the DSPS firmware. +config MSM_SDIO_CTL + bool "SDIO CTL Driver" + depends on MSM_SDIO_CMUX + default n + help + Provides a binary SDIO control port interface. + config MSM_ONCRPCROUTER depends on MSM_SMD default n @@ -1575,6 +1633,15 @@ config MSM_RMT_STORAGE_CLIENT_STATS Collects performance statistics and shows this information through a debugfs file rmt_storage_stats. +config MSM_SDIO_SMEM + depends on MSM_SDIO_AL + default n + bool "SDIO SMEM for remote storage" + help + Copies data from remote MDM9K memory to local MSM8x60 + memory. Used by remote storage client to shadow + MDM9K filesystem. + config MSM_DALRPC bool "DAL RPC support" default n @@ -1631,7 +1698,6 @@ config MSM_AVS_HW config MSM_HW3D tristate "MSM Hardware 3D Register Driver" - default y help Provides access to registers needed by the userspace OpenGL|ES library. @@ -2119,6 +2185,10 @@ config MSM_PM8X60 depends on PM bool +config MSM_NOPM + default y if !PM + bool + config MSM_EVENT_TIMER bool "Event timer" help @@ -2127,10 +2197,6 @@ config MSM_EVENT_TIMER events that require the core to be awake and ready to handle the event. -config MSM_NOPM - default y if !PM - bool - config MSM_BUS_SCALING bool "Bus scaling driver" default n @@ -2201,7 +2267,7 @@ config MSM_RUN_QUEUE_STATS on when to switch off/on the other cores. config MSM_SM_EVENT - bool "Enable system event monitor" + bool "Enable system event monitor select UNCACHED_BUF default n @@ -2581,4 +2647,18 @@ config MSM_OVERCLOCK_GPU Enables overclocking of adreno 203 gpu. This is rather dangerous. If unsure, say N. +config INTELLI_PLUG + bool "Enable intelli-plug cpu hotplug driver" + default n + help + Generic Intelli-plug cpu hotplug driver for ARM SOCs + +config BRICKED_HOTPLUG + bool "Enable kernel based brick" + depends on MSM_RUN_QUEUE_STATS + default n + help + This enables kernel based multi core control. + (up/down hotplug based on load) + endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index de1e7d83..ae13d3ff 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -43,6 +43,9 @@ obj-$(CONFIG_ARCH_MSM_SCORPION) += msm_fault_handlers.o endif obj-$(CONFIG_MSM_VIC) += irq-vic.o +obj-$(CONFIG_MSM_EVENT_TIMER) += event_timer.o +obj-$(CONFIG_BRICKED_HOTPLUG) += bricked_hotplug.o +obj-$(CONFIG_INTELLI_PLUG) += intelli_plug.o ifdef CONFIG_ARCH_QSD8X50 obj-$(CONFIG_MSM_SOC_REV_NONE) += acpuclock-8x50.o @@ -93,6 +96,10 @@ obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o +obj-$(CONFIG_MSM_SDIO_AL) += sdio_al.o +obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_test.o +obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_dloader.o +obj-$(CONFIG_MSM_SDIO_DMUX) += sdio_dmux.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging.o @@ -124,10 +131,13 @@ endif endif endif endif +obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o obj-$(CONFIG_MSM_SMD_PKT) += smd_pkt.o +obj-$(CONFIG_MSM_SDIO_CMUX) += sdio_cmux.o obj-$(CONFIG_MSM_DSPS) += msm_dsps.o +obj-$(CONFIG_MSM_SDIO_CTL) += sdio_ctl.o obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o @@ -140,6 +150,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_xdr.o obj-$(CONFIG_MSM_ONCRPCROUTER) += rpcrouter_smd_xprt.o +obj-$(CONFIG_MSM_RPC_SDIO_XPRT) += rpcrouter_sdio_xprt.o obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o ping_apps_server.o @@ -312,6 +323,7 @@ obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o obj-$(CONFIG_HTC_HEADSET) += htc_headset.o obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o +obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o obj-$(CONFIG_MSM_RPM) += rpm.o ifdef CONFIG_MSM_RPM obj-$(CONFIG_ARCH_APQ8064) += rpm_resources.o @@ -332,7 +344,6 @@ obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/ obj-$(CONFIG_MSM_BUSPM_DEV) += msm-buspm-dev.o obj-$(CONFIG_MSM_IOMMU) += devices-iommu.o iommu_domains.o -obj-$(CONFIG_MSM_EVENT_TIMER) += event_timer.o ifdef CONFIG_VCM obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o @@ -356,7 +367,7 @@ obj-$(CONFIG_MSM_SM_EVENT) += sm_event.o obj-$(CONFIG_MSM_SM_EVENT_LOG) += sm_event_log.o sm_event_driver.o obj-$(CONFIG_MSM_SLEEP_MONITOR) += sleep_monitor.o obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o -obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o +obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o obj-$(CONFIG_BT_MSM_PINTEST) += btpintest.o diff --git a/arch/arm/mach-msm/audio-7627a-devices.c b/arch/arm/mach-msm/audio-7627a-devices.c index 30a079fd..2530ab3e 100644 --- a/arch/arm/mach-msm/audio-7627a-devices.c +++ b/arch/arm/mach-msm/audio-7627a-devices.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "board-msm7627a.h" diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c index 23eb3a7f..5f6f3e0a 100644 --- a/arch/arm/mach-msm/board-8064.c +++ b/arch/arm/mach-msm/board-8064.c @@ -95,7 +95,7 @@ #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION #define HOLE_SIZE 0x20000 -#define MSM_CONTIG_MEM_SIZE 0x65000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000 #ifdef CONFIG_MSM_IOMMU #define MSM_ION_MM_SIZE 0x3800000 #define MSM_ION_SF_SIZE 0 @@ -111,7 +111,7 @@ #define MSM_ION_MFC_SIZE SZ_8K #define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE #else -#define MSM_CONTIG_MEM_SIZE 0x110C000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000 #define MSM_ION_HEAP_NUM 1 #endif @@ -132,14 +132,14 @@ #define PCIE_PWR_EN_PMIC_GPIO 13 #define PCIE_RST_N_PMIC_MPP 1 -#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION -static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE; -static int __init msm_contig_mem_size_setup(char *p) +#ifdef CONFIG_KERNEL_PMEM_EBI_REGION +static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE; +static int __init pmem_kernel_ebi1_size_setup(char *p) { - msm_contig_mem_size = memparse(p, NULL); + pmem_kernel_ebi1_size = memparse(p, NULL); return 0; } -early_param("msm_contig_mem_size", msm_contig_mem_size_setup); +early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); #endif #ifdef CONFIG_ANDROID_PMEM @@ -262,7 +262,7 @@ static void __init reserve_pmem_memory(void) reserve_memory_for(&android_pmem_pdata); reserve_memory_for(&android_pmem_audio_pdata); #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/ - apq8064_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size; + apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; #endif /*CONFIG_ANDROID_PMEM*/ } diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c index f65da89e..cff798e5 100644 --- a/arch/arm/mach-msm/board-8930.c +++ b/arch/arm/mach-msm/board-8930.c @@ -137,7 +137,7 @@ struct sx150x_platform_data msm8930_sx150x_data[] = { #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION #define HOLE_SIZE 0x20000 -#define MSM_CONTIG_MEM_SIZE 0x65000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000 #ifdef CONFIG_MSM_IOMMU #define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */ #define MSM_ION_SF_SIZE 0x0 @@ -164,18 +164,18 @@ struct sx150x_platform_data msm8930_sx150x_data[] = { #define MSM8930_FW_START MSM8930_FIXED_AREA_START #else -#define MSM_CONTIG_MEM_SIZE 0x110C000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000 #define MSM_ION_HEAP_NUM 1 #endif -#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION -static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE; -static int __init msm_contig_mem_size_setup(char *p) +#ifdef CONFIG_KERNEL_PMEM_EBI_REGION +static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE; +static int __init pmem_kernel_ebi1_size_setup(char *p) { - msm_contig_mem_size = memparse(p, NULL); + pmem_kernel_ebi1_size = memparse(p, NULL); return 0; } -early_param("msm_contig_mem_size", msm_contig_mem_size_setup); +early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); #endif #ifdef CONFIG_ANDROID_PMEM @@ -318,7 +318,7 @@ static void __init reserve_pmem_memory(void) reserve_memory_for(&android_pmem_pdata); reserve_memory_for(&android_pmem_audio_pdata); #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/ - msm8930_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size; + msm8930_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; #endif /*CONFIG_ANDROID_PMEM*/ } diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c index d6dd2006..59abf588 100644 --- a/arch/arm/mach-msm/board-8960.c +++ b/arch/arm/mach-msm/board-8960.c @@ -146,7 +146,7 @@ struct sx150x_platform_data msm8960_sx150x_data[] = { #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION #define HOLE_SIZE 0x20000 -#define MSM_CONTIG_MEM_SIZE 0x65000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000 #ifdef CONFIG_MSM_IOMMU #define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */ #define MSM_ION_SF_SIZE 0x0 @@ -174,18 +174,18 @@ struct sx150x_platform_data msm8960_sx150x_data[] = { static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE; #else -#define MSM_CONTIG_MEM_SIZE 0x110C000 +#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000 #define MSM_ION_HEAP_NUM 1 #endif -#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION -static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE; -static int __init msm_contig_mem_size_setup(char *p) +#ifdef CONFIG_KERNEL_PMEM_EBI_REGION +static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE; +static int __init pmem_kernel_ebi1_size_setup(char *p) { - msm_contig_mem_size = memparse(p, NULL); + pmem_kernel_ebi1_size = memparse(p, NULL); return 0; } -early_param("msm_contig_mem_size", msm_contig_mem_size_setup); +early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); #endif #ifdef CONFIG_ANDROID_PMEM @@ -337,7 +337,7 @@ static void __init reserve_pmem_memory(void) reserve_memory_for(&android_pmem_pdata); reserve_memory_for(&android_pmem_audio_pdata); #endif - msm8960_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size; + msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; #endif } diff --git a/arch/arm/mach-msm/board-msm7627a_i6-display.c b/arch/arm/mach-msm/board-msm7627a_i6-display.c new file mode 100644 index 00000000..cf457bc7 --- /dev/null +++ b/arch/arm/mach-msm/board-msm7627a_i6-display.c @@ -0,0 +1,535 @@ +/* Copyright (c) 2012, 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 DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devices.h" +#include "board-msm7627a.h" +#include +#include + +#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER +#define MSM_FB_SIZE 0x4BF000 +#define MSM7x25A_MSM_FB_SIZE 0x1C2000 +#define MSM8x25_MSM_FB_SIZE 0x5FA000 +#else +#define MSM_FB_SIZE 0x32A000 +#define MSM7x25A_MSM_FB_SIZE 0x12C000 +#define MSM8x25_MSM_FB_SIZE 0x3FC000 +#endif + +//linxc 12-06-19 +++ +#define MSM8x25_I6_MSM_FB_SIZE 0x5FB000 //add linxc 2012-12-21 +++ +#define GPIO_I6_LCD_BRDG_RESET_N 85 +#define GPIO_I6_LCD_BACKLIGHT_EN 96 +#define GPIO_I6_LCD_VDD_3V3_EN 12 +#define GPIO_I6_MIPI_DETECT 107 +//linxc 12-06-19 - - - + + +#define MACHINE_IS_JSR_I6 \ + (machine_is_msm7627a_evb() || machine_is_msm8625_evb() || machine_is_msm8625_qrd5() || machine_is_msm7x27a_qrd5a()) + +#define MACHINE_IS_JSR_I6Q \ + (machine_is_msm8625_skud()) + +/* + * Reserve enough v4l2 space for a double buffered full screen + * res image (864x480x1.5x2) + */ +#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 1244160 + +static unsigned fb_size = MSM_FB_SIZE; +static int __init fb_size_setup(char *p) +{ + fb_size = memparse(p, NULL); + return 0; +} + +early_param("fb_size", fb_size_setup); + + +static struct resource msm_fb_resources[] = { + { + .flags = IORESOURCE_DMA, + } +}; + +#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE +static struct resource msm_v4l2_video_overlay_resources[] = { + { + .flags = IORESOURCE_DMA, + } +}; +#endif + + +static int i6_mipi_gpio_initialized = 0; +static int i6_mipi_gpio_status = 0; + +#define GPIO_I6_MIPI_DETECT 107 + +static int I6_mipi_panel_is_novatek_nt35516(void) +{ + unsigned int conf; + pr_err("%s\n", __func__); + if (!i6_mipi_gpio_initialized) { + if (gpio_request(GPIO_I6_MIPI_DETECT, "I6_mipi_detect") < 0) { + pr_err("%s: gpio_request I6_mipi_detect failed!", __func__); + return i6_mipi_gpio_status; + } + conf = GPIO_CFG(GPIO_I6_MIPI_DETECT, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA); // 0x6B0 + if (gpio_tlmm_config(conf, GPIO_CFG_ENABLE) >= 0) { + i6_mipi_gpio_status = gpio_get_value(GPIO_I6_MIPI_DETECT); + pr_err("%s: is_nt35516 = %d\n", __func__, i6_mipi_gpio_status); + i6_mipi_gpio_initialized = 1; + } else { + pr_err("%s: unable to config I6_mipi_detect\n", __func__); + } + gpio_free(GPIO_I6_MIPI_DETECT); + } + return i6_mipi_gpio_status; +} + +static int msm_fb_detect_panel(const char *name) +{ + int ret = -ENODEV; + pr_err("%s: name = \"%s\"\n", __func__, name); + if (MACHINE_IS_JSR_I6) { + if (!strncmp(name, "mipi_cmd_novatek_nt35516_qhd", 28)) { + if (I6_mipi_panel_is_novatek_nt35516()) { + pr_err("I6 LCD is cmd novatek nt35516\n"); + ret = 0; + } + } + if (!strncmp(name, "mipi_cmd_truly_nt35516_qhd", 25)) { + if (!I6_mipi_panel_is_novatek_nt35516()) { + pr_err("I6 LCD is truly\n"); + ret = 0; + } + } + } + return ret; +} + + +static struct msm_fb_platform_data msm_fb_pdata = { + .detect_client = msm_fb_detect_panel, +}; + +static struct platform_device msm_fb_device = { + .name = "msm_fb", + .id = 0, + .num_resources = ARRAY_SIZE(msm_fb_resources), + .resource = msm_fb_resources, + .dev = { + .platform_data = &msm_fb_pdata, + } +}; + +#if 0 +#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE +static struct platform_device msm_v4l2_video_overlay_device = { + .name = "msm_v4l2_overlay_pd", + .id = 0, + .num_resources = ARRAY_SIZE(msm_v4l2_video_overlay_resources), + .resource = msm_v4l2_video_overlay_resources, + }; +#endif +#endif + +static int i6_bl_level = 0; + +static int mipi_I6_qhd_set_bl(int level) +{ + int ret = 0; + int value = 0; + ret = pmapp_disp_backlight_set_brightness(level); + if (ret) + pr_err("%s: can't set lcd backlight! \n", __func__); + if (level == i6_bl_level) { + pr_err("%s: no change\n", __func__); + return 0; + } + if (level == 255) { + value = 0; + } else { + if (i6_bl_level != 255) { + i6_bl_level = level; + return 0; + } + msleep(25); + value = 1; + } + gpio_set_value(GPIO_I6_LCD_BACKLIGHT_EN, value); + i6_bl_level = level; + return 0; +} + +// ------------------------------------------------------------------- + +static int mipi_truly_nt35516_qhd_rotate_panel(void) +{ + int rotate = 0; + if (machine_is_msm8625_qrd5() || machine_is_msm7x27a_qrd5a()) + rotate = 1; + return rotate; +} + +static int mipi_nt35516_qhd_rotate_panel(void) +{ + int rotate = 0; + if (machine_is_msm8625_qrd5() || machine_is_msm7x27a_qrd5a()) + rotate = 1; + return rotate; +} + +// ------------------------------------------------------------------- + +static struct msm_panel_common_pdata mipi_truly_nt35516_qhd_pdata = { + .pmic_backlight = NULL, + .rotate_panel = mipi_truly_nt35516_qhd_rotate_panel, +}; + +static struct platform_device mipi_dsi_truly_nt35516_qhd_panel_device = { + .name = "mipi_truly_nt35516_qhd", + .id = 0, + .dev = { + .platform_data = &mipi_truly_nt35516_qhd_pdata, + } +}; + +// ------------------------------------------------------------------- + +static struct msm_panel_common_pdata mipi_novatek_nt35516_qhd_pdata = { + .pmic_backlight = NULL, + .rotate_panel = mipi_nt35516_qhd_rotate_panel, +}; + +static struct platform_device mipi_dsi_novatek_nt35516_qhd_panel_device = { + .name = "mipi_novatek_nt35516_qhd", + .id = 0, + .dev = { + .platform_data = &mipi_novatek_nt35516_qhd_pdata, + } +}; + +// ------------------------------------------------------------------- + +static struct msm_panel_common_pdata mipi_video_nt35516_qhd_qhd_v2_pdata = { + .pmic_backlight = mipi_I6_qhd_set_bl, + .rotate_panel = mipi_truly_nt35516_qhd_rotate_panel, +}; + +static struct platform_device mipi_dsi_truly_nt35516_qhd_v2_panel_device = { + .name = "mipi_truly_nt35516_qhd", + .id = 0, + .dev = { + .platform_data = &mipi_video_nt35516_qhd_qhd_v2_pdata, + } +}; + +// ------------------------------------------------------------------- + +static struct msm_panel_common_pdata mipi_novatek_nt35516_qhd_v2_pdata = { + .pmic_backlight = mipi_I6_qhd_set_bl, + .rotate_panel = mipi_nt35516_qhd_rotate_panel, +}; + +static struct platform_device mipi_dsi_novatek_nt35516_qhd_v2_panel_device = { + .name = "mipi_novatek_nt35516_qhd", + .id = 0, + .dev = { + .platform_data = &mipi_novatek_nt35516_qhd_v2_pdata, + } +}; + +// ------------------------------------------------------------------- + +static struct platform_device *evb_fb_devices[] __initdata = { + &msm_fb_device, + //&mipi_dsi_NT35510_panel_device, + //&mipi_dsi_NT35516_panel_device, + &mipi_dsi_truly_nt35516_qhd_panel_device, + &mipi_dsi_novatek_nt35516_qhd_panel_device, +}; + +static struct platform_device *evb2_fb_devices[] __initdata = { + &msm_fb_device, + &mipi_dsi_truly_nt35516_qhd_v2_panel_device, + &mipi_dsi_novatek_nt35516_qhd_v2_panel_device, +}; + +// ------------------------------------------------------------------- + +void __init msm_msm7627a_allocate_memory_regions(void) +{ + void *addr; + unsigned long fb_size = MSM_FB_SIZE; + + if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) { + fb_size = MSM7x25A_MSM_FB_SIZE; + } else + if (MACHINE_IS_JSR_I6) { + fb_size = MSM8x25_MSM_FB_SIZE; + if (machine_is_msm8625_qrd5()) + fb_size = MSM8x25_I6_MSM_FB_SIZE; + } else + if (machine_is_msm8625q_skud()) { + fb_size = MSM8x25_MSM_FB_SIZE; + } + + addr = alloc_bootmem_align(fb_size, 0x1000); + msm_fb_resources[0].start = __pa(addr); + msm_fb_resources[0].end = msm_fb_resources[0].start + fb_size - 1; + pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", fb_size, addr, __pa(addr)); + +#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE + fb_size = MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE; + addr = alloc_bootmem_align(fb_size, 0x1000); + msm_v4l2_video_overlay_resources[0].start = __pa(addr); + msm_v4l2_video_overlay_resources[0].end = + msm_v4l2_video_overlay_resources[0].start + fb_size - 1; + pr_debug("allocating %lu bytes at %p (%lx physical) for v4l2\n", + fb_size, addr, __pa(addr)); +#endif + +} + +static struct msm_panel_common_pdata mdp_pdata = { + .gpio = 97, + .mdp_rev = MDP_REV_303, + .cont_splash_enabled = 0x1, +}; + +#define GPIO_LCDC_BRDG_PD 128 +#define GPIO_LCDC_BRDG_RESET_N 129 +#define GPIO_LCD_DSI_SEL 125 +#define LCDC_RESET_PHYS 0x90008014 + +enum { + DSI_SINGLE_LANE = 1, + DSI_TWO_LANES, +}; + +static int msm_fb_get_lane_config(void) +{ + /* For MSM7627A SURF/FFA and QRD */ + int rc = DSI_TWO_LANES; + if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) { + rc = DSI_SINGLE_LANE; + pr_info("DSI_SINGLE_LANES\n"); + } else { + pr_info("DSI_TWO_LANES\n"); + } + return rc; +} + +static int msm_fb_dsi_client_I6_reset(void) +{ + int rc = 0; + pr_err("linxc: %s \n", __func__); + rc = gpio_request(GPIO_I6_LCD_BRDG_RESET_N, "i6_lcd_brdg_reset_n"); + if (rc < 0) + pr_err("%s: failed to request i6 lcd brdg reset_n\n", __func__); + return rc; +} + +static int msm_fb_dsi_client_reset(void) +{ + int rc = 0; + if (MACHINE_IS_JSR_I6) + rc = msm_fb_dsi_client_I6_reset(); + return rc; +} + +static struct regulator_bulk_data regs_dsi[] = { + { .supply = "gp2", .min_uV = 2850000, .max_uV = 2850000 }, + { .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 }, +}; + +static int dsi_gpio_initialized; + +/* Common EXT power control for QRD */ +static struct regulator *gpio_reg_2p85v; +static struct regulator *gpio_reg_1p8v; +//static struct regulator *gpio_reg_3p3v; + +static int mipi_dsi_panel_msm_power(int on) +{ + int rc = 0; + + /* I2C-controlled GPIO Expander -init of the GPIOs very late */ + if (unlikely(!dsi_gpio_initialized)) { + pmapp_disp_backlight_init(); + + rc = gpio_request(GPIO_DISPLAY_PWR_EN, "gpio_disp_pwr"); + if (rc < 0) { + pr_err("failed to request gpio_disp_pwr\n"); + return rc; + } + rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_dsi), regs_dsi); + if (rc) { + pr_err("%s: could not get regulators: %d\n", + __func__, rc); + goto fail_gpio2; + } + + rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_dsi), + regs_dsi); + if (rc) { + pr_err("%s: could not set voltages: %d\n", + __func__, rc); + goto fail_vreg; + } + if (pmapp_disp_backlight_set_brightness(100)) + pr_err("%s: backlight set brightness failed\n", __func__); + + dsi_gpio_initialized = 1; + } + + if (on) { + gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 0); + gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 0); + msleep(20); + gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1); + msleep(20); + } else { + gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 1); + } + + rc = on ? regulator_bulk_enable(ARRAY_SIZE(regs_dsi), regs_dsi) : + regulator_bulk_disable(ARRAY_SIZE(regs_dsi), regs_dsi); + + if (rc) + pr_err("%s: could not %sable regulators: %d\n", + __func__, on ? "en" : "dis", rc); + + return rc; +fail_vreg: + regulator_bulk_free(ARRAY_SIZE(regs_dsi), regs_dsi); +fail_gpio2: +// gpio_free(GPIO_BACKLIGHT_EN); +//fail_gpio1: + gpio_free(GPIO_DISPLAY_PWR_EN); + dsi_gpio_initialized = 0; + return rc; +} + +static char mipi_dsi_splash_is_enabled(void); + +static int mipi_dsi_panel_power(int on) +{ + return mipi_dsi_panel_msm_power(on); +} + +#define MDP_303_VSYNC_GPIO 97 + +#ifdef CONFIG_FB_MSM_MIPI_DSI +static struct mipi_dsi_platform_data mipi_dsi_pdata = { + .vsync_gpio = MDP_303_VSYNC_GPIO, + .dsi_power_save = mipi_dsi_panel_power, + .dsi_client_reset = msm_fb_dsi_client_reset, + .get_lane_config = msm_fb_get_lane_config, + .splash_is_enabled = mipi_dsi_splash_is_enabled, +}; +#endif + +static char mipi_dsi_splash_is_enabled(void) +{ + return mdp_pdata.cont_splash_enabled; +} + +static char prim_panel_name[PANEL_NAME_MAX_LEN]; +static int __init prim_display_setup(char *param) +{ + if (strnlen(param, PANEL_NAME_MAX_LEN)) + strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN); + return 0; +} +early_param("prim_display", prim_display_setup); + +static int disable_splash; + +void msm7x27a_set_display_params(char *prim_panel) +{ + int n0, n1; + const char * pn0 = "mipi_cmd_novatek_nt35516_qhd"; + const char * pn1 = "mipi_cmd_truly_nt35516_qhd"; + char * ppn = (char *)msm_fb_pdata.prim_panel_name; + if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) { + strlcpy(ppn, prim_panel, PANEL_NAME_MAX_LEN); + pr_err("msm_fb_pdata.prim_panel_name = %s\n", ppn); + } + if (strnlen(ppn, PANEL_NAME_MAX_LEN)) { + n0 = strncmp(ppn, pn0, strlen(pn0)); + n1 = strncmp(ppn, pn1, strlen(pn1)); + if (n0 && n1) + disable_splash = 1; + } +} + +void __init msm_fb_add_devices(void) +{ + int rc = 0; + + msm7x27a_set_display_params(prim_panel_name); + + if (MACHINE_IS_JSR_I6) { + if (disable_splash) + mdp_pdata.cont_splash_enabled = 0x0; + if (socinfo_get_platform_version() == 0x10000) { + platform_add_devices(evb_fb_devices, ARRAY_SIZE(evb_fb_devices)); + } + if (socinfo_get_platform_version() == 0x20000) { + platform_add_devices(evb2_fb_devices, ARRAY_SIZE(evb2_fb_devices)); + } + } + + msm_fb_register_device("mdp", &mdp_pdata); + +#ifdef CONFIG_FB_MSM_MIPI_DSI + msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata); +#endif + if (MACHINE_IS_JSR_I6) { + gpio_reg_2p85v = regulator_get(&mipi_dsi_device.dev, "lcd_vdd"); + if (IS_ERR(gpio_reg_2p85v)) + pr_err("%s:ext_2p85v regulator get failed", __func__); + + gpio_reg_1p8v = regulator_get(&mipi_dsi_device.dev, "lcd_vddi"); + if (IS_ERR(gpio_reg_1p8v)) + pr_err("%s:ext_1p8v regulator get failed", __func__); + + if (mdp_pdata.cont_splash_enabled) { + /*Enable EXT_2.85 and 1.8 regulators*/ + rc = regulator_enable(gpio_reg_2p85v); + if (rc < 0) + pr_err("%s: reg enable failed\n", __func__); + rc = regulator_enable(gpio_reg_1p8v); + if (rc < 0) + pr_err("%s: reg enable failed\n", __func__); + } + } +} diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c index 5f0d75f2..cca38b0f 100644 --- a/arch/arm/mach-msm/board-msm7x27.c +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -54,7 +54,6 @@ #include #include #include -#include #include #ifdef CONFIG_USB_G_ANDROID diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c index cf93590b..497d5704 100644 --- a/arch/arm/mach-msm/board-msm7x27a.c +++ b/arch/arm/mach-msm/board-msm7x27a.c @@ -38,7 +38,7 @@ #include #include #include -#include + #include #include #include @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include "devices.h" @@ -68,8 +68,8 @@ #include -#define PMEM_KERNEL_EBI1_SIZE 0x3A000 -#define MSM_PMEM_AUDIO_SIZE 0xF0000 +#define RESERVE_KERNEL_EBI1_SIZE 0x3A000 +#define MSM_RESERVE_AUDIO_SIZE 0xF0000 #define BOOTLOADER_BASE_ADDR 0x10000 //start yang.chenglei@byd added for smem_kpanic @@ -207,20 +207,12 @@ static struct msm_i2c_platform_data msm_gsbi1_qup_i2c_pdata = { }; #ifdef CONFIG_ARCH_MSM7X27A -//lwl modify -#define MSM_PMEM_MDP_SIZE 0xC65D40 -//#define MSM_PMEM_MDP_SIZE 0 -//end -#define MSM7x25A_MSM_PMEM_MDP_SIZE 0x1500000 -#endif +#define MSM_RESERVE_MDP_SIZE 0x2300000 +#define MSM7x25A_MSM_RESERVE_MDP_SIZE 0x1500000 -#ifdef CONFIG_CMA -#define MSM_PMEM_ADSP_SIZE 0 -#define MSM7x25A_MSM_PMEM_ADSP_SIZE 0 +#define MSM_RESERVE_ADSP_SIZE 0x1300000 +#define MSM7x25A_MSM_RESERVE_ADSP_SIZE 0xB91000 #define CAMERA_ZSL_SIZE (SZ_1M * 60) -#else -#define MSM_PMEM_ADSP_SIZE 0xBAEB90 -#define MSM7x25A_MSM_PMEM_ADSP_SIZE 0xB91000 #endif #ifdef CONFIG_ION_MSM @@ -544,62 +536,22 @@ static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = { .v_addr = MSM_CFG_CTL_BASE, }; -static struct android_pmem_platform_data android_pmem_adsp_pdata = { - .name = "pmem_adsp", - .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, - .cached = 1, - .memory_type = MEMTYPE_EBI1, -}; - -static struct platform_device android_pmem_adsp_device = { - .name = "android_pmem", - .id = 1, - .dev = { .platform_data = &android_pmem_adsp_pdata }, -}; - -static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE; -static int __init pmem_mdp_size_setup(char *p) +static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE; +static int __init reserve_mdp_size_setup(char *p) { - pmem_mdp_size = memparse(p, NULL); + reserve_mdp_size = memparse(p, NULL); return 0; } -early_param("pmem_mdp_size", pmem_mdp_size_setup); +early_param("reserve_mdp_size", reserve_mdp_size_setup); -static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE; -static int __init pmem_adsp_size_setup(char *p) +static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; +static int __init reserve_adsp_size_setup(char *p) { - pmem_adsp_size = memparse(p, NULL); + reserve_adsp_size = memparse(p, NULL); return 0; } - -early_param("pmem_adsp_size", pmem_adsp_size_setup); - -static struct android_pmem_platform_data android_pmem_audio_pdata = { - .name = "pmem_audio", - .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, - .cached = 0, - .memory_type = MEMTYPE_EBI1, -}; - -static struct platform_device android_pmem_audio_device = { - .name = "android_pmem", - .id = 2, - .dev = { .platform_data = &android_pmem_audio_pdata }, -}; - -static struct android_pmem_platform_data android_pmem_pdata = { - .name = "pmem", - .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, - .cached = 1, - .memory_type = MEMTYPE_EBI1, -}; - -static struct platform_device android_pmem_device = { - .name = "android_pmem", - .id = 0, - .dev = { .platform_data = &android_pmem_pdata }, -}; +early_param("reserve_adsp_size", reserve_adsp_size_setup); static u32 msm_calculate_batt_capacity(u32 current_voltage); @@ -773,9 +725,6 @@ static struct platform_device *msm7627a_surf_ffa_devices[] __initdata = { static struct platform_device *common_devices[] __initdata = { &android_usb_device, - &android_pmem_device, - &android_pmem_adsp_device, - &android_pmem_audio_device, &msm_device_nand, &msm_device_snd, &msm_device_cad, @@ -803,44 +752,46 @@ static struct platform_device *msm8625_surf_devices[] __initdata = { &msm8625_kgsl_3d0, }; -static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE; -static int __init pmem_kernel_ebi1_size_setup(char *p) +static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE; +static int __init reserve_kernel_ebi1_size_setup(char *p) { - pmem_kernel_ebi1_size = memparse(p, NULL); + reserve_kernel_ebi1_size = memparse(p, NULL); return 0; } -early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); +early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup); -static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE; -static int __init pmem_audio_size_setup(char *p) +static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE; +static int __init reserve_audio_size_setup(char *p) { - pmem_audio_size = memparse(p, NULL); + reserve_audio_size = memparse(p, NULL); return 0; } -early_param("pmem_audio_size", pmem_audio_size_setup); +early_param("reserve_audio_size", reserve_audio_size_setup); static void fix_sizes(void) { if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) { - pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE; - pmem_adsp_size = MSM7x25A_MSM_PMEM_ADSP_SIZE; + reserve_mdp_size = MSM7x25A_MSM_RESERVE_MDP_SIZE;; + reserve_adsp_size = MSM7x25A_MSM_RESERVE_ADSP_SIZE; } else { - pmem_mdp_size = MSM_PMEM_MDP_SIZE; - pmem_adsp_size = MSM_PMEM_ADSP_SIZE; + reserve_mdp_size = MSM_RESERVE_MDP_SIZE; + reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; } //if (get_ddr_size() > SZ_512M) - // pmem_adsp_size = CAMERA_ZSL_SIZE; + // reserve_adsp_size = CAMERA_ZSL_SIZE; #ifdef CONFIG_ION_MSM - msm_ion_audio_size = MSM_PMEM_AUDIO_SIZE; - msm_ion_sf_size = pmem_mdp_size; + msm_ion_audio_size = MSM_RESERVE_AUDIO_SIZE; + msm_ion_sf_size = reserve_mdp_size; #ifdef CONFIG_CMA - msm_ion_camera_size = CAMERA_ZSL_SIZE; - msm_ion_camera_size_carving = 0; + if (get_ddr_size() > SZ_256M) + reserve_adsp_size = CAMERA_ZSL_SIZE; + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = 0; #else - msm_ion_camera_size = pmem_adsp_size; - msm_ion_camera_size_carving = msm_ion_camera_size; + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = msm_ion_camera_size; #endif #endif } @@ -880,7 +831,7 @@ struct ion_platform_heap msm7x27a_heaps[] = { .name = ION_VMALLOC_HEAP_NAME, }, #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION - /* PMEM_ADSP = CAMERA */ + /* ION_ADSP = CAMERA */ { .id = ION_CAMERA_HEAP_ID, .type = CAMERA_HEAP_TYPE, @@ -897,7 +848,7 @@ struct ion_platform_heap msm7x27a_heaps[] = { .memory_type = ION_EBI_TYPE, .extra_data = (void *)&co_ion_pdata, }, - /* PMEM_MDP = SF */ + /* ION_MDP = SF */ { .id = ION_SF_HEAP_ID, .type = ION_HEAP_TYPE_CARVEOUT, @@ -942,54 +893,11 @@ static struct memtype_reserve msm7x27a_reserve_table[] __initdata = { }, }; -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION -static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = { - &android_pmem_adsp_pdata, - &android_pmem_audio_pdata, - &android_pmem_pdata, -}; -#endif -#endif - -static void __init size_pmem_devices(void) -{ -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION - android_pmem_adsp_pdata.size = pmem_adsp_size; - android_pmem_pdata.size = pmem_mdp_size; - android_pmem_audio_pdata.size = pmem_audio_size; -#endif -#endif -} - -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION -static void __init reserve_memory_for(struct android_pmem_platform_data *p) -{ - msm7x27a_reserve_table[p->memory_type].size += p->size; -} -#endif -#endif - -static void __init reserve_pmem_memory(void) -{ -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION - unsigned int i; - for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) - reserve_memory_for(pmem_pdata_array[i]); - - msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; -#endif -#endif -} - static void __init size_ion_devices(void) { #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_pdata.heaps[1].size = msm_ion_camera_size; - ion_pdata.heaps[2].size = PMEM_KERNEL_EBI1_SIZE; + ion_pdata.heaps[2].size = RESERVE_KERNEL_EBI1_SIZE; ion_pdata.heaps[3].size = msm_ion_sf_size; ion_pdata.heaps[4].size = msm_ion_audio_size; #endif @@ -998,8 +906,8 @@ static void __init size_ion_devices(void) static void __init reserve_ion_memory(void) { #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) - msm7x27a_reserve_table[MEMTYPE_EBI1].size += PMEM_KERNEL_EBI1_SIZE; - msm7x27a_reserve_table[MEMTYPE_EBI1].size += + msm7x27a_reserve_table[MEMTYPE_EBI1].size += RESERVE_KERNEL_EBI1_SIZE; + msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_camera_size_carving; msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size; #endif @@ -1008,8 +916,6 @@ static void __init reserve_ion_memory(void) static void __init msm7x27a_calculate_reserve_sizes(void) { fix_sizes(); - size_pmem_devices(); - reserve_pmem_memory(); size_ion_devices(); reserve_ion_memory(); } diff --git a/arch/arm/mach-msm/board-msm7x27a_i6.c b/arch/arm/mach-msm/board-msm7x27a_i6.c new file mode 100644 index 00000000..3bdcb7bc --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x27a_i6.c @@ -0,0 +1,1191 @@ +/* Copyright (c) 2011-2012, 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devices.h" +#include "timer.h" +#include "board-msm7x27a-regulator.h" +#include "devices-msm7x2xa.h" +#include "pm.h" +#include +#include +#include "pm-boot.h" +#include "board-msm7627a.h" + +#define CAMERA_HEAP_BASE 0x0 +#ifdef CONFIG_CMA +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_DMA +#else +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_CARVEOUT +#endif + +#define RESERVE_KERNEL_EBI1_SIZE 0x3A000 +#define MSM_RESERVE_AUDIO_SIZE 0xF0000 +#define BOOTLOADER_BASE_ADDR 0x10000 + +#if defined(CONFIG_GPIO_SX150X) +enum { + SX150X_CORE, +}; + +static struct sx150x_platform_data sx150x_data[] __initdata = { + [SX150X_CORE] = { + .gpio_base = GPIO_CORE_EXPANDER_BASE, + .oscio_is_gpo = false, + .io_pullup_ena = 0, + .io_pulldn_ena = 0x02, + .io_open_drain_ena = 0xfef8, + .irq_summary = -1, + }, +}; +#endif + + +#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE) +static struct platform_device msm_wlan_ar6000_pm_device = { + .name = "wlan_ar6000_pm_dev", + .id = -1, +}; +#endif + +#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X) +static struct i2c_board_info core_exp_i2c_info[] __initdata = { + { + I2C_BOARD_INFO("sx1509q", 0x3e), + }, +}; + +static void __init register_i2c_devices(void) +{ + if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() || + machine_is_msm8625_surf()) + sx150x_data[SX150X_CORE].io_open_drain_ena = 0xe0f0; + + core_exp_i2c_info[0].platform_data = + &sx150x_data[SX150X_CORE]; + + i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID, + core_exp_i2c_info, + ARRAY_SIZE(core_exp_i2c_info)); +} +#endif + +static struct msm_gpio qup_i2c_gpios_io[] = { + { GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(61, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, + { GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, +}; + +static struct msm_gpio qup_i2c_gpios_hw[] = { + { GPIO_CFG(60, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, + { GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, +}; + +static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type) +{ + int rc; + + if (adap_id < 0 || adap_id > 1) + return; + + /* Each adapter gets 2 lines from the table */ + if (config_type) + rc = msm_gpios_request_enable(&qup_i2c_gpios_hw[adap_id*2], 2); + else + rc = msm_gpios_request_enable(&qup_i2c_gpios_io[adap_id*2], 2); + if (rc < 0) + pr_err("QUP GPIO request/enable failed: %d\n", rc); +} + +static struct msm_i2c_platform_data msm_gsbi0_qup_i2c_pdata = { + .clk_freq = 100000, + .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config, +}; + +static struct msm_i2c_platform_data msm_gsbi1_qup_i2c_pdata = { + .clk_freq = 100000, + .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config, +}; + +#ifdef CONFIG_ARCH_MSM7X27A +#define MSM_RESERVE_MDP_SIZE 0x2300000 +#define MSM7x25A_MSM_RESERVE_MDP_SIZE 0x1500000 + +#define MSM_RESERVE_ADSP_SIZE 0x2000000 +#define MSM7x25A_MSM_RESERVE_ADSP_SIZE 0xB91000 +#define CAMERA_ZSL_SIZE (SZ_1M * 60) +#endif + +#ifdef CONFIG_ION_MSM +#define MSM_ION_HEAP_NUM 5 +static struct platform_device ion_dev; +static int msm_ion_camera_size; +static int msm_ion_audio_size; +static int msm_ion_sf_size; +static int msm_ion_camera_size_carving; +#endif + +#define CAMERA_HEAP_BASE 0x0 +#ifdef CONFIG_CMA +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_DMA +#else +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_CARVEOUT +#endif + +static struct android_usb_platform_data android_usb_pdata = { + .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; + +#ifdef CONFIG_USB_EHCI_MSM_72K +static void msm_hsusb_vbus_power(unsigned phy_info, int on) +{ + int rc = 0; + unsigned gpio; + + gpio = GPIO_HOST_VBUS_EN; + + rc = gpio_request(gpio, "i2c_host_vbus_en"); + if (rc < 0) { + pr_err("failed to request %d GPIO\n", gpio); + return; + } + gpio_direction_output(gpio, !!on); + gpio_set_value_cansleep(gpio, !!on); + gpio_free(gpio); +} + +static struct msm_usb_host_platform_data msm_usb_host_pdata = { + .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM), +}; + +static void __init msm7x2x_init_host(void) +{ + msm_add_host(0, &msm_usb_host_pdata); +} +#endif + +#ifdef CONFIG_USB_MSM_OTG_72K +static int hsusb_rpc_connect(int connect) +{ + if (connect) + return msm_hsusb_rpc_connect(); + else + return msm_hsusb_rpc_close(); +} + +static struct regulator *reg_hsusb; +static int msm_hsusb_ldo_init(int init) +{ + int rc = 0; + + if (init) { + reg_hsusb = regulator_get(NULL, "usb"); + if (IS_ERR(reg_hsusb)) { + rc = PTR_ERR(reg_hsusb); + pr_err("%s: could not get regulator: %d\n", + __func__, rc); + goto out; + } + + rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000); + if (rc) { + pr_err("%s: could not set voltage: %d\n", + __func__, rc); + goto reg_free; + } + + return 0; + } + /* else fall through */ +reg_free: + regulator_put(reg_hsusb); +out: + reg_hsusb = NULL; + return rc; +} + +static int msm_hsusb_ldo_enable(int enable) +{ + static int ldo_status; + + if (IS_ERR_OR_NULL(reg_hsusb)) + return reg_hsusb ? PTR_ERR(reg_hsusb) : -ENODEV; + + if (ldo_status == enable) + return 0; + + ldo_status = enable; + + return enable ? + regulator_enable(reg_hsusb) : + regulator_disable(reg_hsusb); +} + +#ifndef CONFIG_USB_EHCI_MSM_72K +static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init) +{ + int ret = 0; + + if (init) + ret = msm_pm_app_rpc_init(callback); + else + msm_pm_app_rpc_deinit(callback); + + return ret; +} +#endif + +static struct msm_otg_platform_data msm_otg_pdata = { +#ifndef CONFIG_USB_EHCI_MSM_72K + .pmic_vbus_notif_init = msm_hsusb_pmic_notif_init, +#else + .vbus_power = msm_hsusb_vbus_power, +#endif + .rpc_connect = hsusb_rpc_connect, + .pemp_level = PRE_EMPHASIS_WITH_20_PERCENT, + .cdr_autoreset = CDR_AUTO_RESET_DISABLE, + .drv_ampl = HS_DRV_AMPLITUDE_DEFAULT, + .se1_gating = SE1_GATING_DISABLE, + .ldo_init = msm_hsusb_ldo_init, + .ldo_enable = msm_hsusb_ldo_enable, + .chg_init = hsusb_chg_init, + .chg_connected = hsusb_chg_connected, + .chg_vbus_draw = hsusb_chg_vbus_draw, +}; +#endif + +static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = { + .is_phy_status_timer_on = 1, +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x90000300, + .end = 0x900003ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(4), + .end = MSM_GPIO_TO_INT(4), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +#ifdef CONFIG_SERIAL_MSM_HS +static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { + .inject_rx_on_wakeup = 1, + .rx_to_inject = 0xFD, +}; +#endif +static struct msm_pm_platform_data msm7x27a_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 16000, + .residency = 20000, + }, + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 12000, + .residency = 20000, + }, + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 1, + .latency = 2000, + .residency = 0, + }, + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 0, + }, +}; + +static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS, + .p_addr = 0, +}; + +/* 8625 PM platform data */ +static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = { + /* CORE0 entries */ + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 16000, + .residency = 20000, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 12000, + .residency = 20000, + }, + + /* picked latency & redisdency values from 7x30 */ + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 500, + .residency = 6000, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 10, + }, + + /* picked latency & redisdency values from 7x30 */ + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 500, + .residency = 6000, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 10, + }, + +}; + +static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR, + .v_addr = MSM_CFG_CTL_BASE, +}; + +static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE; +static int __init reserve_mdp_size_setup(char *p) +{ + reserve_mdp_size = memparse(p, NULL); + return 0; +} + +early_param("reserve_mdp_size", reserve_mdp_size_setup); + +static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; +static int __init reserve_adsp_size_setup(char *p) +{ + reserve_adsp_size = memparse(p, NULL); + return 0; +} + +early_param("reserve_adsp_size", reserve_adsp_size_setup); + +static u32 msm_calculate_batt_capacity(u32 current_voltage); + +static struct msm_psy_batt_pdata msm_psy_batt_data = { + .voltage_min_design = 3200, + .voltage_max_design = 4200, +// .voltage_fail_safe = 3340, + .avail_chg_sources = AC_CHG | USB_CHG , + .batt_technology = POWER_SUPPLY_TECHNOLOGY_LION, + .calculate_capacity = &msm_calculate_batt_capacity, +}; + +static u32 msm_calculate_batt_capacity(u32 current_voltage) +{ + u32 low_voltage = msm_psy_batt_data.voltage_min_design; + u32 high_voltage = msm_psy_batt_data.voltage_max_design; + + if (current_voltage <= low_voltage) + return 0; + else if (current_voltage >= high_voltage) + return 100; + else + return (current_voltage - low_voltage) * 100 + / (high_voltage - low_voltage); +} + +static struct platform_device msm_batt_device = { + .name = "msm-battery", + .id = -1, + .dev.platform_data = &msm_psy_batt_data, +}; + +static struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_16BIT, +}; + +static struct resource smsc911x_resources[] = { + [0] = { + .start = 0x90000000, + .end = 0x90007fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(48), + .end = MSM_GPIO_TO_INT(48), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = 0, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, +}; + +static struct msm_gpio smsc911x_gpios[] = { + { GPIO_CFG(48, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_6MA), + "smsc911x_irq" }, + { GPIO_CFG(49, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_6MA), + "eth_fifo_sel" }, +}; + +static char *msm_adc_surf_device_names[] = { + "XO_ADC", +}; + +static struct msm_adc_platform_data msm_adc_pdata = { + .dev_names = msm_adc_surf_device_names, + .num_adc = ARRAY_SIZE(msm_adc_surf_device_names), + .target_hw = MSM_8x25, +}; + +static struct platform_device msm_adc_device = { + .name = "msm_adc", + .id = -1, + .dev = { + .platform_data = &msm_adc_pdata, + }, +}; + +#define ETH_FIFO_SEL_GPIO 49 +static void msm7x27a_cfg_smsc911x(void) +{ + int res; + + res = msm_gpios_request_enable(smsc911x_gpios, + ARRAY_SIZE(smsc911x_gpios)); + if (res) { + pr_err("%s: unable to enable gpios for SMSC911x\n", __func__); + return; + } + + /* ETH_FIFO_SEL */ + res = gpio_direction_output(ETH_FIFO_SEL_GPIO, 0); + if (res) { + pr_err("%s: unable to get direction for gpio %d\n", __func__, + ETH_FIFO_SEL_GPIO); + msm_gpios_disable_free(smsc911x_gpios, + ARRAY_SIZE(smsc911x_gpios)); + return; + } + gpio_set_value(ETH_FIFO_SEL_GPIO, 0); +} + +#if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) \ + && defined(CONFIG_MSM_SHARED_GPIO_FOR_UART2DM) +static struct msm_gpio uart2dm_gpios[] = { + {GPIO_CFG(19, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_rfr_n" }, + {GPIO_CFG(20, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_cts_n" }, + {GPIO_CFG(21, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_rx" }, + {GPIO_CFG(108, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_tx" }, +}; + +static void msm7x27a_cfg_uart2dm_serial(void) +{ + int ret; + ret = msm_gpios_request_enable(uart2dm_gpios, + ARRAY_SIZE(uart2dm_gpios)); + if (ret) + pr_err("%s: unable to enable gpios for uart2dm\n", __func__); +} +#else +static void msm7x27a_cfg_uart2dm_serial(void) { } +#endif + +static struct platform_device *rumi_sim_devices[] __initdata = { + &msm_device_dmov, + &msm_device_smd, + &smc91x_device, + &msm_device_uart1, + &msm_device_nand, + &msm_device_uart_dm1, + &msm_gsbi0_qup_i2c_device, + &msm_gsbi1_qup_i2c_device, +}; + +static struct platform_device *msm8625_rumi3_devices[] __initdata = { + &msm8625_device_dmov, + &msm8625_device_smd, + &msm8625_device_uart1, + &msm8625_gsbi0_qup_i2c_device, +}; + +static struct platform_device *msm7627a_surf_ffa_devices[] __initdata = { + &msm_device_dmov, + &msm_device_smd, + &msm_device_uart1, + &msm_device_uart_dm1, + &msm_device_uart_dm2, + &msm_gsbi0_qup_i2c_device, + &msm_gsbi1_qup_i2c_device, + &msm_device_otg, + &msm_device_gadget_peripheral, + &smsc911x_device, + &msm_kgsl_3d0, +}; + +static struct platform_device *common_devices[] __initdata = { + &android_usb_device, + &msm_device_nand, + &msm_device_snd, + &msm_device_cad, + &msm_device_adspdec, + &asoc_msm_pcm, + &asoc_msm_dai0, + &asoc_msm_dai1, + &msm_batt_device, + &msm_adc_device, +#ifdef CONFIG_ION_MSM + &ion_dev, +#endif +}; + +static struct platform_device *msm8625_surf_devices[] __initdata = { + &msm8625_device_dmov, + &msm8625_device_uart1, + &msm8625_device_uart_dm1, + &msm8625_device_uart_dm2, + &msm8625_gsbi0_qup_i2c_device, + &msm8625_gsbi1_qup_i2c_device, + &msm8625_device_smd, + &msm8625_device_otg, + &msm8625_device_gadget_peripheral, + &msm8625_kgsl_3d0, +}; + +static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE; +static int __init reserve_kernel_ebi1_size_setup(char *p) +{ + reserve_kernel_ebi1_size = memparse(p, NULL); + return 0; +} +early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup); + +static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE; +static int __init reserve_audio_size_setup(char *p) +{ + reserve_audio_size = memparse(p, NULL); + return 0; +} +early_param("reserve_audio_size", reserve_audio_size_setup); + +static void fix_sizes(void) +{ + if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) { + reserve_mdp_size = MSM7x25A_MSM_RESERVE_MDP_SIZE; + reserve_adsp_size = MSM7x25A_MSM_RESERVE_ADSP_SIZE; + } else { + reserve_mdp_size = MSM_RESERVE_MDP_SIZE; + reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; + } + + if (get_ddr_size() > SZ_512M) + reserve_adsp_size = CAMERA_ZSL_SIZE; +#ifdef CONFIG_ION_MSM + msm_ion_audio_size = MSM_RESERVE_AUDIO_SIZE; + msm_ion_sf_size = reserve_mdp_size; +#ifdef CONFIG_CMA + if (get_ddr_size() > SZ_256M) + reserve_adsp_size = CAMERA_ZSL_SIZE; + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = 0; +#else + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = msm_ion_camera_size; +#endif +#endif +} + +#ifdef CONFIG_ION_MSM +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct ion_co_heap_pdata co_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, +}; + +static struct ion_co_heap_pdata co_mm_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, +}; + +static u64 msm_dmamask = DMA_BIT_MASK(32); + +static struct platform_device ion_cma_device = { + .name = "ion-cma-device", + .id = -1, + .dev = { + .dma_mask = &msm_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif + +/** + * These heaps are listed in the order they will be allocated. + * Don't swap the order unless you know what you are doing! + */ +struct ion_platform_heap msm7x27a_heaps[] = { + { + .id = ION_SYSTEM_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM, + .name = ION_VMALLOC_HEAP_NAME, + }, +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + /* ION_ADSP = CAMERA */ + { + .id = ION_CAMERA_HEAP_ID, + .type = CAMERA_HEAP_TYPE, + .name = ION_CAMERA_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_mm_ion_pdata, + .priv = (void *)&ion_cma_device.dev, + }, + /* AUDIO HEAP 1*/ + { + .id = ION_AUDIO_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + }, + /* ION_MDP = SF */ + { + .id = ION_SF_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_SF_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + }, + /* AUDIO HEAP 2*/ + { + .id = ION_AUDIO_HEAP_BL_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_BL_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + .base = BOOTLOADER_BASE_ADDR, + }, + +#endif +}; + +static struct ion_platform_data ion_pdata = { + .nr = MSM_ION_HEAP_NUM, + .has_outer_cache = 1, + .heaps = msm7x27a_heaps, +}; + +static struct platform_device ion_dev = { + .name = "ion-msm", + .id = 1, + .dev = { .platform_data = &ion_pdata }, +}; +#endif + +static struct memtype_reserve msm7x27a_reserve_table[] __initdata = { + [MEMTYPE_SMI] = { + }, + [MEMTYPE_EBI0] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, + [MEMTYPE_EBI1] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, +}; + +static void __init size_ion_devices(void) +{ +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_pdata.heaps[1].size = msm_ion_camera_size; + ion_pdata.heaps[2].size = RESERVE_KERNEL_EBI1_SIZE; + ion_pdata.heaps[3].size = msm_ion_sf_size; + ion_pdata.heaps[4].size = msm_ion_audio_size; +#endif +} + +static void __init reserve_ion_memory(void) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + msm7x27a_reserve_table[MEMTYPE_EBI1].size += RESERVE_KERNEL_EBI1_SIZE; + msm7x27a_reserve_table[MEMTYPE_EBI1].size += + msm_ion_camera_size_carving; + msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size; +#endif +} + +static void __init msm7x27a_calculate_reserve_sizes(void) +{ + fix_sizes(); + size_ion_devices(); + reserve_ion_memory(); +} + +static int msm7x27a_paddr_to_memtype(unsigned int paddr) +{ + return MEMTYPE_EBI1; +} + +static struct reserve_info msm7x27a_reserve_info __initdata = { + .memtype_reserve_table = msm7x27a_reserve_table, + .calculate_reserve_sizes = msm7x27a_calculate_reserve_sizes, + .paddr_to_memtype = msm7x27a_paddr_to_memtype, +}; + +static void __init msm7x27a_reserve(void) +{ + reserve_info = &msm7x27a_reserve_info; + memblock_remove(BOOTLOADER_BASE_ADDR, msm_ion_audio_size); + msm_reserve(); +#ifdef CONFIG_CMA + dma_declare_contiguous( + &ion_cma_device.dev, + msm_ion_camera_size, + CAMERA_HEAP_BASE, + 0x26000000); +#endif + +#ifdef CONFIG_SRECORDER_MSM + if (0x0 != get_mempools_pstart_addr()) + { + s_srecorder_reserved_mem_phys_start_addr = get_mempools_pstart_addr();// - SRECORDER_RESERVED_MEM_SIZE; + } + else + { + printk(">>>> Can't know the start address for S-Recorder's reserved memory!\n"); + } +#endif /* CONFIG_SRECORDER_MSM */ +} + +static void __init msm8625_reserve(void) +{ + msm7x27a_reserve(); + memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8); + memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32); +} + +static void __init msm7x27a_device_i2c_init(void) +{ + msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata; + msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata; +} + +static void __init msm8625_device_i2c_init(void) +{ + msm8625_gsbi0_qup_i2c_device.dev.platform_data = + &msm_gsbi0_qup_i2c_pdata; + msm8625_gsbi1_qup_i2c_device.dev.platform_data = + &msm_gsbi1_qup_i2c_pdata; +} + +#define MSM_EBI2_PHYS 0xa0d00000 +#define MSM_EBI2_XMEM_CS2_CFG1 0xa0d10030 + +static void __init msm7x27a_init_ebi2(void) +{ + uint32_t ebi2_cfg; + void __iomem *ebi2_cfg_ptr; + + ebi2_cfg_ptr = ioremap_nocache(MSM_EBI2_PHYS, sizeof(uint32_t)); + if (!ebi2_cfg_ptr) + return; + + ebi2_cfg = readl(ebi2_cfg_ptr); + if (machine_is_msm7x27a_rumi3() || machine_is_msm7x27a_surf() || + machine_is_msm7625a_surf() || machine_is_msm8625_surf()) + ebi2_cfg |= (1 << 4); /* CS2 */ + + writel(ebi2_cfg, ebi2_cfg_ptr); + iounmap(ebi2_cfg_ptr); + + /* Enable A/D MUX[bit 31] from EBI2_XMEM_CS2_CFG1 */ + ebi2_cfg_ptr = ioremap_nocache(MSM_EBI2_XMEM_CS2_CFG1, + sizeof(uint32_t)); + if (!ebi2_cfg_ptr) + return; + + ebi2_cfg = readl(ebi2_cfg_ptr); + if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) + ebi2_cfg |= (1 << 31); + + writel(ebi2_cfg, ebi2_cfg_ptr); + iounmap(ebi2_cfg_ptr); +} + +static struct platform_device msm_proccomm_regulator_dev = { + .name = PROCCOMM_REGULATOR_DEV_NAME, + .id = -1, + .dev = { + .platform_data = &msm7x27a_proccomm_regulator_data + } +}; + +static void msm_adsp_add_pdev(void) +{ + int rc = 0; + struct rpc_board_dev *rpc_adsp_pdev; + + rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL); + if (rpc_adsp_pdev == NULL) { + pr_err("%s: Memory Allocation failure\n", __func__); + return; + } + rpc_adsp_pdev->prog = ADSP_RPC_PROG; + + if (cpu_is_msm8625() || cpu_is_msm8625q()) + rpc_adsp_pdev->pdev = msm8625_device_adsp; + else + rpc_adsp_pdev->pdev = msm_adsp_device; + rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1); + if (rc < 0) { + pr_err("%s: return val: %d\n", __func__, rc); + kfree(rpc_adsp_pdev); + } +} + +static void __init msm7627a_rumi3_init(void) +{ + msm7x27a_init_ebi2(); + platform_add_devices(rumi_sim_devices, + ARRAY_SIZE(rumi_sim_devices)); +} + +static void __init msm8625_rumi3_init(void) +{ + msm7x2x_misc_init(); + msm_adsp_add_pdev(); + msm8625_device_i2c_init(); + platform_add_devices(msm8625_rumi3_devices, + ARRAY_SIZE(msm8625_rumi3_devices)); + + msm_pm_set_platform_data(msm8625_pm_data, + ARRAY_SIZE(msm8625_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata)); + msm8x25_spm_device_init(); + msm_pm_register_cpr_ops(); +} + +#define UART1DM_RX_GPIO 45 + +#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE) +static int __init msm7x27a_init_ar6000pm(void) +{ + msm_wlan_ar6000_pm_device.dev.platform_data = &ar600x_wlan_power; + return platform_device_register(&msm_wlan_ar6000_pm_device); +} +#else +static int __init msm7x27a_init_ar6000pm(void) { return 0; } +#endif + +static void __init msm7x27a_init_regulators(void) +{ + int rc = platform_device_register(&msm_proccomm_regulator_dev); + if (rc) + pr_err("%s: could not register regulator device: %d\n", + __func__, rc); +} + +static void __init msm7x27a_add_footswitch_devices(void) +{ + platform_add_devices(msm_footswitch_devices, + msm_num_footswitch_devices); +} + +static void __init msm7x27a_add_platform_devices(void) +{ + if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) { + platform_add_devices(msm8625_surf_devices, + ARRAY_SIZE(msm8625_surf_devices)); + } else { + platform_add_devices(msm7627a_surf_ffa_devices, + ARRAY_SIZE(msm7627a_surf_ffa_devices)); + } + + platform_add_devices(common_devices, + ARRAY_SIZE(common_devices)); +} + +static void __init msm7x27a_uartdm_config(void) +{ + msm7x27a_cfg_uart2dm_serial(); + msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO); + if (cpu_is_msm8625() || cpu_is_msm8625q()) + msm8625_device_uart_dm1.dev.platform_data = + &msm_uart_dm1_pdata; + else + msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; +} + +static void __init msm7x27a_otg_gadget(void) +{ + if (cpu_is_msm8625() || cpu_is_msm8625q()) { + msm_otg_pdata.swfi_latency = + msm8625_pm_data[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency; + msm8625_device_otg.dev.platform_data = &msm_otg_pdata; + msm8625_device_gadget_peripheral.dev.platform_data = + &msm_gadget_pdata; + } else { + msm_otg_pdata.swfi_latency = + msm7x27a_pm_data[ + MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency; + msm_device_otg.dev.platform_data = &msm_otg_pdata; + msm_device_gadget_peripheral.dev.platform_data = + &msm_gadget_pdata; + } +} + +static void __init msm7x27a_pm_init(void) +{ + if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) { + msm_pm_set_platform_data(msm8625_pm_data, + ARRAY_SIZE(msm8625_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata)); + msm8x25_spm_device_init(); + msm_pm_register_cpr_ops(); + } else { + msm_pm_set_platform_data(msm7x27a_pm_data, + ARRAY_SIZE(msm7x27a_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata)); + } + + msm_pm_register_irqs(); +} + +static void __init msm7x2x_init(void) +{ + msm7x2x_misc_init(); + + /* Initialize regulators first so that other devices can use them */ + msm7x27a_init_regulators(); + msm_adsp_add_pdev(); + if (cpu_is_msm8625()) + msm8625_device_i2c_init(); + else + msm7x27a_device_i2c_init(); + msm7x27a_init_ebi2(); + msm7x27a_uartdm_config(); + + msm7x27a_otg_gadget(); + msm7x27a_cfg_smsc911x(); + + msm7x27a_add_footswitch_devices(); + msm7x27a_add_platform_devices(); + /* Ensure ar6000pm device is registered before MMC/SDC */ + msm7x27a_init_ar6000pm(); + msm7627a_init_mmc(); + msm_fb_add_devices(); + msm7x2x_init_host(); + msm7x27a_pm_init(); + register_i2c_devices(); +#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE) + msm7627a_bt_power_init(); +#endif + msm7627a_camera_init(); + msm7627a_add_io_devices(); + /*7x25a kgsl initializations*/ + msm7x25a_kgsl_3d0_init(); + /*8x25 kgsl initializations*/ + msm8x25_kgsl_3d0_init(); +} + +static void __init msm7x2x_init_early(void) +{ + msm_msm7627a_allocate_memory_regions(); +} + +MACHINE_START(MSM7X27A_RUMI3, "QCT MSM7x27a RUMI3") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7627a_rumi3_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7X27A_SURF, "QCT MSM7x27a SURF") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7X27A_FFA, "QCT MSM7x27a FFA") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7625A_SURF, "QCT MSM7625a SURF") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7625A_FFA, "QCT MSM7625a FFA") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_RUMI3, "QCT MSM8625 RUMI3") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm8625_rumi3_init, + .timer = &msm_timer, + .handle_irq = gic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_SURF, "QCT MSM8625 SURF") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_FFA, "QCT MSM8625 FFA") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END diff --git a/arch/arm/mach-msm/board-msm7x27a_i6.cd b/arch/arm/mach-msm/board-msm7x27a_i6.cd new file mode 100644 index 00000000..660bbece --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x27a_i6.cd @@ -0,0 +1,1237 @@ +/* Copyright (c) 2011-2012, 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "devices.h" +#include "timer.h" +#include "board-msm7x27a-regulator.h" +#include "devices-msm7x2xa.h" +#include "pm.h" +#include +#include +#include "pm-boot.h" +#include "board-msm7627a.h" + +#define CAMERA_HEAP_BASE 0x0 +#ifdef CONFIG_CMA +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_DMA +#else +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_CARVEOUT +#endif + +#define RESERVE_KERNEL_EBI1_SIZE 0x3A000 +#define MSM_RESERVE_AUDIO_SIZE 0xF0000 +#define BOOTLOADER_BASE_ADDR 0x10000 + +#if defined(CONFIG_GPIO_SX150X) +enum { + SX150X_CORE, +}; + +static struct sx150x_platform_data sx150x_data[] __initdata = { + [SX150X_CORE] = { + .gpio_base = GPIO_CORE_EXPANDER_BASE, + .oscio_is_gpo = false, + .io_pullup_ena = 0, + .io_pulldn_ena = 0x02, + .io_open_drain_ena = 0xfef8, + .irq_summary = -1, + }, +}; +#endif + + +#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE) +static struct platform_device msm_wlan_ar6000_pm_device = { + .name = "wlan_ar6000_pm_dev", + .id = -1, +}; +#endif + +#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X) +static struct i2c_board_info core_exp_i2c_info[] __initdata = { + { + I2C_BOARD_INFO("sx1509q", 0x3e), + }, +}; + +static void __init register_i2c_devices(void) +{ + if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() || + machine_is_msm8625_surf()) + sx150x_data[SX150X_CORE].io_open_drain_ena = 0xe0f0; + + core_exp_i2c_info[0].platform_data = + &sx150x_data[SX150X_CORE]; + + i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID, + core_exp_i2c_info, + ARRAY_SIZE(core_exp_i2c_info)); +} +#endif + +static struct msm_gpio qup_i2c_gpios_io[] = { + { GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(61, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, + { GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, +}; + +static struct msm_gpio qup_i2c_gpios_hw[] = { + { GPIO_CFG(60, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, + { GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, +}; + +static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type) +{ + int rc; + + if (adap_id < 0 || adap_id > 1) + return; + + /* Each adapter gets 2 lines from the table */ + if (config_type) + rc = msm_gpios_request_enable(&qup_i2c_gpios_hw[adap_id*2], 2); + else + rc = msm_gpios_request_enable(&qup_i2c_gpios_io[adap_id*2], 2); + if (rc < 0) + pr_err("QUP GPIO request/enable failed: %d\n", rc); +} + +static struct msm_i2c_platform_data msm_gsbi0_qup_i2c_pdata = { + .clk_freq = 100000, + .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config, +}; + +static struct msm_i2c_platform_data msm_gsbi1_qup_i2c_pdata = { + .clk_freq = 100000, + .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config, +}; + +#ifdef CONFIG_ARCH_MSM7X27A +#define MSM_RESERVE_MDP_SIZE 0x2300000 +#define MSM7x25A_MSM_RESERVE_MDP_SIZE 0x1500000 + +#define MSM_RESERVE_ADSP_SIZE 0x2000000 +#define MSM7x25A_MSM_RESERVE_ADSP_SIZE 0xB91000 +#define CAMERA_ZSL_SIZE (SZ_1M * 60) +#endif + +#ifdef CONFIG_ION_MSM +#define MSM_ION_HEAP_NUM 5 +static struct platform_device ion_dev; +static int msm_ion_camera_size; +static int msm_ion_audio_size; +static int msm_ion_sf_size; +static int msm_ion_camera_size_carving; +#endif + +#define CAMERA_HEAP_BASE 0x0 +#ifdef CONFIG_CMA +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_DMA +#else +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_CARVEOUT +#endif + +static struct android_usb_platform_data android_usb_pdata = { + .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; + +#ifdef CONFIG_USB_EHCI_MSM_72K +static void msm_hsusb_vbus_power(unsigned phy_info, int on) +{ + int rc = 0; + unsigned gpio; + + gpio = GPIO_HOST_VBUS_EN; + + rc = gpio_request(gpio, "i2c_host_vbus_en"); + if (rc < 0) { + pr_err("failed to request %d GPIO\n", gpio); + return; + } + gpio_direction_output(gpio, !!on); + gpio_set_value_cansleep(gpio, !!on); + gpio_free(gpio); +} + +static struct msm_usb_host_platform_data msm_usb_host_pdata = { + .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM), +}; + +static void __init msm7x2x_init_host(void) +{ + msm_add_host(0, &msm_usb_host_pdata); +} +#endif + +#ifdef CONFIG_USB_MSM_OTG_72K +static int hsusb_rpc_connect(int connect) +{ + if (connect) + return msm_hsusb_rpc_connect(); + else + return msm_hsusb_rpc_close(); +} + +static struct regulator *reg_hsusb; +static int msm_hsusb_ldo_init(int init) +{ + int rc = 0; + + if (init) { + reg_hsusb = regulator_get(NULL, "usb"); + if (IS_ERR(reg_hsusb)) { + rc = PTR_ERR(reg_hsusb); + pr_err("%s: could not get regulator: %d\n", + __func__, rc); + goto out; + } + + rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000); + if (rc) { + pr_err("%s: could not set voltage: %d\n", + __func__, rc); + goto reg_free; + } + + return 0; + } + /* else fall through */ +reg_free: + regulator_put(reg_hsusb); +out: + reg_hsusb = NULL; + return rc; +} + +static int msm_hsusb_ldo_enable(int enable) +{ + static int ldo_status; + + if (IS_ERR_OR_NULL(reg_hsusb)) + return reg_hsusb ? PTR_ERR(reg_hsusb) : -ENODEV; + + if (ldo_status == enable) + return 0; + + ldo_status = enable; + + return enable ? + regulator_enable(reg_hsusb) : + regulator_disable(reg_hsusb); +} + +#ifndef CONFIG_USB_EHCI_MSM_72K +static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init) +{ + int ret = 0; + + if (init) + ret = msm_pm_app_rpc_init(callback); + else + msm_pm_app_rpc_deinit(callback); + + return ret; +} +#endif + +static struct msm_otg_platform_data msm_otg_pdata = { +#ifndef CONFIG_USB_EHCI_MSM_72K + .pmic_vbus_notif_init = msm_hsusb_pmic_notif_init, +#else + .vbus_power = msm_hsusb_vbus_power, +#endif + .rpc_connect = hsusb_rpc_connect, + .pemp_level = PRE_EMPHASIS_WITH_20_PERCENT, + .cdr_autoreset = CDR_AUTO_RESET_DISABLE, + .drv_ampl = HS_DRV_AMPLITUDE_DEFAULT, + .se1_gating = SE1_GATING_DISABLE, + .ldo_init = msm_hsusb_ldo_init, + .ldo_enable = msm_hsusb_ldo_enable, + .chg_init = hsusb_chg_init, + .chg_connected = hsusb_chg_connected, + .chg_vbus_draw = hsusb_chg_vbus_draw, +}; +#endif + +static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = { + .is_phy_status_timer_on = 1, +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x90000300, + .end = 0x900003ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(4), + .end = MSM_GPIO_TO_INT(4), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +#ifdef CONFIG_SERIAL_MSM_HS +static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { + .inject_rx_on_wakeup = 1, + .rx_to_inject = 0xFD, +}; +#endif +static struct msm_pm_platform_data msm7x27a_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 16000, + .residency = 20000, + }, + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 12000, + .residency = 20000, + }, + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 1, + .latency = 2000, + .residency = 0, + }, + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 0, + }, +}; + +static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS, + .p_addr = 0, +}; + +/* 8625 PM platform data */ +static struct msm_pm_platform_data + msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * CONFIG_NR_CPUS] = { + /* CORE0 entries */ + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 16000, + .residency = 20000, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 12000, + .residency = 20000, + }, + + /* picked latency & redisdency values from 7x30 */ + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 500, + .residency = 6000, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 10, + }, + + /* picked latency & redisdency values from 7x30 */ + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 500, + .residency = 6000, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 10, + }, + +}; + +static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR, + .v_addr = MSM_CFG_CTL_BASE, +}; + +static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE; +static int __init reserve_mdp_size_setup(char *p) +{ + reserve_mdp_size = memparse(p, NULL); + return 0; +} + +early_param("reserve_mdp_size", reserve_mdp_size_setup); + +static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; +static int __init reserve_adsp_size_setup(char *p) +{ + reserve_adsp_size = memparse(p, NULL); + return 0; +} + +early_param("reserve_adsp_size", reserve_adsp_size_setup); + +static u32 msm_calculate_batt_capacity(u32 current_voltage); + +static struct msm_psy_batt_pdata msm_psy_batt_data = { + .voltage_min_design = 3200, + .voltage_max_design = 4200, +// .voltage_fail_safe = 3340, + .avail_chg_sources = AC_CHG | USB_CHG , + .batt_technology = POWER_SUPPLY_TECHNOLOGY_LION, + .calculate_capacity = &msm_calculate_batt_capacity, +}; + +static u32 msm_calculate_batt_capacity(u32 current_voltage) +{ + u32 low_voltage = msm_psy_batt_data.voltage_min_design; + u32 high_voltage = msm_psy_batt_data.voltage_max_design; + + if (current_voltage <= low_voltage) + return 0; + else if (current_voltage >= high_voltage) + return 100; + else + return (current_voltage - low_voltage) * 100 + / (high_voltage - low_voltage); +} + +static struct platform_device msm_batt_device = { + .name = "msm-battery", + .id = -1, + .dev.platform_data = &msm_psy_batt_data, +}; + +static struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_16BIT, +}; + +static struct resource smsc911x_resources[] = { + [0] = { + .start = 0x90000000, + .end = 0x90007fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(48), + .end = MSM_GPIO_TO_INT(48), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = 0, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, +}; + +static struct msm_gpio smsc911x_gpios[] = { + { GPIO_CFG(48, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_6MA), + "smsc911x_irq" }, + { GPIO_CFG(49, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_6MA), + "eth_fifo_sel" }, +}; + +static char *msm_adc_surf_device_names[] = { + "XO_ADC", +}; + +static struct msm_adc_platform_data msm_adc_pdata = { + .dev_names = msm_adc_surf_device_names, + .num_adc = ARRAY_SIZE(msm_adc_surf_device_names), + .target_hw = MSM_8x25, +}; + +static struct platform_device msm_adc_device = { + .name = "msm_adc", + .id = -1, + .dev = { + .platform_data = &msm_adc_pdata, + }, +}; + +#define ETH_FIFO_SEL_GPIO 49 +static void msm7x27a_cfg_smsc911x(void) +{ + int res; + + res = msm_gpios_request_enable(smsc911x_gpios, + ARRAY_SIZE(smsc911x_gpios)); + if (res) { + pr_err("%s: unable to enable gpios for SMSC911x\n", __func__); + return; + } + + /* ETH_FIFO_SEL */ + res = gpio_direction_output(ETH_FIFO_SEL_GPIO, 0); + if (res) { + pr_err("%s: unable to get direction for gpio %d\n", __func__, + ETH_FIFO_SEL_GPIO); + msm_gpios_disable_free(smsc911x_gpios, + ARRAY_SIZE(smsc911x_gpios)); + return; + } + gpio_set_value(ETH_FIFO_SEL_GPIO, 0); +} + +#if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) \ + && defined(CONFIG_MSM_SHARED_GPIO_FOR_UART2DM) +static struct msm_gpio uart2dm_gpios[] = { + {GPIO_CFG(19, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_rfr_n" }, + {GPIO_CFG(20, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_cts_n" }, + {GPIO_CFG(21, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_rx" }, + {GPIO_CFG(108, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), + "uart2dm_tx" }, +}; + +static void msm7x27a_cfg_uart2dm_serial(void) +{ + int ret; + ret = msm_gpios_request_enable(uart2dm_gpios, + ARRAY_SIZE(uart2dm_gpios)); + if (ret) + pr_err("%s: unable to enable gpios for uart2dm\n", __func__); +} +#else +static void msm7x27a_cfg_uart2dm_serial(void) { } +#endif + +static struct platform_device *rumi_sim_devices[] __initdata = { + &msm_device_dmov, + &msm_device_smd, + &smc91x_device, + &msm_device_uart1, + &msm_device_nand, + &msm_device_uart_dm1, + &msm_gsbi0_qup_i2c_device, + &msm_gsbi1_qup_i2c_device, +}; + +static struct platform_device *msm8625_rumi3_devices[] __initdata = { + &msm8625_device_dmov, + &msm8625_device_smd, + &msm8625_device_uart1, + &msm8625_gsbi0_qup_i2c_device, +}; + +static struct platform_device *msm7627a_surf_ffa_devices[] __initdata = { + &msm_device_dmov, + &msm_device_smd, + &msm_device_uart1, + &msm_device_uart_dm1, + &msm_device_uart_dm2, + &msm_gsbi0_qup_i2c_device, + &msm_gsbi1_qup_i2c_device, + &msm_device_otg, + &msm_device_gadget_peripheral, + &smsc911x_device, + &msm_kgsl_3d0, +}; + +static struct platform_device *common_devices[] __initdata = { + &android_usb_device, + &msm_device_nand, + &msm_device_snd, + &msm_device_cad, + &msm_device_adspdec, + &asoc_msm_pcm, + &asoc_msm_dai0, + &asoc_msm_dai1, + &msm_batt_device, + &msm_adc_device, +#ifdef CONFIG_ION_MSM + &ion_dev, +#endif +}; + +static struct platform_device *msm8625_surf_devices[] __initdata = { + &msm8625_device_dmov, + &msm8625_device_uart1, + &msm8625_device_uart_dm1, + &msm8625_device_uart_dm2, + &msm8625_gsbi0_qup_i2c_device, + &msm8625_gsbi1_qup_i2c_device, + &msm8625_device_smd, + &msm8625_device_otg, + &msm8625_device_gadget_peripheral, + &msm8625_kgsl_3d0, +}; + +static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE; +static int __init reserve_kernel_ebi1_size_setup(char *p) +{ + reserve_kernel_ebi1_size = memparse(p, NULL); + return 0; +} +early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup); + +static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE; +static int __init reserve_audio_size_setup(char *p) +{ + reserve_audio_size = memparse(p, NULL); + return 0; +} +early_param("reserve_audio_size", reserve_audio_size_setup); + +static void fix_sizes(void) +{ + if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) { + reserve_mdp_size = MSM7x25A_MSM_RESERVE_MDP_SIZE; + reserve_adsp_size = MSM7x25A_MSM_RESERVE_ADSP_SIZE; + } else { + reserve_mdp_size = MSM_RESERVE_MDP_SIZE; + reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; + } + + if (get_ddr_size() > SZ_512M) + reserve_adsp_size = CAMERA_ZSL_SIZE; +#ifdef CONFIG_ION_MSM + msm_ion_audio_size = MSM_RESERVE_AUDIO_SIZE; + msm_ion_sf_size = reserve_mdp_size; +#ifdef CONFIG_CMA + if (get_ddr_size() > SZ_256M) + reserve_adsp_size = CAMERA_ZSL_SIZE; + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = 0; +#else + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = msm_ion_camera_size; +#endif +#endif +} + +#ifdef CONFIG_ION_MSM +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct ion_co_heap_pdata co_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, +}; + +static struct ion_co_heap_pdata co_mm_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, +}; + +static u64 msm_dmamask = DMA_BIT_MASK(32); + +static struct platform_device ion_cma_device = { + .name = "ion-cma-device", + .id = -1, + .dev = { + .dma_mask = &msm_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif + +/** + * These heaps are listed in the order they will be allocated. + * Don't swap the order unless you know what you are doing! + */ +struct ion_platform_heap msm7x27a_heaps[] = { + { + .id = ION_SYSTEM_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM, + .name = ION_VMALLOC_HEAP_NAME, + }, +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + /* ION_ADSP = CAMERA */ + { + .id = ION_CAMERA_HEAP_ID, + .type = CAMERA_HEAP_TYPE, + .name = ION_CAMERA_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_mm_ion_pdata, + .priv = (void *)&ion_cma_device.dev, + }, + /* AUDIO HEAP 1*/ + { + .id = ION_AUDIO_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + }, + /* ION_MDP = SF */ + { + .id = ION_SF_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_SF_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + }, + /* AUDIO HEAP 2*/ + { + .id = ION_AUDIO_HEAP_BL_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_BL_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + .base = BOOTLOADER_BASE_ADDR, + }, + +#endif +}; + +static struct ion_platform_data ion_pdata = { + .nr = MSM_ION_HEAP_NUM, + .has_outer_cache = 1, + .heaps = msm7x27a_heaps, +}; + +static struct platform_device ion_dev = { + .name = "ion-msm", + .id = 1, + .dev = { .platform_data = &ion_pdata }, +}; +#endif + +static struct memtype_reserve msm7x27a_reserve_table[] __initdata = { + [MEMTYPE_SMI] = { + }, + [MEMTYPE_EBI0] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, + [MEMTYPE_EBI1] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, +}; + +static void __init size_ion_devices(void) +{ +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_pdata.heaps[1].size = msm_ion_camera_size; + ion_pdata.heaps[2].size = RESERVE_KERNEL_EBI1_SIZE; + ion_pdata.heaps[3].size = msm_ion_sf_size; + ion_pdata.heaps[4].size = msm_ion_audio_size; +#endif +} + +static void __init reserve_ion_memory(void) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + msm7x27a_reserve_table[MEMTYPE_EBI1].size += RESERVE_KERNEL_EBI1_SIZE; + msm7x27a_reserve_table[MEMTYPE_EBI1].size += + msm_ion_camera_size_carving; + msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size; +#endif +} + +static void __init msm7x27a_calculate_reserve_sizes(void) +{ + fix_sizes(); + size_ion_devices(); + reserve_ion_memory(); +} + +static int msm7x27a_paddr_to_memtype(unsigned int paddr) +{ + return MEMTYPE_EBI1; +} + +static struct reserve_info msm7x27a_reserve_info __initdata = { + .memtype_reserve_table = msm7x27a_reserve_table, + .calculate_reserve_sizes = msm7x27a_calculate_reserve_sizes, + .paddr_to_memtype = msm7x27a_paddr_to_memtype, +}; + +/* define size of reserve memory is 1M */ +#ifdef CONFIG_SRECORDER_MSM +#define SRECORDER_RESERVED_MEM_SIZE (SZ_512K) + +/* define start address of reserve memory */ +static unsigned long s_srecorder_reserved_mem_phys_start_addr = 0x0; + +/* + * Function: unsigned long get_srecorder_reserved_mem_size(void) + * Description: get size of reserve memory + * Calls: No + * Called By: setup_arch + * Table Accessed: No + * Table Updated: No + * Input: No + * Output: No + * Return: SRECORDER_RESERVED_MEM_SIZE: size of reserve memory + * Others: No + */ +unsigned long get_srecorder_reserved_mem_size(void) +{ + return SRECORDER_RESERVED_MEM_SIZE; +} + +/* + * Function: unsigned long get_mempools_pstart_addr(void) + * Description: get start address of reserve memory + * Calls: No + * Called By: msm8625_reserve + * Table Accessed: No + * Table Updated: No + * Input: No + * Output: No + * Return: s_srecorder_reserved_mem_phys_start_addr:start address of reserve memory + * Others: No + */ +unsigned long get_srecorder_reserved_mem_phys_start_addr(void) +{ + return s_srecorder_reserved_mem_phys_start_addr; +} + +extern unsigned long get_mempools_pstart_addr(void); +#endif /* CONFIG_SRECORDER_MSM */ + +static void __init msm7x27a_reserve(void) +{ + reserve_info = &msm7x27a_reserve_info; + memblock_remove(MSM8625_NON_CACHE_MEM, SZ_2K); + memblock_remove(BOOTLOADER_BASE_ADDR, msm_ion_audio_size); + msm_reserve(); +#ifdef CONFIG_CMA + dma_declare_contiguous( + &ion_cma_device.dev, + msm_ion_camera_size, + CAMERA_HEAP_BASE, + 0x26000000); +#endif + +#ifdef CONFIG_SRECORDER_MSM + if (0x0 != get_mempools_pstart_addr()) + { + s_srecorder_reserved_mem_phys_start_addr = get_mempools_pstart_addr();// - SRECORDER_RESERVED_MEM_SIZE; + } + else + { + printk(">>>> Can't know the start address for S-Recorder's reserved memory!\n"); + } +#endif /* CONFIG_SRECORDER_MSM */ +} + +static void __init msm8625_reserve(void) +{ + msm7x27a_reserve(); + memblock_remove(MSM8625_CPU_PHYS, SZ_8); + memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32); + memblock_remove(MSM8625_NON_CACHE_MEM, SZ_2K); +} + +static void __init msm7x27a_device_i2c_init(void) +{ + msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata; + msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata; +} + +static void __init msm8625_device_i2c_init(void) +{ + msm8625_gsbi0_qup_i2c_device.dev.platform_data = + &msm_gsbi0_qup_i2c_pdata; + msm8625_gsbi1_qup_i2c_device.dev.platform_data = + &msm_gsbi1_qup_i2c_pdata; +} + +#define MSM_EBI2_PHYS 0xa0d00000 +#define MSM_EBI2_XMEM_CS2_CFG1 0xa0d10030 + +static void __init msm7x27a_init_ebi2(void) +{ + uint32_t ebi2_cfg; + void __iomem *ebi2_cfg_ptr; + + ebi2_cfg_ptr = ioremap_nocache(MSM_EBI2_PHYS, sizeof(uint32_t)); + if (!ebi2_cfg_ptr) + return; + + ebi2_cfg = readl(ebi2_cfg_ptr); + if (machine_is_msm7x27a_rumi3() || machine_is_msm7x27a_surf() || + machine_is_msm7625a_surf() || machine_is_msm8625_surf()) + ebi2_cfg |= (1 << 4); /* CS2 */ + + writel(ebi2_cfg, ebi2_cfg_ptr); + iounmap(ebi2_cfg_ptr); + + /* Enable A/D MUX[bit 31] from EBI2_XMEM_CS2_CFG1 */ + ebi2_cfg_ptr = ioremap_nocache(MSM_EBI2_XMEM_CS2_CFG1, + sizeof(uint32_t)); + if (!ebi2_cfg_ptr) + return; + + ebi2_cfg = readl(ebi2_cfg_ptr); + if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) + ebi2_cfg |= (1 << 31); + + writel(ebi2_cfg, ebi2_cfg_ptr); + iounmap(ebi2_cfg_ptr); +} + +static struct platform_device msm_proccomm_regulator_dev = { + .name = PROCCOMM_REGULATOR_DEV_NAME, + .id = -1, + .dev = { + .platform_data = &msm7x27a_proccomm_regulator_data + } +}; + +static void msm_adsp_add_pdev(void) +{ + int rc = 0; + struct rpc_board_dev *rpc_adsp_pdev; + + rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL); + if (rpc_adsp_pdev == NULL) { + pr_err("%s: Memory Allocation failure\n", __func__); + return; + } + rpc_adsp_pdev->prog = ADSP_RPC_PROG; + + if (cpu_is_msm8625()) + rpc_adsp_pdev->pdev = msm8625_device_adsp; + else + rpc_adsp_pdev->pdev = msm_adsp_device; + rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1); + if (rc < 0) { + pr_err("%s: return val: %d\n", __func__, rc); + kfree(rpc_adsp_pdev); + } +} + +static void __init msm7627a_rumi3_init(void) +{ + msm7x27a_init_ebi2(); + platform_add_devices(rumi_sim_devices, + ARRAY_SIZE(rumi_sim_devices)); +} + +static void __init msm8625_rumi3_init(void) +{ + msm7x2x_misc_init(); + msm_adsp_add_pdev(); + msm8625_device_i2c_init(); + platform_add_devices(msm8625_rumi3_devices, + ARRAY_SIZE(msm8625_rumi3_devices)); + + msm_pm_set_platform_data(msm8625_pm_data, + ARRAY_SIZE(msm8625_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata)); + msm8x25_spm_device_init(); + msm_pm_register_cpr_ops(); +} + +#define UART1DM_RX_GPIO 45 + +#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE) +static int __init msm7x27a_init_ar6000pm(void) +{ + msm_wlan_ar6000_pm_device.dev.platform_data = &ar600x_wlan_power; + return platform_device_register(&msm_wlan_ar6000_pm_device); +} +#else +static int __init msm7x27a_init_ar6000pm(void) { return 0; } +#endif + +static void __init msm7x27a_init_regulators(void) +{ + int rc = platform_device_register(&msm_proccomm_regulator_dev); + if (rc) + pr_err("%s: could not register regulator device: %d\n", + __func__, rc); +} + +static void __init msm7x27a_add_footswitch_devices(void) +{ + platform_add_devices(msm_footswitch_devices, + msm_num_footswitch_devices); +} + +static void __init msm7x27a_add_platform_devices(void) +{ + if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) { + platform_add_devices(msm8625_surf_devices, + ARRAY_SIZE(msm8625_surf_devices)); + } else { + platform_add_devices(msm7627a_surf_ffa_devices, + ARRAY_SIZE(msm7627a_surf_ffa_devices)); + } + + platform_add_devices(common_devices, + ARRAY_SIZE(common_devices)); +} + +static void __init msm7x27a_uartdm_config(void) +{ + msm7x27a_cfg_uart2dm_serial(); + msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO); + if (cpu_is_msm8625()) + msm8625_device_uart_dm1.dev.platform_data = + &msm_uart_dm1_pdata; + else + msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; +} + +static void __init msm7x27a_otg_gadget(void) +{ + if (cpu_is_msm8625()) { + msm_otg_pdata.swfi_latency = + msm8625_pm_data[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency; + msm8625_device_otg.dev.platform_data = &msm_otg_pdata; + msm8625_device_gadget_peripheral.dev.platform_data = + &msm_gadget_pdata; + } else { + msm_otg_pdata.swfi_latency = + msm7x27a_pm_data[ + MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency; + msm_device_otg.dev.platform_data = &msm_otg_pdata; + msm_device_gadget_peripheral.dev.platform_data = + &msm_gadget_pdata; + } +} + +static void __init msm7x27a_pm_init(void) +{ + if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) { + msm_pm_set_platform_data(msm8625_pm_data, + ARRAY_SIZE(msm8625_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata)); + msm8x25_spm_device_init(); + msm_pm_register_cpr_ops(); + } else { + msm_pm_set_platform_data(msm7x27a_pm_data, + ARRAY_SIZE(msm7x27a_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata)); + } + + msm_pm_register_irqs(); +} + +static void __init msm7x2x_init(void) +{ + msm7x2x_misc_init(); + + /* Initialize regulators first so that other devices can use them */ + msm7x27a_init_regulators(); + msm_adsp_add_pdev(); + if (cpu_is_msm8625()) + msm8625_device_i2c_init(); + else + msm7x27a_device_i2c_init(); + msm7x27a_init_ebi2(); + msm7x27a_uartdm_config(); + + msm7x27a_otg_gadget(); + msm7x27a_cfg_smsc911x(); + + msm7x27a_add_footswitch_devices(); + msm7x27a_add_platform_devices(); + /* Ensure ar6000pm device is registered before MMC/SDC */ + msm7x27a_init_ar6000pm(); + msm7627a_init_mmc(); + msm_fb_add_devices(); + msm7x2x_init_host(); + msm7x27a_pm_init(); + register_i2c_devices(); + //msm7627a_bt_power_init() will check QC or BCM bt chip powers inner. + msm7627a_bt_power_init(); + msm7627a_camera_init(); + msm7627a_add_io_devices(); + /*7x25a kgsl initializations*/ + msm7x25a_kgsl_3d0_init(); + /*8x25 kgsl initializations*/ + msm8x25_kgsl_3d0_init(); +} + +static void __init msm7x2x_init_early(void) +{ + msm_msm7627a_allocate_memory_regions(); +} + +MACHINE_START(MSM7X27A_RUMI3, "QCT MSM7x27a RUMI3") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7627a_rumi3_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7X27A_SURF, "QCT MSM7x27a SURF") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7X27A_FFA, "QCT MSM7x27a FFA") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7625A_SURF, "QCT MSM7625a SURF") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7625A_FFA, "QCT MSM7625a FFA") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7x27a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_RUMI3, "QCT MSM8625 RUMI3") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm8625_rumi3_init, + .timer = &msm_timer, + .handle_irq = gic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_SURF, "QCT MSM8625 SURF") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_FFA, "QCT MSM8625 FFA") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, + .init_early = msm7x2x_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c index 89b86a3c..e349a4d0 100644 --- a/arch/arm/mach-msm/board-qrd7627a.c +++ b/arch/arm/mach-msm/board-qrd7627a.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -33,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,8 +69,8 @@ #include "board-msm7627a.h" #include "board-msm7627a-sensor.h" -#define PMEM_KERNEL_EBI1_SIZE 0x3A000 -#define MSM_PMEM_AUDIO_SIZE 0xF0000 +#define RESERVE_KERNEL_EBI1_SIZE 0x3A000 +#define MSM_RESERVE_AUDIO_SIZE 0xF0000 #define BOOTLOADER_BASE_ADDR 0x10000 #define BAHAMA_SLAVE_ID_FM_REG 0x02 #define FM_GPIO 83 @@ -182,8 +181,8 @@ static struct platform_device msm8625q_i2c_gpio = { }; #ifdef CONFIG_ARCH_MSM7X27A -#define MSM_PMEM_MDP_SIZE 0x2300000 -#define MSM_PMEM_ADSP_SIZE 0x1200000 +#define MSM_RESERVE_MDP_SIZE 0x2300000 +#define MSM_RESERVE_ADSP_SIZE 0x9600000 #define CAMERA_ZSL_SIZE (SZ_1M * 60) #ifdef CONFIG_ION_MSM @@ -491,61 +490,23 @@ static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = { .v_addr = MSM_CFG_CTL_BASE, }; -static struct android_pmem_platform_data android_pmem_adsp_pdata = { - .name = "pmem_adsp", - .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, - .cached = 1, - .memory_type = MEMTYPE_EBI1, -}; - -static struct platform_device android_pmem_adsp_device = { - .name = "android_pmem", - .id = 1, - .dev = { .platform_data = &android_pmem_adsp_pdata }, -}; - -static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE; -static int __init pmem_mdp_size_setup(char *p) +static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE; +static int __init reserve_mdp_size_setup(char *p) { - pmem_mdp_size = memparse(p, NULL); + reserve_mdp_size = memparse(p, NULL); return 0; } -early_param("pmem_mdp_size", pmem_mdp_size_setup); +early_param("reserve_mdp_size", reserve_mdp_size_setup); -static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE; -static int __init pmem_adsp_size_setup(char *p) +static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; +static int __init reserve_adsp_size_setup(char *p) { - pmem_adsp_size = memparse(p, NULL); + reserve_adsp_size = memparse(p, NULL); return 0; } -early_param("pmem_adsp_size", pmem_adsp_size_setup); - -static struct android_pmem_platform_data android_pmem_audio_pdata = { - .name = "pmem_audio", - .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, - .cached = 0, - .memory_type = MEMTYPE_EBI1, -}; - -static struct platform_device android_pmem_audio_device = { - .name = "android_pmem", - .id = 2, - .dev = { .platform_data = &android_pmem_audio_pdata }, -}; - -static struct android_pmem_platform_data android_pmem_pdata = { - .name = "pmem", - .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, - .cached = 1, - .memory_type = MEMTYPE_EBI1, -}; -static struct platform_device android_pmem_device = { - .name = "android_pmem", - .id = 0, - .dev = { .platform_data = &android_pmem_pdata }, -}; +early_param("reserve_adsp_size", reserve_adsp_size_setup); static u32 msm_calculate_batt_capacity(u32 current_voltage); @@ -793,9 +754,6 @@ static struct i2c_board_info i2c2_info[] __initdata = { static struct platform_device *common_devices[] __initdata = { &android_usb_device, - &android_pmem_device, - &android_pmem_adsp_device, - &android_pmem_audio_device, &msm_batt_device, &msm_device_adspdec, &msm_device_snd, @@ -858,42 +816,44 @@ static struct platform_device *msm8625q_lcd_camera_devices[] __initdata = { &evbd_vreg_gpio_ext_1p8v, }; -static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE; -static int __init pmem_kernel_ebi1_size_setup(char *p) +static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE; +static int __init reserve_kernel_ebi1_size_setup(char *p) { - pmem_kernel_ebi1_size = memparse(p, NULL); + reserve_kernel_ebi1_size = memparse(p, NULL); return 0; } -early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); +early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup); -static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE; -static int __init pmem_audio_size_setup(char *p) +static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE; +static int __init reserve_audio_size_setup(char *p) { - pmem_audio_size = memparse(p, NULL); + reserve_audio_size = memparse(p, NULL); return 0; } -early_param("pmem_audio_size", pmem_audio_size_setup); +early_param("reserve_audio_size", reserve_audio_size_setup); static void fix_sizes(void) { if (get_ddr_size() > SZ_512M) - pmem_adsp_size = CAMERA_ZSL_SIZE; + reserve_adsp_size = CAMERA_ZSL_SIZE; else { if (machine_is_msm8625q_skue() || machine_is_msm8625q_evbd() || machine_is_msm8625q_skud()) - pmem_mdp_size = 0; + reserve_mdp_size = 0; } #ifdef CONFIG_ION_MSM - msm_ion_audio_size = MSM_PMEM_AUDIO_SIZE; + msm_ion_audio_size = MSM_RESERVE_AUDIO_SIZE; + msm_ion_sf_size = reserve_mdp_size; #ifdef CONFIG_CMA - msm_ion_camera_size = CAMERA_ZSL_SIZE; - msm_ion_camera_size_carving = 0; + if (get_ddr_size() > SZ_256M) + reserve_adsp_size = CAMERA_ZSL_SIZE; + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = 0; #else - msm_ion_camera_size = pmem_adsp_size; - msm_ion_camera_size_carving = msm_ion_camera_size; + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = msm_ion_camera_size; #endif - msm_ion_sf_size = pmem_mdp_size; #endif } @@ -932,7 +892,7 @@ struct ion_platform_heap msm7627a_heaps[] = { .name = ION_VMALLOC_HEAP_NAME, }, #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION - /* PMEM_ADSP = CAMERA */ + /* ION_ADSP = CAMERA */ { .id = ION_CAMERA_HEAP_ID, .type = CAMERA_HEAP_TYPE, @@ -949,7 +909,7 @@ struct ion_platform_heap msm7627a_heaps[] = { .memory_type = ION_EBI_TYPE, .extra_data = (void *)&co_ion_pdata, }, - /* PMEM_MDP = SF */ + /* ION_MDP = SF */ { .id = ION_SF_HEAP_ID, .type = ION_HEAP_TYPE_CARVEOUT, @@ -994,56 +954,11 @@ static struct memtype_reserve msm7627a_reserve_table[] __initdata = { }, }; -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION -static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = { - &android_pmem_adsp_pdata, - &android_pmem_audio_pdata, - &android_pmem_pdata, -}; -#endif -#endif - -static void __init size_pmem_devices(void) -{ -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION - unsigned int i; - - android_pmem_adsp_pdata.size = pmem_adsp_size; - android_pmem_pdata.size = pmem_mdp_size; - android_pmem_audio_pdata.size = pmem_audio_size; -#endif -#endif -} - -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION -static void __init reserve_memory_for(struct android_pmem_platform_data *p) -{ - msm7627a_reserve_table[p->memory_type].size += p->size; -} -#endif -#endif - -static void __init reserve_pmem_memory(void) -{ -#ifdef CONFIG_ANDROID_PMEM -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION - unsigned int i; - for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) - reserve_memory_for(pmem_pdata_array[i]); - - msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; -#endif -#endif -} - static void __init size_ion_devices(void) { #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_pdata.heaps[1].size = msm_ion_camera_size; - ion_pdata.heaps[2].size = PMEM_KERNEL_EBI1_SIZE; + ion_pdata.heaps[2].size = RESERVE_KERNEL_EBI1_SIZE; ion_pdata.heaps[3].size = msm_ion_sf_size; ion_pdata.heaps[4].size = msm_ion_audio_size; #endif @@ -1052,18 +967,16 @@ static void __init size_ion_devices(void) static void __init reserve_ion_memory(void) { #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) - msm7627a_reserve_table[MEMTYPE_EBI1].size += PMEM_KERNEL_EBI1_SIZE; - msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size; - msm7627a_reserve_table[MEMTYPE_EBI1].size += + msm7627a_reserve_table[MEMTYPE_EBI1].size += RESERVE_KERNEL_EBI1_SIZE; + msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_camera_size_carving; + msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size; #endif } static void __init msm7627a_calculate_reserve_sizes(void) { fix_sizes(); - size_pmem_devices(); - reserve_pmem_memory(); size_ion_devices(); reserve_ion_memory(); } diff --git a/arch/arm/mach-msm/board-qrd7627a_i6.c b/arch/arm/mach-msm/board-qrd7627a_i6.c new file mode 100644 index 00000000..8be83db7 --- /dev/null +++ b/arch/arm/mach-msm/board-qrd7627a_i6.c @@ -0,0 +1,1232 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "board-msm7x27a-regulator.h" +#include "devices.h" +#include "devices-msm7x2xa.h" +#include "pm.h" +#include "timer.h" +#include "pm-boot.h" +#include "board-msm7x27a-regulator.h" +#include "board-msm7627a.h" +#include "board-msm7627a_i6-sensor.h" + +#define RESERVE_KERNEL_EBI1_SIZE 0x3A000 +#define MSM_RESERVE_AUDIO_SIZE 0xF0000 +#define BOOTLOADER_BASE_ADDR 0x10000 +#define BAHAMA_SLAVE_ID_FM_REG 0x02 +#define FM_GPIO 83 +#define BT_PCM_BCLK_MODE 0x88 +#define BT_PCM_DIN_MODE 0x89 +#define BT_PCM_DOUT_MODE 0x8A +#define BT_PCM_SYNC_MODE 0x8B +#define FM_I2S_SD_MODE 0x8E +#define FM_I2S_WS_MODE 0x8F +#define FM_I2S_SCK_MODE 0x90 +#define I2C_PIN_CTL 0x15 +#define I2C_NORMAL 0x40 + + +static struct msm_gpio qup_i2c_gpios_io[] = { + { GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(61, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, + { GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, +}; + +static struct msm_gpio qup_i2c_gpios_hw[] = { + { GPIO_CFG(60, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, + { GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_scl" }, + { GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), + "qup_sda" }, +}; + +static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type) +{ + int rc; + + if (adap_id < 0 || adap_id > 1) + return; + + /* Each adapter gets 2 lines from the table */ + if (config_type) + rc = msm_gpios_request_enable(&qup_i2c_gpios_hw[adap_id*2], 2); + else + rc = msm_gpios_request_enable(&qup_i2c_gpios_io[adap_id*2], 2); + if (rc < 0) + pr_err("QUP GPIO request/enable failed: %d\n", rc); +} + +static struct msm_i2c_platform_data msm_gsbi0_qup_i2c_pdata = { + .clk_freq = 100000, + .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config, +}; + +#if 1 //linxc 2012-12-24 for I2C recovery +static void gsbi1_quptable_i2c_gpio_config(int adap_id,int config_type) +{ + int rc; + + if (adap_id < 0 || adap_id > 1) + return; + + printk("linxc %s adap_id=%d, config_type=%d\n", __func__, adap_id, config_type); + + if(config_type == 0) + { + rc = msm_gpios_request_enable(&qup_i2c_gpios_io[adap_id*2], 2); + if(rc < 0){ + printk("linxc %s check 1111 \n", __func__); + msm_gpios_free(&qup_i2c_gpios_hw[adap_id*2], 2); + rc = msm_gpios_request_enable(&qup_i2c_gpios_io[adap_id*2], 2); + } + } + else + { + rc = msm_gpios_request_enable(&qup_i2c_gpios_hw[adap_id*2], 2); + if(rc < 0){ + printk("linxc %s check 2222 \n", __func__); + msm_gpios_free(&qup_i2c_gpios_io[adap_id*2], 2); + rc = msm_gpios_request_enable(&qup_i2c_gpios_hw[adap_id*2], 2); + } + } + + if (rc < 0) + printk("QUP GPIO request/enable failed: %d\n", rc); + +} + +static struct msm_i2c_platform_data msm_gsbi1_qup_i2c_pdata = { + .clk_freq = 100000, + .pri_clk =131, + .pri_dat = 132, + .msm_i2c_config_gpio = gsbi1_quptable_i2c_gpio_config, +}; +#else +static struct msm_i2c_platform_data msm_gsbi1_qup_i2c_pdata = { + .clk_freq = 100000, + .msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config, +}; +#endif + +#ifdef CONFIG_ARCH_MSM7X27A +#define MSM_RESERVE_MDP_SIZE 0x2D00000 //0x2300000 --> 0x2D00000 45M for QHD Panel linxc 2012-09-04 modified +#define MSM_RESERVE_ADSP_SIZE 0x1200000 +#define CAMERA_ZSL_SIZE (SZ_1M * 60) + +#ifdef CONFIG_ION_MSM +#define MSM_ION_HEAP_NUM 4 +static struct platform_device ion_dev; +static int msm_ion_camera_size; +static int msm_ion_audio_size; +static int msm_ion_sf_size; +static int msm_ion_camera_size_carving; +#endif +#endif + +#define CAMERA_HEAP_BASE 0x0 +#ifdef CONFIG_CMA +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_DMA +#else +#define CAMERA_HEAP_TYPE ION_HEAP_TYPE_CARVEOUT +#endif + +static struct android_usb_platform_data android_usb_pdata = { + .update_pid_and_serial_num = usb_diag_update_pid_and_serial_num, + .cdrom = 1, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; + +#ifdef CONFIG_USB_EHCI_MSM_72K +static void msm_hsusb_vbus_power(unsigned phy_info, int on) +{ + int rc = 0; + unsigned gpio; + + gpio = QRD_GPIO_HOST_VBUS_EN; + + rc = gpio_request(gpio, "i2c_host_vbus_en"); + if (rc < 0) { + pr_err("failed to request %d GPIO\n", gpio); + return; + } + gpio_direction_output(gpio, !!on); + gpio_set_value_cansleep(gpio, !!on); + gpio_free(gpio); +} + +static struct msm_usb_host_platform_data msm_usb_host_pdata = { + .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM), +}; + +static void __init msm7627a_init_host(void) +{ + msm_add_host(0, &msm_usb_host_pdata); +} +#endif + +#ifdef CONFIG_USB_MSM_OTG_72K +static int hsusb_rpc_connect(int connect) +{ + if (connect) + return msm_hsusb_rpc_connect(); + else + return msm_hsusb_rpc_close(); +} + +static struct regulator *reg_hsusb; +static int msm_hsusb_ldo_init(int init) +{ + int rc = 0; + + if (init) { + reg_hsusb = regulator_get(NULL, "usb"); + if (IS_ERR(reg_hsusb)) { + rc = PTR_ERR(reg_hsusb); + pr_err("%s: could not get regulator: %d\n", + __func__, rc); + goto out; + } + + rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000); + if (rc) { + pr_err("%s: could not set voltage: %d\n", + __func__, rc); + goto reg_free; + } + + return 0; + } + /* else fall through */ +reg_free: + regulator_put(reg_hsusb); +out: + reg_hsusb = NULL; + return rc; +} + +static int msm_hsusb_ldo_enable(int enable) +{ + static int ldo_status; + + if (IS_ERR_OR_NULL(reg_hsusb)) + return reg_hsusb ? PTR_ERR(reg_hsusb) : -ENODEV; + + if (ldo_status == enable) + return 0; + + ldo_status = enable; + + return enable ? + regulator_enable(reg_hsusb) : + regulator_disable(reg_hsusb); +} + +#ifndef CONFIG_USB_EHCI_MSM_72K +static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init) +{ + int ret = 0; + + if (init) + ret = msm_pm_app_rpc_init(callback); + else + msm_pm_app_rpc_deinit(callback); + + return ret; +} +#endif + +static struct msm_otg_platform_data msm_otg_pdata = { +#ifndef CONFIG_USB_EHCI_MSM_72K + .pmic_vbus_notif_init = msm_hsusb_pmic_notif_init, +#else + .vbus_power = msm_hsusb_vbus_power, +#endif + .rpc_connect = hsusb_rpc_connect, + .pemp_level = PRE_EMPHASIS_WITH_20_PERCENT, + .cdr_autoreset = CDR_AUTO_RESET_DISABLE, + .drv_ampl = HS_DRV_AMPLITUDE_DEFAULT, + .se1_gating = SE1_GATING_DISABLE, + .ldo_init = msm_hsusb_ldo_init, + .ldo_enable = msm_hsusb_ldo_enable, + .chg_init = hsusb_chg_init, + .chg_connected = hsusb_chg_connected, + .chg_vbus_draw = hsusb_chg_vbus_draw, +}; +#endif + +static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = { + .is_phy_status_timer_on = 1, + .prop_chg = 0, +}; + +#ifdef CONFIG_SERIAL_MSM_HS +static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { + .inject_rx_on_wakeup = 1, + .rx_to_inject = 0xFD, +}; +#endif +static struct msm_pm_platform_data msm7627a_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 16000, + .residency = 20000, + }, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 12000, + .residency = 20000, + }, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 1, + .latency = 2000, + .residency = 0, + }, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 0, + }, +}; + +static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS, + .p_addr = 0, +}; + +/* 8625 PM platform data */ +static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = { + /* CORE0 entries */ + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 16000, + .residency = 20000, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 12000, + .residency = 20000, + }, + + /* picked latency & redisdency values from 7x30 */ + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 500, + .residency = 6000, + }, + + [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 10, + }, + + /* picked latency & redisdency values from 7x30 */ + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 0, + .suspend_enabled = 0, + .latency = 500, + .residency = 6000, + }, + + [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = { + .idle_supported = 1, + .suspend_supported = 1, + .idle_enabled = 1, + .suspend_enabled = 1, + .latency = 2, + .residency = 10, + }, + +}; + +static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = { + .mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR, + .v_addr = MSM_CFG_CTL_BASE, +}; + +static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE; +static int __init reserve_mdp_size_setup(char *p) + { + reserve_mdp_size = memparse(p, NULL); + return 0; + } + +early_param("reserve_mdp_size", reserve_mdp_size_setup); + +static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE; +static int __init reserve_adsp_size_setup(char *p) + { + reserve_adsp_size = memparse(p, NULL); + return 0; + } + +early_param("reserve_adsp_size", reserve_adsp_size_setup); + +static u32 msm_calculate_batt_capacity(u32 current_voltage); + +static struct msm_psy_batt_pdata msm_psy_batt_data = { + .voltage_min_design = 2800, + .voltage_max_design = 4300, + .avail_chg_sources = AC_CHG | USB_CHG | UNKNOWN_CHG, + .batt_technology = POWER_SUPPLY_TECHNOLOGY_LION, + .calculate_capacity = &msm_calculate_batt_capacity, +}; + +static u32 msm_calculate_batt_capacity(u32 current_voltage) +{ + u32 low_voltage = msm_psy_batt_data.voltage_min_design; + u32 high_voltage = msm_psy_batt_data.voltage_max_design; + + if (current_voltage <= low_voltage) + return 0; + else if (current_voltage >= high_voltage) + return 100; + else + return (current_voltage - low_voltage) * 100 + / (high_voltage - low_voltage); +} + +static struct platform_device msm_fastboot_device = { + .name = "fastboot", + .id = -1, +}; + +static struct platform_device msm_batt_device = { + .name = "msm-battery", + .id = -1, + .dev.platform_data = &msm_psy_batt_data, +}; + +static char *msm_adc_surf_device_names[] = { + "XO_ADC", +}; + +static struct msm_adc_platform_data msm_adc_pdata = { + .dev_names = msm_adc_surf_device_names, + .num_adc = ARRAY_SIZE(msm_adc_surf_device_names), + .target_hw = MSM_8x25, +}; + +static struct platform_device msm_adc_device = { + .name = "msm_adc", + .id = -1, + .dev = { + .platform_data = &msm_adc_pdata, + }, +}; + +#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \ + [GPIO_VREG_ID_##_id] = { \ + .init_data = { \ + .constraints = { \ + .valid_ops_mask = REGULATOR_CHANGE_STATUS, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(vreg_consumers_##_id), \ + .consumer_supplies = vreg_consumers_##_id, \ + }, \ + .regulator_name = _reg_name, \ + .active_low = _active_low, \ + .gpio_label = _gpio_label, \ + .gpio = _gpio, \ + } + +#define GPIO_VREG_ID_EXT_2P85V 0 +#define GPIO_VREG_ID_EXT_1P8V 1 + +#if 1 //add by lf 2012.12.20 +#define GPIO_VREG_ID_EXT_3P3V 2 + +static struct regulator_consumer_supply vreg_consumers_EXT_3P3V[] = { + REGULATOR_SUPPLY("lcd_vddj", "mipi_dsi.1"), + }; +#endif + +static struct regulator_consumer_supply vreg_consumers_EXT_2P85V[] = { + REGULATOR_SUPPLY("cam_ov5647_avdd", "0-006c"), + REGULATOR_SUPPLY("cam_ov5647_truly_cm6868_avdd", "0-006c"), + REGULATOR_SUPPLY("cam_ov7692_avdd", "0-0078"), + REGULATOR_SUPPLY("cam_ov8825_avdd", "0-000d"), + REGULATOR_SUPPLY("cam_ov8825_truly_cm8313_avdd", "0-000d"), //add by hanjue + REGULATOR_SUPPLY("cam_gc0339_avdd", "0-0036"), //add by hanjue + REGULATOR_SUPPLY("lcd_vdd", "mipi_dsi.1"), +#ifdef CONFIG_AR0543 + REGULATOR_SUPPLY("cam_ar0543_avdd", "0-0064"), +#endif +}; + +static struct regulator_consumer_supply vreg_consumers_EXT_1P8V[] = { + REGULATOR_SUPPLY("cam_ov5647_vdd", "0-006c"), + REGULATOR_SUPPLY("cam_ov5647_truly_cm6868_vdd", "0-006c"), + REGULATOR_SUPPLY("cam_ov7692_vdd", "0-0078"), + REGULATOR_SUPPLY("cam_ov8825_truly_cm8313_vdd", "0-000d"), //add by hanjue + REGULATOR_SUPPLY("cam_gc0399_vdd", "0-0036"), //add by hanjue + REGULATOR_SUPPLY("lcd_vddi", "mipi_dsi.1"), +#ifdef CONFIG_AR0543 + REGULATOR_SUPPLY("cam_ar0543_vdd", "0-0064"), +#endif +}; + +/* GPIO regulator constraints */ +static struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] = { + GPIO_VREG_INIT(EXT_2P85V, "ext_2p85v", "ext_2p85v_en", 35, 0), + GPIO_VREG_INIT(EXT_1P8V, "ext_1p8v", "ext_1p8v_en", 40, 0), + GPIO_VREG_INIT(EXT_3P3V, "ext_3p3v", "ext_3p3v_en", 12, 0), //linxc 2012-12-21 +++ +}; + +/* GPIO regulator */ +static struct platform_device qrd_vreg_gpio_ext_2p85v __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = 35, + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_2P85V], + }, +}; + +static struct platform_device qrd_vreg_gpio_ext_1p8v __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = 40, + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_1P8V], + }, +}; + +//linxc 2012-12-20 +++ +static struct platform_device qrd_vreg_gpio_ext_3p3v __devinitdata = { + .name = GPIO_REGULATOR_DEV_NAME, + .id = 12, + .dev = { + .platform_data = + &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V], + }, +}; +//linxc 2012-12-20 --- + +static struct platform_device *common_devices[] __initdata = { + &android_usb_device, + &msm_batt_device, + &msm_device_adspdec, + &msm_device_snd, + &msm_device_cad, + &asoc_msm_pcm, + &asoc_msm_dai0, + &asoc_msm_dai1, + &msm_adc_device, +#ifdef CONFIG_ION_MSM + &ion_dev, +#endif + &msm_fastboot_device, +}; + + +static struct platform_device msm_wlan_ar6000_pm_device = { + .name = "wlan_ar6000_pm_dev", + .id = 1, + .num_resources = 0, + .resource = NULL, +}; + +static struct platform_device *qrd7627a_devices[] __initdata = { + &msm_device_dmov, + &msm_device_smd, + &msm_device_uart1, + &msm_device_uart_dm1, + &msm_gsbi0_qup_i2c_device, + &msm_gsbi1_qup_i2c_device, + &msm_device_otg, + &msm_device_gadget_peripheral, + &msm_kgsl_3d0, + &qrd_vreg_gpio_ext_2p85v, + &qrd_vreg_gpio_ext_1p8v, +}; + +static struct platform_device *qrd3_devices[] __initdata = { + &msm_device_nand, +}; + +static struct platform_device *msm8625_evb_devices[] __initdata = { + &msm8625_device_dmov, + &msm8625_device_smd, + &msm8625_gsbi0_qup_i2c_device, + &msm8625_gsbi1_qup_i2c_device, + &msm8625_device_uart1, + &msm8625_device_uart_dm1, + &msm8625_device_otg, + &msm8625_device_gadget_peripheral, + &msm8625_kgsl_3d0, + &qrd_vreg_gpio_ext_2p85v, + &qrd_vreg_gpio_ext_1p8v, + &qrd_vreg_gpio_ext_3p3v, //linxc add +++ 2012-12-20 +}; + +static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE; +static int __init reserve_kernel_ebi1_size_setup(char *p) +{ + reserve_kernel_ebi1_size = memparse(p, NULL); + return 0; +} +early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup); + +static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE; +static int __init reserve_audio_size_setup(char *p) +{ + reserve_audio_size = memparse(p, NULL); + return 0; +} +early_param("reserve_audio_size", reserve_audio_size_setup); + +static void fix_sizes(void) +{ + if (get_ddr_size() > SZ_512M) + reserve_adsp_size = CAMERA_ZSL_SIZE; +#ifdef CONFIG_ION_MSM + msm_ion_audio_size = MSM_RESERVE_AUDIO_SIZE; + msm_ion_sf_size = reserve_mdp_size; +#ifdef CONFIG_CMA + if (get_ddr_size() > SZ_256M) + reserve_adsp_size = CAMERA_ZSL_SIZE; + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = 0; +#else + msm_ion_camera_size = reserve_adsp_size; + msm_ion_camera_size_carving = msm_ion_camera_size; +#endif +#endif +} + +#ifdef CONFIG_ION_MSM +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +static struct ion_co_heap_pdata co_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, +}; + +static struct ion_co_heap_pdata co_mm_ion_pdata = { + .adjacent_mem_id = INVALID_HEAP_ID, + .align = PAGE_SIZE, +}; + +static u64 msm_dmamask = DMA_BIT_MASK(32); + +static struct platform_device ion_cma_device = { + .name = "ion-cma-device", + .id = -1, + .dev = { + .dma_mask = &msm_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif + +/** + * These heaps are listed in the order they will be allocated. + * Don't swap the order unless you know what you are doing! + */ +struct ion_platform_heap qrd7627a_heaps[] = { + { + .id = ION_SYSTEM_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM, + .name = ION_VMALLOC_HEAP_NAME, + }, +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + /* ION_ADSP = CAMERA */ + { + .id = ION_CAMERA_HEAP_ID, + .type = CAMERA_HEAP_TYPE, + .name = ION_CAMERA_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_mm_ion_pdata, + .priv = (void *)&ion_cma_device.dev, + }, + /* AUDIO HEAP 1*/ + { + .id = ION_AUDIO_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + }, + /* ION_MDP = SF */ + { + .id = ION_SF_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_SF_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + }, + /* AUDIO HEAP 2*/ + { + .id = ION_AUDIO_HEAP_BL_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_BL_HEAP_NAME, + .memory_type = ION_EBI_TYPE, + .extra_data = (void *)&co_ion_pdata, + .base = BOOTLOADER_BASE_ADDR, + }, + +#endif +}; + +static struct ion_platform_data ion_pdata = { + .nr = MSM_ION_HEAP_NUM, + .has_outer_cache = 1, + .heaps = qrd7627a_heaps, +}; + +static struct platform_device ion_dev = { + .name = "ion-msm", + .id = 1, + .dev = { .platform_data = &ion_pdata }, +}; +#endif + +static struct memtype_reserve msm7627a_reserve_table[] __initdata = { + [MEMTYPE_SMI] = { + }, + [MEMTYPE_EBI0] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, + [MEMTYPE_EBI1] = { + .flags = MEMTYPE_FLAGS_1M_ALIGN, + }, +}; + +static void __init size_ion_devices(void) +{ +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + ion_pdata.heaps[1].size = msm_ion_camera_size; + ion_pdata.heaps[2].size = RESERVE_KERNEL_EBI1_SIZE; + ion_pdata.heaps[3].size = msm_ion_sf_size; + ion_pdata.heaps[4].size = msm_ion_audio_size; +#endif +} + +static void __init reserve_ion_memory(void) +{ +#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION) + msm7627a_reserve_table[MEMTYPE_EBI1].size += RESERVE_KERNEL_EBI1_SIZE; + msm7627a_reserve_table[MEMTYPE_EBI1].size += + msm_ion_camera_size_carving; + msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size; +#endif +} + +static void __init msm7627a_calculate_reserve_sizes(void) +{ + fix_sizes(); + size_ion_devices(); + reserve_ion_memory(); +} + +static int msm7627a_paddr_to_memtype(unsigned int paddr) +{ + return MEMTYPE_EBI1; +} + +static struct reserve_info msm7627a_reserve_info __initdata = { + .memtype_reserve_table = msm7627a_reserve_table, + .calculate_reserve_sizes = msm7627a_calculate_reserve_sizes, + .paddr_to_memtype = msm7627a_paddr_to_memtype, +}; + +static void __init msm7627a_reserve(void) +{ + reserve_info = &msm7627a_reserve_info; + msm_reserve(); + memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32); +} + +static void __init msm8625_reserve(void) +{ + memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8); + msm7627a_reserve(); +} + +static void msmqrd_adsp_add_pdev(void) +{ + int rc = 0; + struct rpc_board_dev *rpc_adsp_pdev; + + rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL); + if (rpc_adsp_pdev == NULL) { + pr_err("%s: Memory Allocation failure\n", __func__); + return; + } + rpc_adsp_pdev->prog = ADSP_RPC_PROG; + + if (cpu_is_msm8625()) + rpc_adsp_pdev->pdev = msm8625_device_adsp; + else + rpc_adsp_pdev->pdev = msm_adsp_device; + rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1); + if (rc < 0) { + pr_err("%s: return val: %d\n", __func__, rc); + kfree(rpc_adsp_pdev); + } +} + +static void __init msm7627a_device_i2c_init(void) +{ + msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata; + msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata; +} + +static void __init msm8625_device_i2c_init(void) +{ + msm8625_gsbi0_qup_i2c_device.dev.platform_data + = &msm_gsbi0_qup_i2c_pdata; + msm8625_gsbi1_qup_i2c_device.dev.platform_data + = &msm_gsbi1_qup_i2c_pdata; +} + +static struct platform_device msm_proccomm_regulator_dev = { + .name = PROCCOMM_REGULATOR_DEV_NAME, + .id = -1, + .dev = { + .platform_data = &msm7x27a_proccomm_regulator_data + } +}; + +static void __init msm7627a_init_regulators(void) +{ + int rc = platform_device_register(&msm_proccomm_regulator_dev); + if (rc) + pr_err("%s: could not register regulator device: %d\n", + __func__, rc); +} +/*start by lf 2012.12.26 for button-backlight*/ +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +#if 1//def D9_BOARD_MBV2P0_BSP +#define D9_LED_GPIO_KEYBOARD 49 +#else +#define D9_LED_GPIO_KEYBOARD 82 +#endif +static struct gpio_led gpio_leds[] = { + [0] = { + .gpio = D9_LED_GPIO_KEYBOARD, + .name = "button-backlight", + .default_trigger = "none", + .active_low = 0, + }, +}; + +static struct gpio_led_platform_data gpio_led_pdata = { + .num_leds = ARRAY_SIZE(gpio_leds), + .leds = gpio_leds, +}; + +static struct platform_device led_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &gpio_led_pdata, + }, +}; + +static void __init keyboard_leds_init(void) +{ + int rc; + rc = gpio_tlmm_config(GPIO_CFG(D9_LED_GPIO_KEYBOARD, 0, + GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, + GPIO_CFG_2MA), GPIO_CFG_ENABLE); + if (rc < 0) { + pr_err("%s: linxc say unable to enable keypad led gpio!\n", __func__); + return; + } + platform_device_register(&led_device); +} +#endif +/*end by lf 2012.12.26*/ +#define NV_ITEM_WLAN_MAC_ADDR 4678 +extern int msm_read_nv(unsigned int nv_item, void *buf); +unsigned char wlan_mac_addr[6]; + +static int __init msm_qrd_init_ar6000pm(void) +{ + msm_wlan_ar6000_pm_device.dev.platform_data = &ar600x_wlan_power; + msm_read_nv(NV_ITEM_WLAN_MAC_ADDR,wlan_mac_addr); + return platform_device_register(&msm_wlan_ar6000_pm_device); +} + +static void __init msm_add_footswitch_devices(void) +{ + platform_add_devices(msm_footswitch_devices, + msm_num_footswitch_devices); +} + +static void __init add_platform_devices(void) +{ + if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7() + || machine_is_msm8625_qrd5() || machine_is_msm8625q_skud() + || machine_is_msm8625q_skue()) { + platform_add_devices(msm8625_evb_devices, + ARRAY_SIZE(msm8625_evb_devices)); + platform_add_devices(qrd3_devices, + ARRAY_SIZE(qrd3_devices)); + } + else { + platform_add_devices(qrd7627a_devices, + ARRAY_SIZE(qrd7627a_devices)); + } + + if (machine_is_msm7627a_qrd3() || machine_is_msm7627a_evb()) + platform_add_devices(qrd3_devices, + ARRAY_SIZE(qrd3_devices)); +/*start by lf 2012.12.26 for button-backlight*/ + if (machine_is_msm8625_qrd5()){ + #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) + keyboard_leds_init(); + #endif +/*end by lf 2012.12.26 */ + } + platform_add_devices(common_devices, + ARRAY_SIZE(common_devices)); +} + +#define UART1DM_RX_GPIO 45 +static void __init qrd7627a_uart1dm_config(void) +{ + msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO); + if (cpu_is_msm8625()) + msm8625_device_uart_dm1.dev.platform_data = + &msm_uart_dm1_pdata; + else + msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; +} + +static void __init qrd7627a_otg_gadget(void) +{ + if (cpu_is_msm8625()) { + msm_otg_pdata.swfi_latency = msm8625_pm_data + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency; + msm8625_device_otg.dev.platform_data = &msm_otg_pdata; + msm8625_device_gadget_peripheral.dev.platform_data = + &msm_gadget_pdata; + + } else { + msm_otg_pdata.swfi_latency = msm7627a_pm_data + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency; + msm_device_otg.dev.platform_data = &msm_otg_pdata; + msm_device_gadget_peripheral.dev.platform_data = + &msm_gadget_pdata; + } +} + +static void __init msm_pm_init(void) +{ + + if (!cpu_is_msm8625()) { + msm_pm_set_platform_data(msm7627a_pm_data, + ARRAY_SIZE(msm7627a_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata)); + } else { + msm_pm_set_platform_data(msm8625_pm_data, + ARRAY_SIZE(msm8625_pm_data)); + BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata)); + msm8x25_spm_device_init(); + msm_pm_register_cpr_ops(); + } +} + +static void __init msm_qrd_init(void) +{ + msm7x2x_misc_init(); + msm7627a_init_regulators(); + msmqrd_adsp_add_pdev(); + + if (cpu_is_msm8625()) + msm8625_device_i2c_init(); + else + msm7627a_device_i2c_init(); + + /* uart1dm*/ + qrd7627a_uart1dm_config(); + /*OTG gadget*/ + qrd7627a_otg_gadget(); + + msm_add_footswitch_devices(); + add_platform_devices(); + + /* Ensure ar6000pm device is registered before MMC/SDC */ + msm_qrd_init_ar6000pm(); + msm7627a_init_mmc(); + +#ifdef CONFIG_USB_EHCI_MSM_72K + msm7627a_init_host(); +#endif + msm_pm_init(); + + msm_pm_register_irqs(); + msm_fb_add_devices(); + +#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE) + msm7627a_bt_power_init(); +#endif + msm7627a_sensor_init(); + msm7627a_camera_init(); + qrd7627a_add_io_devices(); + msm7x25a_kgsl_3d0_init(); + msm8x25_kgsl_3d0_init(); +} + +static void __init qrd7627a_init_early(void) +{ + msm_msm7627a_allocate_memory_regions(); +} + +#ifdef CONFIG_MSM_AMSS_ENHANCE_DEBUG +#define TASK_OFFSET_SEND(member, name) \ + do { \ + input.extension.len = 2; \ + input.extension.data[0] = (uint32_t)TASK_STRUCT_TAG; \ + input.extension.data[1] = offsetof(struct task_struct, member); \ + input.address = (uint32_t)__virt_to_phys((unsigned long)&init_task); \ + input.size = sizeof(struct task_struct); \ + strncpy(input.file_name, name, NZI_ITEM_FILE_NAME_LENGTH); \ + input.file_name[NZI_ITEM_FILE_NAME_LENGTH - 1] = 0; \ + send_modem_logaddr(&input); \ + } while (0) + +static int __init qrd7627a_logbuf_init(void) +{ + nzi_buf_item_type input; + extern char __log_buf[]; + extern unsigned long totalram_pages; + extern atomic_long_t vm_stat[]; + +#ifdef CONFIG_PRINTK + /* send the kernel log address */ + input.extension.len = 0; + input.address = (uint32_t)__virt_to_phys((unsigned long)__log_buf); + input.size = (1 << CONFIG_LOG_BUF_SHIFT); + strncpy(input.file_name, "dmesg", NZI_ITEM_FILE_NAME_LENGTH); + input.file_name[NZI_ITEM_FILE_NAME_LENGTH - 1] = 0; + send_modem_logaddr(&input); +#endif + + /* ******struct task_struct part ******/ + TASK_OFFSET_SEND(tasks, "tasks_of"); + TASK_OFFSET_SEND(thread_group, "tg_of"); + TASK_OFFSET_SEND(mm, "mm_of"); + TASK_OFFSET_SEND(comm, "comm_of"); + TASK_OFFSET_SEND(pid, "pid_of"); + TASK_OFFSET_SEND(tgid, "tgid_of"); + /* ******struct task_struct end ******/ + + /* totalram_pages */ + input.extension.len = 1; + input.extension.data[0] = (uint32_t)MEM_INFO_TAG; + input.address = (uint32_t)__virt_to_phys((unsigned long)&totalram_pages); + input.size = sizeof(totalram_pages); + strncpy(input.file_name, "totalram", NZI_ITEM_FILE_NAME_LENGTH); + input.file_name[NZI_ITEM_FILE_NAME_LENGTH - 1] = 0; + send_modem_logaddr(&input); + + /* vm_stat[vm_stat[NR_VM_ZONE_STAT_ITEMS]; */ + input.extension.len = 1; + input.extension.data[0] = (uint32_t)MEM_INFO_TAG; + input.address = (uint32_t)__virt_to_phys((unsigned long)vm_stat); + input.size = sizeof(vm_stat); + strncpy(input.file_name, "vm_stat", NZI_ITEM_FILE_NAME_LENGTH); + input.file_name[NZI_ITEM_FILE_NAME_LENGTH - 1] = 0; + send_modem_logaddr(&input); + + return 0; +} +late_initcall(qrd7627a_logbuf_init); +#endif + +MACHINE_START(MSM7627A_QRD1, "QRD MSM7627a QRD1") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7627a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7627A_QRD3, "QRD MSM7627a QRD3") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7627a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM7627A_EVB, "QRD MSM7627a EVB") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7627a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_EVB, "QRD MSM8625 EVB") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END + +MACHINE_START(MSM7X27A_QRD5A, "QRD MSM7x27A QRD5A") + .atag_offset = 0x100, + .map_io = msm_common_io_init, + .reserve = msm7627a_reserve, + .init_irq = msm_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = vic_handle_irq, +MACHINE_END + +MACHINE_START(MSM8625_QRD7, "QRD MSM8625 QRD7") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END +MACHINE_START(MSM8625_QRD5, "QRD MSM8625 QRD5") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END + +MACHINE_START(MSM8625Q_SKUD, "QRD MSM8625Q SKUD") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END + +MACHINE_START(MSM8625Q_SKUE, "QRD MSM8625Q SKUE") + .atag_offset = 0x100, + .map_io = msm8625_map_io, + .reserve = msm8625_reserve, + .init_irq = msm8625_init_irq, + .init_machine = msm_qrd_init, + .timer = &msm_timer, + .init_early = qrd7627a_init_early, + .handle_irq = gic_handle_irq, +MACHINE_END diff --git a/arch/arm/mach-msm/bricked_hotplug.c b/arch/arm/mach-msm/bricked_hotplug.c new file mode 100644 index 00000000..5179de69 --- /dev/null +++ b/arch/arm/mach-msm/bricked_hotplug.c @@ -0,0 +1,892 @@ +/* + * Bricked Hotplug Driver + * + * Copyright (c) 2013-2014, Dennis Rassmann + * Copyright (c) 2013-2014, Pranav Vashi + * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_STATE_NOTIFIER +#include +#else +#include +#endif + +#define DEBUG 0 + +#define MPDEC_TAG "bricked_hotplug" +#define HOTPLUG_ENABLED 0 +#define MSM_MPDEC_STARTDELAY 20000 +#define MSM_MPDEC_DELAY 70 +#define DEFAULT_MIN_CPUS_ONLINE 1 +#define DEFAULT_MAX_CPUS_ONLINE NR_CPUS +#define DEFAULT_MAX_CPUS_ONLINE_SUSP 1 +#define DEFAULT_SUSPEND_DEFER_TIME 10 +#define DEFAULT_DOWN_LOCK_DUR 500 + +#define MSM_MPDEC_IDLE_FREQ 320000 + +enum { + MSM_MPDEC_DISABLED = 0, + MSM_MPDEC_IDLE, + MSM_MPDEC_DOWN, + MSM_MPDEC_UP, +}; + +static struct notifier_block notif; +static struct delayed_work hotplug_work; +static struct delayed_work suspend_work; +static struct work_struct resume_work; +static struct workqueue_struct *hotplug_wq; +static struct workqueue_struct *susp_wq; + +static struct cpu_hotplug { + unsigned int startdelay; + unsigned int suspended; + unsigned int suspend_defer_time; + unsigned int min_cpus_online_res; + unsigned int max_cpus_online_res; + unsigned int max_cpus_online_susp; + unsigned int delay; + unsigned int down_lock_dur; + unsigned long int idle_freq; + unsigned int max_cpus_online; + unsigned int min_cpus_online; + unsigned int bricked_enabled; + struct mutex bricked_hotplug_mutex; + struct mutex bricked_cpu_mutex; +} hotplug = { + .startdelay = MSM_MPDEC_STARTDELAY, + .suspended = 0, + .suspend_defer_time = DEFAULT_SUSPEND_DEFER_TIME, + .min_cpus_online_res = DEFAULT_MIN_CPUS_ONLINE, + .max_cpus_online_res = DEFAULT_MAX_CPUS_ONLINE, + .max_cpus_online_susp = DEFAULT_MAX_CPUS_ONLINE_SUSP, + .delay = MSM_MPDEC_DELAY, + .down_lock_dur = DEFAULT_DOWN_LOCK_DUR, + .idle_freq = MSM_MPDEC_IDLE_FREQ, + .max_cpus_online = DEFAULT_MAX_CPUS_ONLINE, + .min_cpus_online = DEFAULT_MIN_CPUS_ONLINE, + .bricked_enabled = HOTPLUG_ENABLED, +}; + +static unsigned int NwNs_Threshold[8] = {12, 0, 25, 7, 30, 10, 0, 18}; +static unsigned int TwTs_Threshold[8] = {140, 0, 140, 190, 140, 190, 0, 190}; + +struct down_lock { + unsigned int locked; + struct delayed_work lock_rem; +}; +static DEFINE_PER_CPU(struct down_lock, lock_info); + +static void apply_down_lock(unsigned int cpu) +{ + struct down_lock *dl = &per_cpu(lock_info, cpu); + + dl->locked = 1; + queue_delayed_work_on(0, hotplug_wq, &dl->lock_rem, + msecs_to_jiffies(hotplug.down_lock_dur)); +} + +static void remove_down_lock(struct work_struct *work) +{ + struct down_lock *dl = container_of(work, struct down_lock, + lock_rem.work); + dl->locked = 0; +} + +static int check_down_lock(unsigned int cpu) +{ + struct down_lock *dl = &per_cpu(lock_info, cpu); + return dl->locked; +} + +extern unsigned int get_rq_info(void); + +unsigned int state = MSM_MPDEC_DISABLED; + +static int get_slowest_cpu(void) { + unsigned int cpu, slow_cpu = 0, rate, slow_rate = 0; + + for_each_online_cpu(cpu) { + if (cpu == 0) + continue; + rate = cpufreq_quick_get(cpu); + if (rate > 0 && slow_rate <= rate) { + slow_rate = rate; + slow_cpu = cpu; + } + } + + return slow_cpu; +} + +static unsigned int get_slowest_cpu_rate(void) { + unsigned int cpu, rate, slow_rate = 0; + + for_each_online_cpu(cpu) { + rate = cpufreq_quick_get(cpu); + if (rate > 0 && slow_rate <= rate) + slow_rate = rate; + } + + return slow_rate; +} + +static int mp_decision(void) { + static bool first_call = true; + int new_state = MSM_MPDEC_IDLE; + int nr_cpu_online; + int index; + unsigned int rq_depth; + static cputime64_t total_time = 0; + static cputime64_t last_time; + cputime64_t current_time; + cputime64_t this_time = 0; + + if (!hotplug.bricked_enabled) + return MSM_MPDEC_DISABLED; + + current_time = ktime_to_ms(ktime_get()); + + if (first_call) { + first_call = false; + } else { + this_time = current_time - last_time; + } + total_time += this_time; + + rq_depth = get_rq_info(); + nr_cpu_online = num_online_cpus(); + + index = (nr_cpu_online - 1) * 2; + if ((nr_cpu_online < DEFAULT_MAX_CPUS_ONLINE) && (rq_depth >= NwNs_Threshold[index])) { + if ((total_time >= TwTs_Threshold[index]) && + (nr_cpu_online < hotplug.max_cpus_online)) { + new_state = MSM_MPDEC_UP; + if (get_slowest_cpu_rate() <= hotplug.idle_freq) + new_state = MSM_MPDEC_IDLE; + } + } else if ((nr_cpu_online > 1) && (rq_depth <= NwNs_Threshold[index+1])) { + if ((total_time >= TwTs_Threshold[index+1]) && + (nr_cpu_online > hotplug.min_cpus_online)) { + new_state = MSM_MPDEC_DOWN; + if (get_slowest_cpu_rate() > hotplug.idle_freq) + new_state = MSM_MPDEC_IDLE; + } + } else { + new_state = MSM_MPDEC_IDLE; + total_time = 0; + } + + if (new_state != MSM_MPDEC_IDLE) { + total_time = 0; + } + + last_time = ktime_to_ms(ktime_get()); +#if DEBUG + pr_info(MPDEC_TAG"[DEBUG] rq: %u, new_state: %i | Mask=[%d%d%d%d]\n", + rq_depth, new_state, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3)); +#endif + return new_state; +} + +static void __ref bricked_hotplug_work(struct work_struct *work) { + unsigned int cpu; + + if (hotplug.suspended && hotplug.max_cpus_online_susp <= 1) + goto out; + + if (!mutex_trylock(&hotplug.bricked_cpu_mutex)) + goto out; + + state = mp_decision(); + switch (state) { + case MSM_MPDEC_DISABLED: + case MSM_MPDEC_IDLE: + break; + case MSM_MPDEC_DOWN: + cpu = get_slowest_cpu(); + if (cpu > 0) { + if (cpu_online(cpu) && !check_down_lock(cpu)) + cpu_down(cpu); + } + break; + case MSM_MPDEC_UP: + cpu = cpumask_next_zero(0, cpu_online_mask); + if (cpu < DEFAULT_MAX_CPUS_ONLINE) { + if (!cpu_online(cpu)) { + cpu_up(cpu); + apply_down_lock(cpu); + } + } + break; + default: + pr_err(MPDEC_TAG": %s: invalid mpdec hotplug state %d\n", + __func__, state); + } + mutex_unlock(&hotplug.bricked_cpu_mutex); + +out: + if (hotplug.bricked_enabled) + queue_delayed_work(hotplug_wq, &hotplug_work, + msecs_to_jiffies(hotplug.delay)); + return; +} + +static void bricked_hotplug_suspend(struct work_struct *work) +{ + int cpu; + + mutex_lock(&hotplug.bricked_hotplug_mutex); + hotplug.suspended = 1; + hotplug.min_cpus_online_res = hotplug.min_cpus_online; + hotplug.min_cpus_online = 1; + hotplug.max_cpus_online_res = hotplug.max_cpus_online; + hotplug.max_cpus_online = hotplug.max_cpus_online_susp; + mutex_unlock(&hotplug.bricked_hotplug_mutex); + + if (hotplug.max_cpus_online_susp > 1) { + pr_info(MPDEC_TAG": Screen -> off\n"); + return; + } + + /* main work thread can sleep now */ + cancel_delayed_work_sync(&hotplug_work); + + for_each_possible_cpu(cpu) { + if ((cpu >= 1) && (cpu_online(cpu))) + cpu_down(cpu); + } + + pr_info(MPDEC_TAG": Screen -> off. Deactivated bricked hotplug. | Mask=[%d%d%d%d]\n", + cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3)); +} + +static void __ref bricked_hotplug_resume(struct work_struct *work) +{ + int cpu, required_reschedule = 0, required_wakeup = 0; + + if (hotplug.suspended) { + mutex_lock(&hotplug.bricked_hotplug_mutex); + hotplug.suspended = 0; + hotplug.min_cpus_online = hotplug.min_cpus_online_res; + hotplug.max_cpus_online = hotplug.max_cpus_online_res; + mutex_unlock(&hotplug.bricked_hotplug_mutex); + required_wakeup = 1; + /* Initiate hotplug work if it was cancelled */ + if (hotplug.max_cpus_online_susp <= 1) { + required_reschedule = 1; + INIT_DELAYED_WORK(&hotplug_work, bricked_hotplug_work); + } + } + + if (required_wakeup) { + /* Fire up all CPUs */ + for_each_cpu_not(cpu, cpu_online_mask) { + if (cpu == 0) + continue; + cpu_up(cpu); + apply_down_lock(cpu); + } + } + + /* Resume hotplug workqueue if required */ + if (required_reschedule) { + queue_delayed_work(hotplug_wq, &hotplug_work, 0); + pr_info(MPDEC_TAG": Screen -> on. Activated bricked hotplug. | Mask=[%d%d%d%d]\n", + cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3)); + } +} + +static void __bricked_hotplug_resume(void) +{ + if (!hotplug.bricked_enabled) + return; + + flush_workqueue(susp_wq); + cancel_delayed_work_sync(&suspend_work); + queue_work_on(0, susp_wq, &resume_work); +} + +static void __bricked_hotplug_suspend(void) +{ + if (!hotplug.bricked_enabled || hotplug.suspended) + return; + + INIT_DELAYED_WORK(&suspend_work, bricked_hotplug_suspend); + queue_delayed_work_on(0, susp_wq, &suspend_work, + msecs_to_jiffies(hotplug.suspend_defer_time * 1000)); +} + +#ifdef CONFIG_STATE_NOTIFIER +static int state_notifier_callback(struct notifier_block *this, + unsigned long event, void *data) +{ + switch (event) { + case STATE_NOTIFIER_ACTIVE: + __bricked_hotplug_resume(); + break; + case STATE_NOTIFIER_SUSPEND: + __bricked_hotplug_suspend(); + break; + default: + break; + } + + return NOTIFY_OK; +} +#else +static int prev_fb = FB_BLANK_UNBLANK; + +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + + if (evdata && evdata->data && event == FB_EVENT_BLANK) { + blank = evdata->data; + switch (*blank) { + case FB_BLANK_UNBLANK: + if (prev_fb == FB_BLANK_POWERDOWN) { + __bricked_hotplug_resume(); + prev_fb = FB_BLANK_UNBLANK; + } + break; + case FB_BLANK_POWERDOWN: + if (prev_fb == FB_BLANK_UNBLANK) { + __bricked_hotplug_suspend(); + prev_fb = FB_BLANK_POWERDOWN; + } + break; + } + } + + return NOTIFY_OK; +} +#endif + +static int bricked_hotplug_start(void) +{ + int cpu, ret = 0; + struct down_lock *dl; + + hotplug_wq = alloc_workqueue("bricked_hotplug", WQ_HIGHPRI | WQ_FREEZABLE, 0); + if (!hotplug_wq) { + ret = -ENOMEM; + goto err_out; + } + + susp_wq = + alloc_workqueue("susp_wq", WQ_FREEZABLE, 0); + if (!susp_wq) { + pr_err("%s: Failed to allocate suspend workqueue\n", + MPDEC_TAG); + ret = -ENOMEM; + goto err_dev; + } + +#ifdef CONFIG_STATE_NOTIFIER + notif.notifier_call = state_notifier_callback; + if (state_register_client(¬if)) { + pr_err("%s: Failed to register State notifier callback\n", + MPDEC_TAG); + goto err_susp; + } +#else + notif.notifier_call = fb_notifier_callback; + if (fb_register_client(¬if)) { + pr_err("%s: Failed to register FB notifier callback\n", + MPDEC_TAG); + goto err_susp; + } +#endif + + mutex_init(&hotplug.bricked_cpu_mutex); + mutex_init(&hotplug.bricked_hotplug_mutex); + + INIT_DELAYED_WORK(&hotplug_work, bricked_hotplug_work); + INIT_DELAYED_WORK(&suspend_work, bricked_hotplug_suspend); + INIT_WORK(&resume_work, bricked_hotplug_resume); + + for_each_possible_cpu(cpu) { + dl = &per_cpu(lock_info, cpu); + INIT_DELAYED_WORK(&dl->lock_rem, remove_down_lock); + } + + if (hotplug.bricked_enabled) + queue_delayed_work(hotplug_wq, &hotplug_work, + msecs_to_jiffies(hotplug.startdelay)); + + return ret; +err_susp: + destroy_workqueue(susp_wq); +err_dev: + destroy_workqueue(hotplug_wq); +err_out: + hotplug.bricked_enabled = 0; + return ret; +} + +static void bricked_hotplug_stop(void) +{ + int cpu; + struct down_lock *dl; + + for_each_possible_cpu(cpu) { + dl = &per_cpu(lock_info, cpu); + cancel_delayed_work_sync(&dl->lock_rem); + } + + flush_workqueue(susp_wq); + cancel_work_sync(&resume_work); + cancel_delayed_work_sync(&suspend_work); + cancel_delayed_work_sync(&hotplug_work); + mutex_destroy(&hotplug.bricked_hotplug_mutex); + mutex_destroy(&hotplug.bricked_cpu_mutex); +#ifdef CONFIG_STATE_NOTIFIER + state_unregister_client(¬if); +#else + fb_unregister_client(¬if); +#endif + notif.notifier_call = NULL; + destroy_workqueue(susp_wq); + destroy_workqueue(hotplug_wq); + + /* Put all sibling cores to sleep */ + for_each_online_cpu(cpu) { + if (cpu == 0) + continue; + cpu_down(cpu); + } +} + +/**************************** SYSFS START ****************************/ + +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct device *dev, struct device_attribute *bricked_hotplug_attrs, \ + char *buf) \ +{ \ + return sprintf(buf, "%u\n", hotplug.object); \ +} + +show_one(startdelay, startdelay); +show_one(delay, delay); +show_one(down_lock_duration, down_lock_dur); +show_one(min_cpus_online, min_cpus_online); +show_one(max_cpus_online, max_cpus_online); +show_one(max_cpus_online_susp, max_cpus_online_susp); +show_one(suspend_defer_time, suspend_defer_time); +show_one(bricked_enabled, bricked_enabled); + +#define define_one_twts(file_name, arraypos) \ +static ssize_t show_##file_name \ +(struct device *dev, struct device_attribute *bricked_hotplug_attrs, \ + char *buf) \ +{ \ + return sprintf(buf, "%u\n", TwTs_Threshold[arraypos]); \ +} \ +static ssize_t store_##file_name \ +(struct device *dev, struct device_attribute *bricked_hotplug_attrs, \ + const char *buf, size_t count) \ +{ \ + unsigned int input; \ + int ret; \ + ret = sscanf(buf, "%u", &input); \ + if (ret != 1) \ + return -EINVAL; \ + TwTs_Threshold[arraypos] = input; \ + return count; \ +} \ +static DEVICE_ATTR(file_name, 644, show_##file_name, store_##file_name); +define_one_twts(twts_threshold_0, 0); +define_one_twts(twts_threshold_1, 1); +define_one_twts(twts_threshold_2, 2); +define_one_twts(twts_threshold_3, 3); +define_one_twts(twts_threshold_4, 4); +define_one_twts(twts_threshold_5, 5); +define_one_twts(twts_threshold_6, 6); +define_one_twts(twts_threshold_7, 7); + +#define define_one_nwns(file_name, arraypos) \ +static ssize_t show_##file_name \ +(struct device *dev, struct device_attribute *bricked_hotplug_attrs, \ + char *buf) \ +{ \ + return sprintf(buf, "%u\n", NwNs_Threshold[arraypos]); \ +} \ +static ssize_t store_##file_name \ +(struct device *dev, struct device_attribute *bricked_hotplug_attrs, \ + const char *buf, size_t count) \ +{ \ + unsigned int input; \ + int ret; \ + ret = sscanf(buf, "%u", &input); \ + if (ret != 1) \ + return -EINVAL; \ + NwNs_Threshold[arraypos] = input; \ + return count; \ +} \ +static DEVICE_ATTR(file_name, 644, show_##file_name, store_##file_name); +define_one_nwns(nwns_threshold_0, 0); +define_one_nwns(nwns_threshold_1, 1); +define_one_nwns(nwns_threshold_2, 2); +define_one_nwns(nwns_threshold_3, 3); +define_one_nwns(nwns_threshold_4, 4); +define_one_nwns(nwns_threshold_5, 5); +define_one_nwns(nwns_threshold_6, 6); +define_one_nwns(nwns_threshold_7, 7); + +static ssize_t show_idle_freq (struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + char *buf) +{ + return sprintf(buf, "%lu\n", hotplug.idle_freq); +} + +static ssize_t store_startdelay(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + hotplug.startdelay = input; + + return count; +} + +static ssize_t store_delay(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + hotplug.delay = input; + + return count; +} + +static ssize_t store_down_lock_duration(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + int ret; + unsigned int val; + + ret = sscanf(buf, "%u", &val); + if (ret != 1) + return -EINVAL; + + hotplug.down_lock_dur = val; + + return count; +} + +static ssize_t store_idle_freq(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + long unsigned int input; + int ret; + ret = sscanf(buf, "%lu", &input); + if (ret != 1) + return -EINVAL; + + hotplug.idle_freq = input; + + return count; +} + +static ssize_t __ref store_min_cpus_online(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + unsigned int input, cpu; + int ret; + ret = sscanf(buf, "%u", &input); + if ((ret != 1) || input < 1 || input > DEFAULT_MAX_CPUS_ONLINE) + return -EINVAL; + + if (hotplug.max_cpus_online < input) + hotplug.max_cpus_online = input; + + hotplug.min_cpus_online = input; + + if (!hotplug.bricked_enabled) + return count; + + if (num_online_cpus() < hotplug.min_cpus_online) { + for (cpu = 1; cpu < DEFAULT_MAX_CPUS_ONLINE; cpu++) { + if (num_online_cpus() >= hotplug.min_cpus_online) + break; + if (cpu_online(cpu)) + continue; + cpu_up(cpu); + } + pr_info(MPDEC_TAG": min_cpus_online set to %u. Affected CPUs were hotplugged!\n", input); + } + + return count; +} + +static ssize_t store_max_cpus_online(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + unsigned int input, cpu; + int ret; + ret = sscanf(buf, "%u", &input); + if ((ret != 1) || input < 1 || input > DEFAULT_MAX_CPUS_ONLINE) + return -EINVAL; + + if (hotplug.min_cpus_online > input) + hotplug.min_cpus_online = input; + + hotplug.max_cpus_online = input; + + if (!hotplug.bricked_enabled) + return count; + + if (num_online_cpus() > hotplug.max_cpus_online) { + for (cpu = DEFAULT_MAX_CPUS_ONLINE; cpu > 0; cpu--) { + if (num_online_cpus() <= hotplug.max_cpus_online) + break; + if (!cpu_online(cpu)) + continue; + cpu_down(cpu); + } + pr_info(MPDEC_TAG": max_cpus set to %u. Affected CPUs were unplugged!\n", input); + } + + return count; +} + +static ssize_t store_max_cpus_online_susp(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if ((ret != 1) || input < 1 || input > DEFAULT_MAX_CPUS_ONLINE) + return -EINVAL; + + hotplug.max_cpus_online_susp = input; + + return count; +} + +static ssize_t store_suspend_defer_time(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + int ret; + unsigned int val; + + ret = sscanf(buf, "%u", &val); + if (ret != 1) + return -EINVAL; + + hotplug.suspend_defer_time = val; + + return count; +} + +static ssize_t store_bricked_enabled(struct device *dev, + struct device_attribute *bricked_hotplug_attrs, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (input > 1) + input = 1; + + if (input == hotplug.bricked_enabled) + return count; + + hotplug.bricked_enabled = input; + + if (!hotplug.bricked_enabled) { + state = MSM_MPDEC_DISABLED; + bricked_hotplug_stop(); + pr_info(MPDEC_TAG": Disabled\n"); + } else { + state = MSM_MPDEC_IDLE; + bricked_hotplug_start(); + pr_info(MPDEC_TAG": Enabled\n"); + } + + return count; +} + +static DEVICE_ATTR(startdelay, 644, show_startdelay, store_startdelay); +static DEVICE_ATTR(delay, 644, show_delay, store_delay); +static DEVICE_ATTR(down_lock_duration, 644, show_down_lock_duration, store_down_lock_duration); +static DEVICE_ATTR(idle_freq, 644, show_idle_freq, store_idle_freq); +static DEVICE_ATTR(min_cpus, 644, show_min_cpus_online, store_min_cpus_online); +static DEVICE_ATTR(max_cpus, 644, show_max_cpus_online, store_max_cpus_online); +static DEVICE_ATTR(min_cpus_online, 644, show_min_cpus_online, store_min_cpus_online); +static DEVICE_ATTR(max_cpus_online, 644, show_max_cpus_online, store_max_cpus_online); +static DEVICE_ATTR(max_cpus_online_susp, 644, show_max_cpus_online_susp, store_max_cpus_online_susp); +static DEVICE_ATTR(suspend_defer_time, 644, show_suspend_defer_time, store_suspend_defer_time); +static DEVICE_ATTR(enabled, 644, show_bricked_enabled, store_bricked_enabled); + +static struct attribute *bricked_hotplug_attrs[] = { + &dev_attr_startdelay.attr, + &dev_attr_delay.attr, + &dev_attr_down_lock_duration.attr, + &dev_attr_idle_freq.attr, + &dev_attr_min_cpus.attr, + &dev_attr_max_cpus.attr, + &dev_attr_min_cpus_online.attr, + &dev_attr_max_cpus_online.attr, + &dev_attr_max_cpus_online_susp.attr, + &dev_attr_suspend_defer_time.attr, + &dev_attr_enabled.attr, + &dev_attr_twts_threshold_0.attr, + &dev_attr_twts_threshold_1.attr, + &dev_attr_twts_threshold_2.attr, + &dev_attr_twts_threshold_3.attr, + &dev_attr_twts_threshold_4.attr, + &dev_attr_twts_threshold_5.attr, + &dev_attr_twts_threshold_6.attr, + &dev_attr_twts_threshold_7.attr, + &dev_attr_nwns_threshold_0.attr, + &dev_attr_nwns_threshold_1.attr, + &dev_attr_nwns_threshold_2.attr, + &dev_attr_nwns_threshold_3.attr, + &dev_attr_nwns_threshold_4.attr, + &dev_attr_nwns_threshold_5.attr, + &dev_attr_nwns_threshold_6.attr, + &dev_attr_nwns_threshold_7.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = bricked_hotplug_attrs, + .name = "conf", +}; + +/**************************** SYSFS END ****************************/ + +static int bricked_hotplug_probe(struct platform_device *pdev) +{ + int ret = 0; + struct kobject *bricked_kobj; + + bricked_kobj = + kobject_create_and_add("msm_mpdecision", kernel_kobj); + if (!bricked_kobj) { + pr_err("%s kobject create failed!\n", + __func__); + return -ENOMEM; + } + + ret = sysfs_create_group(bricked_kobj, + &attr_group); + + if (ret) { + pr_err("%s bricked_kobj create failed!\n", + __func__); + goto err_dev; + } + + if (hotplug.bricked_enabled) { + ret = bricked_hotplug_start(); + if (ret != 0) + goto err_dev; + } + + return ret; +err_dev: + if (bricked_kobj != NULL) + kobject_put(bricked_kobj); + return ret; +} + +static struct platform_device bricked_hotplug_device = { + .name = MPDEC_TAG, + .id = -1, +}; + +static int bricked_hotplug_remove(struct platform_device *pdev) +{ + if (hotplug.bricked_enabled) + bricked_hotplug_stop(); + + return 0; +} + +static struct platform_driver bricked_hotplug_driver = { + .probe = bricked_hotplug_probe, + .remove = bricked_hotplug_remove, + .driver = { + .name = MPDEC_TAG, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_mpdec_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&bricked_hotplug_driver); + if (ret) { + pr_err("%s: Driver register failed: %d\n", MPDEC_TAG, ret); + return ret; + } + + ret = platform_device_register(&bricked_hotplug_device); + if (ret) { + pr_err("%s: Device register failed: %d\n", MPDEC_TAG, ret); + return ret; + } + + pr_info(MPDEC_TAG": %s init complete.", __func__); + + return ret; +} + +void msm_mpdec_exit(void) +{ + platform_device_unregister(&bricked_hotplug_device); + platform_driver_unregister(&bricked_hotplug_driver); +} + +late_initcall(msm_mpdec_init); +module_exit(msm_mpdec_exit); + +MODULE_AUTHOR("Pranav Vashi "); +MODULE_DESCRIPTION("Bricked Hotplug Driver"); +MODULE_LICENSE("GPLv2"); diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c index 281d1cd9..a965a4dd 100644 --- a/arch/arm/mach-msm/devices-iommu.c +++ b/arch/arm/mach-msm/devices-iommu.c @@ -365,25 +365,25 @@ static struct msm_iommu_dev vcodec_b_iommu = { static struct msm_iommu_dev gfx3d_iommu = { .name = "gfx3d", .ncb = 3, - .ttbr_split = 1, + .ttbr_split = 2, }; static struct msm_iommu_dev gfx3d1_iommu = { .name = "gfx3d1", .ncb = 3, - .ttbr_split = 1, + .ttbr_split = 2, }; static struct msm_iommu_dev gfx2d0_iommu = { .name = "gfx2d0", .ncb = 2, - .ttbr_split = 1, + .ttbr_split = 2, }; static struct msm_iommu_dev gfx2d1_iommu = { .name = "gfx2d1", .ncb = 2, - .ttbr_split = 1, + .ttbr_split = 2, }; static struct msm_iommu_dev vcap_iommu = { diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c index 57fef659..3336f2d4 100644 --- a/arch/arm/mach-msm/devices-msm7x27.c +++ b/arch/arm/mach-msm/devices-msm7x27.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c index a394cbbf..34718d45 100644 --- a/arch/arm/mach-msm/devices-msm7x27a.c +++ b/arch/arm/mach-msm/devices-msm7x27a.c @@ -919,6 +919,14 @@ static struct resource kgsl_3d0_resources[] = { static struct kgsl_device_platform_data kgsl_3d0_pdata = { .pwrlevel = { + { + .gpu_freq = 300000000, + .bus_freq = 200000000, + }, + { + .gpu_freq = 266000000, + .bus_freq = 200000000, + }, { .gpu_freq = 245760000, .bus_freq = 200000000, @@ -928,7 +936,7 @@ static struct kgsl_device_platform_data kgsl_3d0_pdata = { .bus_freq = 160000000, }, { - .gpu_freq = 133330000, + .gpu_freq = 192000000, .bus_freq = 0, }, }, @@ -1873,7 +1881,7 @@ static void __init msm_cpr_init(void) uint8_t ring_osc = 0; #if defined(CONFIG_MSM_FUSE_INFO_DEBUG) char tmp_buf[100] = ""; - uint32_t fuse_len = 0; + uint32_t fuse_len = 0; #endif cpr_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL); diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h index bb14b0c1..f0a40b1a 100644 --- a/arch/arm/mach-msm/devices.h +++ b/arch/arm/mach-msm/devices.h @@ -380,6 +380,12 @@ extern struct platform_device msm_dsps_device_8064; extern struct platform_device *msm_8974_stub_regulator_devices[]; extern int msm_8974_stub_regulator_devices_len; +extern struct platform_device msm8960_cpu_idle_device; +extern struct platform_device msm8930_cpu_idle_device; +extern struct platform_device apq8064_cpu_idle_device; + +extern struct platform_device msm8960_msm_gov_device; +extern struct platform_device msm8930_msm_gov_device; extern struct platform_device apq8064_msm_gov_device; extern struct platform_device msm_bus_8930_apps_fabric; diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index 960ad1a0..afee25f6 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -1,11 +1,7 @@ /* linux/arch/arm/mach-msm/dma.c * * Copyright (C) 2007 Google, Inc. -<<<<<<< HEAD * Copyright (c) 2008-2010, 2012 The Linux Foundation. All rights reserved. -======= - * Copyright (c) 2008-2010, 2012, 2013 The Linux Foundation. All rights reserved. ->>>>>>> d7fe698... msm: dma: upstream to CAF Ifaa5efdde8150f932a12d4f9eeccfb36ecb8f88f * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -35,10 +31,8 @@ enum { CLK_DIS, - CLK_ENABLING, - CLK_EN, CLK_TO_BE_DIS, - CLK_DISABLING + CLK_EN }; struct msm_dmov_ci_conf { @@ -68,8 +62,8 @@ struct msm_dmov_conf { struct list_head staged_commands[MSM_DMOV_CHANNEL_COUNT]; struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; - struct mutex clock_lock; - spinlock_t lock; + struct mutex lock; + spinlock_t list_lock; unsigned int irq; struct clk *clk; struct clk *pclk; @@ -171,16 +165,16 @@ static struct msm_dmov_conf dmov_conf[] = { { .crci_conf = adm0_crci_conf, .chan_conf = adm0_chan_conf, - .clock_lock = __MUTEX_INITIALIZER(dmov_conf[0].clock_lock), - .lock = __SPIN_LOCK_UNLOCKED(dmov_lock), + .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock), + .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock), .clk_ctl = CLK_DIS, .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work, msm_dmov_clock_work), }, { .crci_conf = adm1_crci_conf, .chan_conf = adm1_chan_conf, - .clock_lock = __MUTEX_INITIALIZER(dmov_conf[1].clock_lock), - .lock = __SPIN_LOCK_UNLOCKED(dmov_lock), + .lock = __MUTEX_INITIALIZER(dmov_conf[1].lock), + .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock), .clk_ctl = CLK_DIS, .work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work, msm_dmov_clock_work), @@ -191,8 +185,8 @@ static struct msm_dmov_conf dmov_conf[] = { { .crci_conf = NULL, .chan_conf = NULL, - .clock_lock = __MUTEX_INITIALIZER(dmov_conf[0].clock_lock), - .lock = __SPIN_LOCK_UNLOCKED(dmov_lock), + .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock), + .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock), .clk_ctl = CLK_DIS, .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work, msm_dmov_clock_work), @@ -276,21 +270,13 @@ static void msm_dmov_clock_work(struct work_struct *work) struct msm_dmov_conf *conf = container_of(to_delayed_work(work), struct msm_dmov_conf, work); int adm = DMOV_IRQ_TO_ADM(conf->irq); - unsigned long irq_flags; - - mutex_lock(&conf->clock_lock); - spin_lock_irqsave(&conf->lock, irq_flags); + mutex_lock(&conf->lock); if (conf->clk_ctl == CLK_TO_BE_DIS) { BUG_ON(conf->channel_active); - conf->clk_ctl = CLK_DISABLING; - spin_unlock_irqrestore(&conf->lock, irq_flags); msm_dmov_clk_off(adm); - spin_lock_irqsave(&conf->lock, irq_flags); - if (conf->clk_ctl == CLK_DISABLING) - conf->clk_ctl = CLK_DIS; + conf->clk_ctl = CLK_DIS; } - spin_unlock_irqrestore(&conf->lock, irq_flags); - mutex_unlock(&conf->clock_lock); + mutex_unlock(&conf->lock); } enum { @@ -316,7 +302,7 @@ static struct msm_dmov_cmd *start_ready_cmd(unsigned ch, int adm) if (!dmov_conf[adm].channel_active) enable_irq(dmov_conf[adm].irq); dmov_conf[adm].channel_active |= BIT(ch); - PRINT_IO("start_ready_cmd, %x, ch %d\n", cmd->cmdptr, ch); + PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, ch); writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm)); return cmd; @@ -330,86 +316,37 @@ static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work) unsigned status; unsigned long flags; int adm = DMOV_ID_TO_ADM(id); - int ch = 0; - - mutex_lock(&dmov_conf[adm].clock_lock); - /*No spin_lock is required for the condition check below*/ - BUG_ON(dmov_conf[adm].clk_ctl != CLK_ENABLING); - status = msm_dmov_clk_on(adm); - if (status != 0) { - PRINT_ERROR("ADM: Unexpected clock failure at dma.c:%d/%s()!\n", - __LINE__, __func__); - goto error; - } - - spin_lock_irqsave(&dmov_conf[adm].lock, flags); - - dmov_conf[adm].clk_ctl = CLK_EN; + int ch = DMOV_ID_TO_CHAN(id); - for (ch = 0; ch < MSM_DMOV_CHANNEL_COUNT; ch++) { - while (!list_empty(&dmov_conf[adm].staged_commands[ch])) { - cmd = list_entry(dmov_conf[adm].staged_commands[ch]. - next, typeof(*cmd), list); - list_del(&cmd->list); - list_add_tail(&cmd->list, &dmov_conf[adm]. - ready_commands[ch]); - } - if (!list_empty(&dmov_conf[adm].ready_commands[ch])) { - status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm)); - if (status & DMOV_STATUS_CMD_PTR_RDY) { - PRINT_IO("msm_dmov_enqueue_cmd(%d),"\ - " start command, status %x\n", - id, status); - cmd = start_ready_cmd(ch, adm); - /* - * We added something to the ready list, - * and still hold the list lock. - * Thus, no need to check for cmd == NULL - */ - if (cmd->toflush) { - int flush = (cmd->toflush == GRACEFUL) ? - 1 << 31 : 0; - writel_relaxed(flush, - DMOV_REG(DMOV_FLUSH0(ch), adm)); - } - } else { - if (list_empty(&dmov_conf[adm]. - active_commands[ch])) - PRINT_ERROR("msm_dmov_enqueue_cmd_ext"\ - "(%d), stalled, status %x\n", - id, status); - PRINT_IO("msm_dmov_enqueue_cmd(%d),"\ - "enqueue command, status " - "%x\n", id, status); - } - } + mutex_lock(&dmov_conf[adm].lock); + if (dmov_conf[adm].clk_ctl == CLK_DIS) { + status = msm_dmov_clk_on(adm); + if (status != 0) + goto error; } - spin_unlock_irqrestore(&dmov_conf[adm].lock, flags); -error: - mutex_unlock(&dmov_conf[adm].clock_lock); -} + dmov_conf[adm].clk_ctl = CLK_EN; -void msm_dmov_enqueue_cmd_ext_atomic(unsigned id, struct msm_dmov_cmd *cmd) -{ - unsigned int status; - int adm = DMOV_ID_TO_ADM(id); - int ch = DMOV_ID_TO_CHAN(id); + spin_lock_irqsave(&dmov_conf[adm].list_lock, flags); + cmd = list_entry(dmov_conf[adm].staged_commands[ch].next, typeof(*cmd), + list); + list_del(&cmd->list); + list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]); status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm)); if (status & DMOV_STATUS_CMD_PTR_RDY) { PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); - if (cmd->exec_func) - cmd->exec_func(cmd); - list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]); - if (!dmov_conf[adm].channel_active) - enable_irq(dmov_conf[adm].irq); - dmov_conf[adm].channel_active |= BIT(ch); - PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, - ch); - writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm)); + cmd = start_ready_cmd(ch, adm); + /* + * We added something to the ready list, and still hold the + * list lock. Thus, no need to check for cmd == NULL + */ + if (cmd->toflush) { + int flush = (cmd->toflush == GRACEFUL) ? 1 << 31 : 0; + writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm)); + } } else { - list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]); + cmd->toflush = 0; if (list_empty(&dmov_conf[adm].active_commands[ch]) && !list_empty(&dmov_conf[adm].ready_commands[ch])) PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, " @@ -417,10 +354,16 @@ void msm_dmov_enqueue_cmd_ext_atomic(unsigned id, struct msm_dmov_cmd *cmd) PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status " "%x\n", id, status); } + if (!dmov_conf[adm].channel_active) { + dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS; + schedule_delayed_work(&dmov_conf[adm].work, (HZ/10)); + } + spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags); +error: + mutex_unlock(&dmov_conf[adm].lock); } -static void __msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd, - int onstack) +static void __msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd) { int adm = DMOV_ID_TO_ADM(id); int ch = DMOV_ID_TO_CHAN(id); @@ -432,47 +375,12 @@ static void __msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd, list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]); queue_work(dmov_conf[adm].cmd_wq, &cmd->work); spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags); - spin_lock_irqsave(&dmov_conf[adm].lock, flags); - switch (dmov_conf[adm].clk_ctl) { - case CLK_DIS: - case CLK_DISABLING: - if (onstack) - INIT_WORK_ONSTACK(&cmd->work, - msm_dmov_enqueue_cmd_ext_work); - else - INIT_WORK(&cmd->work, - msm_dmov_enqueue_cmd_ext_work); - list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]); - dmov_conf[adm].clk_ctl = CLK_ENABLING; - queue_work(dmov_conf[adm].cmd_wq, &cmd->work); - break; - - case CLK_ENABLING: - list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]); - break; - - case CLK_EN: - msm_dmov_enqueue_cmd_ext_atomic(id, cmd); - break; - - case CLK_TO_BE_DIS: - __cancel_delayed_work(&dmov_conf[adm].work); - dmov_conf[adm].clk_ctl = CLK_EN; - msm_dmov_enqueue_cmd_ext_atomic(id, cmd); - break; - - default: - PRINT_ERROR("ADM%d: Invalid CLK State.\n", adm); - BUG_ON(dmov_conf[adm].clk_ctl); - } - - spin_unlock_irqrestore(&dmov_conf[adm].lock, flags); - } void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd) { - __msm_dmov_enqueue_cmd_ext(id, cmd, 0); + INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work); + __msm_dmov_enqueue_cmd_ext(id, cmd); } EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext); @@ -480,7 +388,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) { /* Disable callback function (for backwards compatibility) */ cmd->exec_func = NULL; - __msm_dmov_enqueue_cmd_ext(id, cmd, 0); + INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work); + __msm_dmov_enqueue_cmd_ext(id, cmd); } EXPORT_SYMBOL(msm_dmov_enqueue_cmd); @@ -492,7 +401,7 @@ void msm_dmov_flush(unsigned int id, int graceful) int flush = graceful ? DMOV_FLUSH_TYPE : 0; struct msm_dmov_cmd *cmd; - spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); + spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags); /* XXX not checking if flush cmd sent already */ if (!list_empty(&dmov_conf[adm].active_commands[ch])) { PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id); @@ -500,10 +409,8 @@ void msm_dmov_flush(unsigned int id, int graceful) } list_for_each_entry(cmd, &dmov_conf[adm].staged_commands[ch], list) cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL; - list_for_each_entry(cmd, &dmov_conf[adm].ready_commands[ch], list) - cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL; /* spin_unlock_irqrestore has the necessary barrier */ - spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); + spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags); } EXPORT_SYMBOL(msm_dmov_flush); @@ -520,8 +427,7 @@ dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result, struct msm_dmov_errdata *err) { - struct msm_dmov_exec_cmdptr_cmd *cmd = - container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); + struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); cmd->result = result; if (result != 0x80000002 && err) memcpy(&cmd->err, err, sizeof(struct msm_dmov_errdata)); @@ -540,17 +446,16 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) cmd.dmov_cmd.exec_func = NULL; cmd.id = id; cmd.result = 0; + INIT_WORK_ONSTACK(&cmd.dmov_cmd.work, msm_dmov_enqueue_cmd_ext_work); init_completion(&cmd.complete); - __msm_dmov_enqueue_cmd_ext(id, &cmd.dmov_cmd, 1); + __msm_dmov_enqueue_cmd_ext(id, &cmd.dmov_cmd); wait_for_completion_io(&cmd.complete); if (cmd.result != 0x80000002) { - PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", - id, cmd.result); + PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result); PRINT_ERROR("dmov_exec_cmdptr(%d): flush: %x %x %x %x\n", - id, cmd.err.flush[0], cmd.err.flush[1], - cmd.err.flush[2], cmd.err.flush[3]); + id, cmd.err.flush[0], cmd.err.flush[1], cmd.err.flush[2], cmd.err.flush[3]); return -EIO; } PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); @@ -581,17 +486,17 @@ static irqreturn_t msm_dmov_isr(int irq, void *dev_id) struct msm_dmov_cmd *cmd; int adm = DMOV_IRQ_TO_ADM(irq); - spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); + mutex_lock(&dmov_conf[adm].lock); /* read and clear isr */ int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm)); PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status); + spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags); while (int_status) { mask = int_status & -int_status; ch = fls(mask) - 1; id = DMOV_CHAN_ADM_TO_ID(ch, adm); - PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", - int_status, mask, id); + PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", int_status, mask, id); int_status &= ~mask; ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm)); if (!(ch_status & DMOV_STATUS_RSLT_VALID)) { @@ -603,9 +508,8 @@ static irqreturn_t msm_dmov_isr(int irq, void *dev_id) valid = 1; ch_result = readl_relaxed(DMOV_REG(DMOV_RSLT(ch), adm)); if (list_empty(&dmov_conf[adm].active_commands[ch])) { - PRINT_ERROR("msm_datamover_irq_handler id %d,"\ - " got result with no active command," - " status %x, result %x\n", + PRINT_ERROR("msm_datamover_irq_handler id %d, got result " + "with no active command, status %x, result %x\n", id, ch_status, ch_result); cmd = NULL; } else { @@ -613,33 +517,26 @@ static irqreturn_t msm_dmov_isr(int irq, void *dev_id) active_commands[ch].next, typeof(*cmd), list); } - PRINT_FLOW("msm_datamover_irq_handler id %d, status"\ - " %x, result %x\n", id, ch_status, ch_result); + PRINT_FLOW("msm_datamover_irq_handler id %d, status %x, result %x\n", id, ch_status, ch_result); if (ch_result & DMOV_RSLT_DONE) { - PRINT_FLOW("msm_datamover_irq_handler id %d,"\ - " status %x\n", id, ch_status); - PRINT_IO("msm_datamover_irq_handler id %d,"\ - " got result for %p," - " result %x\n", id, cmd, ch_result); + PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", + id, ch_status); + PRINT_IO("msm_datamover_irq_handler id %d, got result " + "for %p, result %x\n", id, cmd, ch_result); if (cmd) { list_del(&cmd->list); - cmd->complete_func(cmd, ch_result, - NULL); + cmd->complete_func(cmd, ch_result, NULL); } } if (ch_result & DMOV_RSLT_FLUSH) { struct msm_dmov_errdata errdata; fill_errdata(&errdata, ch, adm); - PRINT_FLOW("msm_datamover_irq_handler id %d,"\ - " status %x\n", id, ch_status); - PRINT_FLOW("msm_datamover_irq_handler id %d,"\ - " flush, result %x,flush0 %x\n", id, - ch_result, errdata.flush[0]); + PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); + PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); - cmd->complete_func(cmd, ch_result, - &errdata); + cmd->complete_func(cmd, ch_result, &errdata); } } if (ch_result & DMOV_RSLT_ERROR) { @@ -647,47 +544,30 @@ static irqreturn_t msm_dmov_isr(int irq, void *dev_id) fill_errdata(&errdata, ch, adm); - PRINT_ERROR("msm_datamover_irq_handler id %d,"\ - " status %x\n", id, ch_status); - PRINT_ERROR("msm_datamover_irq_handler id %d,"\ - " error, result %x, flush0 %x\n", - id, ch_result, errdata.flush[0]); + PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); + PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); - cmd->complete_func(cmd, ch_result, - &errdata); + cmd->complete_func(cmd, ch_result, &errdata); } - /* this does not seem to work, once we get an - * error. the datamover will no longer accept - * commands - */ + /* this does not seem to work, once we get an error */ + /* the datamover will no longer accept commands */ writel_relaxed(0, DMOV_REG(DMOV_FLUSH0(ch), adm)); } rmb(); ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm)); - PRINT_FLOW("msm_datamover_irq_handler id %d, status"\ - " %x\n", id, ch_status); - if (ch_status & DMOV_STATUS_CMD_PTR_RDY) { - cmd = start_ready_cmd(ch, adm); - - if (cmd != NULL) { - if (cmd->toflush) { - int flush = (cmd->toflush == - GRACEFUL) ? 1 << 31 : 0; - writel_relaxed(flush, - DMOV_REG(DMOV_FLUSH0(ch), adm)); - } - } - } + PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); + if (ch_status & DMOV_STATUS_CMD_PTR_RDY) + start_ready_cmd(ch, adm); } while (ch_status & DMOV_STATUS_RSLT_VALID); if (list_empty(&dmov_conf[adm].active_commands[ch]) && - list_empty(&dmov_conf[adm].ready_commands[ch])) + list_empty(&dmov_conf[adm].ready_commands[ch])) dmov_conf[adm].channel_active &= ~(1U << ch); - PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, - ch_status); + PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); } + spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags); if (!dmov_conf[adm].channel_active && valid) { disable_irq_nosync(dmov_conf[adm].irq); @@ -695,7 +575,7 @@ static irqreturn_t msm_dmov_isr(int irq, void *dev_id) schedule_delayed_work(&dmov_conf[adm].work, (HZ/10)); } - spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); + mutex_unlock(&dmov_conf[adm].lock); return valid ? IRQ_HANDLED : IRQ_NONE; } @@ -703,21 +583,13 @@ static int msm_dmov_suspend_late(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); int adm = (pdev->id >= 0) ? pdev->id : 0; - unsigned long irq_flags; - - mutex_lock(&dmov_conf[adm].clock_lock); - spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); + mutex_lock(&dmov_conf[adm].lock); if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) { BUG_ON(dmov_conf[adm].channel_active); - dmov_conf[adm].clk_ctl = CLK_DISABLING; - spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); msm_dmov_clk_off(adm); - spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags); - if (dmov_conf[adm].clk_ctl == CLK_DISABLING) - dmov_conf[adm].clk_ctl = CLK_DIS; + dmov_conf[adm].clk_ctl = CLK_DIS; } - spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags); - mutex_unlock(&dmov_conf[adm].clock_lock); + mutex_unlock(&dmov_conf[adm].lock); return 0; } @@ -739,7 +611,7 @@ static int msm_dmov_runtime_idle(struct device *dev) return 0; } -static const struct dev_pm_ops msm_dmov_dev_pm_ops = { +static struct dev_pm_ops msm_dmov_dev_pm_ops = { .runtime_suspend = msm_dmov_runtime_suspend, .runtime_resume = msm_dmov_runtime_resume, .runtime_idle = msm_dmov_runtime_idle, @@ -814,7 +686,6 @@ static int msm_dmov_probe(struct platform_device *pdev) platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct resource *mres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - char wq_name[12]; if (pdata) { dmov_conf[adm].sd = pdata->sd; @@ -833,16 +704,15 @@ static int msm_dmov_probe(struct platform_device *pdev) if (!dmov_conf[adm].base) return -ENOMEM; - snprintf(wq_name, sizeof(wq_name), "dmov%d_wq", adm); - dmov_conf[adm].cmd_wq = alloc_workqueue(wq_name, WQ_CPU_INTENSIVE, 1); + dmov_conf[adm].cmd_wq = alloc_ordered_workqueue("dmov%d_wq", 0, adm); if (!dmov_conf[adm].cmd_wq) { PRINT_ERROR("Couldn't allocate ADM%d workqueue.\n", adm); ret = -ENOMEM; goto out_map; } - ret = request_irq(dmov_conf[adm].irq, msm_dmov_isr, - 0, "msmdatamover", NULL); + ret = request_threaded_irq(dmov_conf[adm].irq, NULL, msm_dmov_isr, + IRQF_ONESHOT, "msmdatamover", NULL); if (ret) { PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm, dmov_conf[adm].irq); diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h index 3cb28882..1f0c2d8a 100644 --- a/arch/arm/mach-msm/include/mach/gpio.h +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -22,6 +22,9 @@ #include #include +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value + #define FIRST_BOARD_GPIO NR_GPIO_IRQS extern struct irq_chip msm_gpio_irq_extn; diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index 94c95534..60975979 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -79,6 +79,7 @@ int platform_physical_remove_pages(u64, u64); int platform_physical_active_pages(u64, u64); int platform_physical_low_power_pages(u64, u64); unsigned long get_ddr_size(void); +int msm_get_memory_type_from_name(const char *memtype_name); extern int (*change_memory_power)(u64, u64, int); @@ -119,6 +120,23 @@ void find_membank0_hole(void); (virt) - MEMBANK0_PAGE_OFFSET + MEMBANK0_PHYS_OFFSET) #endif +/* + * Need a temporary unique variable that no one will ever see to ++ * hold the compat string. Line number gives this easily. ++ * Need another layer of indirection to get __LINE__ to expand ++ * properly as opposed to appending and ending up with ++ * __compat___LINE__ ++ */ +#define __CONCAT(a, b) ___CONCAT(a, b) +#define ___CONCAT(a, b) a ## b + +#define EXPORT_COMPAT(com) \ +static char *__CONCAT(__compat_, __LINE__) __used \ + __attribute((__section__(".exportcompat.init"))) = com + +extern char *__compat_exports_start[]; +extern char *__compat_exports_end[]; + #endif #if defined CONFIG_ARCH_MSM_SCORPION || defined CONFIG_ARCH_MSM_KRAIT diff --git a/arch/arm/mach-msm/include/mach/msm_bus.h b/arch/arm/mach-msm/include/mach/msm_bus.h index 41b46a94..f6f83028 100644 --- a/arch/arm/mach-msm/include/mach/msm_bus.h +++ b/arch/arm/mach-msm/include/mach/msm_bus.h @@ -44,8 +44,8 @@ struct msm_bus_vectors { int src; /* Master */ int dst; /* Slave */ - uint64_t ab; /* Arbitrated bandwidth */ - uint64_t ib; /* Instantaneous bandwidth */ + uint64_t ab; /* Arbitrated bandwidth */ + uint64_t ib; /* Instantaneous bandwidth */ }; struct msm_bus_paths { @@ -95,7 +95,6 @@ static inline void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata) { } - static inline uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata) { diff --git a/arch/arm/mach-msm/include/mach/msm_fb.h b/arch/arm/mach-msm/include/mach/msm_fb.h index 3bbaa25d..3e420483 100644 --- a/arch/arm/mach-msm/include/mach/msm_fb.h +++ b/arch/arm/mach-msm/include/mach/msm_fb.h @@ -77,7 +77,7 @@ struct msm_mddi_client_data { uint32_t reg); uint32_t (*remote_read)(struct msm_mddi_client_data *, uint32_t reg); void (*auto_hibernate)(struct msm_mddi_client_data *, int); - /* custom data that needs to be passed from the board file to a + /* custom data that needs to be passed from the board file to a * particular client */ void *private_client_data; struct resource *fb_resource; @@ -190,7 +190,7 @@ struct msm_mddi_bridge_platform_data { struct mdp_v4l2_req; int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par); -int msm_fb_v4l2_update(void *par, +int msm_fb_v4l2_update(void *par, bool bUserPtr, unsigned long srcp0_addr, unsigned long srcp0_size, unsigned long srcp1_addr, unsigned long srcp1_size, unsigned long srcp2_addr, unsigned long srcp2_size); diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h index 64c28e84..6e19acf1 100644 --- a/arch/arm/mach-msm/include/mach/msm_memtypes.h +++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h @@ -66,5 +66,7 @@ struct reserve_info { extern struct reserve_info *reserve_info; -unsigned long __init reserve_memory_for_fmem(unsigned long, unsigned long); +int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname, + int depth, void *data); + #endif diff --git a/arch/arm/mach-msm/intelli_plug.c b/arch/arm/mach-msm/intelli_plug.c new file mode 100644 index 00000000..1b7d3c04 --- /dev/null +++ b/arch/arm/mach-msm/intelli_plug.c @@ -0,0 +1,606 @@ +/* + * Author: Paul Reioux aka Faux123 + * + * Copyright 2012~2014 Paul Reioux + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_POWERSUSPEND +#include +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +//#define DEBUG_INTELLI_PLUG +#undef DEBUG_INTELLI_PLUG + +#define INTELLI_PLUG_MAJOR_VERSION 4 +#define INTELLI_PLUG_MINOR_VERSION 0 +#define INTELLI_PLUG_RELMOD_VERSION 7 + +#define DEF_SAMPLING_MS (268) + +#define DUAL_PERSISTENCE (2500 / DEF_SAMPLING_MS) +#define TRI_PERSISTENCE (1700 / DEF_SAMPLING_MS) +#define QUAD_PERSISTENCE (1000 / DEF_SAMPLING_MS) + +#define BUSY_PERSISTENCE (3500 / DEF_SAMPLING_MS) + +static DEFINE_MUTEX(intelli_plug_mutex); + +static struct delayed_work intelli_plug_work; +static struct delayed_work intelli_plug_boost; + +static struct workqueue_struct *intelliplug_wq; +static struct workqueue_struct *intelliplug_boost_wq; + +static unsigned int intelli_plug_active = 1; +module_param(intelli_plug_active, uint, 0664); + +static unsigned int touch_boost_active = 1; +module_param(touch_boost_active, uint, 0664); + +static unsigned int nr_run_profile_sel = 0; +module_param(nr_run_profile_sel, uint, 0664); + +static unsigned int turbo_active = 1; +module_param(turbo_active, uint, 0444); + +//default to something sane rather than zero +static unsigned int sampling_time = DEF_SAMPLING_MS; + +static int persist_count = 0; + +static bool suspended = false; + +struct ip_cpu_info { + unsigned int sys_max; + unsigned int cur_max; + unsigned long cpu_nr_running; +}; + +static DEFINE_PER_CPU(struct ip_cpu_info, ip_info); + +static unsigned int screen_off_max = UINT_MAX; +module_param(screen_off_max, uint, 0664); + +#define CAPACITY_RESERVE 50 + +#if defined(CONFIG_ARCH_APQ8084) || defined(CONFIG_ARM64) +#define THREAD_CAPACITY (430 - CAPACITY_RESERVE) +#elif defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \ +defined(CONFIG_ARCH_MSM8974) +#define THREAD_CAPACITY (339 - CAPACITY_RESERVE) +#elif defined(CONFIG_ARCH_MSM8226) || defined (CONFIG_ARCH_MSM8926) || \ +defined (CONFIG_ARCH_MSM8610) || defined (CONFIG_ARCH_MSM8228) +#define THREAD_CAPACITY (190 - CAPACITY_RESERVE) +#else +#define THREAD_CAPACITY (250 - CAPACITY_RESERVE) +#endif + +#define MULT_FACTOR 4 +#define DIV_FACTOR 100000 +#define NR_FSHIFT 3 + +static unsigned int nr_fshift = NR_FSHIFT; + +static unsigned int nr_run_thresholds_balance[] = { + (THREAD_CAPACITY * 625 * MULT_FACTOR) / DIV_FACTOR, + (THREAD_CAPACITY * 875 * MULT_FACTOR) / DIV_FACTOR, + (THREAD_CAPACITY * 1125 * MULT_FACTOR) / DIV_FACTOR, + UINT_MAX +}; + +static unsigned int nr_run_thresholds_performance[] = { + (THREAD_CAPACITY * 380 * MULT_FACTOR) / DIV_FACTOR, + (THREAD_CAPACITY * 625 * MULT_FACTOR) / DIV_FACTOR, + (THREAD_CAPACITY * 875 * MULT_FACTOR) / DIV_FACTOR, + UINT_MAX +}; + +static unsigned int nr_run_thresholds_conservative[] = { + (THREAD_CAPACITY * 875 * MULT_FACTOR) / DIV_FACTOR, + (THREAD_CAPACITY * 1625 * MULT_FACTOR) / DIV_FACTOR, + (THREAD_CAPACITY * 2125 * MULT_FACTOR) / DIV_FACTOR, + UINT_MAX +}; + +static unsigned int nr_run_thresholds_eco[] = { + (THREAD_CAPACITY * 380 * MULT_FACTOR) / DIV_FACTOR, + UINT_MAX +}; + +static unsigned int nr_run_thresholds_eco_extreme[] = { + (THREAD_CAPACITY * 750 * MULT_FACTOR) / DIV_FACTOR, + UINT_MAX +}; + +static unsigned int nr_run_thresholds_disable[] = { + 0, 0, 0, UINT_MAX +}; + +static unsigned int *nr_run_profiles[] = { + nr_run_thresholds_balance, + nr_run_thresholds_performance, + nr_run_thresholds_conservative, + nr_run_thresholds_eco, + nr_run_thresholds_eco_extreme, + nr_run_thresholds_disable, +}; + +#define NR_RUN_ECO_MODE_PROFILE 4 +#define NR_RUN_HYSTERESIS_QUAD 8 +#define NR_RUN_HYSTERESIS_DUAL 4 + +#define CPU_NR_THRESHOLD ((THREAD_CAPACITY << 1) + (THREAD_CAPACITY / 2)) + +static unsigned int nr_possible_cores; +module_param(nr_possible_cores, uint, 0444); + +static unsigned int cpu_nr_run_threshold = CPU_NR_THRESHOLD; +module_param(cpu_nr_run_threshold, uint, 0664); + +static unsigned int nr_run_hysteresis = NR_RUN_HYSTERESIS_QUAD; +module_param(nr_run_hysteresis, uint, 0664); + +static unsigned int nr_run_last; + +extern unsigned long avg_nr_running(void); +extern unsigned long avg_cpu_nr_running(unsigned int cpu); + +static unsigned int calculate_thread_stats(void) +{ + unsigned int avg_nr_run = avg_nr_running(); + unsigned int nr_run; + unsigned int threshold_size; + unsigned int *current_profile; + + current_profile = nr_run_profiles[nr_run_profile_sel]; + if (num_possible_cpus() > 2) { + if (nr_run_profile_sel >= NR_RUN_ECO_MODE_PROFILE) + threshold_size = + ARRAY_SIZE(nr_run_thresholds_eco); + else + threshold_size = + ARRAY_SIZE(nr_run_thresholds_balance); + } else + threshold_size = + ARRAY_SIZE(nr_run_thresholds_eco); + + if (nr_run_profile_sel >= NR_RUN_ECO_MODE_PROFILE) + nr_fshift = 1; + else + nr_fshift = num_possible_cpus() - 1; + + for (nr_run = 1; nr_run < threshold_size; nr_run++) { + unsigned int nr_threshold; + nr_threshold = current_profile[nr_run - 1]; + + if (nr_run_last <= nr_run) + nr_threshold += nr_run_hysteresis; + if (avg_nr_run <= (nr_threshold << (FSHIFT - nr_fshift))) + break; + } + nr_run_last = nr_run; + + return nr_run; +} + +static void __ref intelli_plug_boost_fn(struct work_struct *work) +{ + + int nr_cpus = num_online_cpus(); + + if (intelli_plug_active) + if (touch_boost_active) + if (nr_cpus < 2) + cpu_up(1); +} + +/* +static int cmp_nr_running(const void *a, const void *b) +{ + return *(unsigned long *)a - *(unsigned long *)b; +} +*/ + +static void update_per_cpu_stat(void) +{ + unsigned int cpu; + struct ip_cpu_info *l_ip_info; + + for_each_online_cpu(cpu) { + l_ip_info = &per_cpu(ip_info, cpu); + l_ip_info->cpu_nr_running = avg_cpu_nr_running(cpu); +#ifdef DEBUG_INTELLI_PLUG + pr_info("cpu %u nr_running => %lu\n", cpu, + l_ip_info->cpu_nr_running); +#endif + } +} + +static void unplug_cpu(int min_active_cpu) +{ + unsigned int cpu; + struct ip_cpu_info *l_ip_info; + int l_nr_threshold; + + for_each_online_cpu(cpu) { + l_nr_threshold = + cpu_nr_run_threshold << 1 / (num_online_cpus()); + if (cpu == 0) + continue; + l_ip_info = &per_cpu(ip_info, cpu); + if (cpu > min_active_cpu) + if (l_ip_info->cpu_nr_running < l_nr_threshold) + cpu_down(cpu); + } +} + +static void __ref intelli_plug_work_fn(struct work_struct *work) +{ + unsigned int nr_run_stat; + unsigned int cpu_count = 0; + unsigned int nr_cpus = 0; + + int i; + + if (intelli_plug_active) { + nr_run_stat = calculate_thread_stats(); + update_per_cpu_stat(); +#ifdef DEBUG_INTELLI_PLUG + pr_info("nr_run_stat: %u\n", nr_run_stat); +#endif + cpu_count = nr_run_stat; + nr_cpus = num_online_cpus(); + + if (!suspended) { + + if (persist_count > 0) + persist_count--; + + switch (cpu_count) { + case 1: + if (persist_count == 0) { + //take down everyone + unplug_cpu(0); + } +#ifdef DEBUG_INTELLI_PLUG + pr_info("case 1: %u\n", persist_count); +#endif + break; + case 2: + if (persist_count == 0) + persist_count = DUAL_PERSISTENCE; + if (nr_cpus < 2) { + for (i = 1; i < cpu_count; i++) + cpu_up(i); + } else { + unplug_cpu(1); + } +#ifdef DEBUG_INTELLI_PLUG + pr_info("case 2: %u\n", persist_count); +#endif + break; + case 3: + if (persist_count == 0) + persist_count = TRI_PERSISTENCE; + if (nr_cpus < 3) { + for (i = 1; i < cpu_count; i++) + cpu_up(i); + } else { + unplug_cpu(2); + } +#ifdef DEBUG_INTELLI_PLUG + pr_info("case 3: %u\n", persist_count); +#endif + break; + case 4: + if (persist_count == 0) + persist_count = QUAD_PERSISTENCE; + if (nr_cpus < 4) + for (i = 1; i < cpu_count; i++) + cpu_up(i); +#ifdef DEBUG_INTELLI_PLUG + pr_info("case 4: %u\n", persist_count); +#endif + break; + default: + pr_err("Run Stat Error: Bad value %u\n", nr_run_stat); + break; + } + } +#ifdef DEBUG_INTELLI_PLUG + else + pr_info("intelli_plug is suspened!\n"); +#endif + } + queue_delayed_work_on(0, intelliplug_wq, &intelli_plug_work, + msecs_to_jiffies(sampling_time)); +} + +#if defined(CONFIG_POWERSUSPEND) || defined(CONFIG_HAS_EARLYSUSPEND) + +static void screen_off_limit(bool on) +{ + + unsigned int cpu; + struct cpufreq_policy *policy; + struct ip_cpu_info *l_ip_info; + + /* not active, so exit */ + if (screen_off_max == UINT_MAX) { + turbo_active = 1; + return; + } + + for_each_online_cpu(cpu) { + l_ip_info = &per_cpu(ip_info, cpu); + policy = cpufreq_cpu_get(0); + + if (on) { + + turbo_active = 0; + /* save current instance */ + l_ip_info->cur_max = policy->max; + policy->max = screen_off_max; + policy->cpuinfo.max_freq = screen_off_max; +#ifdef DEBUG_INTELLI_PLUG + pr_info("cpuinfo max is (on): %u %u\n", + policy->cpuinfo.max_freq, l_ip_info->sys_max); +#endif + } else { + + turbo_active = 1; + /* restore */ + if (cpu != 0) { + l_ip_info = &per_cpu(ip_info, 0); + } + policy->cpuinfo.max_freq = l_ip_info->sys_max; + policy->max = l_ip_info->cur_max; +#ifdef DEBUG_INTELLI_PLUG + pr_info("cpuinfo max is (off): %u %u\n", + policy->cpuinfo.max_freq, l_ip_info->sys_max); +#endif + } + cpufreq_update_policy(cpu); + + } +} + +#ifdef CONFIG_POWERSUSPEND +static void intelli_plug_suspend(struct power_suspend *handler) +#else +static void intelli_plug_suspend(struct early_suspend *handler) +#endif +{ + if (intelli_plug_active) { + int cpu; + + flush_workqueue(intelliplug_wq); + + mutex_lock(&intelli_plug_mutex); + suspended = true; + screen_off_limit(true); + mutex_unlock(&intelli_plug_mutex); + + // put rest of the cores to sleep unconditionally! + for_each_online_cpu(cpu) { + if (cpu != 0) + cpu_down(cpu); + } + } +} + +static void wakeup_boost(void) +{ + unsigned int cpu; + struct cpufreq_policy *policy; + struct ip_cpu_info *l_ip_info; + + for_each_online_cpu(cpu) { + policy = cpufreq_cpu_get(0); + l_ip_info = &per_cpu(ip_info, 0); + policy->cur = l_ip_info->cur_max; + cpufreq_update_policy(cpu); + } +} + +#ifdef CONFIG_POWERSUSPEND +static void __ref intelli_plug_resume(struct power_suspend *handler) +#else +static void __ref intelli_plug_resume(struct early_suspend *handler) +#endif +{ + + if (intelli_plug_active) { + int cpu; + + mutex_lock(&intelli_plug_mutex); + /* keep cores awake long enough for faster wake up */ + persist_count = BUSY_PERSISTENCE; + suspended = false; + mutex_unlock(&intelli_plug_mutex); + + for_each_possible_cpu(cpu) { + if (cpu == 0) + continue; + cpu_up(cpu); + } + + wakeup_boost(); + screen_off_limit(false); + } + queue_delayed_work_on(0, intelliplug_wq, &intelli_plug_work, + msecs_to_jiffies(10)); +} +#endif + +#ifdef CONFIG_POWERSUSPEND +static struct power_suspend intelli_plug_power_suspend_driver = { + .suspend = intelli_plug_suspend, + .resume = intelli_plug_resume, +}; +#endif /* CONFIG_POWERSUSPEND */ + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend intelli_plug_early_suspend_driver = { + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 10, + .suspend = intelli_plug_suspend, + .resume = intelli_plug_resume, +}; +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static void intelli_plug_input_event(struct input_handle *handle, + unsigned int type, unsigned int code, int value) +{ +#ifdef DEBUG_INTELLI_PLUG + pr_info("intelli_plug touched!\n"); +#endif + queue_delayed_work_on(0, intelliplug_wq, &intelli_plug_boost, + msecs_to_jiffies(10)); +} + +static int intelli_plug_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "intelliplug"; + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + pr_info("%s found and connected!\n", dev->name); + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void intelli_plug_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id intelli_plug_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, /* multi-touch touchscreen */ + { + .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, + .absbit = { [BIT_WORD(ABS_X)] = + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, /* touchpad */ + { }, +}; + +static struct input_handler intelli_plug_input_handler = { + .event = intelli_plug_input_event, + .connect = intelli_plug_input_connect, + .disconnect = intelli_plug_input_disconnect, + .name = "intelliplug_handler", + .id_table = intelli_plug_ids, +}; + +int __init intelli_plug_init(void) +{ + int rc; +#if defined (CONFIG_POWERSUSPEND) || defined(CONFIG_HAS_EARLYSUSPEND) + struct cpufreq_policy *policy; + struct ip_cpu_info *l_ip_info; +#endif + + nr_possible_cores = num_possible_cpus(); + + pr_info("intelli_plug: version %d.%d.m%d_jsr by faux123(modded by lukino563)\n", + INTELLI_PLUG_MAJOR_VERSION, + INTELLI_PLUG_MINOR_VERSION, + INTELLI_PLUG_RELMOD_VERSION); + + if (nr_possible_cores > 2) { + nr_run_hysteresis = NR_RUN_HYSTERESIS_QUAD; + nr_run_profile_sel = 0; + } else { + nr_run_hysteresis = NR_RUN_HYSTERESIS_DUAL; + nr_run_profile_sel = NR_RUN_ECO_MODE_PROFILE; + } + +#if defined (CONFIG_POWERSUSPEND) || defined(CONFIG_HAS_EARLYSUSPEND) + l_ip_info = &per_cpu(ip_info, 0); + policy = cpufreq_cpu_get(0); + l_ip_info->sys_max = policy->cpuinfo.max_freq; + l_ip_info->cur_max = policy->max; +#endif + + rc = input_register_handler(&intelli_plug_input_handler); +#ifdef CONFIG_POWERSUSPEND + register_power_suspend(&intelli_plug_power_suspend_driver); +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND + register_early_suspend(&intelli_plug_early_suspend_driver); +#endif + intelliplug_wq = alloc_workqueue("intelliplug", + WQ_HIGHPRI | WQ_UNBOUND, 1); + intelliplug_boost_wq = alloc_workqueue("iplug_boost", + WQ_HIGHPRI | WQ_UNBOUND, 1); + INIT_DELAYED_WORK(&intelli_plug_work, intelli_plug_work_fn); + INIT_DELAYED_WORK(&intelli_plug_boost, intelli_plug_boost_fn); + queue_delayed_work_on(0, intelliplug_wq, &intelli_plug_work, + msecs_to_jiffies(10)); + + return 0; +} + +int turbo_start_dec(void) +{ + return turbo_active; +} + +MODULE_AUTHOR("Paul Reioux (edit: Lukáš Machata "); +MODULE_DESCRIPTION("'intell_plug' - An intelligent cpu hotplug driver for " + "Low Latency Frequency Transition capable processors"); +MODULE_LICENSE("GPL"); + +late_initcall(intelli_plug_init); diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c index ee1440cf..6749246b 100644 --- a/arch/arm/mach-msm/memory.c +++ b/arch/arm/mach-msm/memory.c @@ -33,7 +33,6 @@ #include #include #endif -#include #include #include #include @@ -41,7 +40,6 @@ /* fixme */ #include #include <../../mm/mm.h> -#include #if defined(CONFIG_ARCH_MSM7X27) static void *strongly_ordered_page; @@ -365,16 +363,6 @@ void store_ttbr0(void) : "=r" (msm_ttbr0)); } -int request_fmem_c_region(void *unused) -{ - return fmem_set_state(FMEM_C_STATE); -} - -int release_fmem_c_region(void *unused) -{ - return fmem_set_state(FMEM_T_STATE); -} - unsigned long get_ddr_size(void) { unsigned int i; diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile index bd24d7c6..ab62c20b 100644 --- a/arch/arm/mach-msm/msm_bus/Makefile +++ b/arch/arm/mach-msm/msm_bus/Makefile @@ -2,7 +2,7 @@ # Makefile for msm-bus driver specific files # obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o -obj-y += msm_bus_rpm.o msm_bus_bimc.o msm_bus_noc.o msm_bus_of.o +obj-y += msm_bus_rpm.o msm_bus_bimc.o msm_bus_noc.o obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o obj-$(CONFIG_ARCH_MSM8960) += msm_bus_board_8960.o obj-$(CONFIG_ARCH_MSM9615) += msm_bus_board_9615.o diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c index e5616b90..6babfd19 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c @@ -32,9 +32,8 @@ #define SEL_FAB_CLK 1 #define SEL_SLAVE_CLK 0 -#define BW_TO_CLK_FREQ_HZ(width, bw) \ - msm_bus_div64(width, bw) - +#define BW_TO_CLK_FREQ_HZ(width, bw) ((unsigned long)\ + DIV_ROUND_UP((bw), (width))) #define IS_MASTER_VALID(mas) \ (((mas >= MSM_BUS_MASTER_FIRST) && (mas <= MSM_BUS_MASTER_LAST)) \ ? 1 : 0) @@ -44,33 +43,6 @@ static DEFINE_MUTEX(msm_bus_lock); -/* This function uses shift operations to divide 64 bit value for higher - * efficiency. The divisor expected are number of ports or bus-width. - * These are expected to be 1, 2, 4, 8, 16 and 32 in most cases. - * - * To account for exception to the above divisor values, the standard - * do_div function is used. - * */ -uint64_t msm_bus_div64(unsigned int w, uint64_t bw) -{ - uint64_t *b = &bw; - - if ((bw > 0) && (bw < w)) - return 1; - - switch (w) { - case 1: return bw; - case 2: return (bw >> 1); - case 4: return (bw >> 2); - case 8: return (bw >> 3); - case 16: return (bw >> 4); - case 32: return (bw >> 5); - } - - do_div(*b, w); - return *b; -} - /** * add_path_node: Adds the path information to the current node * @info: Internal node info structure @@ -306,21 +278,21 @@ static int getpath(int src, int dest) * frequencies is calculated at each node on the path. Commit data to be sent * to RPM for each master and slave is also calculated here. */ -static int update_path(int curr, int pnode, uint64_t req_clk, uint64_t req_bw, - uint64_t curr_clk, uint64_t curr_bw, unsigned int ctx, unsigned int - cl_active_flag) +static int update_path(int curr, int pnode, unsigned long req_clk, unsigned + long req_bw, unsigned long curr_clk, unsigned long curr_bw, + unsigned int ctx, unsigned int cl_active_flag) { int index, ret = 0; struct msm_bus_inode_info *info; int next_pnode; - int64_t add_bw = req_bw - curr_bw; + long int add_bw = req_bw - curr_bw; unsigned bwsum = 0; - uint64_t req_clk_hz, curr_clk_hz, bwsum_hz; + unsigned req_clk_hz, curr_clk_hz, bwsum_hz; int *master_tiers; struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device (GET_FABID(curr)); - MSM_BUS_DBG("args: %d %d %d %llu %llu %llu %llu %u\n", + MSM_BUS_DBG("args: %d %d %d %lu %lu %lu %lu %u\n", curr, GET_NODE(pnode), GET_INDEX(pnode), req_clk, req_bw, curr_clk, curr_bw, ctx); index = GET_INDEX(pnode); @@ -406,8 +378,8 @@ static int update_path(int curr, int pnode, uint64_t req_clk, uint64_t req_bw, req_clk); bwsum_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, bwsum); - MSM_BUS_DBG("up-clk: curr_hz: %llu, req_hz: %llu, bw_hz %llu\n", - curr_clk, req_clk, bwsum_hz); + MSM_BUS_DBG("Calling update-clks: curr_hz: %lu, req_hz: %lu," + " bw_hz %u\n", curr_clk, req_clk, bwsum_hz); ret = fabdev->algo->update_clks(fabdev, hop, index, curr_clk_hz, req_clk_hz, bwsum_hz, SEL_FAB_CLK, ctx, cl_active_flag); @@ -560,7 +532,7 @@ int msm_bus_scale_client_update_request(uint32_t cl, unsigned index) int i, ret = 0; struct msm_bus_scale_pdata *pdata; int pnode, src, curr, ctx; - uint64_t req_clk, req_bw, curr_clk, curr_bw; + unsigned long req_clk, req_bw, curr_clk, curr_bw; struct msm_bus_client *client = (struct msm_bus_client *)cl; if (IS_ERR(client)) { MSM_BUS_ERR("msm_bus_scale_client update req error %d\n", @@ -582,8 +554,9 @@ int msm_bus_scale_client_update_request(uint32_t cl, unsigned index) goto err; } - MSM_BUS_DBG("cl: %u index: %d curr: %d num_paths: %d\n", - cl, index, client->curr, client->pdata->usecase->num_paths); + MSM_BUS_DBG("cl: %u index: %d curr: %d" + " num_paths: %d\n", cl, index, client->curr, + client->pdata->usecase->num_paths); for (i = 0; i < pdata->usecase->num_paths; i++) { src = msm_bus_board_get_iid(client->pdata->usecase[index]. @@ -611,7 +584,7 @@ int msm_bus_scale_client_update_request(uint32_t cl, unsigned index) } else { curr_clk = client->pdata->usecase[curr].vectors[i].ib; curr_bw = client->pdata->usecase[curr].vectors[i].ab; - MSM_BUS_DBG("ab: %llu ib: %llu\n", curr_bw, curr_clk); + MSM_BUS_DBG("ab: %lu ib: %lu\n", curr_bw, curr_clk); } if (!pdata->active_only) { diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c index 4a14b638..f9889f06 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c @@ -1803,7 +1803,7 @@ static void msm_bus_bimc_update_bw(struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info, struct msm_bus_fabric_registration *fab_pdata, void *sel_cdata, int *master_tiers, - int64_t add_bw) + long int add_bw) { struct msm_bus_bimc_info *binfo; struct msm_bus_bimc_qos_bw qbw; @@ -1813,7 +1813,7 @@ static void msm_bus_bimc_update_bw(struct msm_bus_inode_info *hop, struct msm_bus_bimc_commit *sel_cd = (struct msm_bus_bimc_commit *)sel_cdata; - MSM_BUS_DBG("BIMC: Update bw for ID %d, with IID: %d: %lld\n", + MSM_BUS_DBG("BIMC: Update bw for ID %d, with IID: %d: %ld\n", info->node_info->id, info->node_info->priv_id, add_bw); binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data; diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h index e472e888..00f0e43d 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h +++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h @@ -36,7 +36,7 @@ (((slv >= MSM_BUS_SLAVE_FIRST) && (slv <= MSM_BUS_SLAVE_LAST)) ? 1 : 0) #define INTERLEAVED_BW(fab_pdata, bw, ports) \ - ((fab_pdata->il_flag) ? msm_bus_div64((bw), (ports)) : (bw)) + ((fab_pdata->il_flag) ? DIV_ROUND_UP((bw), (ports)) : (bw)) #define INTERLEAVED_VAL(fab_pdata, n) \ ((fab_pdata->il_flag) ? (n) : 1) @@ -83,34 +83,34 @@ struct msm_bus_node_info { }; struct path_node { - uint64_t clk[NUM_CTX]; - uint64_t bw[NUM_CTX]; - uint64_t *sel_clk; - uint64_t *sel_bw; + unsigned long clk[NUM_CTX]; + unsigned long bw[NUM_CTX]; + unsigned long *sel_clk; + unsigned long *sel_bw; int next; }; struct msm_bus_link_info { - uint64_t clk[NUM_CTX]; - uint64_t *sel_clk; - uint64_t memclk; - int64_t bw[NUM_CTX]; - int64_t *sel_bw; + unsigned long clk[NUM_CTX]; + unsigned long *sel_clk; + unsigned long memclk; + long bw[NUM_CTX]; + long *sel_bw; int *tier; int num_tiers; }; struct nodeclk { struct clk *clk; - uint64_t rate; + unsigned long rate; bool dirty; bool enable; }; struct msm_bus_inode_info { struct msm_bus_node_info *node_info; - uint64_t max_bw; - uint64_t max_clk; + unsigned long max_bw; + unsigned long max_clk; struct msm_bus_link_info link_info; int num_pnodes; struct path_node *pnode; @@ -137,7 +137,7 @@ struct msm_bus_hw_algorithm { struct msm_bus_inode_info *info, struct msm_bus_fabric_registration *fab_pdata, void *sel_cdata, int *master_tiers, - int64_t add_bw); + long int add_bw); void (*fill_cdata_buffer)(int *curr, char *buf, const int max_size, void *cdata, int nmasters, int nslaves, int ntslaves); int (*commit)(struct msm_bus_fabric_registration @@ -164,8 +164,8 @@ struct msm_bus_fabric_device { struct msm_bus_fab_algorithm { int (*update_clks)(struct msm_bus_fabric_device *fabdev, struct msm_bus_inode_info *pme, int index, - uint64_t curr_clk, uint64_t req_clk, - uint64_t bwsum, int flag, int ctx, + unsigned long curr_clk, unsigned long req_clk, + unsigned long bwsum, int flag, int ctx, unsigned int cl_active_flag); int (*port_halt)(struct msm_bus_fabric_device *fabdev, int portid); int (*port_unhalt)(struct msm_bus_fabric_device *fabdev, int portid); @@ -177,7 +177,7 @@ struct msm_bus_fab_algorithm { struct list_head *(*get_gw_list)(struct msm_bus_fabric_device *fabdev); void (*update_bw)(struct msm_bus_fabric_device *fabdev, struct msm_bus_inode_info * hop, struct msm_bus_inode_info *info, - int64_t add_bw, int *master_tiers, int ctx); + long int add_bw, int *master_tiers, int ctx); }; struct msm_bus_board_algorithm { @@ -204,7 +204,6 @@ struct msm_bus_client { int curr; }; -uint64_t msm_bus_div64(unsigned int width, uint64_t bw); int msm_bus_fabric_device_register(struct msm_bus_fabric_device *fabric); void msm_bus_fabric_device_unregister(struct msm_bus_fabric_device *fabric); struct msm_bus_fabric_device *msm_bus_get_fabric_device(int fabid); diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c index 001c733a..8471b713 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c @@ -385,11 +385,11 @@ static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata, pdata->usecase[index].vectors[j].dst); i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nab : "); for (j = 0; j < pdata->usecase->num_paths; j++) - i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ", + i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%u ", pdata->usecase[index].vectors[j].ab); i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nib : "); for (j = 0; j < pdata->usecase->num_paths; j++) - i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ", + i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%u ", pdata->usecase[index].vectors[j].ib); i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n"); diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c index 8897ae5e..b9571e3e 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c @@ -222,13 +222,13 @@ static int register_fabric_info(struct platform_device *pdev, */ static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev, struct msm_bus_inode_info *slave, int index, - uint64_t curr_clk_hz, uint64_t req_clk_hz, - uint64_t bwsum_hz, int clk_flag, int ctx, + unsigned long curr_clk_hz, unsigned long req_clk_hz, + unsigned long bwsum_hz, int clk_flag, int ctx, unsigned int cl_active_flag) { int i, status = 0; - uint64_t max_pclk = 0, rate; - uint64_t *pclk = NULL; + unsigned long max_pclk = 0, rate; + unsigned long *pclk = NULL; struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev); struct nodeclk *nodeclk; @@ -261,7 +261,7 @@ static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev, info->link_info.sel_clk = &info->link_info.clk[ctx]; max_pclk = max(max_pclk, *info->link_info.sel_clk); } - MSM_BUS_DBG("max_pclk from gateways: %llu\n", max_pclk); + MSM_BUS_DBG("max_pclk from gateways: %lu\n", max_pclk); /* Maximum of all slave clocks. */ @@ -278,7 +278,7 @@ static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev, } - MSM_BUS_DBG("max_pclk from slaves & gws: %llu\n", max_pclk); + MSM_BUS_DBG("max_pclk from slaves & gws: %lu\n", max_pclk); fabric->info.link_info.sel_clk = &fabric->info.link_info.clk[ctx]; pclk = fabric->info.link_info.sel_clk; @@ -296,7 +296,7 @@ static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev, if (clk_flag) { nodeclk = &fabric->info.nodeclk[ctx]; if (nodeclk->clk) { - MSM_BUS_DBG("clks: id: %d set-clk: %llu bws_hz:%llu\n", + MSM_BUS_DBG("clks: id: %d set-clk: %lu bwsum_hz:%lu\n", fabric->fabdev.id, *pclk, bwsum_hz); if (nodeclk->rate != *pclk) { nodeclk->dirty = true; @@ -308,8 +308,8 @@ static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev, nodeclk = &slave->nodeclk[ctx]; if (nodeclk->clk) { rate = *pclk; - MSM_BUS_DBG("clks: id: %d set-clk: %llu bws_hz: %llu\n", - slave->node_info->priv_id, rate, + MSM_BUS_DBG("AXI_clks: id: %d set-clk: %lu " + "bwsum_hz: %lu\n" , slave->node_info->priv_id, rate, bwsum_hz); if (nodeclk->rate != rate) { nodeclk->dirty = true; @@ -332,7 +332,7 @@ static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev, void msm_bus_fabric_update_bw(struct msm_bus_fabric_device *fabdev, struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info, - int64_t add_bw, int *master_tiers, int ctx) + long int add_bw, int *master_tiers, int ctx) { struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev); void *sel_cdata; diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c index 6c308452..c33ebdee 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c @@ -503,7 +503,7 @@ static void msm_bus_noc_update_bw(struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info, struct msm_bus_fabric_registration *fab_pdata, void *sel_cdata, int *master_tiers, - int64_t add_bw) + long int add_bw) { struct msm_bus_noc_info *ninfo; struct msm_bus_noc_qos_bw qos_bw; @@ -528,7 +528,7 @@ static void msm_bus_noc_update_bw(struct msm_bus_inode_info *hop, bw = INTERLEAVED_BW(fab_pdata, add_bw, ports); - MSM_BUS_DBG("NOC: Update bw for: %d: %lld\n", + MSM_BUS_DBG("NOC: Update bw for: %d: %ld\n", info->node_info->priv_id, add_bw); for (i = 0; i < ports; i++) { sel_cd->mas[info->node_info->masterp[i]].bw += bw; diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c deleted file mode 100644 index 24b0ce27..00000000 --- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__ - -#include -#include -#include -#include -#include -#include - -/** - * msm_bus_cl_get_pdata() - Generate bus client data from device tree - * provided by clients. - * - * of_node: Device tree node to extract information from - * - * The function returns a valid pointer to the allocated bus-scale-pdata - * if the vectors were correctly read from the client's device node. - * Any error in reading or parsing the device node will return NULL - * to the caller. - */ -struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev) -{ - struct device_node *of_node; - struct msm_bus_scale_pdata *pdata = NULL; - struct msm_bus_paths *usecase = NULL; - int i = 0, j, ret, num_usecases = 0, num_paths, len; - const uint32_t *vec_arr = NULL; - bool mem_err = false; - - if (!pdev) { - pr_err("Error: Null Platform device\n"); - return NULL; - } - - of_node = pdev->dev.of_node; - pdata = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_scale_pdata), - GFP_KERNEL); - if (!pdata) { - pr_err("Error: Memory allocation for pdata failed\n"); - mem_err = true; - goto err; - } - - ret = of_property_read_string(of_node, "qcom,msm_bus,name", - &pdata->name); - if (ret) { - pr_err("Error: Client name not found\n"); - goto err; - } - - ret = of_property_read_u32(of_node, "qcom,msm_bus,num_cases", - &num_usecases); - if (ret) { - pr_err("Error: num_usecases not found\n"); - goto err; - } - - pdata->num_usecases = num_usecases; - ret = of_property_read_u32(of_node, "qcom,msm_bus,active_only", - &pdata->active_only); - if (ret) { - pr_info("active_only flag absent.\n"); - pr_info("Using dual context by default\n"); - } - - usecase = devm_kzalloc(&pdev->dev, (sizeof(struct msm_bus_paths) * - pdata->num_usecases), GFP_KERNEL); - if (!usecase) { - pr_err("Error: Memory allocation for paths failed\n"); - mem_err = true; - goto err; - } - - ret = of_property_read_u32(of_node, "qcom,msm_bus,num_paths", - &num_paths); - if (ret) { - pr_err("Error: num_paths not found\n"); - goto err; - } - - vec_arr = of_get_property(of_node, "qcom,msm_bus,vectors", &len); - if (len != num_usecases * num_paths * sizeof(struct msm_bus_vectors)) { - pr_err("Error: Length-error on getting vectors\n"); - goto err; - } - - for (i = 0; i < num_usecases; i++) { - usecase[i].num_paths = num_paths; - usecase[i].vectors = devm_kzalloc(&pdev->dev, num_paths * - sizeof(struct msm_bus_vectors), GFP_KERNEL); - if (!usecase[i].vectors) { - mem_err = true; - pr_err("Error: Mem alloc failure in vectors\n"); - goto err; - } - - for (j = 0; j < num_paths; j++) { - int index = ((i * num_paths) + j) * 4; - usecase[i].vectors[j].src = be32_to_cpu(vec_arr[index]); - usecase[i].vectors[j].dst = - be32_to_cpu(vec_arr[index + 1]); - usecase[i].vectors[j].ab = - be32_to_cpu(vec_arr[index + 2]); - usecase[i].vectors[j].ib = - be32_to_cpu(vec_arr[index + 3]); - } - } - - pdata->usecase = usecase; - return pdata; -err: - if (mem_err) { - for (; i > 0; i--) - kfree(usecase[i-1].vectors); - - kfree(usecase); - kfree(pdata); - } - - return NULL; -} -EXPORT_SYMBOL(msm_bus_cl_get_pdata); - -/** - * msm_bus_cl_clear_pdata() - Clear pdata allocated from device-tree - * of_node: Device tree node to extract information from - */ -void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata) -{ - int i; - - for (i = 0; i < pdata->num_usecases; i++) - kfree(pdata->usecase[i].vectors); - - kfree(pdata->usecase); - kfree(pdata); -} -EXPORT_SYMBOL(msm_bus_cl_clear_pdata); diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c index 57b7f72d..00edd0a0 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c @@ -239,7 +239,7 @@ static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info, struct msm_bus_fabric_registration *fab_pdata, void *sel_cdata, int *master_tiers, - int64_t add_bw) + long int add_bw) { int index, i, j, tiers, ports; struct commit_data *sel_cd = (struct commit_data *)sel_cdata; @@ -302,9 +302,9 @@ static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop, msm_bus_create_bw_tier_pair_bytes(tier, tieredbw); sel_cd->actarb[index] = tieredbw; - MSM_BUS_DBG("tr:%d mpor:%d tbw:%ld bws: %lld\n", - hop_tier, info->node_info->masterp[i], - tieredbw, *hop->link_info.sel_bw); + MSM_BUS_DBG("tier:%d mport: %d tiered_bw:%ld " + "bwsum: %ld\n", hop_tier, info->node_info-> + masterp[i], tieredbw, *hop->link_info.sel_bw); } } } @@ -314,12 +314,10 @@ static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop, for (i = 0; i < ports; i++) { sel_cd->bwsum[hop->node_info->slavep[i]] = (uint16_t)msm_bus_create_bw_tier_pair_bytes(0, - (uint32_t)msm_bus_div64(hop->node_info->num_sports, - *hop->link_info.sel_bw)); - MSM_BUS_DBG("slavep:%d, link_bw: %u\n", - hop->node_info->slavep[i], (uint32_t) - msm_bus_div64(hop->node_info->num_sports, - *hop->link_info.sel_bw)); + (*hop->link_info.sel_bw/hop->node_info->num_sports)); + MSM_BUS_DBG("slavep:%d, link_bw: %ld\n", + hop->node_info->slavep[i], (*hop->link_info.sel_bw/ + hop->node_info->num_sports)); } } @@ -803,7 +801,7 @@ static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info, struct msm_bus_fabric_registration *fab_pdata, void *sel_cdata, int *master_tiers, - int64_t add_bw) + long int add_bw) { int index, i, j, tiers, ports; struct commit_data *sel_cd = (struct commit_data *)sel_cdata; @@ -855,9 +853,9 @@ static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop, sel_cd->arb[tier][index] = msm_bus_create_bw_tier_pair_bytes(0, tieredbw); sel_cd->actarb[tier][index] = tieredbw; - MSM_BUS_DBG("tr:%d mpor:%d tbw:%lu bws: %lld\n", - hop_tier, info->node_info->masterp[i], tieredbw, - *hop->link_info.sel_bw); + MSM_BUS_DBG("tier:%d mport: %d tiered_bw:%lu " + "bwsum: %ld\n", hop_tier, info->node_info-> + masterp[i], tieredbw, *hop->link_info.sel_bw); } } } @@ -867,13 +865,11 @@ static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop, ports = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_sports); for (i = 0; i < ports; i++) { sel_cd->bwsum[hop->node_info->slavep[i]] - = msm_bus_pack_bwsum_bytes((uint32_t) - msm_bus_div64(hop->node_info->num_sports, - *hop->link_info.sel_bw)); - MSM_BUS_DBG("slavep:%d, link_bw: %lld\n", - hop->node_info->slavep[i], - msm_bus_div64(hop->node_info->num_sports, - *hop->link_info.sel_bw)); + = msm_bus_pack_bwsum_bytes((*hop->link_info. + sel_bw/hop->node_info->num_sports)); + MSM_BUS_DBG("slavep:%d, link_bw: %ld\n", + hop->node_info->slavep[i], (*hop->link_info.sel_bw/ + hop->node_info->num_sports)); } } diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c index df6c44f8..4364fccb 100644 --- a/arch/arm/mach-msm/msm_dcvs_scm.c +++ b/arch/arm/mach-msm/msm_dcvs_scm.c @@ -32,16 +32,6 @@ struct scm_register_core { phys_addr_t core_param_phy; }; -struct scm_algo { - uint32_t core_id; - phys_addr_t algo_phy; -}; - -struct scm_init { - uint32_t phy; - uint32_t size; -}; - struct scm_pwr_param { uint32_t core_id; phys_addr_t pwr_param_phy; @@ -57,6 +47,16 @@ struct msm_algo_param { } u; }; +struct scm_algo { + uint32_t core_id; + phys_addr_t algo_phy; +}; + +struct scm_init { + uint32_t phy; + uint32_t size; +}; + int msm_dcvs_scm_init(size_t size) { int ret = 0; diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c index 6ace92a9..27c2bb21 100644 --- a/arch/arm/mach-msm/msm_rq_stats.c +++ b/arch/arm/mach-msm/msm_rq_stats.c @@ -38,7 +38,7 @@ struct notifier_block freq_transition; struct notifier_block cpu_hotplug; -#ifdef CONFIG_MSM_MPDEC +#if defined(CONFIG_MSM_MPDEC) || defined(CONFIG_BRICKED_HOTPLUG) unsigned int get_rq_info(void) { unsigned long flags = 0; diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile index f4fe052c..b13e1b55 100644 --- a/arch/arm/mach-msm/qdsp5/Makefile +++ b/arch/arm/mach-msm/qdsp5/Makefile @@ -1,3 +1,4 @@ + obj-y += adsp.o adsp_driver.o adsp_info.o adsp_rm.o dsp_debug.o adsp_debug.o obj-y += adsp_video_verify_cmd.o obj-y += adsp_videoenc_verify_cmd.o diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c index 8b8703b2..57da251f 100644 --- a/arch/arm/mach-msm/qdsp5/adsp.c +++ b/arch/arm/mach-msm/qdsp5/adsp.c @@ -1094,9 +1094,9 @@ int msm_adsp_enable(struct msm_adsp_module *module) MM_INFO("enable '%s'state[%d] id[%d]\n", module->name, module->state, module->id); - if (!strncmp(module->name, "JPEGTASK", sizeof(module->name))) + if (!strncmp(module->name, "JPEGTASK", sizeof(*module->name))) module_en = find_adsp_module_by_name(&adsp_info, "VIDEOTASK"); - else if (!strncmp(module->name, "VIDEOTASK", sizeof(module->name))) + else if (!strncmp(module->name, "VIDEOTASK", sizeof(*module->name))) module_en = find_adsp_module_by_name(&adsp_info, "JPEGTASK"); if (module_en) { mutex_lock(&module_en->lock); diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h index d2c67444..0922d883 100644 --- a/arch/arm/mach-msm/qdsp5/adsp.h +++ b/arch/arm/mach-msm/qdsp5/adsp.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-msm/qdsp5/adsp_driver.c b/arch/arm/mach-msm/qdsp5/adsp_driver.c index e7784323..eb9c3887 100644 --- a/arch/arm/mach-msm/qdsp5/adsp_driver.c +++ b/arch/arm/mach-msm/qdsp5/adsp_driver.c @@ -25,7 +25,6 @@ #include #include "adsp.h" #include -#include #include struct adsp_ion_info { @@ -139,7 +138,7 @@ static int get_ion_region_info(int fd, struct adsp_ion_region *region) pr_err("%s: could not get flags for the handle\n", __func__); goto flag_error; } - temp_ptr = ion_map_kernel(region->client, region->handle, ionflag); + temp_ptr = ion_map_kernel(region->client, region->handle); if (IS_ERR_OR_NULL(temp_ptr)) { pr_err("%s: could not get virtual address\n", __func__); goto map_error; @@ -267,7 +266,7 @@ int adsp_ion_do_cache_op(struct msm_adsp_module *module, module->name, vaddr, len); return ret; } - if ((region->ion_flag == CACHED) && region->handle) { + if ((region->ion_flag == ION_FLAG_CACHED) && region->handle) { len = ((((len) + 31) & (~31)) + 32); ret = msm_ion_do_cache_op(region->client, region->handle, (void *)paddr, len, cmd); diff --git a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c index 4d03dca2..d03f9a5a 100644 --- a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c +++ b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c @@ -17,11 +17,11 @@ */ #include -#include #include #include "adsp.h" #include +#include #define MAX_FLUSH_SIZE 160 diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c index 18138391..45091629 100644 --- a/arch/arm/mach-msm/qdsp5/audio_aac.c +++ b/arch/arm/mach-msm/qdsp5/audio_aac.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -1373,7 +1373,6 @@ static int audaac_process_eos(struct audio *audio, rc = -EINVAL; goto done; } - if (copy_from_user(frame->data, buf_start, mfield_size)) { rc = -EFAULT; goto done; @@ -1734,7 +1733,7 @@ static int audio_open(struct inode *inode, struct file *file) MM_DBG("allocating mem sz = %d\n", mem_sz); handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1760,7 +1759,7 @@ static int audio_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers,freeing instance 0x%08x\n", (int)audio); @@ -1776,7 +1775,7 @@ static int audio_open(struct inode *inode, struct file *file) mem_sz = (PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT); MM_DBG("allocating mem sz = %d\n", mem_sz); handle = ion_alloc(client, mem_sz, - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate I/P buffers\n"); rc = -ENOMEM; @@ -1803,8 +1802,7 @@ static int audio_open(struct inode *inode, struct file *file) goto input_buff_get_flags_error; } - audio->map_v_read = ion_map_kernel(client, - handle, ionflag); + audio->map_v_read = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("could not map read buffers, freeing instance \ 0x%08x\n", (int)audio); diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c index 61b26a86..4c13a3c1 100644 --- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c +++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include "audmgr.h" @@ -1371,7 +1371,7 @@ static int audaac_in_open(struct inode *inode, struct file *file) MM_DBG("allocating mem sz = %d\n", dma_size); handle = ion_alloc(client, dma_size, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1399,7 +1399,7 @@ static int audaac_in_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_read = ion_map_kernel(client, handle, ionflag); + audio->map_v_read = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("could not map read buffers,freeing instance 0x%08x\n", (int)audio); @@ -1415,7 +1415,7 @@ static int audaac_in_open(struct inode *inode, struct file *file) MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE); handle = ion_alloc(client, BUFFER_SIZE, - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate I/P buffers\n"); rc = -ENOMEM; @@ -1445,8 +1445,7 @@ static int audaac_in_open(struct inode *inode, struct file *file) goto input_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, - handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c index 21cf6cca..ba3fe941 100644 --- a/arch/arm/mach-msm/qdsp5/audio_ac3.c +++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c @@ -1,6 +1,6 @@ /* arch/arm/mach-msm/audio_ac3.c * - * Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved. * * This code also borrows from audio_aac.c, which is * Copyright (C) 2008 Google, Inc. @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include @@ -1034,7 +1034,7 @@ static long audac3_ioctl(struct file *file, unsigned int cmd, handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); audio->input_buff_handle = NULL; @@ -1072,8 +1072,7 @@ static long audac3_ioctl(struct file *file, unsigned int cmd, } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("map of read buf failed\n"); ion_free(audio->client, handle); @@ -1603,7 +1602,7 @@ static int audac3_open(struct inode *inode, struct file *file) audio->client = client; handle = ion_alloc(client, DMASZ, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1629,7 +1628,7 @@ static int audac3_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers,freeing instance 0x%08x\n", (int)audio); diff --git a/arch/arm/mach-msm/qdsp5/audio_acdb.c b/arch/arm/mach-msm/qdsp5/audio_acdb.c index 7f276748..2dc7a62b 100644 --- a/arch/arm/mach-msm/qdsp5/audio_acdb.c +++ b/arch/arm/mach-msm/qdsp5/audio_acdb.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -110,7 +109,6 @@ struct acdb_data { audpp_cmd_cfg_object_params_eqalizer eq; struct audrec_session_info session_info; /*pmem info*/ - int pmem_fd; unsigned long paddr; unsigned long kvaddr; unsigned long pmem_len; @@ -1136,7 +1134,6 @@ static long audio_acdb_ioctl(struct file *file, unsigned int cmd, { int rc = 0; unsigned long flags = 0; - struct msm_audio_pmem_info info; MM_DBG("%s\n", __func__); @@ -1156,23 +1153,6 @@ static long audio_acdb_ioctl(struct file *file, unsigned int cmd, MM_ERR("AUDPP returned err =%d\n", rc); spin_unlock_irqrestore(&acdb_data.dsp_lock, flags); break; - case AUDIO_REGISTER_PMEM: - MM_DBG("AUDIO_REGISTER_PMEM\n"); - if (copy_from_user(&info, (void *) arg, sizeof(info))) { - MM_ERR("Cannot copy from user\n"); - return -EFAULT; - } - rc = get_pmem_file(info.fd, &acdb_data.paddr, - &acdb_data.kvaddr, - &acdb_data.pmem_len, - &acdb_data.file); - if (rc == 0) - acdb_data.pmem_fd = info.fd; - break; - case AUDIO_DEREGISTER_PMEM: - if (acdb_data.pmem_fd) - put_pmem_file(acdb_data.file); - break; case AUDIO_SET_ACDB_BLK: MM_DBG("IOCTL AUDIO_SET_ACDB_BLK\n"); rc = acdb_set_calibration_blk(arg); diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c index fad01db3..4faffd24 100644 --- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c +++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c @@ -2,7 +2,7 @@ * * amrnb audio decoder device * - * Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved. * * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c * @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include @@ -986,7 +986,7 @@ static long audamrnb_ioctl(struct file *file, unsigned int cmd, handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); audio->input_buff_handle = NULL; @@ -1023,8 +1023,7 @@ static long audamrnb_ioctl(struct file *file, unsigned int cmd, break; } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("failed to map read buf\n"); ion_free(audio->client, handle); @@ -1551,7 +1550,7 @@ static int audamrnb_open(struct inode *inode, struct file *file) audio->client = client; handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1577,7 +1576,7 @@ static int audamrnb_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c index 9f85b51f..fbee2f93 100644 --- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c +++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include "audmgr.h" @@ -742,6 +742,7 @@ static long audamrnb_in_ioctl(struct file *file, MM_DBG("\n"); if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; + memset(&stats, 0, sizeof(stats)); stats.byte_count = atomic_read(&audio->in_bytes); stats.sample_count = atomic_read(&audio->in_samples); if (copy_to_user((void *) arg, &stats, sizeof(stats))) @@ -896,7 +897,7 @@ static ssize_t audamrnb_in_read(struct file *file, struct amrnb_encoded_meta_out meta_field; struct audio_frame_nt *nt_frame; MM_DBG("count = %d\n", count); - memset(&meta_field, 0, sizeof(meta_field)); + memset(&meta_field, 0, sizeof(meta_field)); mutex_lock(&audio->read_lock); while (count > 0) { rc = wait_event_interruptible( @@ -1337,7 +1338,7 @@ static int audamrnb_in_open(struct inode *inode, struct file *file) if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) { MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE); handle = ion_alloc(client, BUFFER_SIZE, - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate write buffers\n"); rc = -ENOMEM; @@ -1367,8 +1368,7 @@ static int audamrnb_in_open(struct inode *inode, struct file *file) goto input_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, - handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c index 148a31c4..2b69e9fc 100644 --- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c +++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include @@ -982,7 +982,7 @@ static long audamrwb_ioctl(struct file *file, unsigned int cmd, handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); audio->input_buff_handle = NULL; @@ -1019,8 +1019,7 @@ static long audamrwb_ioctl(struct file *file, unsigned int cmd, break; } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("failed to map mem for read buf\n"); ion_free(audio->client, handle); @@ -1616,7 +1615,7 @@ static int audamrwb_open(struct inode *inode, struct file *file) audio->client = client; handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); goto output_buff_alloc_error; @@ -1641,7 +1640,7 @@ static int audamrwb_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c index 42f33db6..2ac4aea6 100644 --- a/arch/arm/mach-msm/qdsp5/audio_evrc.c +++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -972,7 +972,7 @@ static long audevrc_ioctl(struct file *file, unsigned int cmd, handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); audio->input_buff_handle = NULL; @@ -1009,8 +1009,7 @@ static long audevrc_ioctl(struct file *file, unsigned int cmd, break; } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("failed to map mem" " for read buf\n"); @@ -1543,7 +1542,7 @@ static int audevrc_open(struct inode *inode, struct file *file) audio->client = client; handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1569,7 +1568,7 @@ static int audevrc_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c index 03b105e1..18ea0eaa 100644 --- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c +++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c @@ -33,7 +33,7 @@ #include -#include +#include #include #include @@ -732,7 +732,7 @@ static long audevrc_in_ioctl(struct file *file, MM_DBG("\n"); if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); + memset(&stats, 0, sizeof(stats)); stats.byte_count = atomic_read(&audio->in_bytes); stats.sample_count = atomic_read(&audio->in_samples); if (copy_to_user((void *) arg, &stats, sizeof(stats))) @@ -885,7 +885,7 @@ static ssize_t audevrc_in_read(struct file *file, int rc = 0; struct evrc_encoded_meta_out meta_field; struct audio_frame_nt *nt_frame; - memset(&meta_field, 0, sizeof(meta_field)); + memset(&meta_field, 0, sizeof(meta_field)); MM_DBG("count = %d\n", count); mutex_lock(&audio->read_lock); while (count > 0) { @@ -1321,7 +1321,7 @@ static int audevrc_in_open(struct inode *inode, struct file *file) MM_DBG("allocating mem sz = %d\n", dma_size); handle = ion_alloc(client, dma_size, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1349,7 +1349,7 @@ static int audevrc_in_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_read = ion_map_kernel(client, handle, ionflag); + audio->map_v_read = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("could not map read buffers,freeing instance 0x%08x\n", (int)audio); @@ -1364,7 +1364,7 @@ static int audevrc_in_open(struct inode *inode, struct file *file) if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) { MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE); handle = ion_alloc(client, BUFFER_SIZE, - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate I/P buffers\n"); rc = -ENOMEM; @@ -1394,8 +1394,7 @@ static int audevrc_in_open(struct inode *inode, struct file *file) goto input_buff_alloc_error; } - audio->map_v_write = ion_map_kernel(client, - handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c index a07acf08..707a9eba 100644 --- a/arch/arm/mach-msm/qdsp5/audio_lpa.c +++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -744,7 +744,7 @@ static int audlpa_ion_add(struct audio *audio, pr_err("%s: could not get flags for the handle\n", __func__); goto flag_error; } - kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag); + kvaddr = (unsigned long)ion_map_kernel(audio->client, handle); if (IS_ERR_OR_NULL((void *)kvaddr)) { pr_err("%s: could not get virtual address\n", __func__); goto map_error; diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c index 41d26856..3950a2a6 100644 --- a/arch/arm/mach-msm/qdsp5/audio_mp3.c +++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -1100,7 +1100,7 @@ static int audmp3_ion_add(struct audio *audio, goto flag_error; } - temp_ptr = ion_map_kernel(audio->client, handle, ionflag); + temp_ptr = ion_map_kernel(audio->client, handle); if (IS_ERR_OR_NULL(temp_ptr)) { pr_err("%s: could not get virtual address\n", __func__); goto map_error; @@ -1326,7 +1326,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); + memset(&stats, 0, sizeof(stats)); stats.byte_count = audpp_avsync_byte_count(audio->dec_id); stats.sample_count = audpp_avsync_sample_count(audio->dec_id); if (copy_to_user((void *) arg, &stats, sizeof(stats))) @@ -1531,7 +1531,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); rc = -ENOMEM; @@ -1564,8 +1564,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("map of read buf failed\n"); @@ -2271,7 +2270,7 @@ static int audio_open(struct inode *inode, struct file *file) MM_DBG("memsz = %d\n", mem_sz); handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -2297,7 +2296,7 @@ static int audio_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c index beee4a4c..4ffc2bee 100644 --- a/arch/arm/mach-msm/qdsp5/audio_pcm.c +++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include @@ -826,7 +826,7 @@ static int audpcm_ion_add(struct audio *audio, pr_err("%s: could not get flags for the handle\n", __func__); goto flag_error; } - kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag); + kvaddr = (unsigned long)ion_map_kernel(audio->client, handle); if (IS_ERR_OR_NULL((void *)kvaddr)) { pr_err("%s: could not get virtual address\n", __func__); goto map_error; @@ -1579,7 +1579,7 @@ static int audio_open(struct inode *inode, struct file *file) MM_DBG("memsz = %d\n", mem_sz); handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1605,7 +1605,7 @@ static int audio_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c index 9e59030f..9cbb4a3b 100644 --- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c +++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include @@ -851,7 +851,7 @@ static int audpcm_in_open(struct inode *inode, struct file *file) MM_DBG("allocating mem sz = %d\n", DMASZ); handle = ion_alloc(client, DMASZ, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -879,7 +879,7 @@ static int audpcm_in_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->data = ion_map_kernel(client, handle, ionflag); + audio->data = ion_map_kernel(client, handle); if (IS_ERR(audio->data)) { MM_ERR("could not map read buffers,freeing instance 0x%08x\n", (int)audio); diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c index 4669a739..bb4ffeff 100644 --- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c +++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include @@ -785,7 +785,7 @@ static long audqcelp_ioctl(struct file *file, unsigned int cmd, if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); + memset(&stats, 0, sizeof(stats)); stats.byte_count = audpp_avsync_byte_count(audio->dec_id); stats.sample_count = audpp_avsync_sample_count(audio->dec_id); if (copy_to_user((void *)arg, &stats, sizeof(stats))) @@ -973,7 +973,7 @@ static long audqcelp_ioctl(struct file *file, unsigned int cmd, handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); audio->input_buff_handle = NULL; @@ -1010,8 +1010,7 @@ static long audqcelp_ioctl(struct file *file, unsigned int cmd, break; } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("failed to map read buf\n"); ion_free(audio->client, handle); @@ -1541,7 +1540,7 @@ static int audqcelp_open(struct inode *inode, struct file *file) audio->client = client; handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1567,7 +1566,7 @@ static int audqcelp_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c index 6619c44b..e38cd9b1 100644 --- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c +++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c @@ -33,7 +33,7 @@ #include -#include +#include #include #include @@ -732,6 +732,7 @@ static long audqcelp_in_ioctl(struct file *file, MM_DBG("\n"); if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; + memset(&stats, 0, sizeof(stats)); stats.byte_count = atomic_read(&audio->in_bytes); stats.sample_count = atomic_read(&audio->in_samples); if (copy_to_user((void *) arg, &stats, sizeof(stats))) @@ -884,7 +885,7 @@ static ssize_t audqcelp_in_read(struct file *file, int rc = 0; struct qcelp_encoded_meta_out meta_field; struct audio_frame_nt *nt_frame; - memset(&meta_field, 0, sizeof(meta_field)); + memset(&meta_field, 0, sizeof(meta_field)); MM_DBG("count = %d\n", count); mutex_lock(&audio->read_lock); while (count > 0) { @@ -1313,7 +1314,7 @@ static int audqcelp_in_open(struct inode *inode, struct file *file) MM_DBG("allocating mem sz = %d\n", dma_size); handle = ion_alloc(client, dma_size, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1341,7 +1342,7 @@ static int audqcelp_in_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_read = ion_map_kernel(client, handle, ionflag); + audio->map_v_read = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("could not map read buffers,freeing instance 0x%08x\n", (int)audio); @@ -1356,7 +1357,7 @@ static int audqcelp_in_open(struct inode *inode, struct file *file) if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) { MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE); handle = ion_alloc(client, BUFFER_SIZE, - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate I/P buffers\n"); rc = -ENOMEM; @@ -1386,8 +1387,7 @@ static int audqcelp_in_open(struct inode *inode, struct file *file) goto input_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, - handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c index 163e30da..00ebe20b 100644 --- a/arch/arm/mach-msm/qdsp5/audio_wma.c +++ b/arch/arm/mach-msm/qdsp5/audio_wma.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include @@ -833,7 +833,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); + memset(&stats, 0, sizeof(stats)); stats.byte_count = audpp_avsync_byte_count(audio->dec_id); stats.sample_count = audpp_avsync_sample_count(audio->dec_id); if (copy_to_user((void *)arg, &stats, sizeof(stats))) @@ -1051,7 +1051,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); audio->input_buff_handle = NULL; @@ -1089,8 +1089,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("map of read buf failed\n"); ion_free(audio->client, handle); @@ -1695,7 +1694,7 @@ static int audio_open(struct inode *inode, struct file *file) audio->client = client; handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1721,7 +1720,7 @@ static int audio_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c index 6a7a1d28..fa51f646 100644 --- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c +++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include @@ -821,7 +821,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cmd == AUDIO_GET_STATS) { struct msm_audio_stats stats; - memset(&stats, 0, sizeof(stats)); + memset(&stats, 0, sizeof(stats)); stats.byte_count = audpp_avsync_byte_count(audio->dec_id); stats.sample_count = audpp_avsync_sample_count(audio->dec_id); if (copy_to_user((void *)arg, &stats, sizeof(stats))) @@ -1048,7 +1048,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) handle = ion_alloc(audio->client, (config.buffer_size * config.buffer_count), - SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID)); + SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to alloc I/P buffs\n"); audio->input_buff_handle = NULL; @@ -1086,8 +1086,7 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } audio->map_v_read = ion_map_kernel( - audio->client, - handle, ionflag); + audio->client, handle); if (IS_ERR(audio->map_v_read)) { MM_ERR("map of read buf failed\n"); ion_free(audio->client, handle); @@ -1690,7 +1689,7 @@ static int audio_open(struct inode *inode, struct file *file) audio->client = client; handle = ion_alloc(client, mem_sz, SZ_4K, - ION_HEAP(ION_AUDIO_HEAP_ID)); + ION_HEAP(ION_AUDIO_HEAP_ID), 0); if (IS_ERR_OR_NULL(handle)) { MM_ERR("Unable to create allocate O/P buffers\n"); rc = -ENOMEM; @@ -1716,7 +1715,7 @@ static int audio_open(struct inode *inode, struct file *file) goto output_buff_get_flags_error; } - audio->map_v_write = ion_map_kernel(client, handle, ionflag); + audio->map_v_write = ion_map_kernel(client, handle); if (IS_ERR(audio->map_v_write)) { MM_ERR("could not map write buffers\n"); rc = -ENOMEM; diff --git a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c b/arch/arm/mach-msm/rpcrouter_sdio_xprt.c new file mode 100644 index 00000000..e9818e51 --- /dev/null +++ b/arch/arm/mach-msm/rpcrouter_sdio_xprt.c @@ -0,0 +1,655 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * RPCROUTER SDIO XPRT module. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "smd_rpcrouter.h" + +enum { + MSM_SDIO_XPRT_DEBUG = 1U << 0, + MSM_SDIO_XPRT_INFO = 1U << 1, +}; + +static int msm_sdio_xprt_debug_mask; +module_param_named(debug_mask, msm_sdio_xprt_debug_mask, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +#if defined(CONFIG_MSM_RPC_SDIO_DEBUG) +#define SDIO_XPRT_DBG(x...) do { \ + if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_DEBUG) \ + printk(KERN_DEBUG x); \ + } while (0) + +#define SDIO_XPRT_INFO(x...) do { \ + if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_INFO) \ + printk(KERN_INFO x); \ + } while (0) +#else +#define SDIO_XPRT_DBG(x...) do { } while (0) +#define SDIO_XPRT_INFO(x...) do { } while (0) +#endif + +#define MAX_SDIO_WRITE_RETRY 5 +#define SDIO_BUF_SIZE (RPCROUTER_MSGSIZE_MAX + sizeof(struct rr_header) - 8) +#define NUM_SDIO_BUFS 20 +#define MAX_TX_BUFS 10 +#define MAX_RX_BUFS 10 + +struct sdio_xprt { + struct sdio_channel *handle; + + struct list_head write_list; + spinlock_t write_list_lock; + + struct list_head read_list; + spinlock_t read_list_lock; + + struct list_head free_list; + spinlock_t free_list_lock; + + struct wake_lock read_wakelock; +}; + +struct rpcrouter_sdio_xprt { + struct rpcrouter_xprt xprt; + struct sdio_xprt *channel; +}; + +static struct rpcrouter_sdio_xprt sdio_remote_xprt; + +static void sdio_xprt_read_data(struct work_struct *work); +static DECLARE_DELAYED_WORK(work_read_data, sdio_xprt_read_data); +static struct workqueue_struct *sdio_xprt_read_workqueue; + +struct sdio_buf_struct { + struct list_head list; + uint32_t size; + uint32_t read_index; + uint32_t write_index; + unsigned char data[SDIO_BUF_SIZE]; +}; + +static void sdio_xprt_write_data(struct work_struct *work); +static DECLARE_WORK(work_write_data, sdio_xprt_write_data); +static wait_queue_head_t write_avail_wait_q; +static uint32_t num_free_bufs; +static uint32_t num_tx_bufs; +static uint32_t num_rx_bufs; + +static DEFINE_MUTEX(modem_reset_lock); +static uint32_t modem_reset; + +static void free_sdio_xprt(struct sdio_xprt *chnl) +{ + struct sdio_buf_struct *buf; + unsigned long flags; + + if (!chnl) { + printk(KERN_ERR "Invalid chnl to free\n"); + return; + } + + spin_lock_irqsave(&chnl->free_list_lock, flags); + while (!list_empty(&chnl->free_list)) { + buf = list_first_entry(&chnl->free_list, + struct sdio_buf_struct, list); + list_del(&buf->list); + kfree(buf); + } + num_free_bufs = 0; + spin_unlock_irqrestore(&chnl->free_list_lock, flags); + + spin_lock_irqsave(&chnl->write_list_lock, flags); + while (!list_empty(&chnl->write_list)) { + buf = list_first_entry(&chnl->write_list, + struct sdio_buf_struct, list); + list_del(&buf->list); + kfree(buf); + } + num_tx_bufs = 0; + spin_unlock_irqrestore(&chnl->write_list_lock, flags); + + spin_lock_irqsave(&chnl->read_list_lock, flags); + while (!list_empty(&chnl->read_list)) { + buf = list_first_entry(&chnl->read_list, + struct sdio_buf_struct, list); + list_del(&buf->list); + kfree(buf); + } + num_rx_bufs = 0; + spin_unlock_irqrestore(&chnl->read_list_lock, flags); + wake_unlock(&chnl->read_wakelock); +} + +static struct sdio_buf_struct *alloc_from_free_list(struct sdio_xprt *chnl) +{ + struct sdio_buf_struct *buf; + unsigned long flags; + + spin_lock_irqsave(&chnl->free_list_lock, flags); + if (list_empty(&chnl->free_list)) { + spin_unlock_irqrestore(&chnl->free_list_lock, flags); + SDIO_XPRT_DBG("%s: Free list empty\n", __func__); + return NULL; + } + buf = list_first_entry(&chnl->free_list, struct sdio_buf_struct, list); + list_del(&buf->list); + num_free_bufs--; + spin_unlock_irqrestore(&chnl->free_list_lock, flags); + + buf->size = 0; + buf->read_index = 0; + buf->write_index = 0; + + return buf; +} + +static void return_to_free_list(struct sdio_xprt *chnl, + struct sdio_buf_struct *buf) +{ + unsigned long flags; + + if (!chnl || !buf) { + pr_err("%s: Invalid chnl or buf\n", __func__); + return; + } + + buf->size = 0; + buf->read_index = 0; + buf->write_index = 0; + + spin_lock_irqsave(&chnl->free_list_lock, flags); + list_add_tail(&buf->list, &chnl->free_list); + num_free_bufs++; + spin_unlock_irqrestore(&chnl->free_list_lock, flags); + +} + +static int rpcrouter_sdio_remote_read_avail(void) +{ + int read_avail = 0; + unsigned long flags; + struct sdio_buf_struct *buf; + + spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags); + list_for_each_entry(buf, &sdio_remote_xprt.channel->read_list, list) { + read_avail += buf->size; + } + spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock, + flags); + return read_avail; +} + +static int rpcrouter_sdio_remote_read(void *data, uint32_t len) +{ + struct sdio_buf_struct *buf; + unsigned char *buf_data; + unsigned long flags; + + SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__); + if (len < 0 || !data) + return -EINVAL; + else if (len == 0) + return 0; + + spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags); + if (list_empty(&sdio_remote_xprt.channel->read_list)) { + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->read_list_lock, flags); + return -EINVAL; + } + + buf = list_first_entry(&sdio_remote_xprt.channel->read_list, + struct sdio_buf_struct, list); + if (buf->size < len) { + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->read_list_lock, flags); + return -EINVAL; + } + + buf_data = buf->data + buf->read_index; + memcpy(data, buf_data, len); + buf->read_index += len; + buf->size -= len; + if (buf->size == 0) { + list_del(&buf->list); + num_rx_bufs--; + return_to_free_list(sdio_remote_xprt.channel, buf); + } + + if (list_empty(&sdio_remote_xprt.channel->read_list)) + wake_unlock(&sdio_remote_xprt.channel->read_wakelock); + spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock, + flags); + return len; +} + +static int rpcrouter_sdio_remote_write_avail(void) +{ + uint32_t write_avail = 0; + unsigned long flags; + + SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__); + spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags); + write_avail = (MAX_TX_BUFS - num_tx_bufs) * SDIO_BUF_SIZE; + spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock, + flags); + return write_avail; +} + +static int rpcrouter_sdio_remote_write(void *data, uint32_t len, + enum write_data_type type) +{ + unsigned long flags; + static struct sdio_buf_struct *buf; + unsigned char *buf_data; + + switch (type) { + case HEADER: + spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, + flags); + if (num_tx_bufs == MAX_TX_BUFS) { + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->write_list_lock, + flags); + return -ENOMEM; + } + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->write_list_lock, flags); + + SDIO_XPRT_DBG("sdio_xprt WRITE HEADER %s\n", __func__); + buf = alloc_from_free_list(sdio_remote_xprt.channel); + if (!buf) { + pr_err("%s: alloc_from_free_list failed\n", __func__); + return -ENOMEM; + } + buf_data = buf->data + buf->write_index; + memcpy(buf_data, data, len); + buf->write_index += len; + buf->size += len; + return len; + case PACKMARK: + SDIO_XPRT_DBG("sdio_xprt WRITE PACKMARK %s\n", __func__); + if (!buf) { + pr_err("%s: HEADER not written or alloc failed\n", + __func__); + return -ENOMEM; + } + buf_data = buf->data + buf->write_index; + memcpy(buf_data, data, len); + buf->write_index += len; + buf->size += len; + return len; + case PAYLOAD: + SDIO_XPRT_DBG("sdio_xprt WRITE PAYLOAD %s\n", __func__); + if (!buf) { + pr_err("%s: HEADER not written or alloc failed\n", + __func__); + return -ENOMEM; + } + buf_data = buf->data + buf->write_index; + memcpy(buf_data, data, len); + buf->write_index += len; + buf->size += len; + + SDIO_XPRT_DBG("sdio_xprt flush %d bytes\n", buf->size); + spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, + flags); + list_add_tail(&buf->list, + &sdio_remote_xprt.channel->write_list); + num_tx_bufs++; + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->write_list_lock, flags); + queue_work(sdio_xprt_read_workqueue, &work_write_data); + buf = NULL; + return len; + default: + return -EINVAL; + } +} + +static void sdio_xprt_write_data(struct work_struct *work) +{ + int rc = 0, sdio_write_retry = 0; + unsigned long flags; + struct sdio_buf_struct *buf; + + mutex_lock(&modem_reset_lock); + if (modem_reset) { + mutex_unlock(&modem_reset_lock); + return; + } + + spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags); + while (!list_empty(&sdio_remote_xprt.channel->write_list)) { + buf = list_first_entry(&sdio_remote_xprt.channel->write_list, + struct sdio_buf_struct, list); + list_del(&buf->list); + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->write_list_lock, flags); + mutex_unlock(&modem_reset_lock); + + wait_event(write_avail_wait_q, + (!(modem_reset) && (sdio_write_avail( + sdio_remote_xprt.channel->handle) >= + buf->size))); + + mutex_lock(&modem_reset_lock); + while (!(modem_reset) && + ((rc = sdio_write(sdio_remote_xprt.channel->handle, + buf->data, buf->size)) < 0) && + (sdio_write_retry++ < MAX_SDIO_WRITE_RETRY)) { + printk(KERN_ERR "sdio_write failed with RC %d\n", rc); + mutex_unlock(&modem_reset_lock); + msleep(250); + mutex_lock(&modem_reset_lock); + } + if (modem_reset) { + mutex_unlock(&modem_reset_lock); + kfree(buf); + return; + } else { + return_to_free_list(sdio_remote_xprt.channel, buf); + } + + if (!rc) + SDIO_XPRT_DBG("sdio_write %d bytes completed\n", + buf->size); + + spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, + flags); + num_tx_bufs--; + } + spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock, + flags); + mutex_unlock(&modem_reset_lock); +} + +static int rpcrouter_sdio_remote_close(void) +{ + SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__); + flush_workqueue(sdio_xprt_read_workqueue); + sdio_close(sdio_remote_xprt.channel->handle); + free_sdio_xprt(sdio_remote_xprt.channel); + return 0; +} + +static void sdio_xprt_read_data(struct work_struct *work) +{ + int size = 0, read_avail; + unsigned long flags; + struct sdio_buf_struct *buf; + SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__); + + mutex_lock(&modem_reset_lock); + while (!(modem_reset) && + ((read_avail = + sdio_read_avail(sdio_remote_xprt.channel->handle)) > 0)) { + spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, + flags); + if (num_rx_bufs == MAX_RX_BUFS) { + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->read_list_lock, + flags); + queue_delayed_work(sdio_xprt_read_workqueue, + &work_read_data, + msecs_to_jiffies(100)); + break; + } + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->read_list_lock, flags); + + buf = alloc_from_free_list(sdio_remote_xprt.channel); + if (!buf) { + SDIO_XPRT_DBG("%s: Failed to alloc_from_free_list" + " Try again later\n", __func__); + queue_delayed_work(sdio_xprt_read_workqueue, + &work_read_data, + msecs_to_jiffies(100)); + break; + } + + size = sdio_read(sdio_remote_xprt.channel->handle, + buf->data, read_avail); + if (size < 0) { + printk(KERN_ERR "sdio_read failed," + " read %d bytes, expected %d\n", + size, read_avail); + return_to_free_list(sdio_remote_xprt.channel, buf); + queue_delayed_work(sdio_xprt_read_workqueue, + &work_read_data, + msecs_to_jiffies(100)); + break; + } + + if (size == 0) + size = read_avail; + + buf->size = size; + buf->write_index = size; + spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, + flags); + list_add_tail(&buf->list, + &sdio_remote_xprt.channel->read_list); + num_rx_bufs++; + spin_unlock_irqrestore( + &sdio_remote_xprt.channel->read_list_lock, flags); + wake_lock(&sdio_remote_xprt.channel->read_wakelock); + } + + if (!modem_reset && !list_empty(&sdio_remote_xprt.channel->read_list)) + msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt, + RPCROUTER_XPRT_EVENT_DATA); + mutex_unlock(&modem_reset_lock); +} + +static void rpcrouter_sdio_remote_notify(void *_dev, unsigned event) +{ + if (event == SDIO_EVENT_DATA_READ_AVAIL) { + SDIO_XPRT_DBG("%s Received Notify" + "SDIO_EVENT_DATA_READ_AVAIL\n", __func__); + queue_delayed_work(sdio_xprt_read_workqueue, + &work_read_data, 0); + } + if (event == SDIO_EVENT_DATA_WRITE_AVAIL) { + SDIO_XPRT_DBG("%s Received Notify" + "SDIO_EVENT_DATA_WRITE_AVAIL\n", __func__); + wake_up(&write_avail_wait_q); + } +} + +static int allocate_sdio_xprt(struct sdio_xprt **sdio_xprt_chnl) +{ + struct sdio_buf_struct *buf; + struct sdio_xprt *chnl; + int i; + unsigned long flags; + int rc = -ENOMEM; + + if (!(*sdio_xprt_chnl)) { + chnl = kmalloc(sizeof(struct sdio_xprt), GFP_KERNEL); + if (!chnl) { + printk(KERN_ERR "sdio_xprt channel" + " allocation failed\n"); + return rc; + } + + spin_lock_init(&chnl->write_list_lock); + spin_lock_init(&chnl->read_list_lock); + spin_lock_init(&chnl->free_list_lock); + + INIT_LIST_HEAD(&chnl->write_list); + INIT_LIST_HEAD(&chnl->read_list); + INIT_LIST_HEAD(&chnl->free_list); + wake_lock_init(&chnl->read_wakelock, + WAKE_LOCK_SUSPEND, "rpc_sdio_xprt_read"); + } else { + chnl = *sdio_xprt_chnl; + } + + for (i = 0; i < NUM_SDIO_BUFS; i++) { + buf = kzalloc(sizeof(struct sdio_buf_struct), GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "sdio_buf_struct alloc failed\n"); + goto alloc_failure; + } + spin_lock_irqsave(&chnl->free_list_lock, flags); + list_add_tail(&buf->list, &chnl->free_list); + spin_unlock_irqrestore(&chnl->free_list_lock, flags); + } + num_free_bufs = NUM_SDIO_BUFS; + + *sdio_xprt_chnl = chnl; + return 0; + +alloc_failure: + spin_lock_irqsave(&chnl->free_list_lock, flags); + while (!list_empty(&chnl->free_list)) { + buf = list_first_entry(&chnl->free_list, + struct sdio_buf_struct, + list); + list_del(&buf->list); + kfree(buf); + } + spin_unlock_irqrestore(&chnl->free_list_lock, flags); + wake_lock_destroy(&chnl->read_wakelock); + + kfree(chnl); + *sdio_xprt_chnl = NULL; + return rc; +} + +static int rpcrouter_sdio_remote_probe(struct platform_device *pdev) +{ + int rc; + + SDIO_XPRT_INFO("%s Called\n", __func__); + + mutex_lock(&modem_reset_lock); + if (!modem_reset) { + sdio_xprt_read_workqueue = + create_singlethread_workqueue("sdio_xprt"); + if (!sdio_xprt_read_workqueue) { + mutex_unlock(&modem_reset_lock); + return -ENOMEM; + } + + sdio_remote_xprt.xprt.name = "rpcrotuer_sdio_xprt"; + sdio_remote_xprt.xprt.read_avail = + rpcrouter_sdio_remote_read_avail; + sdio_remote_xprt.xprt.read = rpcrouter_sdio_remote_read; + sdio_remote_xprt.xprt.write_avail = + rpcrouter_sdio_remote_write_avail; + sdio_remote_xprt.xprt.write = rpcrouter_sdio_remote_write; + sdio_remote_xprt.xprt.close = rpcrouter_sdio_remote_close; + sdio_remote_xprt.xprt.priv = NULL; + + init_waitqueue_head(&write_avail_wait_q); + } + modem_reset = 0; + + rc = allocate_sdio_xprt(&sdio_remote_xprt.channel); + if (rc) { + destroy_workqueue(sdio_xprt_read_workqueue); + mutex_unlock(&modem_reset_lock); + return rc; + } + + /* Open up SDIO channel */ + rc = sdio_open("SDIO_RPC", &sdio_remote_xprt.channel->handle, NULL, + rpcrouter_sdio_remote_notify); + + if (rc < 0) { + free_sdio_xprt(sdio_remote_xprt.channel); + destroy_workqueue(sdio_xprt_read_workqueue); + mutex_unlock(&modem_reset_lock); + return rc; + } + mutex_unlock(&modem_reset_lock); + + msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt, + RPCROUTER_XPRT_EVENT_OPEN); + + SDIO_XPRT_INFO("%s Completed\n", __func__); + + return 0; +} + +static int rpcrouter_sdio_remote_remove(struct platform_device *pdev) +{ + SDIO_XPRT_INFO("%s Called\n", __func__); + + mutex_lock(&modem_reset_lock); + modem_reset = 1; + wake_up(&write_avail_wait_q); + free_sdio_xprt(sdio_remote_xprt.channel); + mutex_unlock(&modem_reset_lock); + + msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt, + RPCROUTER_XPRT_EVENT_CLOSE); + + SDIO_XPRT_INFO("%s Completed\n", __func__); + + return 0; +} + +/*Remove this platform driver after mainline of SDIO_AL update*/ +static struct platform_driver rpcrouter_sdio_remote_driver = { + .probe = rpcrouter_sdio_remote_probe, + .driver = { + .name = "SDIO_AL", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver rpcrouter_sdio_driver = { + .probe = rpcrouter_sdio_remote_probe, + .remove = rpcrouter_sdio_remote_remove, + .driver = { + .name = "SDIO_RPC", + .owner = THIS_MODULE, + }, +}; + +static int __init rpcrouter_sdio_init(void) +{ + int rc; + msm_sdio_xprt_debug_mask = 0x2; + rc = platform_driver_register(&rpcrouter_sdio_remote_driver); + if (rc < 0) + return rc; + return platform_driver_register(&rpcrouter_sdio_driver); +} + +module_init(rpcrouter_sdio_init); +MODULE_DESCRIPTION("RPC Router SDIO XPRT"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/sdio_al.c b/arch/arm/mach-msm/sdio_al.c new file mode 100644 index 00000000..bcfc556c --- /dev/null +++ b/arch/arm/mach-msm/sdio_al.c @@ -0,0 +1,4365 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * SDIO-Abstraction-Layer Module. + * + * To be used with Qualcomm's SDIO-Client connected to this host. + */ +#include "sdio_al_private.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../../drivers/mmc/host/msm_sdcc.h" + +/** + * Func#0 has SDIO standard registers + * Func#1 is for Mailbox. + * Functions 2..7 are for channels. + * Currently only functions 2..5 are active due to SDIO-Client + * number of pipes. + * + */ +#define SDIO_AL_MAX_CHANNELS 6 + +/** Func 1..5 */ +#define SDIO_AL_MAX_FUNCS (SDIO_AL_MAX_CHANNELS+1) +#define SDIO_AL_WAKEUP_FUNC 6 + +/** Number of SDIO-Client pipes */ +#define SDIO_AL_MAX_PIPES 16 +#define SDIO_AL_ACTIVE_PIPES 8 + +/** CMD53/CMD54 Block size */ +#define SDIO_AL_BLOCK_SIZE 256 + +/** Func#1 hardware Mailbox base address */ +#define HW_MAILBOX_ADDR 0x1000 + +/** Func#1 peer sdioc software version. + * The header is duplicated also to the mailbox of the other + * functions. It can be used before other functions are enabled. */ +#define SDIOC_SW_HEADER_ADDR 0x0400 + +/** Func#2..7 software Mailbox base address at 16K */ +#define SDIOC_SW_MAILBOX_ADDR 0x4000 + +/** Some Mailbox registers address, written by host for + control */ +#define PIPES_THRESHOLD_ADDR 0x01000 + +#define PIPES_0_7_IRQ_MASK_ADDR 0x01048 + +#define PIPES_8_15_IRQ_MASK_ADDR 0x0104C + +#define FUNC_1_4_MASK_IRQ_ADDR 0x01040 +#define FUNC_5_7_MASK_IRQ_ADDR 0x01044 +#define FUNC_1_4_USER_IRQ_ADDR 0x01050 +#define FUNC_5_7_USER_IRQ_ADDR 0x01054 + +#define EOT_PIPES_ENABLE 0x00 + +/** Maximum read/write data available is SDIO-Client limitation */ +#define MAX_DATA_AVAILABLE (16*1024) +#define INVALID_DATA_AVAILABLE (0x8000) + +/** SDIO-Client HW threshold to generate interrupt to the + * SDIO-Host on write available bytes. + */ +#define DEFAULT_WRITE_THRESHOLD (1024) + +/** SDIO-Client HW threshold to generate interrupt to the + * SDIO-Host on read available bytes, for streaming (non + * packet) rx data. + */ +#define DEFAULT_READ_THRESHOLD (1024) +#define LOW_LATENCY_THRESHOLD (1) + +/* Extra bytes to ensure getting the rx threshold interrupt on stream channels + when restoring the threshold after sleep */ +#define THRESHOLD_CHANGE_EXTRA_BYTES (100) + +/** SW threshold to trigger reading the mailbox. */ +#define DEFAULT_MIN_WRITE_THRESHOLD (1024) +#define DEFAULT_MIN_WRITE_THRESHOLD_STREAMING (1600) + +#define THRESHOLD_DISABLE_VAL (0xFFFFFFFF) + +/** Mailbox polling time for packet channels */ +#define DEFAULT_POLL_DELAY_MSEC 10 +/** Mailbox polling time for streaming channels */ +#define DEFAULT_POLL_DELAY_NOPACKET_MSEC 30 + +/** The SDIO-Client prepares N buffers of size X per Tx pipe. + * Even when the transfer fills a partial buffer, + * that buffer becomes unusable for the next transfer. */ +#define DEFAULT_PEER_TX_BUF_SIZE (128) + +#define ROUND_UP(x, n) (((x + n - 1) / n) * n) + +/** Func#2..7 FIFOs are r/w via + sdio_readsb() & sdio_writesb(),when inc_addr=0 */ +#define PIPE_RX_FIFO_ADDR 0x00 +#define PIPE_TX_FIFO_ADDR 0x00 + +/** Inactivity time to go to sleep in mseconds */ +#define INACTIVITY_TIME_MSEC 30 +#define INITIAL_INACTIVITY_TIME_MSEC 5000 + +/** Context validity check */ +#define SDIO_AL_SIGNATURE 0xAABBCCDD + +/* Vendor Specific Command */ +#define SD_IO_RW_EXTENDED_QCOM 54 + +#define TIME_TO_WAIT_US 500 +#define SDIO_CLOSE_FLUSH_TIMEOUT_MSEC (10000) +#define RX_FLUSH_BUFFER_SIZE (16*1024) + +#define SDIO_TEST_POSTFIX "_TEST" + +#define DATA_DEBUG(x, y...) \ + do { \ + if (sdio_al->debug.debug_data_on) \ + pr_info(y); \ + sdio_al_log(x, y); \ + } while (0) + +#define LPM_DEBUG(x, y...) \ + do { \ + if (sdio_al->debug.debug_lpm_on) \ + pr_info(y); \ + sdio_al_log(x, y); \ + } while (0) + +#define sdio_al_loge(x, y...) \ + do { \ + pr_err(y); \ + sdio_al_log(x, y); \ + } while (0) + +#define sdio_al_logi(x, y...) \ + do { \ + pr_info(y); \ + sdio_al_log(x, y); \ + } while (0) + +#define CLOSE_DEBUG(x, y...) \ + do { \ + if (sdio_al->debug.debug_close_on) \ + pr_info(y); \ + sdio_al_log(x, y); \ + } while (0) + +/* The index of the SDIO card used for the sdio_al_dloader */ +#define SDIO_BOOTLOADER_CARD_INDEX 1 + + +/* SDIO card state machine */ +enum sdio_al_device_state { + CARD_INSERTED, + CARD_REMOVED, + MODEM_RESTART +}; + +struct sdio_al_debug { + u8 debug_lpm_on; + u8 debug_data_on; + u8 debug_close_on; + struct dentry *sdio_al_debug_root; + struct dentry *sdio_al_debug_lpm_on; + struct dentry *sdio_al_debug_data_on; + struct dentry *sdio_al_debug_close_on; + struct dentry *sdio_al_debug_info; + struct dentry *sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES + 1]; +}; + +/* Polling time for the inactivity timer for devices that doesn't have + * a streaming channel + */ +#define SDIO_AL_POLL_TIME_NO_STREAMING 30 + +#define CHAN_TO_FUNC(x) ((x) + 2 - 1) + +/** + * Mailbox structure. + * The Mailbox is located on the SDIO-Client Function#1. + * The mailbox size is 128 bytes, which is one block. + * The mailbox allows the host ton: + * 1. Get the number of available bytes on the pipes. + * 2. Enable/Disable SDIO-Client interrupt, related to pipes. + * 3. Set the Threshold for generating interrupt. + * + */ +struct sdio_mailbox { + u32 pipe_bytes_threshold[SDIO_AL_MAX_PIPES]; /* Addr 0x1000 */ + + /* Mask USER interrupts generated towards host - Addr 0x1040 */ + u32 mask_irq_func_1:8; /* LSB */ + u32 mask_irq_func_2:8; + u32 mask_irq_func_3:8; + u32 mask_irq_func_4:8; + + u32 mask_irq_func_5:8; + u32 mask_irq_func_6:8; + u32 mask_irq_func_7:8; + u32 mask_mutex_irq:8; + + /* Mask PIPE interrupts generated towards host - Addr 0x1048 */ + u32 mask_eot_pipe_0_7:8; + u32 mask_thresh_above_limit_pipe_0_7:8; + u32 mask_overflow_pipe_0_7:8; + u32 mask_underflow_pipe_0_7:8; + + u32 mask_eot_pipe_8_15:8; + u32 mask_thresh_above_limit_pipe_8_15:8; + u32 mask_overflow_pipe_8_15:8; + u32 mask_underflow_pipe_8_15:8; + + /* Status of User interrupts generated towards host - Addr 0x1050 */ + u32 user_irq_func_1:8; + u32 user_irq_func_2:8; + u32 user_irq_func_3:8; + u32 user_irq_func_4:8; + + u32 user_irq_func_5:8; + u32 user_irq_func_6:8; + u32 user_irq_func_7:8; + u32 user_mutex_irq:8; + + /* Status of PIPE interrupts generated towards host */ + /* Note: All sources are cleared once they read. - Addr 0x1058 */ + u32 eot_pipe_0_7:8; + u32 thresh_above_limit_pipe_0_7:8; + u32 overflow_pipe_0_7:8; + u32 underflow_pipe_0_7:8; + + u32 eot_pipe_8_15:8; + u32 thresh_above_limit_pipe_8_15:8; + u32 overflow_pipe_8_15:8; + u32 underflow_pipe_8_15:8; + + u16 pipe_bytes_avail[SDIO_AL_MAX_PIPES]; +}; + +/** Track pending Rx Packet size */ +struct rx_packet_size { + u32 size; /* in bytes */ + struct list_head list; +}; + +#define PEER_SDIOC_SW_MAILBOX_SIGNATURE 0xFACECAFE +#define PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE 0x5D107E57 +#define PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE 0xDEADBEEF + +/* Allow support in old sdio version */ +#define PEER_SDIOC_OLD_VERSION_MAJOR 0x0002 +#define INVALID_SDIO_CHAN 0xFF + +/** + * Peer SDIO-Client software header. + */ +struct peer_sdioc_sw_header { + u32 signature; + u32 version; + u32 max_channels; + char channel_names[SDIO_AL_MAX_CHANNELS][PEER_CHANNEL_NAME_SIZE]; + u32 reserved[23]; +}; + +struct peer_sdioc_boot_sw_header { + u32 signature; + u32 version; + u32 boot_ch_num; + u32 reserved[29]; /* 32 - previous fields */ +}; + +/** + * Peer SDIO-Client software mailbox. + */ +struct peer_sdioc_sw_mailbox { + struct peer_sdioc_sw_header sw_header; + struct peer_sdioc_channel_config ch_config[SDIO_AL_MAX_CHANNELS]; +}; + +#define SDIO_AL_DEBUG_LOG_SIZE 3000 +struct sdio_al_local_log { + char buffer[SDIO_AL_DEBUG_LOG_SIZE]; + unsigned int buf_cur_pos; + spinlock_t log_lock; +}; + +#define SDIO_AL_DEBUG_TMP_LOG_SIZE 250 +static int sdio_al_log(struct sdio_al_local_log *, const char *fmt, ...); + +/** + * SDIO Abstraction Layer driver context. + * + * @pdata - + * @debug - + * @devices - an array of the the devices claimed by sdio_al + * @unittest_mode - a flag to indicate if sdio_al is in + * unittest mode + * @bootloader_dev - the device which is used for the + * bootloader + * @subsys_notif_handle - handle for modem restart + * notifications + * + */ +struct sdio_al { + struct sdio_al_local_log gen_log; + struct sdio_al_local_log device_log[MAX_NUM_OF_SDIO_DEVICES]; + struct sdio_al_platform_data *pdata; + struct sdio_al_debug debug; + struct sdio_al_device *devices[MAX_NUM_OF_SDIO_DEVICES]; + int unittest_mode; + struct sdio_al_device *bootloader_dev; + void *subsys_notif_handle; + int sdioc_major; + int skip_print_info; +}; + +struct sdio_al_work { + struct work_struct work; + struct sdio_al_device *sdio_al_dev; +}; + + +/** + * SDIO Abstraction Layer device context. + * + * @card - card claimed. + * + * @mailbox - A shadow of the SDIO-Client mailbox. + * + * @channel - Channels context. + * + * @workqueue - workqueue to read the mailbox and handle + * pending requests. Reading the mailbox should not happen + * in interrupt context. + * + * @work - work to submit to workqueue. + * + * @is_ready - driver is ready. + * + * @ask_mbox - Flag to request reading the mailbox, + * for different reasons. + * + * @wake_lock - Lock when can't sleep. + * + * @lpm_chan - Channel to use for LPM (low power mode) + * communication. + * + * @is_ok_to_sleep - Mark if driver is OK with going to sleep + * (no pending transactions). + * + * @inactivity_time - time allowed to be in inactivity before + * going to sleep + * + * @timer - timer to use for polling the mailbox. + * + * @poll_delay_msec - timer delay for polling the mailbox. + * + * @is_err - error detected. + * + * @signature - Context Validity Check. + * + * @flashless_boot_on - flag to indicate if sdio_al is in + * flshless boot mode + * + */ +struct sdio_al_device { + struct sdio_al_local_log *dev_log; + struct mmc_card *card; + struct mmc_host *host; + struct sdio_mailbox *mailbox; + struct sdio_channel channel[SDIO_AL_MAX_CHANNELS]; + + struct peer_sdioc_sw_header *sdioc_sw_header; + struct peer_sdioc_boot_sw_header *sdioc_boot_sw_header; + + struct workqueue_struct *workqueue; + struct sdio_al_work sdio_al_work; + struct sdio_al_work boot_work; + + int is_ready; + + wait_queue_head_t wait_mbox; + int ask_mbox; + int bootloader_done; + + struct wake_lock wake_lock; + int lpm_chan; + int is_ok_to_sleep; + unsigned long inactivity_time; + + struct timer_list timer; + u32 poll_delay_msec; + int is_timer_initialized; + + int is_err; + + u32 signature; + + unsigned int is_suspended; + + int flashless_boot_on; + int ch_close_supported; + int state; + int (*lpm_callback)(void *, int); + + int print_after_interrupt; + + u8 *rx_flush_buf; +}; + +/* + * Host operation: + * lower 16bits are operation code + * upper 16bits are operation state + */ +#define PEER_OPERATION(op_code , op_state) ((op_code) | ((op_state) << 16)) +#define GET_PEER_OPERATION_CODE(op) ((op) & 0xffff) +#define GET_PEER_OPERATION_STATE(op) ((op) >> 16) + +enum peer_op_code { + PEER_OP_CODE_CLOSE = 1 +}; + +enum peer_op_state { + PEER_OP_STATE_INIT = 0, + PEER_OP_STATE_START = 1 +}; + + +/* + * On the kernel command line specify + * sdio_al.debug_lpm_on=1 to enable the LPM debug messages + * By default the LPM debug messages are turned off + */ +static int debug_lpm_on; +module_param(debug_lpm_on, int, 0); + +/* + * On the kernel command line specify + * sdio_al.debug_data_on=1 to enable the DATA debug messages + * By default the DATA debug messages are turned off + */ +static int debug_data_on; +module_param(debug_data_on, int, 0); + +/* + * Enables / disables open close debug messages + */ +static int debug_close_on = 1; +module_param(debug_close_on, int, 0); + +/** The driver context */ +static struct sdio_al *sdio_al; + +/* Static functions declaration */ +static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev, + int pipe_index, int enable); +static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev, + int pipe_index, int enable); +static void sdio_func_irq(struct sdio_func *func); +static void sdio_al_timer_handler(unsigned long data); +static int get_min_poll_time_msec(struct sdio_al_device *sdio_al_dev); +static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot); +static u32 remove_handled_rx_packet(struct sdio_channel *ch); +static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev, + int pipe_index, int threshold); +static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev, + u32 not_from_int, struct sdio_channel *ch); +static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev); +static int enable_mask_irq(struct sdio_al_device *sdio_al_dev, + int func_num, int enable, u8 bit_offset); +static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name); +static void sdio_al_print_info(void); +static int sdio_read_internal(struct sdio_channel *ch, void *data, int len); +static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len); +static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev); + +#define SDIO_AL_ERR(func) \ + do { \ + printk_once(KERN_ERR MODULE_NAME \ + ":In Error state, ignore %s\n", \ + func); \ + sdio_al_print_info(); \ + } while (0) + +#ifdef CONFIG_DEBUG_FS +static int debug_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t debug_info_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + sdio_al_print_info(); + return 1; +} + +const struct file_operations debug_info_ops = { + .open = debug_info_open, + .write = debug_info_write, +}; + +struct debugfs_blob_wrapper sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES + 1]; + +/* +* +* Trigger on/off for debug messages +* for trigger off the data messages debug level use: +* echo 0 > /sys/kernel/debugfs/sdio_al/debug_data_on +* for trigger on the data messages debug level use: +* echo 1 > /sys/kernel/debugfs/sdio_al/debug_data_on +* for trigger off the lpm messages debug level use: +* echo 0 > /sys/kernel/debugfs/sdio_al/debug_lpm_on +* for trigger on the lpm messages debug level use: +* echo 1 > /sys/kernel/debugfs/sdio_al/debug_lpm_on +*/ +static int sdio_al_debugfs_init(void) +{ + int i, blob_errs = 0; + + sdio_al->debug.sdio_al_debug_root = debugfs_create_dir("sdio_al", NULL); + if (!sdio_al->debug.sdio_al_debug_root) + return -ENOENT; + + sdio_al->debug.sdio_al_debug_lpm_on = debugfs_create_u8("debug_lpm_on", + S_IRUGO | S_IWUGO, + sdio_al->debug.sdio_al_debug_root, + &sdio_al->debug.debug_lpm_on); + + sdio_al->debug.sdio_al_debug_data_on = debugfs_create_u8( + "debug_data_on", + S_IRUGO | S_IWUGO, + sdio_al->debug.sdio_al_debug_root, + &sdio_al->debug.debug_data_on); + + sdio_al->debug.sdio_al_debug_close_on = debugfs_create_u8( + "debug_close_on", + S_IRUGO | S_IWUGO, + sdio_al->debug.sdio_al_debug_root, + &sdio_al->debug.debug_close_on); + + sdio_al->debug.sdio_al_debug_info = debugfs_create_file( + "sdio_debug_info", + S_IRUGO | S_IWUGO, + sdio_al->debug.sdio_al_debug_root, + NULL, + &debug_info_ops); + + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) { + char temp[18]; + + scnprintf(temp, 18, "sdio_al_log_dev_%d", i + 1); + sdio_al->debug.sdio_al_debug_log_buffers[i] = + debugfs_create_blob(temp, + S_IRUGO | S_IWUGO, + sdio_al->debug.sdio_al_debug_root, + &sdio_al_dbgfs_log[i]); + } + + sdio_al->debug.sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES] = + debugfs_create_blob("sdio_al_gen_log", + S_IRUGO | S_IWUGO, + sdio_al->debug.sdio_al_debug_root, + &sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES]); + + for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) { + if (!sdio_al->debug.sdio_al_debug_log_buffers[i]) { + pr_err(MODULE_NAME ": Failed to create debugfs buffer" + " entry for " + "sdio_al->debug.sdio_al_debug_log_buffers[%d]", + i); + blob_errs = 1; + } + } + + if (blob_errs) { + for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) + if (sdio_al->debug.sdio_al_debug_log_buffers[i]) + debugfs_remove( + sdio_al-> + debug.sdio_al_debug_log_buffers[i]); + } + + + if ((!sdio_al->debug.sdio_al_debug_data_on) && + (!sdio_al->debug.sdio_al_debug_lpm_on) && + (!sdio_al->debug.sdio_al_debug_close_on) && + (!sdio_al->debug.sdio_al_debug_info) && + blob_errs) { + debugfs_remove(sdio_al->debug.sdio_al_debug_root); + sdio_al->debug.sdio_al_debug_root = NULL; + return -ENOENT; + } + + sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].data = + sdio_al->gen_log.buffer; + sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].size = + SDIO_AL_DEBUG_LOG_SIZE; + + return 0; +} + +static void sdio_al_debugfs_cleanup(void) +{ + int i; + + debugfs_remove(sdio_al->debug.sdio_al_debug_lpm_on); + debugfs_remove(sdio_al->debug.sdio_al_debug_data_on); + debugfs_remove(sdio_al->debug.sdio_al_debug_close_on); + debugfs_remove(sdio_al->debug.sdio_al_debug_info); + + for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) + debugfs_remove(sdio_al->debug.sdio_al_debug_log_buffers[i]); + + debugfs_remove(sdio_al->debug.sdio_al_debug_root); +} +#endif + +static int sdio_al_log(struct sdio_al_local_log *log, const char *fmt, ...) +{ + va_list args; + int r; + char *tp, *log_buf; + unsigned int *log_cur_pos; + struct timeval kt; + unsigned long flags; + static char sdio_al_log_tmp[SDIO_AL_DEBUG_TMP_LOG_SIZE]; + + spin_lock_irqsave(&log->log_lock, flags); + + kt = ktime_to_timeval(ktime_get()); + r = scnprintf(sdio_al_log_tmp, SDIO_AL_DEBUG_TMP_LOG_SIZE, + "[%8ld.%6ld] ", kt.tv_sec, kt.tv_usec); + + va_start(args, fmt); + r += vscnprintf(&sdio_al_log_tmp[r], (SDIO_AL_DEBUG_TMP_LOG_SIZE - r), + fmt, args); + va_end(args); + + log_buf = log->buffer; + log_cur_pos = &(log->buf_cur_pos); + + for (tp = sdio_al_log_tmp; tp < (sdio_al_log_tmp + r); tp++) { + log_buf[(*log_cur_pos)++] = *tp; + if ((*log_cur_pos) == SDIO_AL_DEBUG_LOG_SIZE) + *log_cur_pos = 0; + } + + spin_unlock_irqrestore(&log->log_lock, flags); + + return r; +} + +static int sdio_al_verify_func1(struct sdio_al_device *sdio_al_dev, + char const *func) +{ + if (sdio_al_dev == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "sdio_al_dev\n", func); + return -ENODEV; + } + + if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid " + "signature\n", func); + return -ENODEV; + } + + if (!sdio_al_dev->card) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL " + "card\n", func); + return -ENODEV; + } + if (!sdio_al_dev->card->sdio_func[0]) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL " + "func1\n", func); + return -ENODEV; + } + return 0; +} + +static int sdio_al_claim_mutex(struct sdio_al_device *sdio_al_dev, + char const *func) +{ + if (!sdio_al_dev) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "device\n", func); + return -ENODEV; + } + + if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid " + "device signature\n", func); + return -ENODEV; + } + + if (!sdio_al_dev->host) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL " + "host\n", func); + return -ENODEV; + } + + mmc_claim_host(sdio_al_dev->host); + + return 0; +} + +static int sdio_al_release_mutex(struct sdio_al_device *sdio_al_dev, + char const *func) +{ + if (!sdio_al_dev) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "device\n", func); + return -ENODEV; + } + + if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid " + "device signature\n", func); + return -ENODEV; + } + + if (!sdio_al_dev->host) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL " + "host\n", func); + return -ENODEV; + } + + mmc_release_host(sdio_al_dev->host); + + return 0; +} + +static int sdio_al_claim_mutex_and_verify_dev( + struct sdio_al_device *sdio_al_dev, + char const *func) +{ + if (sdio_al_claim_mutex(sdio_al_dev, __func__)) + return -ENODEV; + + if (sdio_al_dev->state != CARD_INSERTED) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid " + "device state %d\n", func, sdio_al_dev->state); + sdio_al_release_mutex(sdio_al_dev, __func__); + return -ENODEV; + } + + return 0; +} + +static void sdio_al_get_into_err_state(struct sdio_al_device *sdio_al_dev) +{ + if ((!sdio_al) || (!sdio_al_dev)) + return; + + sdio_al_dev->is_err = true; + sdio_al->debug.debug_data_on = 0; + sdio_al->debug.debug_lpm_on = 0; + sdio_al_print_info(); +} + +void sdio_al_register_lpm_cb(void *device_handle, + int(*lpm_callback)(void *, int)) +{ + struct sdio_al_device *sdio_al_dev = + (struct sdio_al_device *) device_handle; + + if (!sdio_al_dev) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - " + "device_handle is NULL\n", __func__); + return; + } + + if (lpm_callback) { + sdio_al_dev->lpm_callback = lpm_callback; + lpm_callback((void *)sdio_al_dev, + sdio_al_dev->is_ok_to_sleep); + } + + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d " + "registered for wakeup callback\n", __func__, + sdio_al_dev->host->index); +} + +void sdio_al_unregister_lpm_cb(void *device_handle) +{ + struct sdio_al_device *sdio_al_dev = + (struct sdio_al_device *) device_handle; + + if (!sdio_al_dev) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - " + "device_handle is NULL\n", __func__); + return; + } + + sdio_al_dev->lpm_callback = NULL; + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d " + "unregister for wakeup callback\n", __func__, + sdio_al_dev->host->index); +} + +static void sdio_al_vote_for_sleep(struct sdio_al_device *sdio_al_dev, + int is_vote_for_sleep) +{ + pr_debug(MODULE_NAME ": %s()", __func__); + + if (!sdio_al_dev) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - sdio_al_dev" + " is NULL\n", __func__); + return; + } + + if (is_vote_for_sleep) { + pr_debug(MODULE_NAME ": %s - sdio vote for Sleep", __func__); + wake_unlock(&sdio_al_dev->wake_lock); + } else { + pr_debug(MODULE_NAME ": %s - sdio vote against sleep", + __func__); + wake_lock(&sdio_al_dev->wake_lock); + } + + if (sdio_al_dev->lpm_callback != NULL) { + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - " + "is_vote_for_sleep=%d for card#%d, " + "calling callback...", __func__, + is_vote_for_sleep, + sdio_al_dev->host->index); + sdio_al_dev->lpm_callback((void *)sdio_al_dev, + is_vote_for_sleep); + } +} + +/** + * Write SDIO-Client lpm information + * Should only be called with host claimed. + */ +static int write_lpm_info(struct sdio_al_device *sdio_al_dev) +{ + struct sdio_func *lpm_func = NULL; + int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+ + sizeof(struct peer_sdioc_channel_config) * + sdio_al_dev->lpm_chan+ + offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep); + int ret; + + if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid " + "lpm_chan for card %d\n", + sdio_al_dev->host->index); + return -EINVAL; + } + + if (!sdio_al_dev->card || + !sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": NULL card or lpm_func\n"); + return -ENODEV; + } + lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]; + + pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n", + sdio_al_dev->is_ok_to_sleep, + sdio_al_dev->host->index); + + ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset, + &sdio_al_dev->is_ok_to_sleep, sizeof(u32)); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to " + "write lpm info for card %d\n", + sdio_al_dev->host->index); + return ret; + } + + return 0; +} + +/* Set inactivity counter to intial value to allow clients come up */ +static inline void start_inactive_time(struct sdio_al_device *sdio_al_dev) +{ + sdio_al_dev->inactivity_time = jiffies + + msecs_to_jiffies(INITIAL_INACTIVITY_TIME_MSEC); +} + +static inline void restart_inactive_time(struct sdio_al_device *sdio_al_dev) +{ + sdio_al_dev->inactivity_time = jiffies + + msecs_to_jiffies(INACTIVITY_TIME_MSEC); +} + +static inline int is_inactive_time_expired(struct sdio_al_device *sdio_al_dev) +{ + return time_after(jiffies, sdio_al_dev->inactivity_time); +} + + +static int is_user_irq_enabled(struct sdio_al_device *sdio_al_dev, + int func_num) +{ + int ret = 0; + struct sdio_func *func1; + u32 user_irq = 0; + u32 addr = 0; + u32 offset = 0; + u32 masked_user_irq = 0; + + if (sdio_al_verify_func1(sdio_al_dev, __func__)) + return 0; + func1 = sdio_al_dev->card->sdio_func[0]; + + if (func_num < 4) { + addr = FUNC_1_4_USER_IRQ_ADDR; + offset = func_num * 8; + } else { + addr = FUNC_5_7_USER_IRQ_ADDR; + offset = (func_num - 4) * 8; + } + + user_irq = sdio_readl(func1, addr, &ret); + if (ret) { + pr_debug(MODULE_NAME ":read_user_irq fail\n"); + return 0; + } + + masked_user_irq = (user_irq >> offset) && 0xFF; + if (masked_user_irq == 0x1) { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":user_irq " + "enabled\n"); + return 1; + } + + return 0; +} + +static void sdio_al_sleep(struct sdio_al_device *sdio_al_dev, + struct mmc_host *host) +{ + int i; + + /* Go to sleep */ + pr_debug(MODULE_NAME ":Inactivity timer expired." + " Going to sleep\n"); + /* Stop mailbox timer */ + stop_and_del_timer(sdio_al_dev); + /* Make sure we get interrupt for non-packet-mode right away */ + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + struct sdio_channel *ch = &sdio_al_dev->channel[i]; + if ((ch->state != SDIO_CHANNEL_STATE_OPEN) && + (ch->state != SDIO_CHANNEL_STATE_CLOSED)) { + pr_debug(MODULE_NAME ":continue for channel %s in" + " state %d\n", ch->name, ch->state); + continue; + } + if (ch->is_packet_mode == false) { + ch->read_threshold = LOW_LATENCY_THRESHOLD; + set_pipe_threshold(sdio_al_dev, + ch->rx_pipe_index, + ch->read_threshold); + } + } + /* Prevent modem to go to sleep until we get the PROG_DONE on + the dummy CMD52 */ + msmsdcc_set_pwrsave(sdio_al_dev->host, 0); + /* Mark HOST_OK_TOSLEEP */ + sdio_al_dev->is_ok_to_sleep = 1; + write_lpm_info(sdio_al_dev); + + msmsdcc_lpm_enable(host); + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence" + " for card %d. Sleep now.\n", + sdio_al_dev->host->index); + /* Release wakelock */ + sdio_al_vote_for_sleep(sdio_al_dev, 1); +} + + +/** + * Read SDIO-Client Mailbox from Function#1.thresh_pipe + * + * The mailbox contain the bytes available per pipe, + * and the End-Of-Transfer indication per pipe (if available). + * + * WARNING: Each time the Mailbox is read from the client, the + * read_bytes_avail is incremented with another pending + * transfer. Therefore, a pending rx-packet should be added to a + * list before the next read of the mailbox. + * + * This function should run from a workqueue context since it + * notifies the clients. + * + * This function assumes that sdio_al_claim_mutex was called before + * calling it. + * + */ +static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr) +{ + int ret; + struct sdio_func *func1 = NULL; + struct sdio_mailbox *mailbox = sdio_al_dev->mailbox; + struct mmc_host *host = sdio_al_dev->host; + u32 new_write_avail = 0; + u32 old_write_avail = 0; + u32 any_read_avail = 0; + u32 any_write_pending = 0; + int i; + u32 rx_notify_bitmask = 0; + u32 tx_notify_bitmask = 0; + u32 eot_pipe = 0; + u32 thresh_pipe = 0; + u32 overflow_pipe = 0; + u32 underflow_pipe = 0; + u32 thresh_intr_mask = 0; + int is_closing = 0; + + if (sdio_al_dev->is_err) { + SDIO_AL_ERR(__func__); + return 0; + } + + if (sdio_al_verify_func1(sdio_al_dev, __func__)) + return -ENODEV; + func1 = sdio_al_dev->card->sdio_func[0]; + + pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n" + , __func__, from_isr, sdio_al_dev->host->index); + + pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n"); + memset(mailbox, 0, sizeof(struct sdio_mailbox)); + ret = sdio_memcpy_fromio(func1, mailbox, + HW_MAILBOX_ADDR, sizeof(*mailbox)); + pr_debug(MODULE_NAME ":after sdio_memcpy_fromio.\n"); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read " + "Mailbox for card %d, goto error state\n", + sdio_al_dev->host->index); + sdio_al_get_into_err_state(sdio_al_dev); + goto exit_err; + } + + eot_pipe = (mailbox->eot_pipe_0_7) | + (mailbox->eot_pipe_8_15<<8); + thresh_pipe = (mailbox->thresh_above_limit_pipe_0_7) | + (mailbox->thresh_above_limit_pipe_8_15<<8); + + overflow_pipe = (mailbox->overflow_pipe_0_7) | + (mailbox->overflow_pipe_8_15<<8); + underflow_pipe = mailbox->underflow_pipe_0_7 | + (mailbox->underflow_pipe_8_15<<8); + thresh_intr_mask = + (mailbox->mask_thresh_above_limit_pipe_0_7) | + (mailbox->mask_thresh_above_limit_pipe_8_15<<8); + + if (overflow_pipe || underflow_pipe) + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Mailbox ERROR " + "overflow=0x%x, underflow=0x%x\n", + overflow_pipe, underflow_pipe); + + /* In case of modem reset we would like to read the daya from the modem + to clear the interrupts but do not process it */ + if (sdio_al_dev->state != CARD_INSERTED) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device" + " (card %d) is in invalid state %d\n", + sdio_al_dev->host->index, + sdio_al_dev->state); + return -ENODEV; + } + + pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n", + sdio_al_dev->host->index, + eot_pipe, thresh_pipe); + + /* Scan for Rx Packets available and update read available bytes */ + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + struct sdio_channel *ch = &sdio_al_dev->channel[i]; + u32 old_read_avail; + u32 read_avail; + u32 new_packet_size = 0; + + if (ch->state == SDIO_CHANNEL_STATE_CLOSING) + is_closing = true; /* used to prevent sleep */ + + old_read_avail = ch->read_avail; + read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index]; + + if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) && + (read_avail > 0)) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ":%s: Invalid read_avail 0x%x, for CLOSED ch %s\n", + __func__, read_avail, ch->name); + sdio_read_from_closed_ch(ch, read_avail); + } + if ((ch->state != SDIO_CHANNEL_STATE_OPEN) && + (ch->state != SDIO_CHANNEL_STATE_CLOSING)) + continue; + + if (read_avail > INVALID_DATA_AVAILABLE) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ":Invalid read_avail 0x%x for pipe %d\n", + read_avail, ch->rx_pipe_index); + continue; + } + any_read_avail |= read_avail | old_read_avail; + ch->statistics.last_any_read_avail = any_read_avail; + ch->statistics.last_read_avail = read_avail; + ch->statistics.last_old_read_avail = old_read_avail; + + if (ch->is_packet_mode) { + if ((eot_pipe & (1<rx_pipe_index)) && + sdio_al_dev->print_after_interrupt) { + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME + ":Interrupt on ch %s, " + "card %d", ch->name, + sdio_al_dev->host->index); + } + new_packet_size = check_pending_rx_packet(ch, eot_pipe); + } else { + if ((thresh_pipe & (1<rx_pipe_index)) && + sdio_al_dev->print_after_interrupt) { + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME + ":Interrupt on ch %s, " + "card %d", ch->name, + sdio_al_dev->host->index); + } + ch->read_avail = read_avail; + + /* + * Restore default thresh for non packet channels. + * in case it IS low latency channel then read_threshold + * and def_read_threshold are both + * LOW_LATENCY_THRESHOLD + */ + if ((ch->read_threshold != ch->def_read_threshold) && + (read_avail >= ch->threshold_change_cnt)) { + if (!ch->is_low_latency_ch) { + ch->read_threshold = + ch->def_read_threshold; + set_pipe_threshold(sdio_al_dev, + ch->rx_pipe_index, + ch->read_threshold); + } + } + } + + if ((ch->is_packet_mode) && (new_packet_size > 0)) { + rx_notify_bitmask |= (1<num); + ch->statistics.total_notifs++; + } + + if ((!ch->is_packet_mode) && (ch->read_avail > 0) && + (old_read_avail == 0)) { + rx_notify_bitmask |= (1<num); + ch->statistics.total_notifs++; + } + } + sdio_al_dev->print_after_interrupt = 0; + + /* Update Write available */ + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + struct sdio_channel *ch = &sdio_al_dev->channel[i]; + + if ((ch->state != SDIO_CHANNEL_STATE_OPEN) && + (ch->state != SDIO_CHANNEL_STATE_CLOSING)) + continue; + + new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index]; + + if (new_write_avail > INVALID_DATA_AVAILABLE) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ":Invalid write_avail 0x%x for pipe %d\n", + new_write_avail, ch->tx_pipe_index); + continue; + } + + old_write_avail = ch->write_avail; + ch->write_avail = new_write_avail; + + if ((old_write_avail <= ch->min_write_avail) && + (new_write_avail >= ch->min_write_avail)) + tx_notify_bitmask |= (1<num); + + /* There is not enough write avail for this channel. + We need to keep reading mailbox to wait for the appropriate + write avail and cannot sleep. Ignore SMEM channel that has + only one direction. */ + if (strncmp(ch->name, "SDIO_SMEM", CHANNEL_NAME_SIZE)) + any_write_pending |= + (new_write_avail < ch->ch_config.max_tx_threshold); + } + /* notify clients */ + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + struct sdio_channel *ch = &sdio_al_dev->channel[i]; + + if ((ch->state != SDIO_CHANNEL_STATE_OPEN) || + (ch->notify == NULL)) + continue; + + if (rx_notify_bitmask & (1<num)) + ch->notify(ch->priv, + SDIO_EVENT_DATA_READ_AVAIL); + + if (tx_notify_bitmask & (1<num)) + ch->notify(ch->priv, + SDIO_EVENT_DATA_WRITE_AVAIL); + } + + + if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) && + !any_read_avail && !any_write_pending) { + DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to " + "Notify for card %d, is_closing=%d\n", + sdio_al_dev->host->index, is_closing); + if (is_closing) + restart_inactive_time(sdio_al_dev); + else if (is_inactive_time_expired(sdio_al_dev)) + sdio_al_sleep(sdio_al_dev, host); + } else { + DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask" + " for card %d rx=0x%x, tx=0x%x.\n", + sdio_al_dev->host->index, + rx_notify_bitmask, tx_notify_bitmask); + /* Restart inactivity timer if any activity on the channel */ + restart_inactive_time(sdio_al_dev); + } + + pr_debug(MODULE_NAME ":end %s.\n", __func__); + +exit_err: + return ret; +} + +/** + * Check pending rx packet when reading the mailbox. + */ +static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot) +{ + u32 rx_pending; + u32 rx_avail; + u32 new_packet_size = 0; + struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev; + + + if (sdio_al_dev == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev" + " for channel %s\n", ch->name); + return -EINVAL; + } + + mutex_lock(&ch->ch_lock); + + rx_pending = ch->rx_pending_bytes; + rx_avail = sdio_al_dev->mailbox->pipe_bytes_avail[ch->rx_pipe_index]; + + pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, " + "rx_pending=0x%x\n", + ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail, + rx_pending); + + + /* new packet detected */ + if (eot & (1<rx_pipe_index)) { + struct rx_packet_size *p = NULL; + new_packet_size = rx_avail - rx_pending; + + if ((rx_avail <= rx_pending)) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": Invalid new packet size." + " rx_avail=%d.\n", rx_avail); + new_packet_size = 0; + goto exit_err; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": failed to allocate item for " + "rx_pending list. rx_avail=%d, " + "rx_pending=%d.\n", + rx_avail, rx_pending); + new_packet_size = 0; + goto exit_err; + } + p->size = new_packet_size; + /* Add new packet as last */ + list_add_tail(&p->list, &ch->rx_size_list_head); + ch->rx_pending_bytes += new_packet_size; + + if (ch->read_avail == 0) + ch->read_avail = new_packet_size; + } + +exit_err: + mutex_unlock(&ch->ch_lock); + + return new_packet_size; +} + + + +/** + * Remove first pending packet from the list. + */ +static u32 remove_handled_rx_packet(struct sdio_channel *ch) +{ + struct rx_packet_size *p = NULL; + + mutex_lock(&ch->ch_lock); + + ch->rx_pending_bytes -= ch->read_avail; + + if (!list_empty(&ch->rx_size_list_head)) { + p = list_first_entry(&ch->rx_size_list_head, + struct rx_packet_size, list); + list_del(&p->list); + kfree(p); + } else { + sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: ch " + "%s: unexpected empty list!!\n", + __func__, ch->name); + } + + if (list_empty(&ch->rx_size_list_head)) { + ch->read_avail = 0; + } else { + p = list_first_entry(&ch->rx_size_list_head, + struct rx_packet_size, list); + ch->read_avail = p->size; + } + + mutex_unlock(&ch->ch_lock); + + return ch->read_avail; +} + + +/** + * Bootloader worker function. + * + * @note: clear the bootloader_done flag only after reading the + * mailbox, to ignore more requests while reading the mailbox. + */ +static void boot_worker(struct work_struct *work) +{ + int ret = 0; + int func_num = 0; + int i; + struct sdio_al_device *sdio_al_dev = NULL; + struct sdio_al_work *sdio_al_work = container_of(work, + struct sdio_al_work, + work); + + if (sdio_al_work == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "sdio_al_work\n", __func__); + return; + } + + sdio_al_dev = sdio_al_work->sdio_al_dev; + if (sdio_al_dev == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "sdio_al_dev\n", __func__); + return; + } + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Bootloader Worker Started" + ", wait for bootloader_done event..\n"); + wait_event(sdio_al_dev->wait_mbox, + sdio_al_dev->bootloader_done); + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Got bootloader_done " + "event..\n"); + /* Do polling until MDM is up */ + for (i = 0; i < 5000; ++i) { + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return; + if (is_user_irq_enabled(sdio_al_dev, func_num)) { + sdio_al_release_mutex(sdio_al_dev, __func__); + sdio_al_dev->bootloader_done = 0; + ret = sdio_al_client_setup(sdio_al_dev); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": sdio_al_client_setup failed, " + "for card %d ret=%d\n", + sdio_al_dev->host->index, ret); + sdio_al_get_into_err_state(sdio_al_dev); + } + goto done; + } + sdio_al_release_mutex(sdio_al_dev, __func__); + msleep(100); + } + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for " + "user_irq for card %d\n", + sdio_al_dev->host->index); + sdio_al_get_into_err_state(sdio_al_dev); + +done: + pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n", + sdio_al_dev->host->index); +} + +/** + * Worker function. + * + * @note: clear the ask_mbox flag only after + * reading the mailbox, to ignore more requests while + * reading the mailbox. + */ +static void worker(struct work_struct *work) +{ + int ret = 0; + struct sdio_al_device *sdio_al_dev = NULL; + struct sdio_al_work *sdio_al_work = container_of(work, + struct sdio_al_work, + work); + if (sdio_al_work == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL " + "sdio_al_work\n"); + return; + } + + sdio_al_dev = sdio_al_work->sdio_al_dev; + if (sdio_al_dev == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL " + "sdio_al_dev\n"); + return; + } + pr_debug(MODULE_NAME ":Worker Started..\n"); + while ((sdio_al_dev->is_ready) && (ret == 0)) { + pr_debug(MODULE_NAME ":Wait for read mailbox request..\n"); + wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox); + if (!sdio_al_dev->is_ready) + break; + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + break; + if (sdio_al_dev->is_ok_to_sleep) { + ret = sdio_al_wake_up(sdio_al_dev, 1, NULL); + if (ret) { + sdio_al_release_mutex(sdio_al_dev, __func__); + return; + } + } + ret = read_mailbox(sdio_al_dev, false); + sdio_al_release_mutex(sdio_al_dev, __func__); + sdio_al_dev->ask_mbox = false; + } + + pr_debug(MODULE_NAME ":Worker Exit!\n"); +} + +/** + * Write command using CMD54 rather than CMD53. + * Writing with CMD54 generate EOT interrupt at the + * SDIO-Client. + * Based on mmc_io_rw_extended() + */ +static int sdio_write_cmd54(struct mmc_card *card, unsigned fn, + unsigned addr, const u8 *buf, + unsigned blocks, unsigned blksz) +{ + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + int incr_addr = 1; /* MUST */ + int write = 1; + + BUG_ON(!card); + BUG_ON(fn > 7); + BUG_ON(blocks == 1 && blksz > 512); + WARN_ON(blocks == 0); + WARN_ON(blksz == 0); + + write = true; + pr_debug(MODULE_NAME ":sdio_write_cmd54()" + "fn=%d,buf=0x%x,blocks=%d,blksz=%d\n", + fn, (u32) buf, blocks, blksz); + + memset(&mrq, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + mrq.cmd = &cmd; + mrq.data = &data; + + cmd.opcode = SD_IO_RW_EXTENDED_QCOM; + + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; + cmd.arg |= addr << 9; + if (blocks == 1 && blksz <= 512) + cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ + else + cmd.arg |= 0x08000000 | blocks; /* block mode */ + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + + data.blksz = blksz; + data.blocks = blocks; + data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + sg_init_one(&sg, buf, blksz * blocks); + + mmc_set_data_timeout(&data, card); + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error) + return cmd.error; + if (data.error) + return data.error; + + if (mmc_host_is_spi(card->host)) { + /* host driver already reported errors */ + } else { + if (cmd.resp[0] & R5_ERROR) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME + ":%s: R5_ERROR for card %d", + __func__, card->host->index); + return -EIO; + } + if (cmd.resp[0] & R5_FUNCTION_NUMBER) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME + ":%s: R5_FUNCTION_NUMBER for card %d", + __func__, card->host->index); + return -EINVAL; + } + if (cmd.resp[0] & R5_OUT_OF_RANGE) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME + ":%s: R5_OUT_OF_RANGE for card %d", + __func__, card->host->index); + return -ERANGE; + } + } + + return 0; +} + + +/** + * Write data to channel. + * Handle different data size types. + * + */ +static int sdio_ch_write(struct sdio_channel *ch, const u8 *buf, u32 len) +{ + int ret = 0; + unsigned blksz = ch->func->cur_blksize; + int blocks = len / blksz; + int remain_bytes = len % blksz; + struct mmc_card *card = NULL; + u32 fn = ch->func->num; + + if (!ch) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "channel\n", __func__); + return -ENODEV; + } + + if (!ch->sdio_al_dev) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "sdio_al_dev\n", __func__); + return -ENODEV; + } + + if (len == 0) { + sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":channel " + "%s trying to write 0 bytes\n", ch->name); + return -EINVAL; + } + + card = ch->func->card; + + if (remain_bytes) { + /* CMD53 */ + if (blocks) { + ret = sdio_memcpy_toio(ch->func, PIPE_TX_FIFO_ADDR, + (void *) buf, blocks*blksz); + if (ret != 0) { + sdio_al_loge(ch->sdio_al_dev->dev_log, + MODULE_NAME ":%s: sdio_memcpy_toio " + "failed for channel %s\n", + __func__, ch->name); + sdio_al_get_into_err_state(ch->sdio_al_dev); + return ret; + } + } + + buf += (blocks*blksz); + + ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR, + buf, 1, remain_bytes); + } else { + ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR, + buf, blocks, blksz); + } + + if (ret != 0) { + sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: " + "sdio_write_cmd54 failed for channel %s\n", + __func__, ch->name); + ch->sdio_al_dev->is_err = true; + return ret; + } + + return ret; +} + +static int sdio_al_bootloader_completed(void) +{ + int i; + + pr_debug(MODULE_NAME ":sdio_al_bootloader_completed was called\n"); + + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) { + struct sdio_al_device *dev = NULL; + if (sdio_al->devices[i] == NULL) + continue; + dev = sdio_al->devices[i]; + dev->bootloader_done = 1; + wake_up(&dev->wait_mbox); + } + + return 0; +} + +static int sdio_al_wait_for_bootloader_comp(struct sdio_al_device *sdio_al_dev) +{ + int ret = 0; + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + /* + * Enable function 0 interrupt mask to allow 9k to raise this interrupt + * in power-up. When sdio_downloader will notify its completion + * we will poll on this interrupt to wait for 9k power-up + */ + ret = enable_mask_irq(sdio_al_dev, 0, 1, 0); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": Enable_mask_irq for card %d failed, " + "ret=%d\n", + sdio_al_dev->host->index, ret); + sdio_al_release_mutex(sdio_al_dev, __func__); + return ret; + } + + sdio_al_release_mutex(sdio_al_dev, __func__); + + /* + * Start bootloader worker that will wait for the bootloader + * completion + */ + sdio_al_dev->boot_work.sdio_al_dev = sdio_al_dev; + INIT_WORK(&sdio_al_dev->boot_work.work, boot_worker); + sdio_al_dev->bootloader_done = 0; + queue_work(sdio_al_dev->workqueue, &sdio_al_dev->boot_work.work); + + return 0; +} + +static int sdio_al_bootloader_setup(void) +{ + int ret = 0; + struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev; + struct sdio_func *func1 = NULL; + + if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__)) + return -ENODEV; + + if (bootloader_dev->flashless_boot_on) { + sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already " + "in boot process.\n"); + sdio_al_release_mutex(bootloader_dev, __func__); + return 0; + } + + bootloader_dev->sdioc_boot_sw_header + = kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header), + GFP_KERNEL); + if (bootloader_dev->sdioc_boot_sw_header == NULL) { + sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to " + "allocate sdioc boot sw header.\n"); + sdio_al_release_mutex(bootloader_dev, __func__); + return -ENOMEM; + } + + if (sdio_al_verify_func1(bootloader_dev, __func__)) { + sdio_al_release_mutex(bootloader_dev, __func__); + goto exit_err; + } + func1 = bootloader_dev->card->sdio_func[0]; + + ret = sdio_memcpy_fromio(func1, + bootloader_dev->sdioc_boot_sw_header, + SDIOC_SW_HEADER_ADDR, + sizeof(struct peer_sdioc_boot_sw_header)); + if (ret) { + sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to " + "read sdioc boot sw header.\n"); + sdio_al_release_mutex(bootloader_dev, __func__); + goto exit_err; + } + + if (bootloader_dev->sdioc_boot_sw_header->signature != + (u32) PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE) { + sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid " + "mailbox signature 0x%x.\n", + bootloader_dev->sdioc_boot_sw_header->signature); + sdio_al_release_mutex(bootloader_dev, __func__); + ret = -EINVAL; + goto exit_err; + } + + /* Upper byte has to be equal - no backward compatibility for unequal */ + if ((bootloader_dev->sdioc_boot_sw_header->version >> 16) != + (sdio_al->pdata->peer_sdioc_boot_version_major)) { + sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ": HOST(0x%x)" + " and CLIENT(0x%x) SDIO_AL BOOT VERSION don't match\n", + ((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+ + sdio_al->pdata->peer_sdioc_boot_version_minor), + bootloader_dev->sdioc_boot_sw_header->version); + sdio_al_release_mutex(bootloader_dev, __func__); + ret = -EIO; + goto exit_err; + } + + sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ": SDIOC BOOT SW " + "version 0x%x\n", + bootloader_dev->sdioc_boot_sw_header->version); + + bootloader_dev->flashless_boot_on = true; + + sdio_al_release_mutex(bootloader_dev, __func__); + + ret = sdio_al_wait_for_bootloader_comp(bootloader_dev); + if (ret) { + sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME + ": sdio_al_wait_for_bootloader_comp failed, " + "err=%d\n", ret); + goto exit_err; + } + + ret = sdio_downloader_setup(bootloader_dev->card, 1, + bootloader_dev->sdioc_boot_sw_header->boot_ch_num, + sdio_al_bootloader_completed); + + if (ret) { + sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME + ": sdio_downloader_setup failed, err=%d\n", ret); + goto exit_err; + } + + sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ":In Flashless boot," + " waiting for its completion\n"); + + +exit_err: + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":free " + "sdioc_boot_sw_header.\n"); + kfree(bootloader_dev->sdioc_boot_sw_header); + bootloader_dev->sdioc_boot_sw_header = NULL; + bootloader_dev = NULL; + + return ret; +} + + +/** + * Read SDIO-Client software header + * + */ +static int read_sdioc_software_header(struct sdio_al_device *sdio_al_dev, + struct peer_sdioc_sw_header *header) +{ + int ret; + int i; + int test_version = 0; + int sdioc_test_version = 0; + struct sdio_func *func1 = NULL; + + pr_debug(MODULE_NAME ":reading sdioc sw header.\n"); + + if (sdio_al_verify_func1(sdio_al_dev, __func__)) + return -ENODEV; + + func1 = sdio_al_dev->card->sdio_func[0]; + + ret = sdio_memcpy_fromio(func1, header, + SDIOC_SW_HEADER_ADDR, sizeof(*header)); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read " + "sdioc sw header.\n"); + goto exit_err; + } + + if (header->signature == (u32)PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE) { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW " + "unittest signature. 0x%x\n", + header->signature); + sdio_al->unittest_mode = true; + /* Verify test code compatibility with the modem */ + sdioc_test_version = (header->version & 0xFF00) >> 8; + test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8; + if (test_version != sdioc_test_version) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": HOST(0x%x) and CLIENT(0x%x) " + "testing VERSION don't match\n", + test_version, + sdioc_test_version); + msleep(500); + BUG(); + } + } + + if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) && + (header->signature != (u32) PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE)) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW " + "invalid signature. 0x%x\n", header->signature); + goto exit_err; + } + /* Upper byte has to be equal - no backward compatibility for unequal */ + sdio_al->sdioc_major = header->version >> 16; + if (sdio_al->pdata->allow_sdioc_version_major_2) { + if ((sdio_al->sdioc_major != + sdio_al->pdata->peer_sdioc_version_major) && + (sdio_al->sdioc_major != PEER_SDIOC_OLD_VERSION_MAJOR)) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": HOST(0x%x) and CLIENT(0x%x) " + "SDIO_AL VERSION don't match\n", + ((sdio_al->pdata->peer_sdioc_version_major<<16)+ + sdio_al->pdata->peer_sdioc_version_minor), + header->version); + goto exit_err; + } + } else { + if (sdio_al->sdioc_major != + sdio_al->pdata->peer_sdioc_version_major) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": HOST(0x%x) and CLIENT(0x%x) " + "SDIO_AL VERSION don't match\n", + ((sdio_al->pdata->peer_sdioc_version_major<<16)+ + sdio_al->pdata->peer_sdioc_version_minor), + header->version); + goto exit_err; + } + } + sdio_al_dev->ch_close_supported = (header->version & 0x000F) >= + (sdio_al->pdata->peer_sdioc_version_minor & 0xF); + + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW version 0x%x," + " sdio_al major 0x%x minor 0x%x\n", header->version, + sdio_al->sdioc_major, + sdio_al->pdata->peer_sdioc_version_minor); + + sdio_al_dev->flashless_boot_on = false; + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + struct sdio_channel *ch = &sdio_al_dev->channel[i]; + + /* Set default values */ + ch->read_threshold = DEFAULT_READ_THRESHOLD; + ch->write_threshold = DEFAULT_WRITE_THRESHOLD; + ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD; + ch->is_packet_mode = true; + ch->peer_tx_buf_size = DEFAULT_PEER_TX_BUF_SIZE; + ch->poll_delay_msec = 0; + + ch->num = i; + ch->func = NULL; + ch->rx_pipe_index = ch->num*2; + ch->tx_pipe_index = ch->num*2+1; + + memset(ch->name, 0, sizeof(ch->name)); + + if (header->channel_names[i][0]) { + memcpy(ch->name, SDIO_PREFIX, + strlen(SDIO_PREFIX)); + memcpy(ch->name + strlen(SDIO_PREFIX), + header->channel_names[i], + PEER_CHANNEL_NAME_SIZE); + + ch->state = SDIO_CHANNEL_STATE_IDLE; + ch->sdio_al_dev = sdio_al_dev; + if (sdio_al_dev->card->sdio_func[ch->num+1]) { + ch->func = + sdio_al_dev->card->sdio_func[ch->num+1]; + } else { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": NULL func for channel %s\n", + ch->name); + goto exit_err; + } + } else { + ch->state = SDIO_CHANNEL_STATE_INVALID; + } + + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Channel=%s, " + "state=%d\n", ch->name, ch->state); + } + + return 0; + +exit_err: + sdio_al_get_into_err_state(sdio_al_dev); + memset(header, 0, sizeof(*header)); + + return -EIO; +} + +/** + * Read SDIO-Client channel configuration + * + */ +static int read_sdioc_channel_config(struct sdio_channel *ch) +{ + int ret; + struct peer_sdioc_sw_mailbox *sw_mailbox = NULL; + struct peer_sdioc_channel_config *ch_config = NULL; + struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev; + + if (sdio_al_dev == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev" + " for channel %s\n", ch->name); + return -EINVAL; + } + + if (sdio_al_dev->sdioc_sw_header->version == 0) + return -1; + + pr_debug(MODULE_NAME ":reading sw mailbox %s channel.\n", ch->name); + + sw_mailbox = kzalloc(sizeof(*sw_mailbox), GFP_KERNEL); + if (sw_mailbox == NULL) + return -ENOMEM; + + ret = sdio_memcpy_fromio(ch->func, sw_mailbox, + SDIOC_SW_MAILBOX_ADDR, sizeof(*sw_mailbox)); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read " + "sw mailbox.\n"); + goto exit_err; + } + + ch_config = &sw_mailbox->ch_config[ch->num]; + memcpy(&ch->ch_config, ch_config, + sizeof(struct peer_sdioc_channel_config)); + + if (!ch_config->is_ready) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sw mailbox " + "channel not ready.\n"); + goto exit_err; + } + + ch->read_threshold = LOW_LATENCY_THRESHOLD; + ch->is_low_latency_ch = ch_config->is_low_latency_ch; + /* Threshold on 50% of the maximum size , sdioc uses double-buffer */ + ch->write_threshold = (ch_config->max_tx_threshold * 5) / 10; + ch->threshold_change_cnt = ch->ch_config.max_rx_threshold - + ch->read_threshold + THRESHOLD_CHANGE_EXTRA_BYTES; + + if (ch->is_low_latency_ch) + ch->def_read_threshold = LOW_LATENCY_THRESHOLD; + else /* Aggregation up to 90% of the maximum size */ + ch->def_read_threshold = (ch_config->max_rx_threshold * 9) / 10; + + ch->is_packet_mode = ch_config->is_packet_mode; + if (!ch->is_packet_mode) { + ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC; + ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING; + } + /* The max_packet_size is set by the modem in version 3 and on */ + if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR) + ch->min_write_avail = ch_config->max_packet_size; + + if (ch->min_write_avail > ch->write_threshold) + ch->min_write_avail = ch->write_threshold; + + CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":ch %s " + "read_threshold=%d, write_threshold=%d," + " min_write_avail=%d, max_rx_threshold=%d," + " max_tx_threshold=%d\n", ch->name, ch->read_threshold, + ch->write_threshold, ch->min_write_avail, + ch_config->max_rx_threshold, + ch_config->max_tx_threshold); + + ch->peer_tx_buf_size = ch_config->tx_buf_size; + + kfree(sw_mailbox); + + return 0; + +exit_err: + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Reading SW Mailbox " + "error.\n"); + kfree(sw_mailbox); + + return -1; +} + + +/** + * Enable/Disable EOT interrupt of a pipe. + * + */ +static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev, + int pipe_index, int enable) +{ + int ret = 0; + struct sdio_func *func1; + u32 mask; + u32 pipe_mask; + u32 addr; + + if (sdio_al_verify_func1(sdio_al_dev, __func__)) + return -ENODEV; + func1 = sdio_al_dev->card->sdio_func[0]; + + if (pipe_index < 8) { + addr = PIPES_0_7_IRQ_MASK_ADDR; + pipe_mask = (1<card->sdio_func[0]; + + if (func_num < 4) { + addr = FUNC_1_4_MASK_IRQ_ADDR; + offset = func_num * 8 + bit_offset; + } else { + addr = FUNC_5_7_MASK_IRQ_ADDR; + offset = (func_num - 4) * 8 + bit_offset; + } + + func_mask = 1<dev_log, MODULE_NAME ": " + "enable_mask_irq fail\n"); + goto exit_err; + } + + if (enable) + mask &= (~func_mask); /* 0 = enable */ + else + mask |= (func_mask); /* 1 = disable */ + + pr_debug(MODULE_NAME ":enable_mask_irq, writing mask = 0x%x\n", mask); + + sdio_writel(func1, mask, addr, &ret); + +exit_err: + return ret; +} + +/** + * Enable/Disable Threshold interrupt of a pipe. + * + */ +static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev, + int pipe_index, int enable) +{ + int ret = 0; + struct sdio_func *func1; + u32 mask; + u32 pipe_mask; + u32 addr; + + if (sdio_al_verify_func1(sdio_al_dev, __func__)) + return -ENODEV; + func1 = sdio_al_dev->card->sdio_func[0]; + + if (pipe_index < 8) { + addr = PIPES_0_7_IRQ_MASK_ADDR; + pipe_mask = (1<card->sdio_func[0]; + + sdio_writel(func1, threshold, + PIPES_THRESHOLD_ADDR+pipe_index*4, &ret); + if (ret) + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": " + "set_pipe_threshold err=%d\n", -ret); + + return ret; +} + +/** + * Enable func w/ retries + * + */ +static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name) +{ + int ret, i; + for (i = 0; i < 200; i++) { + ret = sdio_enable_func(func); + if (ret) { + pr_debug(MODULE_NAME ":retry enable %s func#%d " + "ret=%d\n", + name, func->num, ret); + msleep(10); + } else + break; + } + + return ret; +} + +/** + * Open Channel + * + * 1. Init Channel Context. + * 2. Init the Channel SDIO-Function. + * 3. Init the Channel Pipes on Mailbox. + */ +static int open_channel(struct sdio_channel *ch) +{ + int ret = 0; + struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev; + + if (sdio_al_dev == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL " + "sdio_al_dev for channel %s\n", ch->name); + return -EINVAL; + } + + /* Init channel Context */ + /** Func#1 is reserved for mailbox */ + ch->func = sdio_al_dev->card->sdio_func[ch->num+1]; + ch->rx_pipe_index = ch->num*2; + ch->tx_pipe_index = ch->num*2+1; + ch->signature = SDIO_AL_SIGNATURE; + + ch->total_rx_bytes = 0; + ch->total_tx_bytes = 0; + + ch->write_avail = 0; + ch->read_avail = 0; + ch->rx_pending_bytes = 0; + + mutex_init(&ch->ch_lock); + + pr_debug(MODULE_NAME ":open_channel %s func#%d\n", + ch->name, ch->func->num); + + INIT_LIST_HEAD(&(ch->rx_size_list_head)); + + /* Init SDIO Function */ + ret = sdio_al_enable_func_retry(ch->func, ch->name); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": " + "sdio_enable_func() err=%d\n", -ret); + goto exit_err; + } + + /* Note: Patch Func CIS tuple issue */ + ret = sdio_set_block_size(ch->func, SDIO_AL_BLOCK_SIZE); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": " + "sdio_set_block_size()failed, err=%d\n", -ret); + goto exit_err; + } + + ch->func->max_blksize = SDIO_AL_BLOCK_SIZE; + + sdio_set_drvdata(ch->func, ch); + + /* Get channel parameters from the peer SDIO-Client */ + read_sdioc_channel_config(ch); + + /* Set Pipes Threshold on Mailbox */ + ret = set_pipe_threshold(sdio_al_dev, + ch->rx_pipe_index, ch->read_threshold); + if (ret) + goto exit_err; + ret = set_pipe_threshold(sdio_al_dev, + ch->tx_pipe_index, ch->write_threshold); + if (ret) + goto exit_err; + + /* Set flag before interrupts are enabled to allow notify */ + ch->state = SDIO_CHANNEL_STATE_OPEN; + pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name); + + sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev); + + /* lpm mechanism lives under the assumption there is always a timer */ + /* Check if need to start the timer */ + if ((sdio_al_dev->poll_delay_msec) && + (sdio_al_dev->is_timer_initialized == false)) { + + init_timer(&sdio_al_dev->timer); + sdio_al_dev->timer.data = (unsigned long) sdio_al_dev; + sdio_al_dev->timer.function = sdio_al_timer_handler; + sdio_al_dev->timer.expires = jiffies + + msecs_to_jiffies(sdio_al_dev->poll_delay_msec); + add_timer(&sdio_al_dev->timer); + sdio_al_dev->is_timer_initialized = true; + } + + /* Enable Pipes Interrupts */ + enable_eot_interrupt(sdio_al_dev, ch->rx_pipe_index, true); + enable_eot_interrupt(sdio_al_dev, ch->tx_pipe_index, true); + + enable_threshold_interrupt(sdio_al_dev, ch->rx_pipe_index, true); + enable_threshold_interrupt(sdio_al_dev, ch->tx_pipe_index, true); + +exit_err: + + return ret; +} + +/** + * Ask the worker to read the mailbox. + */ +static void ask_reading_mailbox(struct sdio_al_device *sdio_al_dev) +{ + if (!sdio_al_dev->ask_mbox) { + pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n", + sdio_al_dev->host->index); + sdio_al_dev->ask_mbox = true; + wake_up(&sdio_al_dev->wait_mbox); + } +} + +/** + * Start the timer + */ +static void start_timer(struct sdio_al_device *sdio_al_dev) +{ + if ((sdio_al_dev->poll_delay_msec) && + (sdio_al_dev->state == CARD_INSERTED)) { + sdio_al_dev->timer.expires = jiffies + + msecs_to_jiffies(sdio_al_dev->poll_delay_msec); + add_timer(&sdio_al_dev->timer); + } +} + +/** + * Restart(postpone) the already working timer + */ +static void restart_timer(struct sdio_al_device *sdio_al_dev) +{ + if ((sdio_al_dev->poll_delay_msec) && + (sdio_al_dev->state == CARD_INSERTED)) { + ulong expires = jiffies + + msecs_to_jiffies(sdio_al_dev->poll_delay_msec); + mod_timer(&sdio_al_dev->timer, expires); + } +} + +/** + * Stop and delete the timer + */ +static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev) +{ + if (sdio_al_dev->is_timer_initialized) { + sdio_al_dev->poll_delay_msec = 0; + del_timer_sync(&sdio_al_dev->timer); + } +} + +/** + * Do the wakup sequence. + * This function should be called after claiming the host! + * The caller is responsible for releasing the host. + * + * Wake up sequence + * 1. Get lock + * 2. Enable wake up function if needed + * 3. Mark NOT OK to sleep and write it + * 4. Restore default thresholds + * 5. Start the mailbox and inactivity timer again + */ +static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev, + u32 not_from_int, struct sdio_channel *ch) +{ + int ret = 0; + struct sdio_func *wk_func = NULL; + unsigned long time_to_wait; + struct mmc_host *host = sdio_al_dev->host; + + if (sdio_al_dev->is_err) { + SDIO_AL_ERR(__func__); + return -ENODEV; + } + + if (!sdio_al_dev->is_ok_to_sleep) { + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d " + "already awake, no need to wake up\n", + sdio_al_dev->host->index); + return 0; + } + + /* Wake up sequence */ + if (not_from_int) { + if (ch) { + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up" + " card %d (not by interrupt), ch %s", + sdio_al_dev->host->index, + ch->name); + } else { + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up" + " card %d (not by interrupt)", + sdio_al_dev->host->index); + } + } else { + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card " + "%d by interrupt", + sdio_al_dev->host->index); + sdio_al_dev->print_after_interrupt = 1; + } + + sdio_al_vote_for_sleep(sdio_al_dev, 0); + + msmsdcc_lpm_disable(host); + msmsdcc_set_pwrsave(host, 0); + /* Poll the GPIO */ + time_to_wait = jiffies + msecs_to_jiffies(1000); + while (time_before(jiffies, time_to_wait)) { + if (sdio_al->pdata->get_mdm2ap_status()) + break; + udelay(TIME_TO_WAIT_US); + } + + pr_debug(MODULE_NAME ":GPIO mdm2ap_status=%d\n", + sdio_al->pdata->get_mdm2ap_status()); + + /* Here get_mdm2ap_status() returning 0 is not an error condition */ + if (sdio_al->pdata->get_mdm2ap_status() == 0) + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": " + "get_mdm2ap_status() is 0\n"); + + /* Enable Wake up Function */ + if (!sdio_al_dev->card || + !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": NULL card or wk_func\n"); + return -ENODEV; + } + wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]; + ret = sdio_al_enable_func_retry(wk_func, "wakeup func"); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": " + "sdio_enable_func() err=%d\n", -ret); + goto error_exit; + } + /* Mark NOT OK_TOSLEEP */ + sdio_al_dev->is_ok_to_sleep = 0; + ret = write_lpm_info(sdio_al_dev); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": " + "write_lpm_info() failed, err=%d\n", -ret); + sdio_al_dev->is_ok_to_sleep = 1; + sdio_disable_func(wk_func); + goto error_exit; + } + sdio_disable_func(wk_func); + + /* Start the timer again*/ + restart_inactive_time(sdio_al_dev); + sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev); + start_timer(sdio_al_dev); + + LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence" + " for card %d", sdio_al_dev->host->index); + + msmsdcc_set_pwrsave(host, 1); + pr_debug(MODULE_NAME ":Turn clock off\n"); + + return ret; +error_exit: + sdio_al_vote_for_sleep(sdio_al_dev, 1); + msmsdcc_set_pwrsave(host, 1); + WARN_ON(ret); + sdio_al_get_into_err_state(sdio_al_dev); + return ret; +} + + +/** + * SDIO Function Interrupt handler. + * + * Interrupt shall be triggered by SDIO-Client when: + * 1. End-Of-Transfer (EOT) detected in packet mode. + * 2. Bytes-available reached the threshold. + * + * Reading the mailbox clears the EOT/Threshold interrupt + * source. + * The interrupt source should be cleared before this ISR + * returns. This ISR is called from IRQ Thread and not + * interrupt, so it may sleep. + * + */ +static void sdio_func_irq(struct sdio_func *func) +{ + struct sdio_al_device *sdio_al_dev = sdio_get_drvdata(func); + + pr_debug(MODULE_NAME ":start %s.\n", __func__); + + if (sdio_al_dev == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device"); + return; + } + + if (sdio_al_dev->is_ok_to_sleep) + sdio_al_wake_up(sdio_al_dev, 0, NULL); + else + restart_timer(sdio_al_dev); + + read_mailbox(sdio_al_dev, true); + + pr_debug(MODULE_NAME ":end %s.\n", __func__); +} + +/** + * Timer Expire Handler + * + */ +static void sdio_al_timer_handler(unsigned long data) +{ + struct sdio_al_device *sdio_al_dev = (struct sdio_al_device *)data; + if (sdio_al_dev == NULL) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": NULL " + "sdio_al_dev for data %lu\n", data); + return; + } + if (sdio_al_dev->state != CARD_INSERTED) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": sdio_al_dev " + "is in invalid state %d\n", sdio_al_dev->state); + return; + } + pr_debug(MODULE_NAME " Timer Expired\n"); + + ask_reading_mailbox(sdio_al_dev); + + restart_timer(sdio_al_dev); +} + +/** + * Driver Setup. + * + */ +static int sdio_al_setup(struct sdio_al_device *sdio_al_dev) +{ + int ret = 0; + struct mmc_card *card = sdio_al_dev->card; + struct sdio_func *func1 = NULL; + int i = 0; + int fn = 0; + + if (sdio_al_verify_func1(sdio_al_dev, __func__)) + return -ENODEV; + func1 = card->sdio_func[0]; + + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for " + "card %d\n", sdio_al_dev->host->index); + + ret = sdio_al->pdata->config_mdm2ap_status(1); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not " + "request GPIO\n"); + return ret; + } + + INIT_WORK(&sdio_al_dev->sdio_al_work.work, worker); + /* disable all pipes interrupts before claim irq. + since all are enabled by default. */ + for (i = 0 ; i < SDIO_AL_MAX_PIPES; i++) { + enable_eot_interrupt(sdio_al_dev, i, false); + enable_threshold_interrupt(sdio_al_dev, i, false); + } + + /* Disable all SDIO Functions before claim irq. */ + for (fn = 1 ; fn <= card->sdio_funcs; fn++) + sdio_disable_func(card->sdio_func[fn-1]); + + sdio_set_drvdata(func1, sdio_al_dev); + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card " + "%d\n", sdio_al_dev->host->index); + + ret = sdio_claim_irq(func1, sdio_func_irq); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim" + " IRQ for card %d\n", + sdio_al_dev->host->index); + return ret; + } + + sdio_al_dev->is_ready = true; + + /* Start worker before interrupt might happen */ + queue_work(sdio_al_dev->workqueue, &sdio_al_dev->sdio_al_work.work); + + start_inactive_time(sdio_al_dev); + + pr_debug(MODULE_NAME ":Ready.\n"); + + return 0; +} + +/** + * Driver Tear-Down. + * + */ +static void sdio_al_tear_down(void) +{ + int i, j; + struct sdio_al_device *sdio_al_dev = NULL; + struct sdio_func *func1; + + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) { + if (sdio_al->devices[i] == NULL) + continue; + sdio_al_dev = sdio_al->devices[i]; + + if (sdio_al_dev->is_ready) { + sdio_al_dev->is_ready = false; /* Flag worker to exit */ + sdio_al_dev->ask_mbox = false; + ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */ + /* allow gracefully exit of the worker thread */ + msleep(100); + + flush_workqueue(sdio_al_dev->workqueue); + destroy_workqueue(sdio_al_dev->workqueue); + + sdio_al_vote_for_sleep(sdio_al_dev, 1); + + if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, + __func__)) { + if (!sdio_al_dev->card || + !sdio_al_dev->card->sdio_func[0]) { + sdio_al_loge(sdio_al_dev->dev_log, + MODULE_NAME + ": %s: Invalid func1", + __func__); + return; + } + func1 = sdio_al_dev->card->sdio_func[0]; + sdio_release_irq(func1); + sdio_disable_func(func1); + sdio_al_release_mutex(sdio_al_dev, __func__); + } + } + + for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) + sdio_al_dev->channel[j].signature = 0x0; + sdio_al_dev->signature = 0; + + kfree(sdio_al_dev->sdioc_sw_header); + kfree(sdio_al_dev->mailbox); + kfree(sdio_al_dev->rx_flush_buf); + kfree(sdio_al_dev); + } + + sdio_al->pdata->config_mdm2ap_status(0); +} + +/** + * Find channel by name. + * + */ +static struct sdio_channel *find_channel_by_name(const char *name) +{ + struct sdio_channel *ch = NULL; + int i, j; + struct sdio_al_device *sdio_al_dev = NULL; + + for (j = 0; j < MAX_NUM_OF_SDIO_DEVICES; ++j) { + if (sdio_al->devices[j] == NULL) + continue; + sdio_al_dev = sdio_al->devices[j]; + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + if (sdio_al_dev->channel[i].state == + SDIO_CHANNEL_STATE_INVALID) + continue; + if (strncmp(sdio_al_dev->channel[i].name, name, + CHANNEL_NAME_SIZE) == 0) { + ch = &sdio_al_dev->channel[i]; + break; + } + } + if (ch != NULL) + break; + } + + return ch; +} + +/** + * Find the minimal poll time. + * + */ +static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev) +{ + int i; + int poll_delay_msec = 0x0FFFFFFF; + + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) + if ((sdio_sl_dev->channel[i].state == + SDIO_CHANNEL_STATE_OPEN) && + (sdio_sl_dev->channel[i].poll_delay_msec > 0) && + (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec)) + poll_delay_msec = + sdio_sl_dev->channel[i].poll_delay_msec; + + if (poll_delay_msec == 0x0FFFFFFF) + poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING; + + pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec); + + return poll_delay_msec; +} + +/** + * Open SDIO Channel. + * + * Enable the channel. + * Set the channel context. + * Trigger reading the mailbox to check available bytes. + * + */ +int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv, + void (*notify)(void *priv, unsigned ch_event)) +{ + int ret = 0; + struct sdio_channel *ch = NULL; + struct sdio_al_device *sdio_al_dev = NULL; + + *ret_ch = NULL; /* default */ + + ch = find_channel_by_name(name); + if (ch == NULL) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find " + "channel name %s\n", name); + return -EINVAL; + } + + sdio_al_dev = ch->sdio_al_dev; + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + if ((ch->state != SDIO_CHANNEL_STATE_IDLE) && + (ch->state != SDIO_CHANNEL_STATE_CLOSED)) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s " + "state %d\n", name, ch->state); + ret = -EPERM; + goto exit_err; + } + + if (sdio_al_dev->is_err) { + SDIO_AL_ERR(__func__); + ret = -ENODEV; + goto exit_err; + } + + ret = sdio_al_wake_up(sdio_al_dev, 1, ch); + if (ret) + goto exit_err; + + ch->notify = notify; + ch->priv = priv; + + /* Note: Set caller returned context before interrupts are enabled */ + *ret_ch = ch; + + ret = open_channel(ch); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s " + "err=%d\n", name, -ret); + goto exit_err; + } + + CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s " + "completed OK\n", name); + if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) { + if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) { + if (!ch->is_packet_mode) { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME + ":setting channel %s as " + "lpm_chan\n", name); + sdio_al_dev->lpm_chan = ch->num; + } + } else { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": " + "setting channel %s as lpm_chan\n", + name); + sdio_al_dev->lpm_chan = ch->num; + } + } + +exit_err: + sdio_al_release_mutex(sdio_al_dev, __func__); + return ret; +} +EXPORT_SYMBOL(sdio_open); + +/** + * Request peer operation + * note: sanity checks of parameters done by caller + * called under bus locked + */ +static int peer_set_operation(u32 opcode, + struct sdio_al_device *sdio_al_dev, + struct sdio_channel *ch) +{ + int ret; + int offset; + struct sdio_func *wk_func = NULL; + u32 peer_operation; + int loop_count = 0; + + if (!sdio_al_dev->card || + !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": NULL card or wk_func\n"); + ret = -ENODEV; + goto exit; + } + wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]; + + /* calculate offset of peer_operation field in sw mailbox struct */ + offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) + + sizeof(struct peer_sdioc_channel_config) * ch->num + + offsetof(struct peer_sdioc_channel_config, peer_operation); + + ret = sdio_al_wake_up(sdio_al_dev, 1, ch); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to " + "wake up\n"); + goto exit; + } + /* request operation from MDM peer */ + peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT); + ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset, + &peer_operation, sizeof(u32)); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to " + "request close operation\n"); + goto exit; + } + ret = sdio_al_enable_func_retry(wk_func, "wk_func"); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable" + " Func#%d\n", wk_func->num); + goto exit; + } + pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n", + __func__, ch->name); + /* send "start" operation to MDM */ + peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START); + ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset, + &peer_operation, sizeof(u32)); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to " + "send start close operation\n"); + goto exit; + } + ret = sdio_disable_func(wk_func); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to " + "disable Func#%d\n", wk_func->num); + goto exit; + } + /* poll for peer operation ack */ + while (peer_operation != 0) { + ret = sdio_memcpy_fromio(ch->func, + &peer_operation, + SDIOC_SW_MAILBOX_ADDR+offset, + sizeof(u32)); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ":failed to request ack on close" + " operation, loop_count = %d\n", + loop_count); + goto exit; + } + loop_count++; + if (loop_count > 10) { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: " + "peer_operation=0x%x wait loop" + " %d on ch %s\n", __func__, + peer_operation, loop_count, ch->name); + } + } +exit: + return ret; +} + +static int channel_close(struct sdio_channel *ch, int flush_flag) +{ + int ret; + struct sdio_al_device *sdio_al_dev = NULL; + int flush_len; + ulong flush_expires; + + if (!ch) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL " + "channel\n", __func__); + return -ENODEV; + } + + if (!ch->func) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func" + " on channel:%d\n", __func__, ch->num); + return -ENODEV; + } + + sdio_al_dev = ch->sdio_al_dev; + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + if (!sdio_al_dev->ch_close_supported) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not " + "supported by mdm, ch %s\n", + __func__, ch->name); + ret = -ENOTSUPP; + goto error_exit; + } + + if (sdio_al_dev->is_err) { + SDIO_AL_ERR(__func__); + ret = -ENODEV; + goto error_exit; + } + if (ch->state != SDIO_CHANNEL_STATE_OPEN) { + sdio_al_loge(sdio_al_dev->dev_log, + MODULE_NAME ":%s: ch %s is not in " + "open state (%d)\n", + __func__, ch->name, ch->state); + ret = -ENODEV; + goto error_exit; + } + ch->state = SDIO_CHANNEL_STATE_CLOSING; + ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: " + "peer_set_operation() failed: %d\n", + __func__, ret); + ret = -ENODEV; + goto error_exit; + } + /* udate poll time for opened channels */ + if (ch->poll_delay_msec > 0) { + sdio_al_dev->poll_delay_msec = + get_min_poll_time_msec(sdio_al_dev); + } + sdio_al_release_mutex(ch->sdio_al_dev, __func__); + + flush_expires = jiffies + + msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC); + /* flush rx packets of the channel */ + if (flush_flag) { + do { + while (ch->read_avail > 0) { + flush_len = ch->read_avail; + ret = sdio_read_internal(ch, + sdio_al_dev->rx_flush_buf, + flush_len); + if (ret) { + sdio_al_loge(&sdio_al->gen_log, + MODULE_NAME ":%s sdio_read" + " failed: %d, ch %s\n", + __func__, ret, + ch->name); + return ret; + } + + if (time_after(jiffies, flush_expires) != 0) { + sdio_al_loge(&sdio_al->gen_log, + MODULE_NAME ":%s flush rx " + "packets timeout: ch %s\n", + __func__, ch->name); + sdio_al_get_into_err_state(sdio_al_dev); + return -EBUSY; + } + } + msleep(100); + if (ch->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(&sdio_al->gen_log, + MODULE_NAME ":%s: after sleep," + " invalid signature" + " 0x%x\n", __func__, + ch->signature); + return -ENODEV; + } + if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev, + __func__)) + return -ENODEV; + + ret = read_mailbox(sdio_al_dev, false); + if (ret) { + sdio_al_loge(&sdio_al->gen_log, + MODULE_NAME ":%s: failed to" + " read mailbox", __func__); + goto error_exit; + } + sdio_al_release_mutex(ch->sdio_al_dev, __func__); + } while (ch->read_avail > 0); + } + if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev, + __func__)) + return -ENODEV; + /* disable function to be able to open the channel again */ + ret = sdio_disable_func(ch->func); + if (ret) { + sdio_al_loge(&sdio_al->gen_log, + MODULE_NAME ":Fail to disable Func#%d\n", + ch->func->num); + goto error_exit; + } + ch->state = SDIO_CHANNEL_STATE_CLOSED; + CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed " + "successfully\n", __func__, ch->name); + +error_exit: + sdio_al_release_mutex(ch->sdio_al_dev, __func__); + + return ret; +} + +/** + * Close SDIO Channel. + * + */ +int sdio_close(struct sdio_channel *ch) +{ + return channel_close(ch, true); +} +EXPORT_SYMBOL(sdio_close); + +/** + * Get the number of available bytes to write. + * + */ +int sdio_write_avail(struct sdio_channel *ch) +{ + if (!ch) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL " + "channel\n", __func__); + return -ENODEV; + } + if (ch->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: " + "Invalid signature 0x%x\n", __func__, + ch->signature); + return -ENODEV; + } + if (ch->state != SDIO_CHANNEL_STATE_OPEN) { + sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: " + "channel %s state is not open (%d)\n", + __func__, ch->name, ch->state); + return -ENODEV; + } + pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n", + ch->name, ch->write_avail); + + return ch->write_avail; +} +EXPORT_SYMBOL(sdio_write_avail); + +/** + * Get the number of available bytes to read. + * + */ +int sdio_read_avail(struct sdio_channel *ch) +{ + if (!ch) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL " + "channel\n", __func__); + return -ENODEV; + } + if (ch->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: " + "Invalid signature 0x%x\n", __func__, + ch->signature); + return -ENODEV; + } + if (ch->state != SDIO_CHANNEL_STATE_OPEN) { + sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: " + "channel %s state is not open (%d)\n", + __func__, ch->name, ch->state); + return -ENODEV; + } + pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n", + ch->name, ch->read_avail); + + return ch->read_avail; +} +EXPORT_SYMBOL(sdio_read_avail); + +static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len) +{ + int ret = 0; + struct sdio_al_device *sdio_al_dev = NULL; + + if (!ch) { + sdio_al_loge(ch->sdio_al_dev->dev_log, + MODULE_NAME ":%s: NULL channel\n", __func__); + return -ENODEV; + } + + sdio_al_dev = ch->sdio_al_dev; + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf, + PIPE_RX_FIFO_ADDR, len); + + if (ret) { + sdio_al_loge(ch->sdio_al_dev->dev_log, + MODULE_NAME ":ch %s: %s err=%d, len=%d\n", + ch->name, __func__, -ret, len); + sdio_al_dev->is_err = true; + sdio_al_release_mutex(sdio_al_dev, __func__); + return ret; + } + + restart_inactive_time(sdio_al_dev); + + sdio_al_release_mutex(sdio_al_dev, __func__); + + return 0; +} + +/** + * Internal read from SDIO Channel. + * + * Reading from the pipe will trigger interrupt if there are + * other pending packets on the SDIO-Client. + * + */ +static int sdio_read_internal(struct sdio_channel *ch, void *data, int len) +{ + int ret = 0; + struct sdio_al_device *sdio_al_dev = NULL; + + if (!ch) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL " + "channel\n", __func__); + return -ENODEV; + } + if (!data) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n", + __func__); + return -ENODEV; + } + if (len == 0) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying" + " to read 0 bytes\n", ch->name); + return -EINVAL; + } + + if (ch->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid " + "signature 0x%x\n", __func__, ch->signature); + return -ENODEV; + } + + sdio_al_dev = ch->sdio_al_dev; + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + if (sdio_al_dev->is_err) { + SDIO_AL_ERR(__func__); + ret = -ENODEV; + goto exit; + } + + /* lpm policy says we can't go to sleep when we have pending rx data, + so either we had rx interrupt and woken up, or we never went to + sleep */ + if (sdio_al_dev->is_ok_to_sleep) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called " + "when is_ok_to_sleep is set for ch %s, len=%d," + " last_any_read_avail=%d, last_read_avail=%d, " + "last_old_read_avail=%d", __func__, ch->name, + len, ch->statistics.last_any_read_avail, + ch->statistics.last_read_avail, + ch->statistics.last_old_read_avail); + } + BUG_ON(sdio_al_dev->is_ok_to_sleep); + + if ((ch->state != SDIO_CHANNEL_STATE_OPEN) && + (ch->state != SDIO_CHANNEL_STATE_CLOSING)) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong " + "channel %s state %d\n", + __func__, ch->name, ch->state); + ret = -EINVAL; + goto exit; + } + + DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d " + "avail %d.\n", ch->name, len, ch->read_avail); + + restart_inactive_time(sdio_al_dev); + + if ((ch->is_packet_mode) && (len != ch->read_avail)) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch " + "%s len != read_avail\n", ch->name); + ret = -EINVAL; + goto exit; + } + + if (len > ch->read_avail) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: " + "reading more bytes (%d) than the avail(%d).\n", + ch->name, len, ch->read_avail); + ret = -ENOMEM; + goto exit; + } + + ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len); + + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: " + "sdio_read err=%d, len=%d, read_avail=%d, " + "last_read_avail=%d, last_old_read_avail=%d\n", + ch->name, -ret, len, ch->read_avail, + ch->statistics.last_read_avail, + ch->statistics.last_old_read_avail); + sdio_al_get_into_err_state(sdio_al_dev); + goto exit; + } + + ch->statistics.total_read_times++; + + /* Remove handled packet from the list regardless if ret is ok */ + if (ch->is_packet_mode) + remove_handled_rx_packet(ch); + else + ch->read_avail -= len; + + ch->total_rx_bytes += len; + DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d " + "avail %d total %d.\n", ch->name, len, + ch->read_avail, ch->total_rx_bytes); + + if ((ch->read_avail == 0) && !(ch->is_packet_mode)) + ask_reading_mailbox(sdio_al_dev); + +exit: + sdio_al_release_mutex(sdio_al_dev, __func__); + + return ret; +} + +/** + * Read from SDIO Channel. + * + * Reading from the pipe will trigger interrupt if there are + * other pending packets on the SDIO-Client. + * + */ +int sdio_read(struct sdio_channel *ch, void *data, int len) +{ + if (!ch) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL " + "channel\n", __func__); + return -ENODEV; + } + if (ch->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: " + "Invalid signature 0x%x\n", __func__, ch->signature); + return -ENODEV; + } + if (ch->state == SDIO_CHANNEL_STATE_OPEN) { + return sdio_read_internal(ch, data, len); + } else { + sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME + ":%s: Invalid channel %s state %d\n", + __func__, ch->name, ch->state); + } + return -ENODEV; +} +EXPORT_SYMBOL(sdio_read); + +/** + * Write to SDIO Channel. + * + */ +int sdio_write(struct sdio_channel *ch, const void *data, int len) +{ + int ret = 0; + struct sdio_al_device *sdio_al_dev = NULL; + + if (!ch) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL " + "channel\n", __func__); + return -ENODEV; + } + if (!data) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n", + __func__); + return -ENODEV; + } + if (len == 0) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying" + " to write 0 bytes\n", ch->name); + return -EINVAL; + } + + if (ch->signature != SDIO_AL_SIGNATURE) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid " + "signature 0x%x\n", __func__, ch->signature); + return -ENODEV; + } + + sdio_al_dev = ch->sdio_al_dev; + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + WARN_ON(len > ch->write_avail); + + if (sdio_al_dev->is_err) { + SDIO_AL_ERR(__func__); + ret = -ENODEV; + goto exit; + } + + if (ch->state != SDIO_CHANNEL_STATE_OPEN) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to " + "closed channel %s\n", ch->name); + ret = -EINVAL; + goto exit; + } + + if (sdio_al_dev->is_ok_to_sleep) { + ret = sdio_al_wake_up(sdio_al_dev, 1, ch); + if (ret) + goto exit; + } else { + restart_inactive_time(sdio_al_dev); + } + + DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d " + "avail %d.\n", ch->name, len, ch->write_avail); + + if (len > ch->write_avail) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: " + "write more bytes (%d) than available %d.\n", + ch->name, len, ch->write_avail); + ret = -ENOMEM; + goto exit; + } + + ret = sdio_ch_write(ch, data, len); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write " + "on channel %s err=%d\n", ch->name, -ret); + goto exit; + } + + ch->total_tx_bytes += len; + DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d " + "avail %d total %d.\n", ch->name, len, + ch->write_avail, ch->total_tx_bytes); + + /* Round up to whole buffer size */ + len = ROUND_UP(len, ch->peer_tx_buf_size); + /* Protect from wraparound */ + len = min(len, (int) ch->write_avail); + ch->write_avail -= len; + + if (ch->write_avail < ch->min_write_avail) + ask_reading_mailbox(sdio_al_dev); + +exit: + sdio_al_release_mutex(sdio_al_dev, __func__); + + return ret; +} +EXPORT_SYMBOL(sdio_write); + +static int __devinit msm_sdio_al_probe(struct platform_device *pdev) +{ + if (!sdio_al) { + pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__); + return -ENODEV; + } + + sdio_al->pdata = pdev->dev.platform_data; + return 0; +} + +static int __devexit msm_sdio_al_remove(struct platform_device *pdev) +{ + return 0; +} + +static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev) +{ + int j; + int ret; + struct sdio_channel *ch = NULL; + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__); + + if (!sdio_al_dev) { + sdio_al_loge(sdio_al_dev->dev_log, + MODULE_NAME ": %s: NULL device", __func__); + return; + } + for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) { + ch = &sdio_al_dev->channel[j]; + + if (ch->state == SDIO_CHANNEL_STATE_OPEN) { + sdio_al_loge(sdio_al_dev->dev_log, + MODULE_NAME ": %s: Call to sdio_close() for" + " ch %s\n", __func__, ch->name); + ret = channel_close(ch, false); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, + MODULE_NAME ": %s: failed sdio_close()" + " for ch %s (%d)\n", + __func__, ch->name, ret); + } + } else { + pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s" + " (state=%d)\n", __func__, + ch->name, ch->state); + } + } +} + +static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev, + struct platform_device **pdev_arr) +{ + int j; + + pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d", + __func__, sdio_al_dev->host->index); + for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) { + if (sdio_al_dev->channel[j].state == + SDIO_CHANNEL_STATE_INVALID) + continue; + pdev_arr[j] = sdio_al_dev->channel[j].pdev; + sdio_al_dev->channel[j].signature = 0x0; + sdio_al_dev->channel[j].state = + SDIO_CHANNEL_STATE_INVALID; + } +} + +static void sdio_al_modem_reset_operations(struct sdio_al_device + *sdio_al_dev) +{ + int ret = 0; + struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS]; + int j; + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__); + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return; + + if (sdio_al_dev->state == CARD_REMOVED) { + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: " + "card %d is already removed", __func__, + sdio_al_dev->host->index); + goto exit_err; + } + + if (sdio_al_dev->state == MODEM_RESTART) { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: " + "card %d was already notified for modem reset", + __func__, sdio_al_dev->host->index); + goto exit_err; + } + + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the " + "state to MODEM_RESTART for card %d", + __func__, sdio_al_dev->host->index); + sdio_al_dev->state = MODEM_RESTART; + sdio_al_dev->is_ready = false; + + /* Stop mailbox timer */ + stop_and_del_timer(sdio_al_dev); + + if ((sdio_al_dev->is_ok_to_sleep) && + (!sdio_al_dev->is_err)) { + pr_debug(MODULE_NAME ": %s: wakeup modem for " + "card %d", __func__, + sdio_al_dev->host->index); + ret = sdio_al_wake_up(sdio_al_dev, 1, NULL); + } + + if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card && + sdio_al_dev->card->sdio_func[0]) { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME + ": %s: sdio_release_irq for card %d", + __func__, + sdio_al_dev->host->index); + sdio_release_irq(sdio_al_dev->card->sdio_func[0]); + } + + memset(pdev_arr, 0, sizeof(pdev_arr)); + sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr); + + sdio_al_release_mutex(sdio_al_dev, __func__); + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO " + "clients for card %d", + __func__, sdio_al_dev->host->index); + for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) { + if (!pdev_arr[j]) + continue; + platform_device_unregister(pdev_arr[j]); + } + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying " + "SDIO clients for card %d", + __func__, sdio_al_dev->host->index); + + return; + +exit_err: + sdio_al_release_mutex(sdio_al_dev, __func__); + return; +} + +#ifdef CONFIG_MSM_SUBSYSTEM_RESTART +static void sdio_al_reset(void) +{ + int i; + struct sdio_al_device *sdio_al_dev; + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__); + + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) { + if (sdio_al->devices[i] == NULL) { + pr_debug(MODULE_NAME ": %s: NULL device in index %d", + __func__, i); + continue; + } + sdio_al_dev = sdio_al->devices[i]; + sdio_al_modem_reset_operations(sdio_al->devices[i]); + } + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__); +} +#endif + +static void msm_sdio_al_shutdown(struct platform_device *pdev) +{ + int i; + struct sdio_al_device *sdio_al_dev; + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME + "Initiating msm_sdio_al_shutdown..."); + + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) { + if (sdio_al->devices[i] == NULL) { + pr_debug(MODULE_NAME ": %s: NULL device in index %d", + __func__, i); + continue; + } + sdio_al_dev = sdio_al->devices[i]; + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return; + + if (sdio_al_dev->ch_close_supported) + sdio_al_close_all_channels(sdio_al_dev); + + sdio_al_release_mutex(sdio_al_dev, __func__); + + sdio_al_modem_reset_operations(sdio_al_dev); + } + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: " + "msm_sdio_al_shutdown complete.", __func__); +} + +static struct platform_driver msm_sdio_al_driver = { + .probe = msm_sdio_al_probe, + .remove = __exit_p(msm_sdio_al_remove), + .shutdown = msm_sdio_al_shutdown, + .driver = { + .name = "msm_sdio_al", + }, +}; + +/** + * Initialize SDIO_AL channels. + * + */ +static int init_channels(struct sdio_al_device *sdio_al_dev) +{ + int ret = 0; + int i; + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + ret = read_sdioc_software_header(sdio_al_dev, + sdio_al_dev->sdioc_sw_header); + if (ret) + goto exit; + + ret = sdio_al_setup(sdio_al_dev); + if (ret) + goto exit; + + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + int ch_name_size; + if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID) + continue; + if (sdio_al->unittest_mode) { + memset(sdio_al_dev->channel[i].ch_test_name, 0, + sizeof(sdio_al_dev->channel[i].ch_test_name)); + ch_name_size = strnlen(sdio_al_dev->channel[i].name, + CHANNEL_NAME_SIZE); + strncpy(sdio_al_dev->channel[i].ch_test_name, + sdio_al_dev->channel[i].name, + ch_name_size); + strncat(sdio_al_dev->channel[i].ch_test_name + + ch_name_size, + SDIO_TEST_POSTFIX, + SDIO_TEST_POSTFIX_SIZE); + pr_debug(MODULE_NAME ":pdev.name = %s\n", + sdio_al_dev->channel[i].ch_test_name); + sdio_al_dev->channel[i].pdev = platform_device_alloc( + sdio_al_dev->channel[i].ch_test_name, -1); + } else { + pr_debug(MODULE_NAME ":pdev.name = %s\n", + sdio_al_dev->channel[i].name); + sdio_al_dev->channel[i].pdev = platform_device_alloc( + sdio_al_dev->channel[i].name, -1); + } + if (!sdio_al_dev->channel[i].pdev) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ":NULL platform device for ch %s", + sdio_al_dev->channel[i].name); + sdio_al_dev->channel[i].state = + SDIO_CHANNEL_STATE_INVALID; + continue; + } + ret = platform_device_add(sdio_al_dev->channel[i].pdev); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ":platform_device_add failed, " + "ret=%d\n", ret); + sdio_al_dev->channel[i].state = + SDIO_CHANNEL_STATE_INVALID; + } + } + +exit: + sdio_al_release_mutex(sdio_al_dev, __func__); + return ret; +} + +/** + * Initialize SDIO_AL channels according to the client setup. + * This function also check if the client is in boot mode and + * flashless boot is required to be activated or the client is + * up and running. + * + */ +static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev) +{ + int ret = 0; + struct sdio_func *func1; + int signature = 0; + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or " + "func1\n"); + sdio_al_release_mutex(sdio_al_dev, __func__); + return -ENODEV; + } + func1 = sdio_al_dev->card->sdio_func[0]; + + /* Read the header signature to determine the status of the MDM + * SDIO Client + */ + signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret); + sdio_al_release_mutex(sdio_al_dev, __func__); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read " + "signature from sw header.\n"); + return ret; + } + + switch (signature) { + case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE: + if (sdio_al_dev == sdio_al->bootloader_dev) { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup " + "bootloader on card %d\n", + sdio_al_dev->host->index); + return sdio_al_bootloader_setup(); + } else { + sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait " + "for bootloader completion " + "on card %d\n", + sdio_al_dev->host->index); + return sdio_al_wait_for_bootloader_comp(sdio_al_dev); + } + case PEER_SDIOC_SW_MAILBOX_SIGNATURE: + case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE: + return init_channels(sdio_al_dev); + default: + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid " + "signature 0x%x\n", signature); + return -EINVAL; + } + + return 0; +} + +static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev) +{ + sdio_al_dev->is_ready = 0; + sdio_al_dev->bootloader_done = 0; + sdio_al_dev->lpm_chan = 0; + sdio_al_dev->is_ok_to_sleep = 0; + sdio_al_dev->inactivity_time = 0; + sdio_al_dev->poll_delay_msec = 0; + sdio_al_dev->is_timer_initialized = 0; + sdio_al_dev->is_err = 0; + sdio_al_dev->is_suspended = 0; + sdio_al_dev->flashless_boot_on = 0; + sdio_al_dev->ch_close_supported = 0; + sdio_al_dev->print_after_interrupt = 0; + memset(sdio_al_dev->sdioc_sw_header, 0, + sizeof(*sdio_al_dev->sdioc_sw_header)); + memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox)); + memset(sdio_al_dev->rx_flush_buf, 0, + sizeof(*sdio_al_dev->rx_flush_buf)); +} + +/* + * SDIO driver functions + */ +static int sdio_al_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *sdio_dev_id) +{ + int ret = 0; + struct sdio_al_device *sdio_al_dev = NULL; + int i; + struct mmc_card *card = NULL; + + if (!func) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n", + __func__); + return -ENODEV; + } + card = func->card; + + if (!card) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n", + __func__); + return -ENODEV; + } + + if (!card->sdio_func[0]) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "func1\n", + __func__); + return -ENODEV; + } + + if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) { + dev_info(&card->dev, + "SDIO-functions# %d less than expected.\n", + card->sdio_funcs); + return -ENODEV; + } + + /* Check if there is already a device for this card */ + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) { + if (sdio_al->devices[i] == NULL) + continue; + if (sdio_al->devices[i]->host == card->host) { + sdio_al_dev = sdio_al->devices[i]; + if (sdio_al_dev->state == CARD_INSERTED) + return 0; + clean_sdio_al_device_data(sdio_al_dev); + break; + } + } + + if (!sdio_al_dev) { + sdio_al_dev = kzalloc(sizeof(struct sdio_al_device), + GFP_KERNEL); + if (sdio_al_dev == NULL) + return -ENOMEM; + + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i) + if (sdio_al->devices[i] == NULL) { + sdio_al->devices[i] = sdio_al_dev; + sdio_al_dev->dev_log = &sdio_al->device_log[i]; + spin_lock_init(&sdio_al_dev->dev_log->log_lock); + #ifdef CONFIG_DEBUG_FS + sdio_al_dbgfs_log[i].data = + sdio_al_dev->dev_log->buffer; + sdio_al_dbgfs_log[i].size = + SDIO_AL_DEBUG_LOG_SIZE; + #endif + break; + } + if (i == MAX_NUM_OF_SDIO_DEVICES) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space " + "in devices array for the device\n"); + return -ENOMEM; + } + } + + dev_info(&card->dev, "SDIO Card claimed.\n"); + sdio_al->skip_print_info = 0; + + sdio_al_dev->state = CARD_INSERTED; + + if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX) + sdio_al->bootloader_dev = sdio_al_dev; + + sdio_al_dev->is_ready = false; + + sdio_al_dev->signature = SDIO_AL_SIGNATURE; + + sdio_al_dev->is_suspended = 0; + sdio_al_dev->is_timer_initialized = false; + + sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN; + + sdio_al_dev->card = card; + sdio_al_dev->host = card->host; + + if (!sdio_al_dev->mailbox) { + sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox), + GFP_KERNEL); + if (sdio_al_dev->mailbox == NULL) + return -ENOMEM; + } + + if (!sdio_al_dev->sdioc_sw_header) { + sdio_al_dev->sdioc_sw_header + = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header), + GFP_KERNEL); + if (sdio_al_dev->sdioc_sw_header == NULL) + return -ENOMEM; + } + + if (!sdio_al_dev->rx_flush_buf) { + sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE, + GFP_KERNEL); + if (sdio_al_dev->rx_flush_buf == NULL) { + sdio_al_loge(&sdio_al->gen_log, + MODULE_NAME ":Fail to allocate " + "rx_flush_buf for card %d\n", + card->host->index); + return -ENOMEM; + } + } + + sdio_al_dev->timer.data = (unsigned long)sdio_al_dev; + + wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME); + /* Don't allow sleep until all required clients register */ + sdio_al_vote_for_sleep(sdio_al_dev, 0); + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return -ENODEV; + + /* Init Func#1 */ + ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1"); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to " + "enable Func#%d\n", card->sdio_func[0]->num); + goto exit; + } + + /* Patch Func CIS tuple issue */ + ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE); + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set " + "block size, Func#%d\n", card->sdio_func[0]->num); + goto exit; + } + sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE; + + sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq"); + sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev; + init_waitqueue_head(&sdio_al_dev->wait_mbox); + + ret = sdio_al_client_setup(sdio_al_dev); + +exit: + sdio_al_release_mutex(sdio_al_dev, __func__); + return ret; +} + +static void sdio_al_sdio_remove(struct sdio_func *func) +{ + struct sdio_al_device *sdio_al_dev = NULL; + int i; + struct mmc_card *card = NULL; + struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS]; + + if (!func) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n", + __func__); + return; + } + card = func->card; + + if (!card) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n", + __func__); + return; + } + + /* Find the sdio_al_device of this card */ + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) { + if (sdio_al->devices[i] == NULL) + continue; + if (sdio_al->devices[i]->card == card) { + sdio_al_dev = sdio_al->devices[i]; + break; + } + } + if (sdio_al_dev == NULL) { + pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n", + __func__, card->host->index); + return; + } + + if (sdio_al_claim_mutex(sdio_al_dev, __func__)) + return; + + if (sdio_al_dev->state == CARD_REMOVED) { + sdio_al_release_mutex(sdio_al_dev, __func__); + return; + } + + if (!card->sdio_func[0]) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL " + "func1\n", __func__); + sdio_al_release_mutex(sdio_al_dev, __func__); + return; + } + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n", + __func__, card->host->index); + + sdio_al_dev->state = CARD_REMOVED; + + memset(pdev_arr, 0, sizeof(pdev_arr)); + sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr); + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox " + "for card %d\n", __func__, card->host->index); + sdio_al_dev->is_ready = false; /* Flag worker to exit */ + sdio_al_dev->ask_mbox = false; + ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */ + + stop_and_del_timer(sdio_al_dev); + + sdio_al_release_mutex(sdio_al_dev, __func__); + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO " + "clients for card %d", + __func__, sdio_al_dev->host->index); + for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) { + if (!pdev_arr[i]) + continue; + platform_device_unregister(pdev_arr[i]); + } + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying " + "SDIO clients for card %d", + __func__, sdio_al_dev->host->index); + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for " + "card %d\n", __func__, card->host->index); + sdio_al_vote_for_sleep(sdio_al_dev, 1); + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for " + "card %d\n", __func__, card->host->index); + flush_workqueue(sdio_al_dev->workqueue); + destroy_workqueue(sdio_al_dev->workqueue); + wake_lock_destroy(&sdio_al_dev->wake_lock); + + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed." + "\n", __func__, card->host->index); +} + +static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox) +{ + int k = 0; + char buf[256]; + char buf1[10]; + + if (!mailbox) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is " + "NULL\n"); + return; + } + + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x," + " thresh=0x%x, overflow=0x%x, " + "underflow=0x%x, mask_thresh=0x%x\n", + prefix_str, mailbox->eot_pipe_0_7, + mailbox->thresh_above_limit_pipe_0_7, + mailbox->overflow_pipe_0_7, + mailbox->underflow_pipe_0_7, + mailbox->mask_thresh_above_limit_pipe_0_7); + + memset(buf, 0, sizeof(buf)); + strncat(buf, ": bytes_avail:", sizeof(buf)); + + for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) { + snprintf(buf1, sizeof(buf1), "%d, ", + mailbox->pipe_bytes_avail[k]); + strncat(buf, buf1, sizeof(buf)); + } + + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf); +} + +static void sdio_al_print_info(void) +{ + int i = 0; + int j = 0; + int ret = 0; + struct sdio_mailbox *mailbox = NULL; + struct sdio_mailbox *hw_mailbox = NULL; + struct peer_sdioc_channel_config *ch_config = NULL; + struct sdio_func *func1 = NULL; + struct sdio_func *lpm_func = NULL; + int offset = 0; + int is_ok_to_sleep = 0; + char buf[50]; + + if (sdio_al->skip_print_info == 1) + return; + + sdio_al->skip_print_info = 1; + + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n", + __func__); + + if (!sdio_al) { + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - " + "sdio_al is NULL\n", __func__); + return; + } + + sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n", + sdio_al->pdata->get_mdm2ap_status()); + + for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) { + struct sdio_al_device *sdio_al_dev = sdio_al->devices[j]; + + if (sdio_al_dev == NULL) { + continue; + } + + if (!sdio_al_dev->host) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host" + " is NULL\n);"); + continue; + } + + snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB", + sdio_al_dev->host->index); + + /* printing Shadowing HW Mailbox*/ + mailbox = sdio_al_dev->mailbox; + sdio_print_mailbox(buf, mailbox); + + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: " + "is_ok_to_sleep=%d\n", + sdio_al_dev->host->index, + sdio_al_dev->is_ok_to_sleep); + + + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: " + "Shadow channels SW MB:", + sdio_al_dev->host->index); + + /* printing Shadowing SW Mailbox per channel*/ + for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) { + struct sdio_channel *ch = &sdio_al_dev->channel[i]; + + if (ch == NULL) { + continue; + } + + if (ch->state == SDIO_CHANNEL_STATE_INVALID) + continue; + + ch_config = &sdio_al_dev->channel[i].ch_config; + + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": Ch %s: max_rx_thres=0x%x, " + "max_tx_thres=0x%x, tx_buf=0x%x, " + "is_packet_mode=%d, " + "max_packet=0x%x, min_write=0x%x", + ch->name, ch_config->max_rx_threshold, + ch_config->max_tx_threshold, + ch_config->tx_buf_size, + ch_config->is_packet_mode, + ch_config->max_packet_size, + ch->min_write_avail); + + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": total_rx=0x%x, total_tx=0x%x, " + "read_avail=0x%x, write_avail=0x%x, " + "rx_pending=0x%x, num_reads=0x%x, " + "num_notifs=0x%x", ch->total_rx_bytes, + ch->total_tx_bytes, ch->read_avail, + ch->write_avail, ch->rx_pending_bytes, + ch->statistics.total_read_times, + ch->statistics.total_notifs); + } /* end loop over all channels */ + + } /* end loop over all devices */ + + /* reading from client and printing is_host_ok_to_sleep per device */ + for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) { + struct sdio_al_device *sdio_al_dev = sdio_al->devices[j]; + + if (sdio_al_verify_func1(sdio_al_dev, __func__)) + continue; + + if (!sdio_al_dev->host) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": Host is NULL"); + continue; + } + + if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": %s - for Card#%d, is lpm_chan==" + "INVALID_SDIO_CHAN. continuing...", + __func__, sdio_al_dev->host->index); + continue; + } + + offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+ + sizeof(struct peer_sdioc_channel_config) * + sdio_al_dev->lpm_chan+ + offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep); + + lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev-> + lpm_chan+1]; + if (!lpm_func) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": %s - lpm_func is NULL for card#%d" + " continuing...\n", __func__, + sdio_al_dev->host->index); + continue; + } + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return; + ret = sdio_memcpy_fromio(lpm_func, + &is_ok_to_sleep, + SDIOC_SW_MAILBOX_ADDR+offset, + sizeof(int)); + sdio_al_release_mutex(sdio_al_dev, __func__); + + if (ret) + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": %s - fail to read " + "is_HOST_ok_to_sleep from mailbox for card %d", + __func__, sdio_al_dev->host->index); + else + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": Card#%d: " + "is_HOST_ok_to_sleep=%d\n", + sdio_al_dev->host->index, + is_ok_to_sleep); + } + + for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) { + struct sdio_al_device *sdio_al_dev = sdio_al->devices[j]; + + if (!sdio_al_dev) + continue; + + /* Reading HW Mailbox */ + hw_mailbox = sdio_al_dev->mailbox; + + if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__)) + return; + + if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) { + sdio_al_release_mutex(sdio_al_dev, __func__); + return; + } + func1 = sdio_al_dev->card->sdio_func[0]; + ret = sdio_memcpy_fromio(func1, hw_mailbox, + HW_MAILBOX_ADDR, sizeof(*hw_mailbox)); + sdio_al_release_mutex(sdio_al_dev, __func__); + + if (ret) { + sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME + ": fail to read " + "mailbox for card#%d. " + "continuing...\n", + sdio_al_dev->host->index); + continue; + } + + snprintf(buf, sizeof(buf), "Card#%d: Current HW MB", + sdio_al_dev->host->index); + + /* Printing HW Mailbox */ + sdio_print_mailbox(buf, hw_mailbox); + } +} + +static struct sdio_device_id sdio_al_sdioid[] = { + {.class = 0, .vendor = 0x70, .device = 0x2460}, + {.class = 0, .vendor = 0x70, .device = 0x0460}, + {.class = 0, .vendor = 0x70, .device = 0x23F1}, + {.class = 0, .vendor = 0x70, .device = 0x23F0}, + {} +}; + +static struct sdio_driver sdio_al_sdiofn_driver = { + .name = "sdio_al_sdiofn", + .id_table = sdio_al_sdioid, + .probe = sdio_al_sdio_probe, + .remove = sdio_al_sdio_remove, +}; + +#ifdef CONFIG_MSM_SUBSYSTEM_RESTART +/* + * Callback for notifications from restart mudule. + * This function handles only the BEFORE_RESTART notification. + * Stop all the activity on the card and notify our clients. + */ +static int sdio_al_subsys_notifier_cb(struct notifier_block *this, + unsigned long notif_type, + void *data) +{ + if (notif_type != SUBSYS_BEFORE_SHUTDOWN) { + sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got " + "notification %ld", __func__, notif_type); + return NOTIFY_DONE; + } + + sdio_al_reset(); + return NOTIFY_OK; +} + +static struct notifier_block sdio_al_nb = { + .notifier_call = sdio_al_subsys_notifier_cb, +}; +#endif + +/** + * Module Init. + * + * @warn: allocate sdio_al context before registering driver. + * + */ +static int __init sdio_al_init(void) +{ + int ret = 0; + int i; + + pr_debug(MODULE_NAME ":sdio_al_init\n"); + + pr_info(MODULE_NAME ":SDIO-AL SW version %s\n", + DRV_VERSION); + + sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL); + if (sdio_al == NULL) + return -ENOMEM; + + for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i) + sdio_al->devices[i] = NULL; + + sdio_al->unittest_mode = false; + + sdio_al->debug.debug_lpm_on = debug_lpm_on; + sdio_al->debug.debug_data_on = debug_data_on; + sdio_al->debug.debug_close_on = debug_close_on; + +#ifdef CONFIG_DEBUG_FS + sdio_al_debugfs_init(); +#endif + + +#ifdef CONFIG_MSM_SUBSYSTEM_RESTART + sdio_al->subsys_notif_handle = subsys_notif_register_notifier( + "external_modem", &sdio_al_nb); +#endif + + ret = platform_driver_register(&msm_sdio_al_driver); + if (ret) { + pr_err(MODULE_NAME ": platform_driver_register failed: %d\n", + ret); + goto exit; + } + + sdio_register_driver(&sdio_al_sdiofn_driver); + + spin_lock_init(&sdio_al->gen_log.log_lock); + +exit: + if (ret) + kfree(sdio_al); + return ret; +} + +/** + * Module Exit. + * + * Free allocated memory. + * Disable SDIO-Card. + * Unregister driver. + * + */ +static void __exit sdio_al_exit(void) +{ + if (sdio_al == NULL) + return; + + pr_debug(MODULE_NAME ":sdio_al_exit\n"); + +#ifdef CONFIG_MSM_SUBSYSTEM_RESTART + subsys_notif_unregister_notifier( + sdio_al->subsys_notif_handle, &sdio_al_nb); +#endif + + sdio_al_tear_down(); + + sdio_unregister_driver(&sdio_al_sdiofn_driver); + + kfree(sdio_al); + +#ifdef CONFIG_DEBUG_FS + sdio_al_debugfs_cleanup(); +#endif + + platform_driver_unregister(&msm_sdio_al_driver); + + pr_debug(MODULE_NAME ":sdio_al_exit complete\n"); +} + +module_init(sdio_al_init); +module_exit(sdio_al_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SDIO Abstraction Layer"); +MODULE_AUTHOR("Amir Samuelov "); +MODULE_VERSION(DRV_VERSION); + diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c new file mode 100644 index 00000000..167c163c --- /dev/null +++ b/arch/arm/mach-msm/sdio_al_dloader.c @@ -0,0 +1,2541 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * SDIO-Downloader + * + * To be used with Qualcomm's SDIO-Client connected to this host. + */ + +/* INCLUDES */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "sdio_al_private.h" +#include +#include +#include +#include +#include +#include + +/* DEFINES AND MACROS */ +#define MAX_NUM_DEVICES 1 +#define TTY_SDIO_DEV "tty_sdio_0" +#define TTY_SDIO_DEV_TEST "tty_sdio_test_0" +#define SDIOC_MAILBOX_ADDRESS 0 +#define SDIO_DL_BLOCK_SIZE 512 +#define SDIO_DL_MAIN_THREAD_NAME "sdio_tty_main_thread" +#define SDIOC_DL_BUFF_ADDRESS 0 +#define SDIOC_UP_BUFF_ADDRESS 0x4 +#define SDIOC_DL_BUFF_SIZE_OFFSET 0x8 +#define SDIOC_UP_BUFF_SIZE_OFFSET 0xC +#define SDIOC_DL_WR_PTR 0x10 +#define SDIOC_DL_RD_PTR 0x14 +#define SDIOC_UL_WR_PTR 0x18 +#define SDIOC_UL_RD_PTR 0x1C +#define SDIOC_EXIT_PTR 0x20 +#define SDIOC_OP_MODE_PTR 0x24 +#define SDIOC_PTRS_OFFSET 0x10 +#define SDIOC_PTR_REGS_SIZE 0x10 +#define SDIOC_CFG_REGS_SIZE 0x10 +#define WRITE_RETRIES 0xFFFFFFFF +#define INPUT_SPEED 4800 +#define OUTPUT_SPEED 4800 +#define SDIOC_EXIT_CODE 0xDEADDEAD +#define SLEEP_MS 10 +#define PRINTING_GAP 200 +#define TIMER_DURATION 10 +#define PUSH_TIMER_DURATION 5000 +#define MULTIPLE_RATIO 1 +#define MS_IN_SEC 1000 +#define BITS_IN_BYTE 8 +#define BYTES_IN_KB 1024 +#define WRITE_TILL_END_RETRIES 5 +#define SDIO_DLD_NORMAL_MODE_NAME "SDIO DLD NORMAL MODE" +#define SDIO_DLD_BOOT_TEST_MODE_NAME "SDIO DLD BOOT TEST MODE" +#define SDIO_DLD_AMSS_TEST_MODE_NAME "SDIO DLD AMSS TEST MODE" +#define TEST_NAME_MAX_SIZE 30 +#define PUSH_STRING +#define SDIO_DLD_OUTGOING_BUFFER_SIZE (48*1024*MULTIPLE_RATIO) + +/* FORWARD DECLARATIONS */ +static int sdio_dld_open(struct tty_struct *tty, struct file *file); +static void sdio_dld_close(struct tty_struct *tty, struct file *file); +static int sdio_dld_write_callback(struct tty_struct *tty, + const unsigned char *buf, int count); +static int sdio_dld_write_room(struct tty_struct *tty); +static int sdio_dld_main_task(void *card); +static void sdio_dld_print_info(void); +#ifdef CONFIG_DEBUG_FS +static int sdio_dld_debug_info_open(struct inode *inode, struct file *file); +static ssize_t sdio_dld_debug_info_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos); +#endif + + +/* STRUCTURES AND TYPES */ +enum sdio_dld_op_mode { + SDIO_DLD_NO_MODE = 0, + SDIO_DLD_NORMAL_MODE = 1, + SDIO_DLD_BOOT_TEST_MODE = 2, + SDIO_DLD_AMSS_TEST_MODE = 3, + SDIO_DLD_NUM_OF_MODES, +}; + +struct sdioc_reg_sequential_chunk_ptrs { + unsigned int dl_wr_ptr; + unsigned int dl_rd_ptr; + unsigned int up_wr_ptr; + unsigned int up_rd_ptr; +}; + +struct sdioc_reg_sequential_chunk_cfg { + unsigned int dl_buff_address; + unsigned int up_buff_address; + unsigned int dl_buff_size; + unsigned int ul_buff_size; +}; + +struct sdioc_reg { + unsigned int reg_val; + unsigned int reg_offset; +}; + +struct sdioc_reg_chunk { + struct sdioc_reg dl_buff_address; + struct sdioc_reg up_buff_address; + struct sdioc_reg dl_buff_size; + struct sdioc_reg ul_buff_size; + struct sdioc_reg dl_wr_ptr; + struct sdioc_reg dl_rd_ptr; + struct sdioc_reg up_wr_ptr; + struct sdioc_reg up_rd_ptr; + struct sdioc_reg good_to_exit_ptr; +}; + +struct sdio_data { + char *data; + int offset_read_p; + int offset_write_p; + int buffer_size; + int num_of_bytes_in_use; +}; + +struct sdio_dld_data { + struct sdioc_reg_chunk sdioc_reg; + struct sdio_data incoming_data; + struct sdio_data outgoing_data; +}; + +struct sdio_dld_wait_event { + wait_queue_head_t wait_event; + int wake_up_signal; +}; + +struct sdio_dld_task { + struct task_struct *dld_task; + const char *task_name; + struct sdio_dld_wait_event exit_wait; + atomic_t please_close; +}; + +#ifdef CONFIG_DEBUG_FS +struct sdio_dloader_debug { + struct dentry *sdio_dld_debug_root; + struct dentry *sdio_al_dloader; +}; + +const struct file_operations sdio_dld_debug_info_ops = { + .open = sdio_dld_debug_info_open, + .write = sdio_dld_debug_info_write, +}; +#endif + +struct sdio_downloader { + int sdioc_boot_func; + struct sdio_dld_wait_event write_callback_event; + struct sdio_dld_task dld_main_thread; + struct tty_driver *tty_drv; + struct tty_struct *tty_str; + struct sdio_dld_data sdio_dloader_data; + struct mmc_card *card; + int(*done_callback)(void); + struct sdio_dld_wait_event main_loop_event; + struct timer_list timer; + unsigned int poll_ms; + struct timer_list push_timer; + unsigned int push_timer_ms; + enum sdio_dld_op_mode op_mode; + char op_mode_name[TEST_NAME_MAX_SIZE]; +}; + +struct sdio_dld_global_info { + int global_bytes_write_toio; + int global_bytes_write_tty; + int global_bytes_read_fromio; + int global_bytes_push_tty; + u64 start_time; + u64 end_time; + u64 delta_jiffies; + unsigned int time_msec; + unsigned int throughput; + int cl_dl_wr_ptr; + int cl_dl_rd_ptr; + int cl_up_wr_ptr; + int cl_up_rd_ptr; + int host_read_ptr; + int host_write_ptr; + int cl_dl_buffer_size; + int cl_up_buffer_size; + int host_outgoing_buffer_size; + int cl_dl_buffer_address; + int cl_up_buffer_address; +}; + +static const struct tty_operations sdio_dloader_tty_ops = { + .open = sdio_dld_open, + .close = sdio_dld_close, + .write = sdio_dld_write_callback, + .write_room = sdio_dld_write_room, +}; + +/* GLOBAL VARIABLES */ +struct sdio_downloader *sdio_dld; +struct sdio_dld_global_info sdio_dld_info; +static char outgoing_data_buffer[SDIO_DLD_OUTGOING_BUFFER_SIZE]; + +static DEFINE_SPINLOCK(lock1); +static unsigned long lock_flags1; +static DEFINE_SPINLOCK(lock2); +static unsigned long lock_flags2; + +/* + * sdio_op_mode sets the operation mode of the sdio_dloader - + * it may be in NORMAL_MODE, BOOT_TEST_MODE or AMSS_TEST_MODE + */ +static int sdio_op_mode = (int)SDIO_DLD_NORMAL_MODE; +module_param(sdio_op_mode, int, 0); + +#ifdef CONFIG_DEBUG_FS + +struct sdio_dloader_debug sdio_dld_debug; + +#define ARR_SIZE 30000 +#define SDIO_DLD_DEBUGFS_INIT_VALUE 87654321 +#define SDIO_DLD_DEBUGFS_CASE_1_CODE 11111111 +#define SDIO_DLD_DEBUGFS_CASE_2_CODE 22222222 +#define SDIO_DLD_DEBUGFS_CASE_3_CODE 33333333 +#define SDIO_DLD_DEBUGFS_CASE_4_CODE 44444444 +#define SDIO_DLD_DEBUGFS_CASE_5_CODE 55555555 +#define SDIO_DLD_DEBUGFS_CASE_6_CODE 66666666 +#define SDIO_DLD_DEBUGFS_CASE_7_CODE 77777777 +#define SDIO_DLD_DEBUGFS_CASE_8_CODE 88888888 +#define SDIO_DLD_DEBUGFS_CASE_9_CODE 99999999 +#define SDIO_DLD_DEBUGFS_CASE_10_CODE 10101010 +#define SDIO_DLD_DEBUGFS_CASE_11_CODE 11001100 +#define SDIO_DLD_DEBUGFS_CASE_12_CODE 12001200 +#define SDIO_DLD_DEBUGFS_LOOP_WAIT 7 +#define SDIO_DLD_DEBUGFS_LOOP_WAKEUP 8 +#define SDIO_DLD_DEBUGFS_CB_WAIT 3 +#define SDIO_DLD_DEBUGFS_CB_WAKEUP 4 + +static int curr_index; +struct ptrs { + int h_w_ptr; + int h_r_ptr; + int c_u_w_ptr; + int c_u_r_ptr; + int code; + int h_has_to_send; + int c_has_to_receive; + int min_of; + int reserve2; + int tty_count; + int write_tty; + int write_toio; + int loop_wait_wake; + int cb_wait_wake; + int c_d_w_ptr; + int c_d_r_ptr; + int to_read; + int push_to_tty; + int global_tty_send; + int global_sdio_send; + int global_tty_received; + int global_sdio_received; + int reserve22; + int reserve23; + int reserve24; + int reserve25; + int reserve26; + int reserve27; + int reserve28; + int reserve29; + int reserve30; + int reserve31; +}; + +struct global_data { + int curr_i; + int duration_ms; + int global_bytes_sent; + int throughput_Mbs; + int host_outgoing_buffer_size_KB; + int client_up_buffer_size_KB; + int client_dl_buffer_size_KB; + int client_dl_buffer_address; + int client_up_buffer_address; + int global_bytes_received; + int global_bytes_pushed; + int reserve11; + int reserve12; + int reserve13; + int reserve14; + int reserve15; + int reserve16; + int reserve17; + int reserve18; + int reserve19; + int reserve20; + int reserve21; + int reserve22; + int reserve23; + int reserve24; + int reserve25; + int reserve26; + int reserve27; + int reserve28; + int reserve29; + int reserve30; + int reserve31; + struct ptrs ptr_array[ARR_SIZE]; +}; + +static struct global_data gd; +static struct debugfs_blob_wrapper blob; +static struct dentry *root; +static struct dentry *dld; + +struct debugfs_global { + int global_8k_has; + int global_9k_has; + int global_min; + int global_count; + int global_write_tty; + int global_write_toio; + int global_bytes_cb_tty; + int global_to_read; + int global_push_to_tty; + int global_tty_send; + int global_sdio_send; + int global_sdio_received; + int global_tty_push; +}; + +static struct debugfs_global debugfs_glob; + +static void update_standard_fields(int index) +{ + + gd.ptr_array[index].global_tty_send = + sdio_dld_info.global_bytes_write_tty; + gd.ptr_array[index].global_sdio_send = + sdio_dld_info.global_bytes_write_toio; + gd.ptr_array[index].global_tty_received = + sdio_dld_info.global_bytes_push_tty; + gd.ptr_array[index].global_sdio_received = + sdio_dld_info.global_bytes_read_fromio; +} + +static void update_gd(int code) +{ + struct sdioc_reg_chunk *reg_str = + &sdio_dld->sdio_dloader_data.sdioc_reg; + struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data; + int index = curr_index%ARR_SIZE; + + gd.curr_i = curr_index; + gd.duration_ms = 0; + gd.global_bytes_sent = 0; + gd.throughput_Mbs = 0; + gd.host_outgoing_buffer_size_KB = 0; + gd.client_up_buffer_size_KB = 0; + gd.client_dl_buffer_size_KB = 0; + gd.client_dl_buffer_address = 0; + gd.client_up_buffer_address = 0; + gd.global_bytes_received = 0; + gd.global_bytes_pushed = 0; + gd.reserve11 = 0; + gd.reserve12 = 0; + gd.reserve13 = 0; + gd.reserve14 = 0; + gd.reserve15 = 0; + gd.reserve16 = 0; + gd.reserve17 = 0; + gd.reserve18 = 0; + gd.reserve19 = 0; + gd.reserve20 = 0; + gd.reserve21 = 0; + gd.reserve22 = 0; + gd.reserve23 = 0; + gd.reserve24 = 0; + gd.reserve25 = 0; + gd.reserve26 = 0; + gd.reserve27 = 0; + gd.reserve28 = 0; + gd.reserve29 = 0; + gd.reserve30 = 0; + gd.reserve31 = 0; + + gd.ptr_array[index].h_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*0*/ + gd.ptr_array[index].h_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*1*/ + gd.ptr_array[index].c_u_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*2*/ + gd.ptr_array[index].c_u_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*3*/ + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_INIT_VALUE; /*4*/ + gd.ptr_array[index].h_has_to_send = SDIO_DLD_DEBUGFS_INIT_VALUE;/*5*/ + gd.ptr_array[index].c_has_to_receive = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*6*/ + gd.ptr_array[index].min_of = SDIO_DLD_DEBUGFS_INIT_VALUE; /*7*/ + gd.ptr_array[index].reserve2 = SDIO_DLD_DEBUGFS_INIT_VALUE; /*8*/ + gd.ptr_array[index].tty_count = SDIO_DLD_DEBUGFS_INIT_VALUE; /*9*/ + gd.ptr_array[index].write_tty = SDIO_DLD_DEBUGFS_INIT_VALUE; /*A*/ + gd.ptr_array[index].write_toio = SDIO_DLD_DEBUGFS_INIT_VALUE; /*B*/ + gd.ptr_array[index].loop_wait_wake = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*C*/ + gd.ptr_array[index].cb_wait_wake = SDIO_DLD_DEBUGFS_INIT_VALUE; /*D*/ + gd.ptr_array[index].c_d_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*E*/ + gd.ptr_array[index].c_d_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*F*/ + gd.ptr_array[index].to_read = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x10*/ + gd.ptr_array[index].push_to_tty = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x11*/ + gd.ptr_array[index].global_tty_send = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x12*/ + gd.ptr_array[index].global_sdio_send = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x13*/ + gd.ptr_array[index].global_tty_received = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x14*/ + gd.ptr_array[index].global_sdio_received = + SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x15*/ + gd.ptr_array[index].reserve22 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve23 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve24 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve25 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve26 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve27 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve28 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve29 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve30 = SDIO_DLD_DEBUGFS_INIT_VALUE; + gd.ptr_array[index].reserve31 = SDIO_DLD_DEBUGFS_INIT_VALUE; + + switch (code) { + case SDIO_DLD_DEBUGFS_CASE_1_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_1_CODE; + gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p; + gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p; + gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val; + gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val; + gd.ptr_array[index].c_d_w_ptr = reg_str->dl_wr_ptr.reg_val; + gd.ptr_array[index].c_d_r_ptr = reg_str->dl_rd_ptr.reg_val; + break; + + case SDIO_DLD_DEBUGFS_CASE_2_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_2_CODE; + gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val; + gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val; + gd.ptr_array[index].h_has_to_send = debugfs_glob.global_8k_has; + gd.ptr_array[index].c_has_to_receive = + debugfs_glob.global_9k_has; + gd.ptr_array[index].min_of = debugfs_glob.global_min; + break; + + case SDIO_DLD_DEBUGFS_CASE_3_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_3_CODE; + gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p; + gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p; + gd.ptr_array[index].write_tty = debugfs_glob.global_write_tty; + break; + + case SDIO_DLD_DEBUGFS_CASE_4_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_4_CODE; + gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p; + gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p; + gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val; + gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val; + gd.ptr_array[index].write_toio = + debugfs_glob.global_write_toio; + break; + + case SDIO_DLD_DEBUGFS_CASE_5_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_5_CODE; + gd.ptr_array[index].tty_count = debugfs_glob.global_count; + break; + + case SDIO_DLD_DEBUGFS_CASE_6_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_6_CODE; + gd.ptr_array[index].loop_wait_wake = 7; + break; + + case SDIO_DLD_DEBUGFS_CASE_7_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_7_CODE; + gd.ptr_array[index].loop_wait_wake = 8; + break; + + case SDIO_DLD_DEBUGFS_CASE_8_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_8_CODE; + gd.ptr_array[index].cb_wait_wake = 3; + break; + + case SDIO_DLD_DEBUGFS_CASE_9_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_9_CODE; + gd.ptr_array[index].cb_wait_wake = 4; + break; + + case SDIO_DLD_DEBUGFS_CASE_10_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_10_CODE; + gd.ptr_array[index].cb_wait_wake = + debugfs_glob.global_bytes_cb_tty; + break; + + case SDIO_DLD_DEBUGFS_CASE_11_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_11_CODE; + gd.ptr_array[index].to_read = debugfs_glob.global_to_read; + break; + + case SDIO_DLD_DEBUGFS_CASE_12_CODE: + gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_12_CODE; + gd.ptr_array[index].push_to_tty = + debugfs_glob.global_push_to_tty; + break; + + default: + break; + } + update_standard_fields(index); + curr_index++; +} + +static int bootloader_debugfs_init(void) +{ + /* /sys/kernel/debug/bootloader there will be dld_arr file */ + root = debugfs_create_dir("bootloader", NULL); + if (!root) { + pr_info(MODULE_NAME ": %s - creating root dir " + "failed\n", __func__); + return -ENODEV; + } + + blob.data = &gd; + blob.size = sizeof(struct global_data); + dld = debugfs_create_blob("dld_arr", S_IRUGO, root, &blob); + if (!dld) { + debugfs_remove_recursive(root); + pr_err(MODULE_NAME ": %s, failed to create debugfs entry\n", + __func__); + return -ENODEV; + } + + return 0; +} + +/* +* for triggering the sdio_dld info use: +* echo 1 > /sys/kernel/debug/sdio_al_dld/sdio_al_dloader_info +*/ +static int sdio_dld_debug_init(void) +{ + sdio_dld_debug.sdio_dld_debug_root = + debugfs_create_dir("sdio_al_dld", NULL); + if (!sdio_dld_debug.sdio_dld_debug_root) { + pr_err(MODULE_NAME ": %s - Failed to create folder. " + "sdio_dld_debug_root is NULL", + __func__); + return -ENOENT; + } + + sdio_dld_debug.sdio_al_dloader = debugfs_create_file( + "sdio_al_dloader_info", + S_IRUGO | S_IWUGO, + sdio_dld_debug.sdio_dld_debug_root, + NULL, + &sdio_dld_debug_info_ops); + + if (!sdio_dld_debug.sdio_al_dloader) { + pr_err(MODULE_NAME ": %s - Failed to create a file. " + "sdio_al_dloader is NULL", + __func__); + debugfs_remove(sdio_dld_debug.sdio_dld_debug_root); + sdio_dld_debug.sdio_dld_debug_root = NULL; + return -ENOENT; + } + + return 0; +} + +static int sdio_dld_debug_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t sdio_dld_debug_info_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + sdio_dld_print_info(); + return count; +} +#endif /* CONFIG_DEBUG_FS */ + +static void sdio_dld_print_info(void) +{ + + sdio_dld_info.end_time = get_jiffies_64(); /* read the current time */ + sdio_dld_info.delta_jiffies = + sdio_dld_info.end_time - sdio_dld_info.start_time; + sdio_dld_info.time_msec = jiffies_to_msecs(sdio_dld_info.delta_jiffies); + + sdio_dld_info.throughput = sdio_dld_info.global_bytes_write_toio * + BITS_IN_BYTE / sdio_dld_info.time_msec; + sdio_dld_info.throughput /= MS_IN_SEC; + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - DURATION IN MSEC = %d\n", + __func__, + sdio_dld_info.time_msec); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES WRITTEN ON SDIO BUS " + "= %d...BYTES SENT BY TTY = %d", + __func__, + sdio_dld_info.global_bytes_write_toio, + sdio_dld_info.global_bytes_write_tty); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES RECEIVED ON SDIO BUS " + "= %d...BYTES SENT TO TTY = %d", + __func__, + sdio_dld_info.global_bytes_read_fromio, + sdio_dld_info.global_bytes_push_tty); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - THROUGHPUT=%d Mbit/Sec", + __func__, sdio_dld_info.throughput); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL_BUFFER_SIZE=%d" + " KB..CLIENT UL_BUFFER=%d KB\n", + __func__, + sdio_dld_info.cl_dl_buffer_size/BYTES_IN_KB, + sdio_dld_info.cl_up_buffer_size/BYTES_IN_KB); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST OUTGOING BUFFER_SIZE" + "=%d KB", + __func__, + sdio_dld_info.host_outgoing_buffer_size/BYTES_IN_KB); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL BUFFER " + "ADDRESS = 0x%x", __func__, + sdio_dld_info.cl_dl_buffer_address); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT UP BUFFER " + "ADDRESS = 0x%x", + __func__, + sdio_dld_info.cl_up_buffer_address); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - " + "READ POINTER = %d", __func__, + sdio_dld_info.cl_up_rd_ptr); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - " + "WRITE POINTER = %d", __func__, + sdio_dld_info.cl_up_wr_ptr); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - " + "READ POINTER = %d", __func__, + sdio_dld_info.cl_dl_rd_ptr); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - " + "WRITE POINTER = %d", __func__, + sdio_dld_info.cl_dl_wr_ptr); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - " + "READ POINTER = %d", __func__, + sdio_dld_info.host_read_ptr); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - " + "WRITE POINTER = %d", __func__, + sdio_dld_info.host_write_ptr); + + pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - END DEBUG INFO", __func__); +} + +/** + * sdio_dld_set_op_mode + * sets the op_mode and the name of the op_mode. Also, in case + * it's invalid mode sets op_mode to SDIO_DLD_NORMAL_MODE + * + * @op_mode: the operation mode to be set + * @return NONE + */ +static void sdio_dld_set_op_mode(enum sdio_dld_op_mode op_mode) +{ + sdio_dld->op_mode = op_mode; + + switch (op_mode) { + case SDIO_DLD_NORMAL_MODE: + memcpy(sdio_dld->op_mode_name, + SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE); + break; + case SDIO_DLD_BOOT_TEST_MODE: + memcpy(sdio_dld->op_mode_name, + SDIO_DLD_BOOT_TEST_MODE_NAME, TEST_NAME_MAX_SIZE); + break; + case SDIO_DLD_AMSS_TEST_MODE: + memcpy(sdio_dld->op_mode_name, + SDIO_DLD_AMSS_TEST_MODE_NAME, TEST_NAME_MAX_SIZE); + break; + default: + sdio_dld->op_mode = SDIO_DLD_NORMAL_MODE; + pr_err(MODULE_NAME ": %s - Invalid Op_Mode = %d. Settings " + "Op_Mode to default - NORMAL_MODE\n", + __func__, op_mode); + memcpy(sdio_dld->op_mode_name, + SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE); + break; + } + + if (sdio_dld->op_mode_name != NULL) { + pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - Op_Mode is set to " + "%s\n", __func__, sdio_dld->op_mode_name); + } else { + pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - op_mode_name is " + "NULL\n", __func__); + } +} + +/** + * sdio_dld_allocate_local_buffers + * allocates local outgoing and incoming buffers and also sets + * threshold for outgoing data. + * + * @return 0 on success or negative value on error. + */ +static int sdio_dld_allocate_local_buffers(void) +{ + struct sdioc_reg_chunk *reg_str = &sdio_dld->sdio_dloader_data. + sdioc_reg; + struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data; + struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data; + + incoming->data = + kzalloc(reg_str->dl_buff_size.reg_val, GFP_KERNEL); + + if (!incoming->data) { + pr_err(MODULE_NAME ": %s - param ""incoming->data"" is NULL. " + "Couldn't allocate incoming_data local buffer\n", + __func__); + return -ENOMEM; + } + + incoming->buffer_size = reg_str->dl_buff_size.reg_val; + + outgoing->data = outgoing_data_buffer; + + outgoing->buffer_size = SDIO_DLD_OUTGOING_BUFFER_SIZE; + + if (outgoing->buffer_size != + reg_str->ul_buff_size.reg_val*MULTIPLE_RATIO) { + pr_err(MODULE_NAME ": %s - HOST outgoing buffer size (%d bytes)" + "must be a multiple of ClIENT uplink buffer size (%d " + "bytes). HOST_SIZE == n*CLIENT_SIZE.(n=1,2,3...)\n", + __func__, + SDIO_DLD_OUTGOING_BUFFER_SIZE, + reg_str->ul_buff_size.reg_val); + kfree(incoming->data); + return -EINVAL; + } + + /* keep sdio_dld_info up to date */ + sdio_dld_info.host_outgoing_buffer_size = outgoing->buffer_size; + + return 0; +} + +/** + * sdio_dld_dealloc_local_buffers frees incoming and outgoing + * buffers. + * + * @return None. + */ +static void sdio_dld_dealloc_local_buffers(void) +{ + kfree((void *)sdio_dld->sdio_dloader_data.incoming_data.data); +} + +/** + * mailbox_to_seq_chunk_read_cfg + * reads 4 configuration registers of mailbox from str_func, as + * a sequentail chunk in memory, and updates global struct + * accordingly. + * + * @str_func: a pointer to func struct. + * @return 0 on success or negative value on error. + */ +static int mailbox_to_seq_chunk_read_cfg(struct sdio_func *str_func) +{ + struct sdioc_reg_sequential_chunk_cfg seq_chunk; + struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg; + int status = 0; + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + sdio_claim_host(str_func); + + /* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */ + status = sdio_memcpy_fromio(str_func, + (void *)&seq_chunk, + SDIOC_MAILBOX_ADDRESS, + SDIOC_CFG_REGS_SIZE); + if (status) { + pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()" + " READING CFG MAILBOX failed. status=%d.\n", + __func__, status); + } + + sdio_release_host(str_func); + + reg->dl_buff_address.reg_val = seq_chunk.dl_buff_address; + reg->up_buff_address.reg_val = seq_chunk.up_buff_address; + reg->dl_buff_size.reg_val = seq_chunk.dl_buff_size; + reg->ul_buff_size.reg_val = seq_chunk.ul_buff_size; + + /* keep sdio_dld_info up to date */ + sdio_dld_info.cl_dl_buffer_size = seq_chunk.dl_buff_size; + sdio_dld_info.cl_up_buffer_size = seq_chunk.ul_buff_size; + sdio_dld_info.cl_dl_buffer_address = seq_chunk.dl_buff_address; + sdio_dld_info.cl_up_buffer_address = seq_chunk.up_buff_address; + + return status; +} + +/** + * mailbox_to_seq_chunk_read_ptrs + * reads 4 pointers registers of mailbox from str_func, as a + * sequentail chunk in memory, and updates global struct + * accordingly. + * + * @str_func: a pointer to func struct. + * @return 0 on success or negative value on error. + */ +static int mailbox_to_seq_chunk_read_ptrs(struct sdio_func *str_func) +{ + struct sdioc_reg_sequential_chunk_ptrs seq_chunk; + struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg; + int status = 0; + + struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data; + static int counter = 1; + static int offset_write_p; + static int offset_read_p; + static int up_wr_ptr; + static int up_rd_ptr; + static int dl_wr_ptr; + static int dl_rd_ptr; + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + sdio_claim_host(str_func); + + /* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */ + status = sdio_memcpy_fromio(str_func, + (void *)&seq_chunk, + SDIOC_PTRS_OFFSET, + SDIOC_PTR_REGS_SIZE); + if (status) { + pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()" + " READING PTRS MAILBOX failed. status=%d.\n", + __func__, status); + } + + sdio_release_host(str_func); + + reg->dl_rd_ptr.reg_val = seq_chunk.dl_rd_ptr; + reg->dl_wr_ptr.reg_val = seq_chunk.dl_wr_ptr; + reg->up_rd_ptr.reg_val = seq_chunk.up_rd_ptr; + reg->up_wr_ptr.reg_val = seq_chunk.up_wr_ptr; + + /* keeping sdio_dld_info up to date */ + sdio_dld_info.cl_dl_rd_ptr = seq_chunk.dl_rd_ptr; + sdio_dld_info.cl_dl_wr_ptr = seq_chunk.dl_wr_ptr; + sdio_dld_info.cl_up_rd_ptr = seq_chunk.up_rd_ptr; + sdio_dld_info.cl_up_wr_ptr = seq_chunk.up_wr_ptr; + + + /* DEBUG - if there was a change in value */ + if ((offset_write_p != outgoing->offset_write_p) || + (offset_read_p != outgoing->offset_read_p) || + (up_wr_ptr != reg->up_wr_ptr.reg_val) || + (up_rd_ptr != reg->up_rd_ptr.reg_val) || + (dl_wr_ptr != reg->dl_wr_ptr.reg_val) || + (dl_rd_ptr != reg->dl_rd_ptr.reg_val) || + (counter % PRINTING_GAP == 0)) { + counter = 1; + pr_debug(MODULE_NAME ": %s MailBox pointers: BLOCK_SIZE=%d, " + "hw=%d, hr=%d, cuw=%d, cur=%d, cdw=%d, cdr=%d\n", + __func__, + SDIO_DL_BLOCK_SIZE, + outgoing->offset_write_p, + outgoing->offset_read_p, + reg->up_wr_ptr.reg_val, + reg->up_rd_ptr.reg_val, + reg->dl_wr_ptr.reg_val, + reg->dl_rd_ptr.reg_val); + +#ifdef CONFIG_DEBUG_FS + update_gd(SDIO_DLD_DEBUGFS_CASE_1_CODE); +#endif + /* update static variables */ + offset_write_p = outgoing->offset_write_p; + offset_read_p = outgoing->offset_read_p; + up_wr_ptr = reg->up_wr_ptr.reg_val; + up_rd_ptr = reg->up_rd_ptr.reg_val; + dl_wr_ptr = reg->dl_wr_ptr.reg_val; + dl_rd_ptr = reg->dl_rd_ptr.reg_val; + } else { + counter++; + } + return status; +} + +/** + * sdio_dld_init_func + * enables the sdio func, and sets the func block size. + * + * @str_func: a pointer to func struct. + * @return 0 on success or negative value on error. + */ +static int sdio_dld_init_func(struct sdio_func *str_func) +{ + int status1 = 0; + int status2 = 0; + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + sdio_claim_host(str_func); + + status1 = sdio_enable_func(str_func); + if (status1) { + sdio_release_host(str_func); + pr_err(MODULE_NAME ": %s - sdio_enable_func() failed. " + "status=%d\n", __func__, status1); + return status1; + } + + status2 = sdio_set_block_size(str_func, SDIO_DL_BLOCK_SIZE); + if (status2) { + pr_err(MODULE_NAME ": %s - sdio_set_block_size() failed. " + "status=%d\n", __func__, status2); + status1 = sdio_disable_func(str_func); + if (status1) { + pr_err(MODULE_NAME ": %s - sdio_disable_func() " + "failed. status=%d\n", __func__, status1); + } + sdio_release_host(str_func); + return status2; + } + + sdio_release_host(str_func); + str_func->max_blksize = SDIO_DL_BLOCK_SIZE; + return 0; +} + +/** + * sdio_dld_allocate_buffers + * initializes the sdio func, and then reads the mailbox, in + * order to allocate incoming and outgoing buffers according to + * the size that was read from the mailbox. + * + * @str_func: a pointer to func struct. + * @return 0 on success or negative value on error. + */ +static int sdio_dld_allocate_buffers(struct sdio_func *str_func) +{ + int status = 0; + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + status = mailbox_to_seq_chunk_read_cfg(str_func); + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "mailbox_to_seq_chunk_read_cfg(). status=%d\n", + __func__, status); + return status; + } + + status = sdio_dld_allocate_local_buffers(); + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdio_dld_allocate_local_buffers(). status=%d\n", + __func__, status); + return status; + } + return 0; +} + +/** + * sdio_dld_create_thread + * creates thread and wakes it up. + * + * @return 0 on success or negative value on error. + */ +static int sdio_dld_create_thread(void) +{ + sdio_dld->dld_main_thread.task_name = SDIO_DL_MAIN_THREAD_NAME; + + sdio_dld->dld_main_thread.dld_task = + kthread_create(sdio_dld_main_task, + (void *)(sdio_dld->card), + sdio_dld->dld_main_thread.task_name); + + if (IS_ERR(sdio_dld->dld_main_thread.dld_task)) { + pr_err(MODULE_NAME ": %s - kthread_create() failed\n", + __func__); + return -ENOMEM; + } + wake_up_process(sdio_dld->dld_main_thread.dld_task); + return 0; +} + +/** + * start_timer + * sets the timer and starts. + * + * @timer: the timer to configure and add + * @ms: the ms until it expires + * @return None. + */ +static void start_timer(struct timer_list *timer, unsigned int ms) +{ + if ((ms == 0) || (timer == NULL)) { + pr_err(MODULE_NAME ": %s - invalid parameter", __func__); + } else { + timer->expires = jiffies + + msecs_to_jiffies(ms); + add_timer(timer); + } +} + +/** + * sdio_dld_timer_handler + * this is the timer handler. whenever it is invoked, it wakes + * up the main loop task, and the write callback, and starts + * the timer again. + * + * @data: a pointer to the tty device driver structure. + * @return None. + */ + +static void sdio_dld_timer_handler(unsigned long data) +{ + pr_debug(MODULE_NAME " Timer Expired\n"); + spin_lock_irqsave(&lock2, lock_flags2); + if (sdio_dld->main_loop_event.wake_up_signal == 0) { + sdio_dld->main_loop_event.wake_up_signal = 1; + wake_up(&sdio_dld->main_loop_event.wait_event); + } + spin_unlock_irqrestore(&lock2, lock_flags2); + + sdio_dld->write_callback_event.wake_up_signal = 1; + wake_up(&sdio_dld->write_callback_event.wait_event); + + start_timer(&sdio_dld->timer, sdio_dld->poll_ms); +} + +/** + * sdio_dld_push_timer_handler + * this is a timer handler of the push_timer. + * + * @data: a pointer to the tty device driver structure. + * @return None. + */ +static void sdio_dld_push_timer_handler(unsigned long data) +{ + pr_err(MODULE_NAME " %s - Push Timer Expired... Trying to " + "push data to TTY Core for over then %d ms.\n", + __func__, sdio_dld->push_timer_ms); +} + +/** + * sdio_dld_open + * this is the open callback of the tty driver. + * it initializes the sdio func, allocates the buffers, and + * creates the main thread. + * + * @tty: a pointer to the tty struct. + * @file: file descriptor. + * @return 0 on success or negative value on error. + */ +static int sdio_dld_open(struct tty_struct *tty, struct file *file) +{ + int status = 0; + int func_in_array = + REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func); + struct sdio_func *str_func = sdio_dld->card->sdio_func[func_in_array]; + + sdio_dld->tty_str = tty; + sdio_dld->tty_str->low_latency = 1; + sdio_dld->tty_str->icanon = 0; + set_bit(TTY_NO_WRITE_SPLIT, &sdio_dld->tty_str->flags); + + pr_info(MODULE_NAME ": %s, TTY DEVICE FOR FLASHLESS BOOT OPENED\n", + __func__); + sdio_dld_info.start_time = get_jiffies_64(); /* read the current time */ + + if (!tty) { + pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + atomic_set(&sdio_dld->dld_main_thread.please_close, 0); + sdio_dld->dld_main_thread.exit_wait.wake_up_signal = 0; + + status = sdio_dld_allocate_buffers(str_func); + if (status) { + pr_err(MODULE_NAME ": %s, failed in " + "sdio_dld_allocate_buffers(). status=%d\n", + __func__, status); + return status; + } + + /* init waiting event of the write callback */ + init_waitqueue_head(&sdio_dld->write_callback_event.wait_event); + + /* init waiting event of the main loop */ + init_waitqueue_head(&sdio_dld->main_loop_event.wait_event); + + /* configure and init the timer */ + sdio_dld->poll_ms = TIMER_DURATION; + init_timer(&sdio_dld->timer); + sdio_dld->timer.data = (unsigned long) sdio_dld; + sdio_dld->timer.function = sdio_dld_timer_handler; + sdio_dld->timer.expires = jiffies + + msecs_to_jiffies(sdio_dld->poll_ms); + add_timer(&sdio_dld->timer); + + sdio_dld->push_timer_ms = PUSH_TIMER_DURATION; + init_timer(&sdio_dld->push_timer); + sdio_dld->push_timer.data = (unsigned long) sdio_dld; + sdio_dld->push_timer.function = sdio_dld_push_timer_handler; + + status = sdio_dld_create_thread(); + if (status) { + del_timer_sync(&sdio_dld->timer); + del_timer_sync(&sdio_dld->push_timer); + sdio_dld_dealloc_local_buffers(); + pr_err(MODULE_NAME ": %s, failed in sdio_dld_create_thread()." + "status=%d\n", __func__, status); + return status; + } + return 0; +} + +/** + * sdio_dld_close + * this is the close callback of the tty driver. it requests + * the main thread to exit, and waits for notification of it. + * it also de-allocates the buffers, and unregisters the tty + * driver and device. + * + * @tty: a pointer to the tty struct. + * @file: file descriptor. + * @return None. + */ +static void sdio_dld_close(struct tty_struct *tty, struct file *file) +{ + int status = 0; + struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg; + + /* informing the SDIOC that it can exit boot phase */ + sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_val = + SDIOC_EXIT_CODE; + + atomic_set(&sdio_dld->dld_main_thread.please_close, 1); + + pr_debug(MODULE_NAME ": %s - CLOSING - WAITING...", __func__); + + wait_event(sdio_dld->dld_main_thread.exit_wait.wait_event, + sdio_dld->dld_main_thread.exit_wait.wake_up_signal); + pr_debug(MODULE_NAME ": %s - CLOSING - WOKE UP...", __func__); + + del_timer_sync(&sdio_dld->timer); + del_timer_sync(&sdio_dld->push_timer); + + sdio_dld_dealloc_local_buffers(); + + tty_unregister_device(sdio_dld->tty_drv, 0); + + status = tty_unregister_driver(sdio_dld->tty_drv); + + if (status) { + pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n", + __func__); + } + +#ifdef CONFIG_DEBUG_FS + gd.curr_i = curr_index; + gd.duration_ms = sdio_dld_info.time_msec; + gd.global_bytes_sent = sdio_dld_info.global_bytes_write_toio; + gd.global_bytes_received = 0; + gd.throughput_Mbs = sdio_dld_info.throughput; + gd.host_outgoing_buffer_size_KB = sdio_dld->sdio_dloader_data. + outgoing_data.buffer_size/BYTES_IN_KB; + gd.client_up_buffer_size_KB = reg->ul_buff_size.reg_val/BYTES_IN_KB; + gd.client_dl_buffer_size_KB = reg->dl_buff_size.reg_val/BYTES_IN_KB; + gd.client_dl_buffer_address = reg->dl_buff_address.reg_val; + gd.client_up_buffer_address = reg->up_buff_address.reg_val; + gd.global_bytes_received = sdio_dld_info.global_bytes_read_fromio; + gd.global_bytes_pushed = sdio_dld_info.global_bytes_push_tty; +#endif + + /* saving register values before deallocating sdio_dld + in order to use it in sdio_dld_print_info() through shell command */ + sdio_dld_info.cl_dl_rd_ptr = reg->dl_rd_ptr.reg_val; + sdio_dld_info.cl_dl_wr_ptr = reg->dl_wr_ptr.reg_val; + sdio_dld_info.cl_up_rd_ptr = reg->up_rd_ptr.reg_val; + sdio_dld_info.cl_up_wr_ptr = reg->up_wr_ptr.reg_val; + + sdio_dld_info.host_read_ptr = + sdio_dld->sdio_dloader_data.outgoing_data.offset_read_p; + + sdio_dld_info.host_write_ptr = + sdio_dld->sdio_dloader_data.outgoing_data.offset_write_p; + + sdio_dld_info.cl_dl_buffer_size = + sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_val; + + sdio_dld_info.cl_up_buffer_size = + sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_val; + + sdio_dld_info.host_outgoing_buffer_size = + sdio_dld->sdio_dloader_data.outgoing_data.buffer_size; + + sdio_dld_info.cl_dl_buffer_address = + sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_val; + + sdio_dld_info.cl_up_buffer_address = + sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_val; + + sdio_dld_print_info(); + + if (sdio_dld->done_callback) + sdio_dld->done_callback(); + + pr_info(MODULE_NAME ": %s - Freeing sdio_dld data structure, and " + " returning...", __func__); + kfree(sdio_dld); +} + +/** + * writing_size_to_buf + * writes from src buffer into dest buffer. if dest buffer + * reaches its end, rollover happens. + * + * @dest: destination buffer. + * @src: source buffer. + * @dest_wr_ptr: writing pointer in destination buffer. + * @dest_size: destination buffer size. + * @dest_rd_ptr: reading pointer in destination buffer. + * @size_to_write: size of bytes to write. + * @return -how many bytes actually written to destination + * buffer. + * + * ONLY destination buffer is treated as cyclic buffer. + */ +static int writing_size_to_buf(char *dest, + const unsigned char *src, + int *dest_wr_ptr, + int dest_size, + int dest_rd_ptr, + int size_to_write) +{ + int actually_written = 0; + int size_to_add = *dest_wr_ptr; + + if (!dest) { + pr_err(MODULE_NAME ": %s - param ""dest"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!src) { + pr_err(MODULE_NAME ": %s - param ""src"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!dest_wr_ptr) { + pr_err(MODULE_NAME ": %s - param ""dest_wr_ptr"" is NULL.\n", + __func__); + return -EINVAL; + } + + for (actually_written = 0 ; + actually_written < size_to_write ; ++actually_written) { + /* checking if buffer is full */ + if (((size_to_add + 1) % dest_size) == dest_rd_ptr) { + *dest_wr_ptr = size_to_add; + return actually_written; + } + + dest[size_to_add] = src[actually_written]; + size_to_add = (size_to_add+1)%dest_size; + } + + *dest_wr_ptr = size_to_add; + + return actually_written; +} + +/** + * sdioc_bytes_till_end_of_buffer - this routine calculates how many bytes are + * empty/in use. if calculation requires rap around - it will ignore the rap + * around and will do the calculation untill the end of the buffer + * + * @write_ptr: writing pointer. + * @read_ptr: reading pointer. + * @total_size: buffer size. + * @free_bytes: return value-how many free bytes. + * @bytes_in_use: return value-how many bytes in use. + * @return 0 on success or negative value on error. + * + * buffer is treated as a cyclic buffer. + */ +static int sdioc_bytes_till_end_of_buffer(int write_ptr, + int read_ptr, + int total_size, + int *free_bytes, + int *bytes_in_use) +{ + if (!free_bytes) { + pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!bytes_in_use) { + pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (write_ptr >= read_ptr) { + if (read_ptr == 0) + *free_bytes = total_size - write_ptr - 1; + else + *free_bytes = total_size - write_ptr; + *bytes_in_use = write_ptr - read_ptr; + } else { + *bytes_in_use = total_size - read_ptr; + *free_bytes = read_ptr - write_ptr - 1; + } + + return 0; +} + +/** + * sdioc_bytes_free_in_buffer + * this routine calculates how many bytes are free in a buffer + * and how many are in use, according to its reading and + * writing pointer offsets. + * + * @write_ptr: writing pointer. + * @read_ptr: reading pointer. + * @total_size: buffer size. + * @free_bytes: return value-how many free bytes in buffer. + * @bytes_in_use: return value-how many bytes in use in buffer. + * @return 0 on success or negative value on error. + * + * buffer is treated as a cyclic buffer. + */ +static int sdioc_bytes_free_in_buffer(int write_ptr, + int read_ptr, + int total_size, + int *free_bytes, + int *bytes_in_use) +{ + if (!free_bytes) { + pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!bytes_in_use) { + pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n", + __func__); + return -EINVAL; + } + + /* if pointers equel - buffers are empty. nothing to read/write */ + + if (write_ptr >= read_ptr) + *bytes_in_use = write_ptr - read_ptr; + else + *bytes_in_use = total_size - (read_ptr - write_ptr); + + *free_bytes = total_size - *bytes_in_use - 1; + + return 0; +} + +/* +* sdio_dld_write_room +* +* This is the write_room function of the tty driver. +* +* @tty: pointer to tty struct. +* @return free bytes for write. +* +*/ +static int sdio_dld_write_room(struct tty_struct *tty) +{ + return sdio_dld->sdio_dloader_data.outgoing_data.buffer_size; +} + +/** + * sdio_dld_write_callback + * this is the write callback of the tty driver. + * + * @tty: pointer to tty struct. + * @buf: buffer to write from. + * @count: number of bytes to write. + * @return bytes written or negative value on error. + * + * if destination buffer has not enough room for the incoming + * data, returns an error. + */ +static int sdio_dld_write_callback(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data; + int dst_free_bytes = 0; + int dummy = 0; + int status = 0; + int bytes_written = 0; + int total_written = 0; + static int write_retry; + int pending_to_write = count; + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_count = count; + update_gd(SDIO_DLD_DEBUGFS_CASE_5_CODE); +#endif + + pr_debug(MODULE_NAME ": %s - WRITING CALLBACK CALLED WITH %d bytes\n", + __func__, count); + + if (!outgoing->data) { + pr_err(MODULE_NAME ": %s - param ""outgoing->data"" is NULL.\n", + __func__); + return -EINVAL; + } + + pr_debug(MODULE_NAME ": %s - WRITE CALLBACK size to write to outgoing" + " buffer %d\n", __func__, count); + + /* as long as there is something to write to outgoing buffer */ + do { + int bytes_to_write = 0; + status = sdioc_bytes_free_in_buffer( + outgoing->offset_write_p, + outgoing->offset_read_p, + outgoing->buffer_size, + &dst_free_bytes, + &dummy); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdioc_bytes_free_in_buffer(). status=%d\n", + __func__, status); + return status; + } + + /* + * if there is free room in outgoing buffer + * lock mutex and request trigger notification from the main + * task. unlock mutex, and wait for sinal + */ + if (dst_free_bytes > 0) { + write_retry = 0; + /* + * if there is more data to write to outgoing buffer + * than it can receive, wait for signal from main task + */ + if (pending_to_write > dst_free_bytes) { + + /* sampling updated dst_free_bytes */ + status = sdioc_bytes_free_in_buffer( + outgoing->offset_write_p, + outgoing->offset_read_p, + outgoing->buffer_size, + &dst_free_bytes, + &dummy); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in " + "Function " + "sdioc_bytes_free_in_buffer(). " + "status=%d\n", __func__, status); + return status; + } + } + + bytes_to_write = min(pending_to_write, dst_free_bytes); + bytes_written = + writing_size_to_buf(outgoing->data, + buf+total_written, + &outgoing->offset_write_p, + outgoing->buffer_size, + outgoing->offset_read_p, + bytes_to_write); + + /* keeping sdio_dld_info up to date */ + sdio_dld_info.host_write_ptr = + sdio_dld->sdio_dloader_data. + outgoing_data.offset_write_p; + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_write_tty = bytes_written; + update_gd(SDIO_DLD_DEBUGFS_CASE_3_CODE); +#endif + sdio_dld_info.global_bytes_write_tty += bytes_written; + + spin_lock_irqsave(&lock2, lock_flags2); + if (sdio_dld->main_loop_event.wake_up_signal == 0) { + sdio_dld->main_loop_event.wake_up_signal = 1; + wake_up(&sdio_dld->main_loop_event.wait_event); + } + spin_unlock_irqrestore(&lock2, lock_flags2); + + /* + * although outgoing buffer has enough room, writing + * failed + */ + if (bytes_written != bytes_to_write) { + pr_err(MODULE_NAME ": %s - couldn't write " + "%d bytes to " "outgoing buffer." + "bytes_written=%d\n", + __func__, bytes_to_write, + bytes_written); + return -EIO; + } + + total_written += bytes_written; + pending_to_write -= bytes_written; + outgoing->num_of_bytes_in_use += bytes_written; + + pr_debug(MODULE_NAME ": %s - WRITE CHUNK to outgoing " + "buffer. pending_to_write=%d, " + "outgoing_free_bytes=%d, " + "bytes_written=%d\n", + __func__, + pending_to_write, + dst_free_bytes, + bytes_written); + + } else { + write_retry++; + + pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - NO ROOM." + " pending_to_write=%d, write_retry=%d\n", + __func__, + pending_to_write, + write_retry); + + spin_lock_irqsave(&lock1, lock_flags1); + sdio_dld->write_callback_event.wake_up_signal = 0; + spin_unlock_irqrestore(&lock1, lock_flags1); + + pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - " + "WAITING...", __func__); +#ifdef CONFIG_DEBUG_FS + update_gd(SDIO_DLD_DEBUGFS_CASE_8_CODE); +#endif + wait_event(sdio_dld->write_callback_event.wait_event, + sdio_dld->write_callback_event. + wake_up_signal); +#ifdef CONFIG_DEBUG_FS + update_gd(SDIO_DLD_DEBUGFS_CASE_9_CODE); +#endif + pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - " + "WOKE UP...", __func__); + } + } while (pending_to_write > 0 && write_retry < WRITE_RETRIES); + + if (pending_to_write > 0) { + + pr_err(MODULE_NAME ": %s - WRITE CALLBACK - pending data is " + "%d out of %d > 0. total written in this " + "callback = %d\n", + __func__, pending_to_write, count, total_written); + } + + if (write_retry == WRITE_RETRIES) { + pr_err(MODULE_NAME ": %s, write_retry=%d= max\n", + __func__, write_retry); + } + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_bytes_cb_tty = total_written; + update_gd(SDIO_DLD_DEBUGFS_CASE_10_CODE); +#endif + + return total_written; +} + +/** + * sdio_memcpy_fromio_wrapper - + * reads from sdioc, and updats the sdioc registers according + * to how many bytes were actually read. + * + * @str_func: a pointer to func struct. + * @client_rd_ptr: sdioc value of downlink read ptr. + * @client_wr_ptr: sdioc value of downlink write ptr. + * @buffer_to_store: buffer to store incoming data. + * @address_to_read: address to start reading from in sdioc. + * @size_to_read: size of bytes to read. + * @client_buffer_size: sdioc downlink buffer size. + * @return 0 on success or negative value on error. + */ +static int sdio_memcpy_fromio_wrapper(struct sdio_func *str_func, + unsigned int client_rd_ptr, + unsigned int client_wr_ptr, + void *buffer_to_store, + unsigned int address_to_read_from, + int size_to_read, + int client_buffer_size) +{ + int status = 0; + struct sdioc_reg_chunk *reg_str = + &sdio_dld->sdio_dloader_data.sdioc_reg; + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!buffer_to_store) { + pr_err(MODULE_NAME ": %s - param ""buffer_to_store"" is " + "NULL.\n", + __func__); + return -EINVAL; + } + + if (size_to_read < 0) { + pr_err(MODULE_NAME ": %s - invalid size to read=%d\n", + __func__, size_to_read); + return -EINVAL; + } + + sdio_claim_host(str_func); + + pr_debug(MODULE_NAME ": %s, READING DATA - from add %d, " + "size_to_read=%d\n", + __func__, address_to_read_from, size_to_read); + + status = sdio_memcpy_fromio(str_func, + (void *)buffer_to_store, + address_to_read_from, + size_to_read); + if (status) { + pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()" + " DATA failed. status=%d.\n", + __func__, status); + sdio_release_host(str_func); + return status; + } + + /* updating an offset according to cyclic buffer size */ + reg_str->dl_rd_ptr.reg_val = + (reg_str->dl_rd_ptr.reg_val + size_to_read) % + client_buffer_size; + /* keeping sdio_dld_info up to date */ + sdio_dld_info.cl_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val; + + status = sdio_memcpy_toio(str_func, + reg_str->dl_rd_ptr.reg_offset, + (void *)®_str->dl_rd_ptr.reg_val, + sizeof(reg_str->dl_rd_ptr.reg_val)); + + if (status) { + pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() " + "UPDATE PTR failed. status=%d.\n", + __func__, status); + } + + sdio_release_host(str_func); + return status; +} + +/** + * sdio_memcpy_toio_wrapper + * writes to sdioc, and updats the sdioc registers according + * to how many bytes were actually read. + * + * @str_func: a pointer to func struct. + * @client_wr_ptr: sdioc downlink write ptr. + * @h_read_ptr: host incoming read ptrs + * @buf_write_from: buffer to write from. + * @bytes_to_write: number of bytes to write. + * @return 0 on success or negative value on error. + */ +static int sdio_memcpy_toio_wrapper(struct sdio_func *str_func, + unsigned int client_wr_ptr, + unsigned int h_read_ptr, + void *buf_write_from, + int bytes_to_write) +{ + int status = 0; + struct sdioc_reg_chunk *reg_str = + &sdio_dld->sdio_dloader_data.sdioc_reg; + struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data; + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!buf_write_from) { + pr_err(MODULE_NAME ": %s - param ""buf_write_from"" is NULL.\n", + __func__); + return -EINVAL; + } + + sdio_claim_host(str_func); + + pr_debug(MODULE_NAME ": %s, WRITING DATA TOIO to address 0x%x, " + "bytes_to_write=%d\n", + __func__, + reg_str->up_buff_address.reg_val + reg_str->up_wr_ptr.reg_val, + bytes_to_write); + + status = sdio_memcpy_toio(str_func, + reg_str->up_buff_address.reg_val + + reg_str->up_wr_ptr.reg_val, + (void *) (outgoing->data + h_read_ptr), + bytes_to_write); + + if (status) { + pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() " + "DATA failed. status=%d.\n", __func__, status); + sdio_release_host(str_func); + return status; + } + + sdio_dld_info.global_bytes_write_toio += bytes_to_write; + outgoing->num_of_bytes_in_use -= bytes_to_write; + + /* + * if writing to client succeeded, then + * 1. update the client up_wr_ptr + * 2. update the host outgoing rd ptr + **/ + reg_str->up_wr_ptr.reg_val = + ((reg_str->up_wr_ptr.reg_val + bytes_to_write) % + reg_str->ul_buff_size.reg_val); + + /* keeping sdio_dld_info up to date */ + sdio_dld_info.cl_up_wr_ptr = reg_str->up_wr_ptr.reg_val; + + outgoing->offset_read_p = + ((outgoing->offset_read_p + bytes_to_write) % + outgoing->buffer_size); + + /* keeping sdio_dld_info up to date*/ + sdio_dld_info.host_read_ptr = outgoing->offset_read_p; + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_write_toio = bytes_to_write; + update_gd(SDIO_DLD_DEBUGFS_CASE_4_CODE); +#endif + + /* updating uplink write pointer according to size that was written */ + status = sdio_memcpy_toio(str_func, + reg_str->up_wr_ptr.reg_offset, + (void *)(®_str->up_wr_ptr.reg_val), + sizeof(reg_str->up_wr_ptr.reg_val)); + if (status) { + pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() " + "UPDATE PTR failed. status=%d.\n", + __func__, status); + } + + sdio_release_host(str_func); + return status; +} + +/** + * sdio_dld_read + * reads from sdioc + * + * @client_rd_ptr: sdioc downlink read ptr. + * @client_wr_ptr: sdioc downlink write ptr. + * @reg_str: sdioc register shadowing struct. + * @str_func: a pointer to func struct. + * @bytes_read:how many bytes read. + * @return 0 on success or negative value on error. + */ +static int sdio_dld_read(unsigned int client_rd_ptr, + unsigned int client_wr_ptr, + struct sdioc_reg_chunk *reg_str, + struct sdio_func *str_func, + int *bytes_read) +{ + int status = 0; + struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data; + + if (!reg_str) { + pr_err(MODULE_NAME ": %s - param ""reg_str"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!bytes_read) { + pr_err(MODULE_NAME ": %s - param ""bytes_read"" is NULL.\n", + __func__); + return -EINVAL; + } + + /* there is data to read in ONE chunk */ + if (client_wr_ptr > client_rd_ptr) { + status = sdio_memcpy_fromio_wrapper( + str_func, + client_rd_ptr, + client_wr_ptr, + (void *)incoming->data, + reg_str->dl_buff_address.reg_val + client_rd_ptr, + client_wr_ptr - client_rd_ptr, + reg_str->dl_buff_size.reg_val); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdio_memcpy_fromio_wrapper(). " + "SINGLE CHUNK READ. status=%d\n", + __func__, status); + return status; + } + + incoming->num_of_bytes_in_use += client_wr_ptr - client_rd_ptr; + *bytes_read = client_wr_ptr - client_rd_ptr; + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_to_read = + client_wr_ptr - client_rd_ptr; + update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE); +#endif + } + + /* there is data to read in TWO chunks */ + else { + int dl_buf_size = reg_str->dl_buff_size.reg_val; + int tail_size = dl_buf_size - client_rd_ptr; + + /* reading chunk#1: from rd_ptr to the end of the buffer */ + status = sdio_memcpy_fromio_wrapper( + str_func, + client_rd_ptr, + dl_buf_size, + (void *)incoming->data, + reg_str->dl_buff_address.reg_val + client_rd_ptr, + tail_size, + dl_buf_size); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdio_memcpy_fromio_wrapper(). " + "1 of 2 CHUNKS READ. status=%d\n", + __func__, status); + return status; + } + + incoming->num_of_bytes_in_use += tail_size; + *bytes_read = tail_size; + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_to_read = tail_size; + update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE); +#endif + + /* reading chunk#2: reading from beginning buffer */ + status = sdio_memcpy_fromio_wrapper( + str_func, + client_rd_ptr, + client_wr_ptr, + (void *)(incoming->data + tail_size), + reg_str->dl_buff_address.reg_val, + client_wr_ptr, + reg_str->dl_buff_size.reg_val); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdio_memcpy_fromio_wrapper(). " + "2 of 2 CHUNKS READ. status=%d\n", + __func__, status); + return status; + } + + incoming->num_of_bytes_in_use += client_wr_ptr; + *bytes_read += client_wr_ptr; + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_to_read = client_wr_ptr; + update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE); +#endif + } + return 0; +} + +/** + * sdio_dld_main_task + * sdio downloader main task. reads mailboxf checks if there is + * anything to read, checks if host has anything to + * write. + * + * @card: a pointer to mmc_card. + * @return 0 on success or negative value on error. + */ +static int sdio_dld_main_task(void *card) +{ + int status = 0; + struct tty_struct *tty = sdio_dld->tty_str; + struct sdioc_reg_chunk *reg_str = + &sdio_dld->sdio_dloader_data.sdioc_reg; + int func = sdio_dld->sdioc_boot_func; + struct sdio_func *str_func = NULL; + struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data; + struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data; + struct sdio_dld_task *task = &sdio_dld->dld_main_thread; + int retries = 0; +#ifdef PUSH_STRING + int bytes_pushed = 0; +#endif + + msleep(SLEEP_MS); + + if (!card) { + pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!tty) { + pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n", + __func__); + return -EINVAL; + } + + str_func = ((struct mmc_card *)card)-> + sdio_func[REAL_FUNC_TO_FUNC_IN_ARRAY(func)]; + + if (!str_func) { + pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n", + __func__); + return -EINVAL; + } + + while (true) { + /* client pointers for both buffers */ + int client_ul_wr_ptr = 0; + int client_ul_rd_ptr = 0; + int client_dl_wr_ptr = 0; + int client_dl_rd_ptr = 0; + + /* host pointer for outgoing buffer */ + int h_out_wr_ptr = 0; + int h_out_rd_ptr = 0; + + int h_bytes_rdy_wr = 0; + int c_bytes_rdy_rcve = 0; + + int need_to_write = 0; + int need_to_read = 0; + + /* + * forever, checking for signal to die, then read MailBox. + * if nothing to read or nothing to write to client, sleep, + * and again read MailBox + */ + do { + int dummy = 0; + + /* checking if a signal to die was sent */ + if (atomic_read(&task->please_close) == 1) { + + pr_debug(MODULE_NAME ": %s - 0x%x was written " + "to 9K\n", __func__, SDIOC_EXIT_CODE); + + sdio_claim_host(str_func); + + /* returned value is not checked on purpose */ + sdio_memcpy_toio( + str_func, + reg_str->good_to_exit_ptr.reg_offset, + (void *)®_str->good_to_exit_ptr. + reg_val, + sizeof(reg_str->good_to_exit_ptr. + reg_val)); + + sdio_release_host(str_func); + + task->exit_wait.wake_up_signal = 1; + wake_up(&task->exit_wait.wait_event); + return 0; + } + + status = mailbox_to_seq_chunk_read_ptrs(str_func); + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "mailbox_to_seq_chunk_read_ptrs(). " + "status=%d\n", __func__, status); + return status; + } + + /* calculate how many bytes the host has send */ + h_out_wr_ptr = outgoing->offset_write_p; + h_out_rd_ptr = outgoing->offset_read_p; + + status = sdioc_bytes_till_end_of_buffer( + h_out_wr_ptr, + h_out_rd_ptr, + outgoing->buffer_size, + &dummy, + &h_bytes_rdy_wr); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdioc_bytes_till_end_of_buffer(). " + "status=%d\n", __func__, status); + return status; + } + + /* is there something to read from client */ + client_dl_wr_ptr = reg_str->dl_wr_ptr.reg_val; + client_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val; + + if (client_dl_rd_ptr != client_dl_wr_ptr) + need_to_read = 1; + + /* + * calculate how many bytes the client can receive + * from host + */ + client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val; + client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val; + + status = sdioc_bytes_till_end_of_buffer( + client_ul_wr_ptr, + client_ul_rd_ptr, + reg_str->ul_buff_size.reg_val, + &c_bytes_rdy_rcve, + &dummy); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdioc_bytes_till_end_of_buffer(). " + "status=%d\n", __func__, status); + return status; + } + + /* if host has anything to write */ + if (h_bytes_rdy_wr > 0) + need_to_write = 1; + + if (need_to_write || need_to_read) + break; + + spin_lock_irqsave(&lock2, lock_flags2); + sdio_dld->main_loop_event.wake_up_signal = 0; + spin_unlock_irqrestore(&lock2, lock_flags2); + + pr_debug(MODULE_NAME ": %s - MAIN LOOP - WAITING...\n", + __func__); +#ifdef CONFIG_DEBUG_FS + update_gd(SDIO_DLD_DEBUGFS_CASE_6_CODE); +#endif + wait_event(sdio_dld->main_loop_event.wait_event, + sdio_dld->main_loop_event.wake_up_signal); +#ifdef CONFIG_DEBUG_FS + update_gd(SDIO_DLD_DEBUGFS_CASE_7_CODE); +#endif + + pr_debug(MODULE_NAME ": %s - MAIN LOOP - WOKE UP...\n", + __func__); + + } while (1); + + /* CHECK IF THERE IS ANYTHING TO READ IN CLIENT */ + if (need_to_read) { +#ifdef PUSH_STRING + int num_push = 0; + int left = 0; + int bytes_read; +#else + int i; +#endif + need_to_read = 0; + + status = sdio_dld_read(client_dl_rd_ptr, + client_dl_wr_ptr, + reg_str, + str_func, + &bytes_read); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdio_dld_read(). status=%d\n", + __func__, status); + return status; + } + + sdio_dld_info.global_bytes_read_fromio += + bytes_read; + + bytes_pushed = 0; +#ifdef PUSH_STRING + left = incoming->num_of_bytes_in_use; + start_timer(&sdio_dld->push_timer, + sdio_dld->push_timer_ms); + do { + num_push = tty_insert_flip_string( + tty, + incoming->data+bytes_pushed, + left); + + bytes_pushed += num_push; + left -= num_push; + tty_flip_buffer_push(tty); + } while (left != 0); + + del_timer(&sdio_dld->push_timer); + + if (bytes_pushed != incoming->num_of_bytes_in_use) { + pr_err(MODULE_NAME ": %s - failed\n", + __func__); + } +#else + pr_debug(MODULE_NAME ": %s - NEED TO READ %d\n", + __func__, incoming->num_of_bytes_in_use); + + for (i = 0 ; i < incoming->num_of_bytes_in_use ; ++i) { + int err = 0; + err = tty_insert_flip_char(tty, + incoming->data[i], + TTY_NORMAL); + tty_flip_buffer_push(tty); + } + + pr_debug(MODULE_NAME ": %s - JUST READ\n", __func__); +#endif /*PUSH_STRING*/ + sdio_dld_info.global_bytes_push_tty += + incoming->num_of_bytes_in_use; +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_push_to_tty = bytes_read; + update_gd(SDIO_DLD_DEBUGFS_CASE_12_CODE); +#endif + incoming->num_of_bytes_in_use = 0; + tty_flip_buffer_push(tty); + } + + /* CHECK IF THERE IS ANYTHING TO WRITE IN HOST AND HOW MUCH */ + if (need_to_write) { + int dummy = 0; + + do { + int bytes_to_write = min(c_bytes_rdy_rcve, + h_bytes_rdy_wr); + + /* + * in case nothing to send or no room to + * receive + */ + if (bytes_to_write == 0) + break; + + if (client_ul_rd_ptr == 0 && + (client_ul_rd_ptr != client_ul_wr_ptr)) + break; + + /* + * if client_rd_ptr points to start, but there + * is data to read wait until WRITE_TILL_END + * before writing a chunk of data, to avoid + * writing until (BUF_SIZE - 1), because it will + * yield an extra write of "1" bytes + */ + if (client_ul_rd_ptr == 0 && + (client_ul_rd_ptr != client_ul_wr_ptr) && + retries < WRITE_TILL_END_RETRIES) { + retries++; + break; + } + retries = 0; + +#ifdef CONFIG_DEBUG_FS + debugfs_glob.global_8k_has = h_bytes_rdy_wr; + debugfs_glob.global_9k_has = c_bytes_rdy_rcve; + debugfs_glob.global_min = bytes_to_write; + update_gd(SDIO_DLD_DEBUGFS_CASE_2_CODE); +#endif + need_to_write = 0; + + pr_debug(MODULE_NAME ": %s - NEED TO WRITE " + "TOIO %d\n", + __func__, bytes_to_write); + + status = sdio_memcpy_toio_wrapper( + str_func, + reg_str->up_wr_ptr.reg_val, + outgoing->offset_read_p, + (void *)((char *)outgoing->data + + outgoing->offset_read_p), + bytes_to_write); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in " + "Function " + "sdio_memcpy_toio_wrapper(). " + "SINGLE CHUNK WRITE. " + "status=%d\n", + __func__, status); + return status; + } + + sdio_claim_host(str_func); + + status = sdio_memcpy_fromio( + str_func, + (void *)®_str->up_rd_ptr.reg_val, + SDIOC_UL_RD_PTR, + sizeof(reg_str->up_rd_ptr.reg_val)); + + if (status) { + pr_err(MODULE_NAME ": %s - " + "sdio_memcpy_fromio() " + "failed. status=%d\n", + __func__, status); + sdio_release_host(str_func); + + return status; + } + + sdio_release_host(str_func); + + spin_lock_irqsave(&lock1, lock_flags1); + if (sdio_dld->write_callback_event. + wake_up_signal == 0) { + sdio_dld->write_callback_event. + wake_up_signal = 1; + wake_up(&sdio_dld-> + write_callback_event. + wait_event); + } + + spin_unlock_irqrestore(&lock1, lock_flags1); + client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val; + client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val; + + status = sdioc_bytes_till_end_of_buffer( + client_ul_wr_ptr, + client_ul_rd_ptr, + reg_str->ul_buff_size.reg_val, + &c_bytes_rdy_rcve, + &dummy); + + /* calculate how many bytes host has to send */ + h_out_wr_ptr = outgoing->offset_write_p; + h_out_rd_ptr = outgoing->offset_read_p; + + status = sdioc_bytes_till_end_of_buffer( + h_out_wr_ptr, + h_out_rd_ptr, + outgoing->buffer_size, + &dummy, + &h_bytes_rdy_wr); + + } while (h_out_wr_ptr != h_out_rd_ptr); + } + } + return 0; +} + +/** + * sdio_dld_init_global + * initialization of sdio_dld global struct + * + * @card: a pointer to mmc_card. + * @return 0 on success or negative value on error. + */ +static int sdio_dld_init_global(struct mmc_card *card, + int(*done)(void)) +{ + if (!card) { + pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!done) { + pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n", + __func__); + return -EINVAL; + } + + sdio_dld->done_callback = done; + sdio_dld->card = card; + init_waitqueue_head(&sdio_dld->dld_main_thread.exit_wait.wait_event); + sdio_dld->write_callback_event.wake_up_signal = 1; + sdio_dld->main_loop_event.wake_up_signal = 1; + + sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_offset = + SDIOC_DL_BUFF_SIZE_OFFSET; + + sdio_dld->sdio_dloader_data.sdioc_reg.dl_rd_ptr.reg_offset = + SDIOC_DL_RD_PTR; + + sdio_dld->sdio_dloader_data.sdioc_reg.dl_wr_ptr.reg_offset = + SDIOC_DL_WR_PTR; + + sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_offset = + SDIOC_UP_BUFF_SIZE_OFFSET; + + sdio_dld->sdio_dloader_data.sdioc_reg.up_rd_ptr.reg_offset = + SDIOC_UL_RD_PTR; + + sdio_dld->sdio_dloader_data.sdioc_reg.up_wr_ptr.reg_offset = + SDIOC_UL_WR_PTR; + + sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_offset = + SDIOC_EXIT_PTR; + + sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_offset = + SDIOC_DL_BUFF_ADDRESS; + + sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_offset = + SDIOC_UP_BUFF_ADDRESS; + + sdio_dld_set_op_mode(SDIO_DLD_NORMAL_MODE); + + return 0; +} + +/** + * sdio_downloader_setup + * initializes the TTY driver + * + * @card: a pointer to mmc_card. + * @num_of_devices: number of devices. + * @channel_number: channel number. + * @return 0 on success or negative value on error. + * + * The TTY stack needs to know in advance how many devices it should + * plan to manage. Use this call to set up the ports that will + * be exported through SDIO. + */ +int sdio_downloader_setup(struct mmc_card *card, + unsigned int num_of_devices, + int channel_number, + int(*done)(void)) +{ + int status = 0; + int result = 0; + int func_in_array = 0; + struct sdio_func *str_func = NULL; + struct device *tty_dev; + + if (num_of_devices == 0 || num_of_devices > MAX_NUM_DEVICES) { + pr_err(MODULE_NAME ": %s - invalid number of devices\n", + __func__); + return -EINVAL; + } + + if (!card) { + pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n", + __func__); + return -EINVAL; + } + + if (!done) { + pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n", + __func__); + return -EINVAL; + } + + sdio_dld = kzalloc(sizeof(struct sdio_downloader), GFP_KERNEL); + if (!sdio_dld) { + pr_err(MODULE_NAME ": %s - couldn't allocate sdio_dld data " + "structure.", __func__); + return -ENOMEM; + } + +#ifdef CONFIG_DEBUG_FS + bootloader_debugfs_init(); +#endif /* CONFIG_DEBUG_FS */ + + status = sdio_dld_init_global(card, done); + + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdio_dld_init_global(). status=%d\n", + __func__, status); + kfree(sdio_dld); + return status; + } + + sdio_dld->tty_drv = alloc_tty_driver(num_of_devices); + + if (!sdio_dld->tty_drv) { + pr_err(MODULE_NAME ": %s - param ""sdio_dld->tty_drv"" is " + "NULL.\n", __func__); + kfree(sdio_dld); + return -EINVAL; + } + + sdio_dld_set_op_mode((enum sdio_dld_op_mode)sdio_op_mode); + + /* according to op_mode, a different tty device is created */ + if (sdio_dld->op_mode == SDIO_DLD_BOOT_TEST_MODE) + sdio_dld->tty_drv->name = TTY_SDIO_DEV_TEST; + else + sdio_dld->tty_drv->name = TTY_SDIO_DEV; + + sdio_dld->tty_drv->owner = THIS_MODULE; + sdio_dld->tty_drv->driver_name = "SDIO_Dloader"; + + /* uses dynamically assigned dev_t values */ + sdio_dld->tty_drv->type = TTY_DRIVER_TYPE_SERIAL; + sdio_dld->tty_drv->subtype = SERIAL_TYPE_NORMAL; + sdio_dld->tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV + | TTY_DRIVER_RESET_TERMIOS; + + /* initializing the tty driver */ + sdio_dld->tty_drv->init_termios = tty_std_termios; + sdio_dld->tty_drv->init_termios.c_cflag = + B4800 | CS8 | CREAD | HUPCL | CLOCAL; + sdio_dld->tty_drv->init_termios.c_ispeed = INPUT_SPEED; + sdio_dld->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED; + + tty_set_operations(sdio_dld->tty_drv, &sdio_dloader_tty_ops); + + status = tty_register_driver(sdio_dld->tty_drv); + if (status) { + put_tty_driver(sdio_dld->tty_drv); + pr_err(MODULE_NAME ": %s - tty_register_driver() failed\n", + __func__); + + sdio_dld->tty_drv = NULL; + kfree(sdio_dld); + return status; + } + + tty_dev = tty_register_device(sdio_dld->tty_drv, 0, NULL); + if (IS_ERR(tty_dev)) { + pr_err(MODULE_NAME ": %s - tty_register_device() " + "failed\n", __func__); + tty_unregister_driver(sdio_dld->tty_drv); + kfree(sdio_dld); + return PTR_ERR(tty_dev); + } + + sdio_dld->sdioc_boot_func = SDIOC_CHAN_TO_FUNC_NUM(channel_number); + func_in_array = REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func); + str_func = sdio_dld->card->sdio_func[func_in_array]; + status = sdio_dld_init_func(str_func); + if (status) { + pr_err(MODULE_NAME ": %s - Failure in Function " + "sdio_dld_init_func(). status=%d\n", + __func__, status); + goto exit_err; + } + +#ifdef CONFIG_DEBUG_FS + sdio_dld_debug_init(); +#endif + + sdio_claim_host(str_func); + + /* + * notifing the client by writing what mode we are by writing + * to a special register + */ + status = sdio_memcpy_toio(str_func, + SDIOC_OP_MODE_PTR, + (void *)&sdio_dld->op_mode, + sizeof(sdio_dld->op_mode)); + + sdio_release_host(str_func); + + if (status) { + pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() " + "writing to OP_MODE_REGISTER failed. " + "status=%d.\n", + __func__, status); + goto exit_err; + } + + return 0; + +exit_err: + tty_unregister_device(sdio_dld->tty_drv, 0); + result = tty_unregister_driver(sdio_dld->tty_drv); + if (result) + pr_err(MODULE_NAME ": %s - tty_unregister_driver() " + "failed. result=%d\n", __func__, -result); + kfree(sdio_dld); + return status; +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SDIO Downloader"); +MODULE_AUTHOR("Yaniv Gardi "); +MODULE_VERSION(DRV_VERSION); + diff --git a/arch/arm/mach-msm/sdio_al_private.h b/arch/arm/mach-msm/sdio_al_private.h new file mode 100644 index 00000000..3a5ab79b --- /dev/null +++ b/arch/arm/mach-msm/sdio_al_private.h @@ -0,0 +1,267 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * SDIO-Abstraction-Layer internal interface. + */ + +#ifndef __SDIO_AL_PRIVATE__ +#define __SDIO_AL_PRIVATE__ + +#include +#include +#include + +#define DRV_VERSION "1.30" +#define MODULE_NAME "sdio_al" +#define SDIOC_CHAN_TO_FUNC_NUM(x) ((x)+2) +#define REAL_FUNC_TO_FUNC_IN_ARRAY(x) ((x)-1) +#define SDIO_PREFIX "SDIO_" +#define PEER_CHANNEL_NAME_SIZE 4 +#define CHANNEL_NAME_SIZE (sizeof(SDIO_PREFIX) + PEER_CHANNEL_NAME_SIZE) +#define SDIO_TEST_POSTFIX_SIZE 5 +#define MAX_NUM_OF_SDIO_DEVICES 2 +#define TEST_CH_NAME_SIZE (CHANNEL_NAME_SIZE + SDIO_TEST_POSTFIX_SIZE) + +struct sdio_al_device; /* Forward Declaration */ + +enum sdio_channel_state { + SDIO_CHANNEL_STATE_INVALID, /* before reading software header */ + SDIO_CHANNEL_STATE_IDLE, /* channel valid, not opened */ + SDIO_CHANNEL_STATE_CLOSED, /* was closed */ + SDIO_CHANNEL_STATE_OPEN, /* opened */ + SDIO_CHANNEL_STATE_CLOSING, /* during flush, when closing */ +}; +/** + * Peer SDIO-Client channel configuration. + * + * @is_ready - channel is ready and the data is valid. + * + * @max_rx_threshold - maximum rx threshold, according to the + * total buffers size on the peer pipe. + * @max_tx_threshold - maximum tx threshold, according to the + * total buffers size on the peer pipe. + * @tx_buf_size - size of a single buffer on the peer pipe; a + * transfer smaller than the buffer size still + * make the buffer unusable for the next transfer. + * @max_packet_size + * @is_host_ok_to_sleep - Host marks this bit when it's okay to + * sleep (no pending transactions) + */ +struct peer_sdioc_channel_config { + u32 is_ready; + u32 max_rx_threshold; /* Downlink */ + u32 max_tx_threshold; /* Uplink */ + u32 tx_buf_size; + u32 max_packet_size; + u32 is_host_ok_to_sleep; + u32 is_packet_mode; + u32 peer_operation; + u32 is_low_latency_ch; + u32 reserved[23]; +}; + + +/** + * Peer SDIO-Client channel statsitics. + * + * @last_any_read_avail - the last read avail in all the + * channels including this channel. + * @last_read_avail - the last read_avail that was read from HW + * mailbox. + * @last_old_read_avail - the last read_avail channel shadow. + * @total_notifs - the total number of read notifications sent + * to this channel client + * @total_read_times - the total number of successful sdio_read + * calls for this channel + */ +struct sdio_channel_statistics { + int last_any_read_avail; + int last_read_avail; + int last_old_read_avail; + int total_notifs; + int total_read_times; +}; + +/** + * SDIO Channel context. + * + * @name - channel name. Used by the caller to open the + * channel. + * + * @read_threshold - Threshold on SDIO-Client mailbox for Rx + * Data available bytes. When the limit exceed + * the SDIO-Client generates an interrupt to the + * host. + * + * @write_threshold - Threshold on SDIO-Client mailbox for Tx + * Data available bytes. When the limit exceed + * the SDIO-Client generates an interrupt to the + * host. + * + * @def_read_threshold - Default theshold on SDIO-Client for Rx + * + * @min_write_avail - Threshold of minimal available bytes + * to write. Below that threshold the host + * will initiate reading the mailbox. + * + * @poll_delay_msec - Delay between polling the mailbox. When + * the SDIO-Client doesn't generates EOT + * interrupt for Rx Available bytes, the host + * should poll the SDIO-Client mailbox. + * + * @is_packet_mode - The host get interrupt when a packet is + * available at the SDIO-client (pipe EOT + * indication). + * + * @num - channel number. + * + * @notify - Client's callback. Should not call sdio read/write. + * + * @priv - Client's private context, provided to callback. + * + * @is_valid - Channel is used (we have a list of + * SDIO_AL_MAX_CHANNELS and not all of them are in + * use). + * + * @is_open - Channel is open. + * + * @func - SDIO Function handle. + * + * @rx_pipe_index - SDIO-Client Pipe Index for Rx Data. + * + * @tx_pipe_index - SDIO-Client Pipe Index for Tx Data. + * + * @ch_lock - Channel lock to protect channel specific Data + * + * @rx_pending_bytes - Total number of Rx pending bytes, at Rx + * packet list. Maximum of 16KB-1 limited by + * SDIO-Client specification. + * + * @read_avail - Available bytes to read. + * + * @write_avail - Available bytes to write. + * + * @rx_size_list_head - The head of Rx Pending Packets List. + * + * @pdev - platform device - clients to probe for the sdio-al. + * + * @signature - Context Validity check. + * + * @sdio_al_dev - a pointer to the sdio_al_device instance of + * this channel + * + * @statistics - channel statistics + * + */ +struct sdio_channel { + /* Channel Configuration Parameters*/ + char name[CHANNEL_NAME_SIZE]; + char ch_test_name[TEST_CH_NAME_SIZE]; + int read_threshold; + int write_threshold; + int def_read_threshold; + int threshold_change_cnt; + int min_write_avail; + int poll_delay_msec; + int is_packet_mode; + int is_low_latency_ch; + + struct peer_sdioc_channel_config ch_config; + + /* Channel Info */ + int num; + + void (*notify)(void *priv, unsigned channel_event); + void *priv; + + int state; + + struct sdio_func *func; + + int rx_pipe_index; + int tx_pipe_index; + + struct mutex ch_lock; + + u32 read_avail; + u32 write_avail; + + u32 peer_tx_buf_size; + + u16 rx_pending_bytes; + + struct list_head rx_size_list_head; + + struct platform_device *pdev; + + u32 total_rx_bytes; + u32 total_tx_bytes; + + u32 signature; + + struct sdio_al_device *sdio_al_dev; + + struct sdio_channel_statistics statistics; +}; + +/** + * sdio_downloader_setup + * initializes the TTY driver + * + * @card: a pointer to mmc_card. + * @num_of_devices: number of devices. + * @channel_number: channel number. + * @return 0 on success or negative value on error. + * + * The TTY stack needs to know in advance how many devices it should + * plan to manage. Use this call to set up the ports that will + * be exported through SDIO. + */ +int sdio_downloader_setup(struct mmc_card *card, + unsigned int num_of_devices, + int func_number, + int(*func)(void)); + +/** + * test_channel_init + * initializes a test channel + * + * @name: the channel name. + * @return 0 on success or negative value on error. + * + */ +int test_channel_init(char *name); + +/** + * sdio_al_register_lpm_cb + * Allow the sdio_al test to register for lpm voting + * notifications + * + * @device_handle: the device handle. + * @wakeup_callback: callback function to be called when voting. + * + */ +void sdio_al_register_lpm_cb(void *device_handle, + int(*lpm_callback)(void *, int)); + +/** + * sdio_al_unregister_lpm_cb + * Allow the sdio_al test to unregister for lpm voting + * notifications + * + * @device_handle: the device handle. + * + */ +void sdio_al_unregister_lpm_cb(void *device_handle); + +#endif /* __SDIO_AL_PRIVATE__ */ diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c new file mode 100644 index 00000000..2c9f675e --- /dev/null +++ b/arch/arm/mach-msm/sdio_al_test.c @@ -0,0 +1,6500 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * SDIO-Abstraction-Layer Test Module. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sdio_al_private.h" +#include + +#include +enum lpm_test_msg_type { + LPM_NO_MSG, /* 0 */ + LPM_MSG_SEND, /* 1 */ + LPM_MSG_REC, /* 2 */ + LPM_SLEEP, /* 3 */ + LPM_WAKEUP, /* 4 */ + LPM_NOTIFY /* 5 */ +}; + +#define LPM_NO_MSG_NAME "LPM No Event" +#define LPM_MSG_SEND_NAME "LPM Send Msg Event" +#define LPM_MSG_REC_NAME "LPM Receive Msg Event" +#define LPM_SLEEP_NAME "LPM Sleep Event" +#define LPM_WAKEUP_NAME "LPM Wakeup Event" + +/** Module name string */ +#define TEST_MODULE_NAME "sdio_al_test" + +#define TEST_SIGNATURE 0x12345678 +#define TEST_CONFIG_SIGNATURE 0xBEEFCAFE + +#define MAX_XFER_SIZE (16*1024) +#define SMEM_MAX_XFER_SIZE 0xBC000 +#define A2_MIN_PACKET_SIZE 5 +#define RMNT_PACKET_SIZE (4*1024) +#define DUN_PACKET_SIZE (2*1024) +#define CSVT_PACKET_SIZE 1700 + +#define TEST_DBG(x...) if (test_ctx->runtime_debug) pr_info(x) + +#define LPM_TEST_NUM_OF_PACKETS 100 +#define LPM_MAX_OPEN_CHAN_PER_DEV 4 +#define LPM_ARRAY_SIZE (7*LPM_TEST_NUM_OF_PACKETS*LPM_MAX_OPEN_CHAN_PER_DEV) +#define SDIO_LPM_TEST "sdio_lpm_test_reading_task" +#define LPM_TEST_CONFIG_SIGNATURE 0xDEADBABE +#define LPM_MSG_NAME_SIZE 20 +#define MAX_STR_SIZE 10 +#define MAX_AVG_RTT_TIME_USEC 2500 +#define SDIO_RMNT_RTT_PACKET_SIZE 32 +#define SDIO_CSVT_RTT_PACKET_SIZE 1900 + +#define A2_HEADER_OVERHEAD 8 + +enum rx_process_state { + RX_PROCESS_PACKET_INIT, + RX_PROCESS_A2_HEADER, + RX_PROCESS_PACKET_DATA, +}; + +enum sdio_test_case_type { + SDIO_TEST_LOOPBACK_HOST, + SDIO_TEST_LOOPBACK_CLIENT, + SDIO_TEST_LPM_HOST_WAKER, + SDIO_TEST_LPM_CLIENT_WAKER, + SDIO_TEST_LPM_RANDOM, + SDIO_TEST_HOST_SENDER_NO_LP, + SDIO_TEST_CLOSE_CHANNEL, + SDIO_TEST_A2_VALIDATION, + /* The following tests are not part of the 9k tests and should be + * kept last in case new tests are added + */ + SDIO_TEST_PERF, + SDIO_TEST_RTT, + SDIO_TEST_MODEM_RESET, +}; + +struct lpm_task { + struct task_struct *lpm_task; + const char *task_name; +}; + +struct lpm_entry_type { + enum lpm_test_msg_type msg_type; + char msg_name[LPM_MSG_NAME_SIZE]; + u32 counter; + u32 current_ms; + u32 read_avail_mask; + char chan_name[CHANNEL_NAME_SIZE]; +}; + +struct lpm_msg { + u32 signature; + u32 counter; + u32 reserve1; + u32 reserve2; +}; + +struct test_config_msg { + u32 signature; + u32 test_case; + u32 test_param; + u32 num_packets; + u32 num_iterations; +}; + +struct test_result_msg { + u32 signature; + u32 is_successful; +}; + +struct test_work { + struct work_struct work; + struct test_channel *test_ch; +}; + +enum sdio_channels_ids { + SDIO_RPC, + SDIO_QMI, + SDIO_RMNT, + SDIO_DIAG, + SDIO_DUN, + SDIO_SMEM, + SDIO_CSVT, + SDIO_MAX_CHANNELS +}; + +enum sdio_test_results { + TEST_NO_RESULT, + TEST_FAILED, + TEST_PASSED +}; + +enum sdio_lpm_vote_state { + SDIO_NO_VOTE, + SDIO_VOTE_FOR_SLEEP, + SDIO_VOTE_AGAINST_SLEEP +}; + +struct sdio_test_device { + int open_channels_counter_to_recv; + int open_channels_counter_to_send; + struct lpm_entry_type *lpm_arr; + int array_size; + void *sdio_al_device; + spinlock_t lpm_array_lock; + unsigned long lpm_array_lock_flags; + u32 next_avail_entry_in_array; + struct lpm_task lpm_test_task; + u32 next_mask_id; + u32 read_avail_mask; + int modem_result_per_dev; + int final_result_per_dev; +}; + +struct test_channel { + struct sdio_channel *ch; + + char name[CHANNEL_NAME_SIZE]; + int ch_id; + + struct sdio_test_device *test_device; + + u32 *buf; + u32 buf_size; + + struct workqueue_struct *workqueue; + struct test_work test_work; + + u32 rx_bytes; + u32 tx_bytes; + + wait_queue_head_t wait_q; + atomic_t rx_notify_count; + atomic_t tx_notify_count; + atomic_t any_notify_count; + atomic_t wakeup_client; + atomic_t card_detected_event; + + int wait_counter; + + int is_used; + int test_type; + int ch_ready; + + struct test_config_msg config_msg; + + int test_completed; + int test_result; + struct timer_list timer; + int timer_interval_ms; + + struct timer_list timeout_timer; + int timeout_ms; + void *sdio_al_device; + int is_ok_to_sleep; + unsigned int packet_length; + int random_packet_size; + int next_index_in_sent_msg_per_chan; + int channel_mask_id; + int modem_result_per_chan; + int notify_counter_per_chan; + int max_burst_size; /* number of writes before close/open */ + int card_removed; +}; + +struct sdio_al_test_debug { + u32 dun_throughput; + u32 rmnt_throughput; + struct dentry *debug_root; + struct dentry *debug_test_result; + struct dentry *debug_dun_throughput; + struct dentry *debug_rmnt_throughput; + struct dentry *rpc_sender_test; + struct dentry *rpc_qmi_diag_sender_test; + struct dentry *smem_test; + struct dentry *smem_rpc_test; + struct dentry *rmnet_a2_validation_test; + struct dentry *dun_a2_validation_test; + struct dentry *rmnet_a2_perf_test; + struct dentry *dun_a2_perf_test; + struct dentry *csvt_a2_perf_test; + struct dentry *rmnet_dun_a2_perf_test; + struct dentry *rpc_sender_rmnet_a2_perf_test; + struct dentry *all_channels_test; + struct dentry *host_sender_no_lp_diag_test; + struct dentry *host_sender_no_lp_diag_rpc_test; + struct dentry *rmnet_small_packets_test; + struct dentry *rmnet_rtt_test; + struct dentry *csvt_rtt_test; + struct dentry *modem_reset_rpc_test; + struct dentry *modem_reset_rmnet_test; + struct dentry *modem_reset_channels_4bit_dev_test; + struct dentry *modem_reset_channels_8bit_dev_test; + struct dentry *modem_reset_all_channels_test; + struct dentry *open_close_test; + struct dentry *open_close_dun_rmnet_test; + struct dentry *close_chan_lpm_test; + struct dentry *lpm_test_client_wakes_host_test; + struct dentry *lpm_test_host_wakes_client_test; + struct dentry *lpm_test_random_single_channel_test; + struct dentry *lpm_test_random_multi_channel_test; +}; + +struct test_context { + dev_t dev_num; + struct device *dev; + struct cdev *cdev; + int number_of_active_devices; + int max_number_of_devices; + + struct sdio_test_device test_dev_arr[MAX_NUM_OF_SDIO_DEVICES]; + + struct test_channel *test_ch; + + struct test_channel *test_ch_arr[SDIO_MAX_CHANNELS]; + + long testcase; + + const char *name; + + int exit_flag; + + u32 signature; + + int runtime_debug; + + struct platform_device *smem_pdev; + struct sdio_smem_client *sdio_smem; + int smem_was_init; + u8 *smem_buf; + uint32_t smem_counter; + + struct platform_device *csvt_app_pdev; + + wait_queue_head_t wait_q; + int test_completed; + int test_result; + struct sdio_al_test_debug debug; + + struct wake_lock wake_lock; + + unsigned int lpm_pseudo_random_seed; +}; + +/* FORWARD DECLARATIONS */ +static int set_params_loopback_9k(struct test_channel *tch); +static int set_params_smem_test(struct test_channel *tch); +static int set_params_a2_validation(struct test_channel *tch); +static int set_params_a2_perf(struct test_channel *tch); +static int set_params_8k_sender_no_lp(struct test_channel *tch); +static int set_params_a2_small_pkts(struct test_channel *tch); +static int set_params_rtt(struct test_channel *tch); +static int set_params_loopback_9k_close(struct test_channel *tch); +static int close_channel_lpm_test(int channel_num); +static int set_params_lpm_test(struct test_channel *tch, + enum sdio_test_case_type test, + int timer_interval_ms); +static void set_pseudo_random_seed(void); +static int set_params_modem_reset(struct test_channel *tch); +static int test_start(void); +static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count); +static void sdio_al_test_cleanup_channels(void); +static void notify(void *priv, unsigned channel_event); +#ifdef CONFIG_MSM_SDIO_SMEM +static int sdio_smem_open(struct sdio_smem_client *sdio_smem); +#endif + +/* + * Seed for pseudo random time sleeping in Random LPM test. + * If not set, current time in jiffies is used. + */ +static unsigned int seed; +module_param(seed, int, 0); +static struct test_context *test_ctx; + +static void sdio_al_test_initial_dev_and_chan(struct test_context *test_ctx) +{ + int i = 0; + + if (!test_ctx) { + pr_err(TEST_MODULE_NAME ":%s - test_ctx is NULL.\n", __func__); + return; + } + + for (i = 0 ; i < MAX_NUM_OF_SDIO_DEVICES ; ++i) + test_ctx->test_dev_arr[i].sdio_al_device = NULL; + + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + if (!tch) + continue; + tch->is_used = 0; + } + + sdio_al_test_cleanup_channels(); +} + +#ifdef CONFIG_DEBUG_FS + +static int message_repeat; + +static int sdio_al_test_extract_number(const char __user *buf, + size_t count) +{ + int ret = 0; + int number = -1; + char local_buf[MAX_STR_SIZE] = {0}; + char *start = NULL; + + if (count > MAX_STR_SIZE) { + pr_err(TEST_MODULE_NAME ": %s - MAX_STR_SIZE(%d) < count(%d). " + "Please choose smaller number\n", + __func__, MAX_STR_SIZE, (int)count); + return -EINVAL; + } + + if (copy_from_user(local_buf, buf, count)) { + pr_err(TEST_MODULE_NAME ": %s - copy_from_user() failed\n", + __func__); + return -EINVAL; + } + + /* adding null termination to the string */ + local_buf[count] = '\0'; + + /* stripping leading and trailing white spaces */ + start = strstrip(local_buf); + + ret = kstrtoint(start, 10, &number); + + if (ret) { + pr_err(TEST_MODULE_NAME " : %s - kstrtoint() failed\n", + __func__); + return ret; + } + + return number; +} + +static int sdio_al_test_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + message_repeat = 1; + return 0; +} + +static void sdio_al_test_cleanup_channels(void) +{ + int channel_num; + int dummy = 0; + + for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ; + ++channel_num) { + if (channel_num == SDIO_SMEM) + continue; + + rx_cleanup(test_ctx->test_ch_arr[channel_num], &dummy); + } + + return; +} + +/* RPC SENDER TEST */ +static ssize_t rpc_sender_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- RPC SENDER TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rpc_sender_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRPC_SENDER_TEST\n" + "===============\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rpc_sender_test_ops = { + .open = sdio_al_test_open, + .write = rpc_sender_test_write, + .read = rpc_sender_test_read, +}; + +/* RPC, QMI & DIAG SENDER TEST */ +static ssize_t rpc_qmi_diag_sender_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- RPC, QMI AND DIAG SENDER TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]); + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]); + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rpc_qmi_diag_sender_test_read(struct file *file, + char __user + *buffer, size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRPC_QMI_DIAG_SENDER_TEST\n" + "========================\n" + "Description:\n" + "TBD\n"); + + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rpc_qmi_diag_sender_test_ops = { + .open = sdio_al_test_open, + .write = rpc_qmi_diag_sender_test_write, + .read = rpc_qmi_diag_sender_test_read, +}; + +/* SMEM TEST */ +static ssize_t smem_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- SMEM TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t smem_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nSMEM_TEST\n" + "=========\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations smem_test_ops = { + .open = sdio_al_test_open, + .write = smem_test_write, + .read = smem_test_read, +}; + +/* SMEM & RPC TEST */ +static ssize_t smem_rpc_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- SMEM AND RPC TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]); + set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t smem_rpc_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nSMEM_RPC_TEST\n" + "=============\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations smem_rpc_test_ops = { + .open = sdio_al_test_open, + .write = smem_rpc_test_write, + .read = smem_rpc_test_read, +}; + +/* RMNET A2 VALIDATION TEST */ +static ssize_t rmnet_a2_validation_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- RMNET A2 VALIDATION TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_a2_validation(test_ctx->test_ch_arr[SDIO_RMNT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rmnet_a2_validation_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRMNET_A2_VALIDATION_TEST\n" + "=========================\n" + "Description:\n" + "In this test, the HOST sends multiple packets to the\n" + "CLIENT and validates the packets loop backed from A2\n" + "for the RMNET channel.\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rmnet_a2_validation_test_ops = { + .open = sdio_al_test_open, + .write = rmnet_a2_validation_test_write, + .read = rmnet_a2_validation_test_read, +}; + +/* DUN A2 VALIDATION TEST */ +static ssize_t dun_a2_validation_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- DUN A2 VALIDATION TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_a2_validation(test_ctx->test_ch_arr[SDIO_DUN]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t dun_a2_validation_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nDUN_A2_VALIDATION_TEST\n" + "=========================\n" + "Description:\n" + "In this test, the HOST sends multiple packets to the\n" + "CLIENT and validates the packets loop backed from A2\n" + "for the DUN channel.\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations dun_a2_validation_test_ops = { + .open = sdio_al_test_open, + .write = dun_a2_validation_test_write, + .read = dun_a2_validation_test_read, +}; + +/* RMNET A2 PERFORMANCE TEST */ +static ssize_t rmnet_a2_perf_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- RMNET A2 PERFORMANCE TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rmnet_a2_perf_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRMNET_A2_PERFORMANCE_TEST\n" + "=========================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rmnet_a2_perf_test_ops = { + .open = sdio_al_test_open, + .write = rmnet_a2_perf_test_write, + .read = rmnet_a2_perf_test_read, +}; + +/* DUN A2 PERFORMANCE TEST */ +static ssize_t dun_a2_perf_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- DUN A2 PERFORMANCE TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t dun_a2_perf_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nDUN_A2_PERFORMANCE_TEST\n" + "=======================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations dun_a2_perf_test_ops = { + .open = sdio_al_test_open, + .write = dun_a2_perf_test_write, + .read = dun_a2_perf_test_read, +}; + +/* CSVT A2 PERFORMANCE TEST */ +static ssize_t csvt_a2_perf_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- CSVT A2 PERFORMANCE TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t csvt_a2_perf_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nCSVT_A2_PERFORMANCE_TEST\n" + "========================\n" + "Description:\n" + "Loopback test on the CSVT Channel, in order to check " + "throughput performance.\n" + "Packet size that are sent on the CSVT channel in this " + "test is %d.bytes\n\n" + "END OF DESCRIPTION\n", CSVT_PACKET_SIZE); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations csvt_a2_perf_test_ops = { + .open = sdio_al_test_open, + .write = csvt_a2_perf_test_write, + .read = csvt_a2_perf_test_read, +}; + +/* RMNET DUN A2 PERFORMANCE TEST */ +static ssize_t rmnet_dun_a2_perf_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- RMNET AND DUN A2 PERFORMANCE TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]); + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rmnet_dun_a2_perf_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRMNET_DUN_A2_PERFORMANCE_TEST\n" + "=============================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rmnet_dun_a2_perf_test_ops = { + .open = sdio_al_test_open, + .write = rmnet_dun_a2_perf_test_write, + .read = rmnet_dun_a2_perf_test_read, +}; + +/* RPC SENDER & RMNET A2 PERFORMANCE TEST */ +static ssize_t rpc_sender_rmnet_a2_perf_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "--RPC SENDER AND RMNET A2 " + "PERFORMANCE --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]); + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rpc_sender_rmnet_a2_perf_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRPC_SENDER_RMNET_A2_PERFORMANCE_TEST\n" + "====================================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rpc_sender_rmnet_a2_perf_test_ops = { + .open = sdio_al_test_open, + .write = rpc_sender_rmnet_a2_perf_test_write, + .read = rpc_sender_rmnet_a2_perf_test_read, +}; + +/* ALL CHANNELS TEST */ +static ssize_t all_channels_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- ALL THE CHANNELS TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]); + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]); + set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]); + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]); + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]); + set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]); + set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t all_channels_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nALL_CHANNELS_TEST\n" + "=================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations all_channels_test_ops = { + .open = sdio_al_test_open, + .write = all_channels_test_write, + .read = all_channels_test_read, +}; + +/* HOST SENDER NO LP DIAG TEST */ +static ssize_t host_sender_no_lp_diag_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t host_sender_no_lp_diag_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nHOST_SENDER_NO_LP_DIAG_TEST\n" + "===========================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations host_sender_no_lp_diag_test_ops = { + .open = sdio_al_test_open, + .write = host_sender_no_lp_diag_test_write, + .read = host_sender_no_lp_diag_test_read, +}; + +/* HOST SENDER NO LP DIAG, RPC TEST */ +static ssize_t host_sender_no_lp_diag_rpc_test_write( + struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG, RPC " + "TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]); + set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_RPC]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t host_sender_no_lp_diag_rpc_test_read( + struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nHOST_SENDER_NO_LP_DIAG_RPC_TEST\n" + "===================================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations host_sender_no_lp_diag_rpc_test_ops = { + .open = sdio_al_test_open, + .write = host_sender_no_lp_diag_rpc_test_write, + .read = host_sender_no_lp_diag_rpc_test_read, +}; + +/* RMNET SMALL PACKETS TEST */ +static ssize_t rmnet_small_packets_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- RMNET SMALL PACKETS (5-128) TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_a2_small_pkts(test_ctx->test_ch_arr[SDIO_RMNT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rmnet_small_packets_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRMNET_SMALL_PACKETS_TEST\n" + "========================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rmnet_small_packets_test_ops = { + .open = sdio_al_test_open, + .write = rmnet_small_packets_test_write, + .read = rmnet_small_packets_test_read, +}; + +/* RMNET RTT TEST */ +static ssize_t rmnet_rtt_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- RMNET RTT TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_rtt(test_ctx->test_ch_arr[SDIO_RMNT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t rmnet_rtt_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nRMNET_RTT_TEST\n" + "==============\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations rmnet_rtt_test_ops = { + .open = sdio_al_test_open, + .write = rmnet_rtt_test_write, + .read = rmnet_rtt_test_read, +}; + +/* CSVT RTT TEST */ +static ssize_t csvt_rtt_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- CSVT RTT TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_rtt(test_ctx->test_ch_arr[SDIO_CSVT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t csvt_rtt_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nCSVT_RTT_TEST\n" + "==============\n" + "Description:\n" + "In this test the HOST send a message of %d bytes " + "to the CLIENT\n\n" + "END OF DESCRIPTION\n", SDIO_CSVT_RTT_PACKET_SIZE); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations csvt_rtt_test_ops = { + .open = sdio_al_test_open, + .write = csvt_rtt_test_write, + .read = csvt_rtt_test_read, +}; + +/* MODEM RESET RPC TEST */ +static ssize_t modem_reset_rpc_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- MODEM RESET - RPC CHANNEL TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t modem_reset_rpc_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nMODEM_RESET_RPC_TEST\n" + "====================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations modem_reset_rpc_test_ops = { + .open = sdio_al_test_open, + .write = modem_reset_rpc_test_write, + .read = modem_reset_rpc_test_read, +}; + +/* MODEM RESET RMNET TEST */ +static ssize_t modem_reset_rmnet_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- MODEM RESET - RMNT CHANNEL TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t modem_reset_rmnet_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nMODEM_RESET_RMNET_TEST\n" + "======================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations modem_reset_rmnet_test_ops = { + .open = sdio_al_test_open, + .write = modem_reset_rmnet_test_write, + .read = modem_reset_rmnet_test_read, +}; + +/* MODEM RESET - CHANNELS IN 4BIT DEVICE TEST */ +static ssize_t modem_reset_channels_4bit_dev_test_write( + struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN " + "4BIT DEVICE TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]); + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]); + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t modem_reset_channels_4bit_dev_test_read( + struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nMODEM_RESET_CHANNELS_4BIT_DEV_TEST\n" + "==================================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations modem_reset_channels_4bit_dev_test_ops = { + .open = sdio_al_test_open, + .write = modem_reset_channels_4bit_dev_test_write, + .read = modem_reset_channels_4bit_dev_test_read, +}; + +/* MODEM RESET - CHANNELS IN 8BIT DEVICE TEST */ +static ssize_t modem_reset_channels_8bit_dev_test_write( + struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN " + "8BIT DEVICE TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]); + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t modem_reset_channels_8bit_dev_test_read( + struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nMODEM_RESET_CHANNELS_8BIT_DEV_TEST\n" + "==================================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations modem_reset_channels_8bit_dev_test_ops = { + .open = sdio_al_test_open, + .write = modem_reset_channels_8bit_dev_test_write, + .read = modem_reset_channels_8bit_dev_test_read, +}; + +/* MODEM RESET - ALL CHANNELS TEST */ +static ssize_t modem_reset_all_channels_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]); + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]); + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]); + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]); + set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t modem_reset_all_channels_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nMODEM_RESET_ALL_CHANNELS_TEST\n" + "=============================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations modem_reset_all_channels_test_ops = { + .open = sdio_al_test_open, + .write = modem_reset_all_channels_test_write, + .read = modem_reset_all_channels_test_read, +}; + +/* HOST SENDER WITH OPEN/CLOSE TEST */ +static ssize_t open_close_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + struct test_channel **ch_arr = test_ctx->test_ch_arr; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_loopback_9k_close(ch_arr[SDIO_DIAG]); + set_params_loopback_9k_close(ch_arr[SDIO_RPC]); + set_params_loopback_9k_close(ch_arr[SDIO_SMEM]); + set_params_loopback_9k_close(ch_arr[SDIO_QMI]); + set_params_loopback_9k_close(ch_arr[SDIO_RMNT]); + set_params_loopback_9k_close(ch_arr[SDIO_DUN]); + set_params_loopback_9k_close(ch_arr[SDIO_CSVT]); + + ret = test_start(); + + if (ret) + break; + + pr_info(TEST_MODULE_NAME " -- correctness test for" + "DIAG "); + set_params_loopback_9k(ch_arr[SDIO_DIAG]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t open_close_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nOPEN_CLOSE_TEST\n" + "============================\n" + "Description:\n" + "In this test the host sends 5k packets to the modem in the " + "following sequence: Send a random burst of packets on " + "Diag and Rmnet channels, read 0 or a random number " + "of packets, close and re-open the channel. At the end of the " + "test, the channel is verified by running a loopback test\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations open_close_test_ops = { + .open = sdio_al_test_open, + .write = open_close_test_write, + .read = open_close_test_read, +}; + +/* HOST SENDER WITH OPEN/CLOSE FOR DUN & RMNET TEST */ +static ssize_t open_close_dun_rmnet_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + struct test_channel **ch_arr = test_ctx->test_ch_arr; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE FOR " + "DUN AND RMNET TEST --"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_loopback_9k_close(ch_arr[SDIO_DUN]); + set_params_loopback_9k_close(ch_arr[SDIO_RMNT]); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t open_close_dun_rmnet_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nOPEN_CLOSE_DUN_RMNET_TEST\n" + "============================\n" + "Description:\n" + "In this test the host sends 5k packets to the modem in the " + "following sequence: Send a random burst of packets on " + "DUN and Rmnet channels, read 0 or a random number " + "of packets, close and re-open the channel.\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations open_close_dun_rmnet_test_ops = { + .open = sdio_al_test_open, + .write = open_close_dun_rmnet_test_write, + .read = open_close_dun_rmnet_test_read, +}; + +/* CLOSE CHANNEL & LPM TEST HOST WAKES THE CLIENT TEST */ +static ssize_t close_chan_lpm_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int channel_num = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- CLOSE CHANNEL & LPM TEST " + "HOST WAKES THE CLIENT TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ; + channel_num++) { + + ret = close_channel_lpm_test(channel_num); + + if (ret) + break; + + set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC], + SDIO_TEST_LPM_HOST_WAKER, 120); + + ret = test_start(); + + if (ret) + break; + } + + if (ret) { + pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test " + "FAILED: %d --\n", ret); + } else { + pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test " + "PASSED\n"); + } + } + + return count; +} + +static ssize_t close_chan_lpm_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nCLOSE_CHAN_LPM_TEST\n" + "===================\n" + "Description:\n" + "TBD\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations close_chan_lpm_test_ops = { + .open = sdio_al_test_open, + .write = close_chan_lpm_test_write, + .read = close_chan_lpm_test_read, +}; + +/* LPM TEST FOR DEVICE 1. CLIENT WAKES THE HOST TEST */ +static ssize_t lpm_test_client_wakes_host_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. CLIENT " + "WAKES THE HOST TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC], + SDIO_TEST_LPM_CLIENT_WAKER, 90); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t lpm_test_client_wakes_host_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nLPM_TEST_CLIENT_WAKES_HOST_TEST\n" + "===============================\n" + "Description:\n" + "In this test, the HOST is going into LPM mode,\n" + "and the CLIENT is responsible to send it a message\n" + "in order to wake it up\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations lpm_test_client_wakes_host_test_ops = { + .open = sdio_al_test_open, + .write = lpm_test_client_wakes_host_test_write, + .read = lpm_test_client_wakes_host_test_read, +}; + +/* LPM TEST FOR DEVICE 1. HOST WAKES THE CLIENT TEST */ +static ssize_t lpm_test_host_wakes_client_test_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. HOST " + "WAKES THE CLIENT TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC], + SDIO_TEST_LPM_HOST_WAKER, 120); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t lpm_test_host_wakes_client_test_read(struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nLPM_TEST_HOST_WAKES_CLIENT_TEST\n" + "===============================\n" + "Description:\n" + "In this test, the CLIENT goes into LPM mode, and the\n" + "HOST is responsible to send it a message\n" + "in order to wake it up\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations lpm_test_host_wakes_client_test_ops = { + .open = sdio_al_test_open, + .write = lpm_test_host_wakes_client_test_write, + .read = lpm_test_host_wakes_client_test_read, +}; + +/* LPM TEST RANDOM, SINGLE CHANNEL TEST */ +static ssize_t lpm_test_random_single_channel_test_write( + struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM SINGLE " + "CHANNEL TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_pseudo_random_seed(); + set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC], + SDIO_TEST_LPM_RANDOM, 0); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t lpm_test_random_single_channel_test_read( + struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nLPM_TEST_RANDOM_SINGLE_CHANNEL_TEST\n" + "===================================\n" + "Description:\n" + "In this test, the HOST and CLIENT " + "send messages to each other,\n" + "random in time, over RPC channel only.\n" + "All events are being recorded, and later on,\n" + "they are being analysed by the HOST and by the CLIENT\n," + "in order to check if the LPM mechanism worked properly,\n" + "meaning:" + " When all the relevant conditions are met, a device should:\n" + "1. Go to sleep\n" + "2. Wake up\n" + "3. Stay awake\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations lpm_test_random_single_channel_test_ops = { + .open = sdio_al_test_open, + .write = lpm_test_random_single_channel_test_write, + .read = lpm_test_random_single_channel_test_read, +}; + +/* LPM TEST RANDOM, MULTI CHANNEL TEST */ +static ssize_t lpm_test_random_multi_channel_test_write( + struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int ret = 0; + int i = 0; + int number = -1; + + pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM MULTI CHANNEL TEST --\n"); + + number = sdio_al_test_extract_number(buf, count); + + if (number < 0) { + pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() " + "failed. number = %d\n", __func__, number); + return count; + } + + for (i = 0 ; i < number ; ++i) { + pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number); + pr_info(TEST_MODULE_NAME " ==================="); + + sdio_al_test_initial_dev_and_chan(test_ctx); + + set_pseudo_random_seed(); + + set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC], + SDIO_TEST_LPM_RANDOM, 0); + set_params_lpm_test(test_ctx->test_ch_arr[SDIO_DIAG], + SDIO_TEST_LPM_RANDOM, 0); + set_params_lpm_test(test_ctx->test_ch_arr[SDIO_QMI], + SDIO_TEST_LPM_RANDOM, 0); + + ret = test_start(); + + if (ret) + break; + } + + return count; +} + +static ssize_t lpm_test_random_multi_channel_test_read( + struct file *file, + char __user *buffer, + size_t count, + loff_t *offset) +{ + memset((void *)buffer, 0, count); + + snprintf(buffer, count, + "\nLPM_TEST_RANDOM_MULTI_CHANNEL_TEST\n" + "==================================\n" + "Description:\n" + "In this test, the HOST and CLIENT " + "send messages to each other,\n" + "random in time, over RPC, QMI AND DIAG channels\n" + "(i.e, on both SDIO devices).\n" + "All events are being recorded, and later on,\n" + "they are being analysed by the HOST and by the CLIENT,\n" + "in order to check if the LPM mechanism worked properly,\n" + "meaning:" + " When all the relevant conditions are met, a device should:\n" + "1. Go to sleep\n" + "2. Wake up\n" + "3. Stay awake\n\n" + "END OF DESCRIPTION\n"); + + if (message_repeat == 1) { + message_repeat = 0; + return strnlen(buffer, count); + } else { + return 0; + } +} + +const struct file_operations lpm_test_random_multi_channel_test_ops = { + .open = sdio_al_test_open, + .write = lpm_test_random_multi_channel_test_write, + .read = lpm_test_random_multi_channel_test_read, +}; + +static int sdio_al_test_debugfs_init(void) +{ + test_ctx->debug.debug_root = debugfs_create_dir("sdio_al_test", + NULL); + if (!test_ctx->debug.debug_root) + return -ENOENT; + + test_ctx->debug.debug_test_result = debugfs_create_u32( + "test_result", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + &test_ctx->test_result); + + test_ctx->debug.debug_dun_throughput = debugfs_create_u32( + "dun_throughput", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + &test_ctx->debug.dun_throughput); + + test_ctx->debug.debug_rmnt_throughput = debugfs_create_u32( + "rmnt_throughput", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + &test_ctx->debug.rmnt_throughput); + + test_ctx->debug.rpc_sender_test = + debugfs_create_file("10_rpc_sender_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rpc_sender_test_ops); + + test_ctx->debug.rpc_qmi_diag_sender_test = + debugfs_create_file("20_rpc_qmi_diag_sender_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rpc_qmi_diag_sender_test_ops); + + test_ctx->debug.rmnet_a2_validation_test = + debugfs_create_file("30_rmnet_a2_validation_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rmnet_a2_validation_test_ops); + + test_ctx->debug.dun_a2_validation_test = + debugfs_create_file("40_dun_a2_validation_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &dun_a2_validation_test_ops); + + test_ctx->debug.rmnet_a2_perf_test = + debugfs_create_file("50_rmnet_a2_perf_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rmnet_a2_perf_test_ops); + + test_ctx->debug.dun_a2_perf_test = + debugfs_create_file("60_dun_a2_perf_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &dun_a2_perf_test_ops); + + test_ctx->debug.csvt_a2_perf_test = + debugfs_create_file("71_csvt_a2_perf_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &csvt_a2_perf_test_ops); + + test_ctx->debug.rmnet_dun_a2_perf_test = + debugfs_create_file("70_rmnet_dun_a2_perf_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rmnet_dun_a2_perf_test_ops); + + test_ctx->debug.rpc_sender_rmnet_a2_perf_test = + debugfs_create_file("80_rpc_sender_rmnet_a2_perf_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rpc_sender_rmnet_a2_perf_test_ops); + + test_ctx->debug.smem_test = + debugfs_create_file("90_smem_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &smem_test_ops); + + test_ctx->debug.smem_rpc_test = + debugfs_create_file("100_smem_rpc_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &smem_rpc_test_ops); + + test_ctx->debug.all_channels_test = + debugfs_create_file("150_all_channels_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &all_channels_test_ops); + + test_ctx->debug.host_sender_no_lp_diag_test = + debugfs_create_file("160_host_sender_no_lp_diag_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &host_sender_no_lp_diag_test_ops); + + test_ctx->debug.host_sender_no_lp_diag_rpc_test = + debugfs_create_file("170_host_sender_no_lp_diag_rpc_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &host_sender_no_lp_diag_rpc_test_ops); + + test_ctx->debug.rmnet_small_packets_test = + debugfs_create_file("180_rmnet_small_packets_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rmnet_small_packets_test_ops); + + test_ctx->debug.rmnet_rtt_test = + debugfs_create_file("190_rmnet_rtt_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &rmnet_rtt_test_ops); + + test_ctx->debug.csvt_rtt_test = + debugfs_create_file("191_csvt_rtt_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &csvt_rtt_test_ops); + + test_ctx->debug.modem_reset_rpc_test = + debugfs_create_file("220_modem_reset_rpc_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &modem_reset_rpc_test_ops); + + test_ctx->debug.modem_reset_rmnet_test = + debugfs_create_file("230_modem_reset_rmnet_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &modem_reset_rmnet_test_ops); + + test_ctx->debug.modem_reset_channels_4bit_dev_test = + debugfs_create_file("240_modem_reset_channels_4bit_dev_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &modem_reset_channels_4bit_dev_test_ops); + + test_ctx->debug.modem_reset_channels_8bit_dev_test = + debugfs_create_file("250_modem_reset_channels_8bit_dev_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &modem_reset_channels_8bit_dev_test_ops); + + test_ctx->debug.modem_reset_all_channels_test = + debugfs_create_file("260_modem_reset_all_channels_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &modem_reset_all_channels_test_ops); + + test_ctx->debug.open_close_test = + debugfs_create_file("270_open_close_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &open_close_test_ops); + + test_ctx->debug.open_close_dun_rmnet_test = + debugfs_create_file("271_open_close_dun_rmnet_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &open_close_dun_rmnet_test_ops); + + test_ctx->debug.close_chan_lpm_test = + debugfs_create_file("280_close_chan_lpm_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &close_chan_lpm_test_ops); + + test_ctx->debug.lpm_test_client_wakes_host_test = + debugfs_create_file("600_lpm_test_client_wakes_host_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &lpm_test_client_wakes_host_test_ops); + + test_ctx->debug.lpm_test_host_wakes_client_test = + debugfs_create_file("610_lpm_test_host_wakes_client_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &lpm_test_host_wakes_client_test_ops); + + test_ctx->debug.lpm_test_random_single_channel_test = + debugfs_create_file("620_lpm_test_random_single_channel_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &lpm_test_random_single_channel_test_ops); + + test_ctx->debug.lpm_test_random_multi_channel_test = + debugfs_create_file("630_lpm_test_random_multi_channel_test", + S_IRUGO | S_IWUGO, + test_ctx->debug.debug_root, + NULL, + &lpm_test_random_multi_channel_test_ops); + + if ((!test_ctx->debug.debug_dun_throughput) && + (!test_ctx->debug.debug_rmnt_throughput)) { + debugfs_remove_recursive(test_ctx->debug.debug_root); + test_ctx->debug.debug_root = NULL; + return -ENOENT; + } + return 0; +} + +static void sdio_al_test_debugfs_cleanup(void) +{ + debugfs_remove(test_ctx->debug.debug_dun_throughput); + debugfs_remove(test_ctx->debug.debug_rmnt_throughput); + debugfs_remove(test_ctx->debug.debug_root); +} +#endif + +static int channel_name_to_id(char *name) +{ + pr_info(TEST_MODULE_NAME "%s: channel name %s\n", + __func__, name); + + if (!strncmp(name, "SDIO_RPC_TEST", + strnlen("SDIO_RPC_TEST", CHANNEL_NAME_SIZE))) + return SDIO_RPC; + else if (!strncmp(name, "SDIO_QMI_TEST", + strnlen("SDIO_QMI_TEST", TEST_CH_NAME_SIZE))) + return SDIO_QMI; + else if (!strncmp(name, "SDIO_RMNT_TEST", + strnlen("SDIO_RMNT_TEST", TEST_CH_NAME_SIZE))) + return SDIO_RMNT; + else if (!strncmp(name, "SDIO_DIAG_TEST", + strnlen("SDIO_DIAG", TEST_CH_NAME_SIZE))) + return SDIO_DIAG; + else if (!strncmp(name, "SDIO_DUN_TEST", + strnlen("SDIO_DUN_TEST", TEST_CH_NAME_SIZE))) + return SDIO_DUN; + else if (!strncmp(name, "SDIO_SMEM_TEST", + strnlen("SDIO_SMEM_TEST", TEST_CH_NAME_SIZE))) + return SDIO_SMEM; + else if (!strncmp(name, "SDIO_CSVT_TEST", + strnlen("SDIO_CSVT_TEST", TEST_CH_NAME_SIZE))) + return SDIO_CSVT; + else + return SDIO_MAX_CHANNELS; + + return SDIO_MAX_CHANNELS; +} + +/** + * Allocate and add SDIO_SMEM platform device + */ +#ifdef CONFIG_MSM_SDIO_SMEM +static int add_sdio_smem(void) +{ + int ret = 0; + + test_ctx->smem_pdev = platform_device_alloc("SDIO_SMEM", -1); + ret = platform_device_add(test_ctx->smem_pdev); + if (ret) { + pr_err(TEST_MODULE_NAME ": platform_device_add failed, " + "ret=%d\n", ret); + return ret; + } + return 0; +} +#endif + +static int open_sdio_ch(struct test_channel *tch) +{ + int ret = 0; + + if (!tch) { + pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__); + return -EINVAL; + } + + if (!tch->ch_ready) { + TEST_DBG(TEST_MODULE_NAME ":openning channel %s\n", + tch->name); + if (tch->ch_id == SDIO_SMEM) { +#ifdef CONFIG_MSM_SDIO_SMEM + if (!test_ctx->smem_pdev) + ret = add_sdio_smem(); + else + ret = sdio_smem_open(test_ctx->sdio_smem); + if (ret) { + pr_err(TEST_MODULE_NAME + ":openning channel %s failed\n", + tch->name); + tch->ch_ready = false; + return -EINVAL; + } +#endif + } else { + tch->ch_ready = true; + ret = sdio_open(tch->name , &tch->ch, tch, + notify); + if (ret) { + pr_err(TEST_MODULE_NAME + ":openning channel %s failed\n", + tch->name); + tch->ch_ready = false; + return -EINVAL; + } + } + } + return ret; +} + +static int close_sdio_ch(struct test_channel *tch) +{ + int ret = 0; + + if (!tch) { + pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__); + return -EINVAL; + } + + if (tch->ch_id == SDIO_SMEM) { +#ifdef CONFIG_MSM_SDIO_SMEM + TEST_DBG(TEST_MODULE_NAME":%s closing channel %s", + __func__, tch->name); + ret = sdio_smem_unregister_client(); + test_ctx->smem_counter = 0; +#endif + } else { + ret = sdio_close(tch->ch); + } + + if (ret) { + pr_err(TEST_MODULE_NAME":%s close channel %s" + " failed\n", __func__, tch->name); + } else { + TEST_DBG(TEST_MODULE_NAME":%s close channel %s" + " success\n", __func__, tch->name); + tch->ch_ready = false; + } + return ret; +} + +/** + * Config message + */ + +static void send_config_msg(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 write_avail = 0; + int size = sizeof(test_ch->config_msg); + + pr_debug(TEST_MODULE_NAME "%s\n", __func__); + + memcpy(test_ch->buf, (void *)&test_ch->config_msg, size); + + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + + pr_info(TEST_MODULE_NAME ":Sending the config message.\n"); + + /* wait for data ready event */ + write_avail = sdio_write_avail(test_ch->ch); + pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail); + if (write_avail < size) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->tx_notify_count)); + atomic_dec(&test_ch->tx_notify_count); + } + + write_avail = sdio_write_avail(test_ch->ch); + pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail); + if (write_avail < size) { + pr_info(TEST_MODULE_NAME ":not enough write avail.\n"); + return; + } + + ret = sdio_write(test_ch->ch, test_ch->buf, size); + if (ret) + pr_err(TEST_MODULE_NAME ":%s sdio_write err=%d.\n", + __func__, -ret); + else + pr_info(TEST_MODULE_NAME ":%s sent config_msg successfully.\n", + __func__); +} + +/** + * Loopback Test + */ +static void loopback_test(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 read_avail = 0; + u32 write_avail = 0; + + while (1) { + + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + + TEST_DBG(TEST_MODULE_NAME "--LOOPBACK WAIT FOR EVENT--.\n"); + /* wait for data ready event */ + wait_event(test_ch->wait_q, + atomic_read(&test_ch->rx_notify_count)); + atomic_dec(&test_ch->rx_notify_count); + + read_avail = sdio_read_avail(test_ch->ch); + if (read_avail == 0) + continue; + + + write_avail = sdio_write_avail(test_ch->ch); + if (write_avail < read_avail) { + pr_info(TEST_MODULE_NAME + ":not enough write avail.\n"); + continue; + } + + ret = sdio_read(test_ch->ch, test_ch->buf, read_avail); + if (ret) { + pr_info(TEST_MODULE_NAME + ":worker, sdio_read err=%d.\n", -ret); + continue; + } + test_ch->rx_bytes += read_avail; + + TEST_DBG(TEST_MODULE_NAME ":worker total rx bytes = 0x%x.\n", + test_ch->rx_bytes); + + + ret = sdio_write(test_ch->ch, + test_ch->buf, read_avail); + if (ret) { + pr_info(TEST_MODULE_NAME + ":loopback sdio_write err=%d.\n", + -ret); + continue; + } + test_ch->tx_bytes += read_avail; + + TEST_DBG(TEST_MODULE_NAME + ":loopback total tx bytes = 0x%x.\n", + test_ch->tx_bytes); + } /* end of while */ +} + +/** + * Check if all tests completed + */ +static void check_test_completion(void) +{ + int i; + + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + + if ((!tch) || (!tch->is_used) || (!tch->ch_ready)) + continue; + if (!tch->test_completed) { + pr_info(TEST_MODULE_NAME ": %s - Channel %s test is " + "not completed", __func__, tch->name); + return; + } + } + pr_info(TEST_MODULE_NAME ": %s - Test is completed", __func__); + test_ctx->test_completed = 1; + wake_up(&test_ctx->wait_q); +} + +static int pseudo_random_seed(unsigned int *seed_number) +{ + if (!seed_number) + return 0; + + *seed_number = (unsigned int)(((unsigned long)*seed_number * + (unsigned long)1103515367) + 35757); + return (int)((*seed_number / (64*1024)) % 500); +} + +/* this function must be locked before accessing it */ +static void lpm_test_update_entry(struct test_channel *tch, + enum lpm_test_msg_type msg_type, + char *msg_name, + int counter) +{ + u32 index = 0; + static int print_full = 1; + struct sdio_test_device *test_device; + + if (!tch) { + pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__); + return; + } + + test_device = tch->test_device; + + if (!test_device) { + pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__); + return; + } + + if (!test_device->lpm_arr) { + pr_err(TEST_MODULE_NAME ": %s - NULL lpm_arr\n", __func__); + return; + } + + if (test_device->next_avail_entry_in_array >= + test_device->array_size) { + pr_err(TEST_MODULE_NAME ": %s - lpm array is full", + __func__); + + if (print_full) { + print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": lpm_arr:", + 0, 32, 2, + (void *)test_device->lpm_arr, + sizeof(test_device->lpm_arr), false); + print_full = 0; + } + return; + } + + index = test_device->next_avail_entry_in_array; + if ((msg_type == LPM_MSG_SEND) || (msg_type == LPM_MSG_REC)) + test_device->lpm_arr[index].counter = counter; + else + test_device->lpm_arr[index].counter = 0; + + test_device->lpm_arr[index].msg_type = msg_type; + memcpy(test_device->lpm_arr[index].msg_name, msg_name, + LPM_MSG_NAME_SIZE); + test_device->lpm_arr[index].current_ms = + jiffies_to_msecs(get_jiffies_64()); + + test_device->lpm_arr[index].read_avail_mask = + test_device->read_avail_mask; + + if ((msg_type == LPM_SLEEP) || (msg_type == LPM_WAKEUP)) + memcpy(test_device->lpm_arr[index].chan_name, "DEVICE ", + CHANNEL_NAME_SIZE); + else + memcpy(test_device->lpm_arr[index].chan_name, tch->name, + CHANNEL_NAME_SIZE); + + test_device->next_avail_entry_in_array++; +} + +static int wait_for_result_msg(struct test_channel *test_ch) +{ + u32 read_avail = 0; + int ret = 0; + + pr_info(TEST_MODULE_NAME ": %s - START, channel %s\n", + __func__, test_ch->name); + + while (1) { + read_avail = sdio_read_avail(test_ch->ch); + + if (read_avail == 0) { + pr_info(TEST_MODULE_NAME + ": read_avail is 0 for chan %s\n", + test_ch->name); + wait_event(test_ch->wait_q, + atomic_read(&test_ch->rx_notify_count)); + atomic_dec(&test_ch->rx_notify_count); + continue; + } + + memset(test_ch->buf, 0x00, test_ch->buf_size); + + ret = sdio_read(test_ch->ch, test_ch->buf, read_avail); + if (ret) { + pr_info(TEST_MODULE_NAME ": sdio_read for chan" + "%s failed, err=%d.\n", + test_ch->name, -ret); + goto exit_err; + } + + if (test_ch->buf[0] != TEST_CONFIG_SIGNATURE) { + pr_info(TEST_MODULE_NAME ": Not a test_result " + "signature. expected 0x%x. received 0x%x " + "for chan %s\n", + TEST_CONFIG_SIGNATURE, + test_ch->buf[0], + test_ch->name); + continue; + } else { + pr_info(TEST_MODULE_NAME ": Signature is " + "TEST_CONFIG_SIGNATURE as expected for" + "channel %s\n", test_ch->name); + break; + } + } + + return test_ch->buf[1]; + +exit_err: + return 0; +} + +static void print_random_lpm_test_array(struct sdio_test_device *test_dev) +{ + int i; + + if (!test_dev) { + pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__); + return; + } + + for (i = 0 ; i < test_dev->next_avail_entry_in_array ; ++i) { + if (i == 0) + pr_err(TEST_MODULE_NAME ": index %4d, chan=%2s, " + "code=%1d=%4s, msg#%1d, ms from before=-1, " + "read_mask=0x%d, ms=%2u", + i, + test_dev->lpm_arr[i].chan_name, + test_dev->lpm_arr[i].msg_type, + test_dev->lpm_arr[i].msg_name, + test_dev->lpm_arr[i].counter, + test_dev->lpm_arr[i].read_avail_mask, + test_dev->lpm_arr[i].current_ms); + else + pr_err(TEST_MODULE_NAME ": index " + "%4d, %2s, code=%1d=%4s, msg#%1d, ms from " + "before=%2u, read_mask=0x%d, ms=%2u", + i, + test_dev->lpm_arr[i].chan_name, + test_dev->lpm_arr[i].msg_type, + test_dev->lpm_arr[i].msg_name, + test_dev->lpm_arr[i].counter, + test_dev->lpm_arr[i].current_ms - + test_dev->lpm_arr[i-1].current_ms, + test_dev->lpm_arr[i].read_avail_mask, + test_dev->lpm_arr[i].current_ms); + + udelay(1000); + } +} + +static int check_random_lpm_test_array(struct sdio_test_device *test_dev) +{ + int i = 0, j = 0; + unsigned int delta_ms = 0; + int arr_ind = 0; + int ret = 0; + int notify_counter = 0; + int sleep_counter = 0; + int wakeup_counter = 0; + int lpm_activity_counter = 0; + + if (!test_dev) { + pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__); + return -ENODEV; + } + + for (i = 0; i < test_dev->next_avail_entry_in_array; i++) { + notify_counter = 0; + sleep_counter = 0; + wakeup_counter = 0; + + if ((test_dev->lpm_arr[i].msg_type == LPM_MSG_SEND) || + (test_dev->lpm_arr[i].msg_type == LPM_MSG_REC)) { + /* find the next message in the array */ + arr_ind = test_dev->next_avail_entry_in_array; + for (j = i+1; j < arr_ind; j++) { + if ((test_dev->lpm_arr[j].msg_type == + LPM_MSG_SEND) || + (test_dev->lpm_arr[j].msg_type == + LPM_MSG_REC) || + (test_dev->lpm_arr[j].msg_type == + LPM_NOTIFY)) + break; + if (test_dev->lpm_arr[j].msg_type == + LPM_SLEEP) + sleep_counter++; + if (test_dev->lpm_arr[j].msg_type == + LPM_WAKEUP) + wakeup_counter++; + } + if (j == arr_ind) { + ret = 0; + break; + } + + delta_ms = test_dev->lpm_arr[j].current_ms - + test_dev->lpm_arr[i].current_ms; + if (delta_ms < 30) { + if ((sleep_counter == 0) + && (wakeup_counter == 0)) { + continue; + } else { + pr_err(TEST_MODULE_NAME "%s: lpm " + "activity while delta is less " + "than 30, i=%d, j=%d, " + "sleep_counter=%d, " + "wakeup_counter=%d", + __func__, i, j, + sleep_counter, wakeup_counter); + ret = -ENODEV; + break; + } + } else { + if ((delta_ms > 90) && + (test_dev->lpm_arr[i]. + read_avail_mask == 0)) { + if (j != i+3) { + pr_err(TEST_MODULE_NAME + "%s: unexpected " + "lpm activity " + "while delta is " + "bigger than " + "90, i=%d, " + "j=%d, " + "notify_counter" + "=%d", + __func__, i, j, + notify_counter); + ret = -ENODEV; + break; + } + lpm_activity_counter++; + } + } + } + } + + pr_info(TEST_MODULE_NAME ": %s - lpm_activity_counter=%d", + __func__, lpm_activity_counter); + + return ret; +} + +static int lpm_test_main_task(void *ptr) +{ + u32 read_avail = 0; + int last_msg_index = 0; + struct test_channel *test_ch = (struct test_channel *)ptr; + struct sdio_test_device *test_dev; + struct lpm_msg lpm_msg; + int ret = 0; + int host_result = 0; + + if (!test_ch) { + pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__); + return -ENODEV; + } + + pr_err(TEST_MODULE_NAME ": %s - STARTED. channel %s\n", + __func__, test_ch->name); + + test_dev = test_ch->test_device; + + if (!test_dev) { + pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__); + return -ENODEV; + } + + while (last_msg_index < test_ch->config_msg.num_packets - 1) { + + TEST_DBG(TEST_MODULE_NAME ": %s - " + "IN LOOP last_msg_index=%d\n", + __func__, last_msg_index); + + read_avail = sdio_read_avail(test_ch->ch); + if (read_avail == 0) { + TEST_DBG(TEST_MODULE_NAME + ":read_avail 0 for chan %s, " + "wait for event\n", + test_ch->name); + wait_event(test_ch->wait_q, + atomic_read(&test_ch->rx_notify_count)); + atomic_dec(&test_ch->rx_notify_count); + + read_avail = sdio_read_avail(test_ch->ch); + if (read_avail == 0) { + pr_err(TEST_MODULE_NAME + ":read_avail size %d for chan %s not as" + " expected\n", + read_avail, test_ch->name); + continue; + } + } + + memset(test_ch->buf, 0x00, sizeof(test_ch->buf)); + + ret = sdio_read(test_ch->ch, test_ch->buf, read_avail); + if (ret) { + pr_info(TEST_MODULE_NAME ":sdio_read for chan %s" + " err=%d.\n", test_ch->name, -ret); + goto exit_err; + } + + memcpy((void *)&lpm_msg, test_ch->buf, sizeof(lpm_msg)); + + /* + * when reading from channel, we want to turn off the bit + * mask that implies that there is pending data on that channel + */ + if (test_ch->test_device != NULL) { + spin_lock_irqsave(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + + test_ch->notify_counter_per_chan--; + + /* + * if the channel has no pending data, turn off the + * pending data bit mask of the channel + */ + if (test_ch->notify_counter_per_chan == 0) { + test_ch->test_device->read_avail_mask = + test_ch->test_device->read_avail_mask & + ~test_ch->channel_mask_id; + } + + last_msg_index = lpm_msg.counter; + lpm_test_update_entry(test_ch, + LPM_MSG_REC, + "RECEIVE", + last_msg_index); + + spin_unlock_irqrestore(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + } + } + + pr_info(TEST_MODULE_NAME ":%s: Finished to recieve all (%d) " + "packets from the modem %s. Waiting for result_msg", + __func__, test_ch->config_msg.num_packets, test_ch->name); + + /* Wait for the resault message from the modem */ + test_ch->modem_result_per_chan = wait_for_result_msg(test_ch); + + /* + * the DEVICE modem result is a failure if one of the channels on + * that device, got modem_result = 0. this is why we bitwise "AND" each + * time another channel completes its task + */ + test_dev->modem_result_per_dev &= test_ch->modem_result_per_chan; + + /* + * when reading from channel, we want to turn off the bit + * mask that implies that there is pending data on that channel + */ + spin_lock_irqsave(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + + test_dev->open_channels_counter_to_recv--; + + /* turning off the read_avail bit of the channel */ + test_ch->test_device->read_avail_mask = + test_ch->test_device->read_avail_mask & + ~test_ch->channel_mask_id; + + spin_unlock_irqrestore(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + + /* Wait for all the packets to be sent to the modem */ + while (1) { + spin_lock_irqsave(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + + if (test_ch->next_index_in_sent_msg_per_chan >= + test_ch->config_msg.num_packets - 1) { + + spin_unlock_irqrestore(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + break; + } else { + pr_info(TEST_MODULE_NAME ":%s: Didn't finished to send " + "all packets, " + "next_index_in_sent_msg_per_chan = %d ", + __func__, + test_ch->next_index_in_sent_msg_per_chan); + } + spin_unlock_irqrestore(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + msleep(60); + } + + /* + * if device has still open channels to test, then the test on the + * device is still running but the test on current channel is completed + */ + if (test_dev->open_channels_counter_to_recv != 0 || + test_dev->open_channels_counter_to_send != 0) { + test_ch->test_completed = 1; + return 0; + } else { + test_ctx->number_of_active_devices--; + sdio_al_unregister_lpm_cb(test_ch->sdio_al_device); + + if (test_ch->test_type == SDIO_TEST_LPM_RANDOM) + host_result = check_random_lpm_test_array(test_dev); + + if (host_result || + !test_dev->modem_result_per_dev || + test_ctx->runtime_debug) + print_random_lpm_test_array(test_dev); + + pr_info(TEST_MODULE_NAME ": %s - host_result=%d.(0 for " + "SUCCESS) device_modem_result=%d (1 for SUCCESS)", + __func__, host_result, test_dev->modem_result_per_dev); + + test_ch->test_completed = 1; + if (test_dev->modem_result_per_dev && !host_result) { + pr_info(TEST_MODULE_NAME ": %s - Random LPM " + "TEST_PASSED for device %d of %d\n", + __func__, + (test_ctx->max_number_of_devices- + test_ctx->number_of_active_devices), + test_ctx->max_number_of_devices); + test_dev->final_result_per_dev = 1; /* PASSED */ + } else { + pr_info(TEST_MODULE_NAME ": %s - Random LPM " + "TEST_FAILED for device %d of %d\n", + __func__, + (test_ctx->max_number_of_devices- + test_ctx->number_of_active_devices), + test_ctx->max_number_of_devices); + test_dev->final_result_per_dev = 0; /* FAILED */ + } + + check_test_completion(); + + kfree(test_ch->test_device->lpm_arr); + + return 0; + } + +exit_err: + pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n", + test_ch->name); + test_ch->test_completed = 1; + test_dev->open_channels_counter_to_recv--; + test_dev->next_avail_entry_in_array = 0; + test_ch->next_index_in_sent_msg_per_chan = 0; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return -ENODEV; +} + +static int lpm_test_create_read_thread(struct test_channel *test_ch) +{ + struct sdio_test_device *test_dev; + + pr_info(TEST_MODULE_NAME ": %s - STARTED channel %s\n", + __func__, test_ch->name); + + if (!test_ch) { + pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__); + return -ENODEV; + } + + test_dev = test_ch->test_device; + + if (!test_dev) { + pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__); + return -ENODEV; + } + + test_dev->lpm_test_task.task_name = SDIO_LPM_TEST; + + test_dev->lpm_test_task.lpm_task = + kthread_create(lpm_test_main_task, + (void *)(test_ch), + test_dev->lpm_test_task.task_name); + + if (IS_ERR(test_dev->lpm_test_task.lpm_task)) { + pr_err(TEST_MODULE_NAME ": %s - kthread_create() failed\n", + __func__); + return -ENOMEM; + } + + wake_up_process(test_dev->lpm_test_task.lpm_task); + + return 0; +} + +static void lpm_continuous_rand_test(struct test_channel *test_ch) +{ + unsigned int local_ms = 0; + int ret = 0; + unsigned int write_avail = 0; + struct sdio_test_device *test_dev; + + pr_info(MODULE_NAME ": %s - STARTED\n", __func__); + + if (!test_ch) { + pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__); + return; + } + + test_dev = test_ch->test_device; + + if (!test_dev) { + pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__); + return; + } + + ret = lpm_test_create_read_thread(test_ch); + if (ret != 0) { + pr_err(TEST_MODULE_NAME ": %s - failed to create lpm reading " + "thread", __func__); + } + + while (1) { + + struct lpm_msg msg; + u32 ret = 0; + + /* sleeping period is dependent on number of open channels */ + test_ch->config_msg.test_param = + test_ctx->lpm_pseudo_random_seed; + + local_ms = test_dev->open_channels_counter_to_send * + test_ctx->lpm_pseudo_random_seed; + TEST_DBG(TEST_MODULE_NAME ":%s: SLEEPING for %d ms", + __func__, local_ms); + msleep(local_ms); + + msg.counter = test_ch->next_index_in_sent_msg_per_chan; + msg.signature = LPM_TEST_CONFIG_SIGNATURE; + msg.reserve1 = 0; + msg.reserve2 = 0; + + /* wait for data ready event */ + write_avail = sdio_write_avail(test_ch->ch); + pr_debug(TEST_MODULE_NAME ": %s: write_avail=%d\n", + __func__, write_avail); + if (write_avail < sizeof(msg)) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->tx_notify_count)); + atomic_dec(&test_ch->tx_notify_count); + } + + write_avail = sdio_write_avail(test_ch->ch); + if (write_avail < sizeof(msg)) { + pr_info(TEST_MODULE_NAME ": %s: not enough write " + "avail.\n", __func__); + break; + } + + ret = sdio_write(test_ch->ch, (u32 *)&msg, sizeof(msg)); + if (ret) + pr_err(TEST_MODULE_NAME ":%s: sdio_write err=%d.\n", + __func__, -ret); + + TEST_DBG(TEST_MODULE_NAME ": %s: for chan %s, write, " + "msg # %d\n", + __func__, + test_ch->name, + test_ch->next_index_in_sent_msg_per_chan); + + if (test_ch->test_type == SDIO_TEST_LPM_RANDOM) { + spin_lock_irqsave(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + lpm_test_update_entry(test_ch, LPM_MSG_SEND, + "SEND ", + test_ch-> + next_index_in_sent_msg_per_chan); + + test_ch->next_index_in_sent_msg_per_chan++; + + if (test_ch->next_index_in_sent_msg_per_chan == + test_ch->config_msg.num_packets) { + spin_unlock_irqrestore( + &test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + break; + } + + spin_unlock_irqrestore(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + } + } + + spin_lock_irqsave(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + test_dev->open_channels_counter_to_send--; + spin_unlock_irqrestore(&test_dev->lpm_array_lock, + test_dev->lpm_array_lock_flags); + + pr_info(TEST_MODULE_NAME ": %s: - Finished to send all (%d) " + "packets to the modem on channel %s", + __func__, test_ch->config_msg.num_packets, test_ch->name); + + return; +} + +static void lpm_test(struct test_channel *test_ch) +{ + pr_info(TEST_MODULE_NAME ": %s - START channel %s\n", __func__, + test_ch->name); + + if (!test_ch) { + pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__); + return; + } + + test_ch->modem_result_per_chan = wait_for_result_msg(test_ch); + pr_debug(TEST_MODULE_NAME ": %s - delete the timeout timer\n", + __func__); + del_timer_sync(&test_ch->timeout_timer); + + if (test_ch->modem_result_per_chan == 0) { + pr_err(TEST_MODULE_NAME ": LPM TEST - Client didn't sleep. " + "Result Msg - is_successful=%d\n", test_ch->buf[1]); + goto exit_err; + } else { + pr_info(TEST_MODULE_NAME ": %s -" + "LPM 9K WAS SLEEPING - PASS\n", __func__); + if (test_ch->test_result == TEST_PASSED) { + pr_info(TEST_MODULE_NAME ": LPM TEST_PASSED\n"); + test_ch->test_completed = 1; + check_test_completion(); + } else { + pr_err(TEST_MODULE_NAME ": LPM TEST - Host didn't " + "sleep. Client slept\n"); + goto exit_err; + } + } + + return; + +exit_err: + pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n", + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + + +/** + * LPM Test while the host wakes up the modem + */ +static void lpm_test_host_waker(struct test_channel *test_ch) +{ + pr_info(TEST_MODULE_NAME ": %s - START\n", __func__); + wait_event(test_ch->wait_q, atomic_read(&test_ch->wakeup_client)); + atomic_set(&test_ch->wakeup_client, 0); + + pr_info(TEST_MODULE_NAME ": %s - Sending the config_msg to wakeup " + " the client\n", __func__); + send_config_msg(test_ch); + + lpm_test(test_ch); +} + +/** + * Writes number of packets into test channel + * @test_ch: test channel control struct + * @burst_size: number of packets to send + */ +static int write_packet_burst(struct test_channel *test_ch, + int burst_size) +{ + int ret = 0; + int packet_count = 0; + unsigned int random_num = 0; + int size = test_ch->packet_length; /* first packet size */ + u32 write_avail = 0; + + while (packet_count < burst_size) { + /* wait for data ready event */ + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":%s write_avail=%d,size=%d on chan" + " %s\n", __func__, + write_avail, size, test_ch->name); + if (write_avail < size) { + TEST_DBG(TEST_MODULE_NAME ":%s wait for event on" + " chan %s\n", __func__, test_ch->name); + wait_event(test_ch->wait_q, + atomic_read(&test_ch->tx_notify_count)); + atomic_dec(&test_ch->tx_notify_count); + } + write_avail = sdio_write_avail(test_ch->ch); + if (write_avail < size) { + pr_info(TEST_MODULE_NAME ":%s not enough write" + " avail %d, need %d on chan %s\n", + __func__, write_avail, size, + test_ch->name); + continue; + } + ret = sdio_write(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s sdio_write " + "failed (%d) on chan %s\n", __func__, + ret, test_ch->name); + break; + } + udelay(1000); /*low bus usage while running number of channels*/ + TEST_DBG(TEST_MODULE_NAME ":%s() successfully write %d bytes" + ", packet_count=%d on chan %s\n", __func__, + size, packet_count, test_ch->name); + test_ch->tx_bytes += size; + packet_count++; + /* get next packet size */ + random_num = get_random_int(); + size = (random_num % test_ch->packet_length) + 1; + } + return ret; +} + +/** + * Reads packet from test channel and checks that packet number + * encoded into the packet is equal to packet_counter + * This function is applicable for packet mode channels only + * + * @test_ch: test channel + * @size: expected packet size + * @packet_counter: number to validate readed packet + */ +static int read_data_from_packet_ch(struct test_channel *test_ch, + unsigned int size, + int packet_counter) +{ + u32 read_avail = 0; + int ret = 0; + + if (!test_ch || !test_ch->ch) { + pr_err(TEST_MODULE_NAME + ":%s: NULL channel\n", __func__); + return -EINVAL; + } + + if (!test_ch->ch->is_packet_mode) { + pr_err(TEST_MODULE_NAME + ":%s:not packet mode ch %s\n", + __func__, test_ch->name); + return -EINVAL; + } + read_avail = sdio_read_avail(test_ch->ch); + /* wait for read data ready event */ + if (read_avail < size) { + TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on " + "chan %s\n", __func__, test_ch->name); + wait_event(test_ch->wait_q, + atomic_read(&test_ch->rx_notify_count)); + atomic_dec(&test_ch->rx_notify_count); + } + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n", + __func__, read_avail, test_ch->name); + + if (read_avail != size) { + pr_err(TEST_MODULE_NAME + ":read_avail size %d for chan %s not as " + "expected size %d\n", + read_avail, test_ch->name, size); + return -EINVAL; + } + + ret = sdio_read(test_ch->ch, test_ch->buf, read_avail); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n", + __func__, test_ch->name, -ret); + return ret; + } + if ((test_ch->buf[0] != packet_counter) && (size != 1)) { + pr_err(TEST_MODULE_NAME ":Read WRONG DATA" + " for chan %s, size=%d\n", + test_ch->name, size); + return -EINVAL; + } + return 0; +} + + +/** + * Reads packet from test channel and checks that packet number + * encoded into the packet is equal to packet_counter + * This function is applicable for streaming mode channels only + * + * @test_ch: test channel + * @size: expected packet size + * @packet_counter: number to validate readed packet + */ +static int read_data_from_stream_ch(struct test_channel *test_ch, + unsigned int size, + int packet_counter) +{ + u32 read_avail = 0; + int ret = 0; + + if (!test_ch || !test_ch->ch) { + pr_err(TEST_MODULE_NAME + ":%s: NULL channel\n", __func__); + return -EINVAL; + } + + if (test_ch->ch->is_packet_mode) { + pr_err(TEST_MODULE_NAME + ":%s:not streaming mode ch %s\n", + __func__, test_ch->name); + return -EINVAL; + } + read_avail = sdio_read_avail(test_ch->ch); + /* wait for read data ready event */ + if (read_avail < size) { + TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on " + "chan %s\n", __func__, test_ch->name); + wait_event(test_ch->wait_q, + atomic_read(&test_ch->rx_notify_count)); + atomic_dec(&test_ch->rx_notify_count); + } + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n", + __func__, read_avail, test_ch->name); + + if (read_avail < size) { + pr_err(TEST_MODULE_NAME + ":read_avail size %d for chan %s not as " + "expected size %d\n", + read_avail, test_ch->name, size); + return -EINVAL; + } + + ret = sdio_read(test_ch->ch, test_ch->buf, size + A2_HEADER_OVERHEAD); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n", + __func__, test_ch->name, -ret); + return ret; + } + if ((test_ch->buf[A2_HEADER_OVERHEAD/4] != packet_counter) && + (size != 1)) { + pr_err(TEST_MODULE_NAME ":Read WRONG DATA" + " for chan %s, size=%d, packet_counter=%d\n", + test_ch->name, size, packet_counter); + print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": rmnet:", + 0, 32, 2, + (void *)test_ch->buf, + size + A2_HEADER_OVERHEAD, false); + return -EINVAL; + } + return 0; +} + +/** + * Test close channel feature for SDIO_SMEM channel: + * close && re-open the SDIO_SMEM channel. + */ +#ifdef CONFIG_MSM_SDIO_SMEM +static void open_close_smem_test(struct test_channel *test_ch) +{ + int i = 0; + int ret = 0; + + pr_info(TEST_MODULE_NAME ":%s\n", __func__); + + for (i = 0; i < 100 ; ++i) { + ret = close_sdio_ch(test_ch); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s close_sdio_ch for ch %s" + " failed\n", + __func__, test_ch->name); + goto exit_err; + } + ret = open_sdio_ch(test_ch); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s open_sdio_ch for ch %s " + " failed\n", + __func__, test_ch->name); + goto exit_err; + } + } + + pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__, + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_PASSED; + check_test_completion(); + return; +exit_err: + pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__, + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} +#endif + +/** + * Test close channel feature: + * 1. write random packet number into channel + * 2. read some data from channel (do this only for second half of + * requested packets to send). + * 3. close && re-open then repeat 1. + * + * Total packets to send: test_ch->config_msg.num_packets. + * Burst size is random in [1..test_ch->max_burst_size] range + * Packet size is random in [1..test_ch->packet_length] + */ +static void open_close_test(struct test_channel *test_ch) +{ + int ret = 0; + u32 read_avail = 0; + int total_packet_count = 0; + int size = 0; + u16 *buf16 = NULL; + int i; + int max_packet_count = 0; + unsigned int random_num = 0; + int curr_burst_size = 0; + + if (!test_ch || !test_ch->ch) { + pr_err(TEST_MODULE_NAME ":%s NULL channel\n", + __func__); + return; + } + + curr_burst_size = test_ch->max_burst_size; + size = test_ch->packet_length; + buf16 = (u16 *) test_ch->buf; + + /* the test sends configured number of packets in + 2 portions: first without reading between write bursts, + second with it */ + max_packet_count = test_ch->config_msg.num_packets / 2; + + pr_info(TEST_MODULE_NAME ":%s channel %s, total packets:%d," + " max packet size %d, max burst size:%d\n", + __func__, test_ch->name, + test_ch->config_msg.num_packets, test_ch->packet_length, + test_ch->max_burst_size); + for (i = 0 ; i < size / 2 ; i++) + buf16[i] = (u16) (i & 0xFFFF); + + for (i = 0; i < 2 ; i++) { + total_packet_count = 0; + while (total_packet_count < max_packet_count) { + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":%s exit test\n", + __func__); + return; + } + test_ch->buf[0] = total_packet_count; + random_num = get_random_int(); + curr_burst_size = (random_num % + test_ch->max_burst_size) + 1; + + /* limit burst size to send + * no more than configured packets */ + if (curr_burst_size + total_packet_count > + max_packet_count) { + curr_burst_size = max_packet_count - + total_packet_count; + } + TEST_DBG(TEST_MODULE_NAME ":%s Current burst size:%d" + " on chan %s\n", __func__, + curr_burst_size, test_ch->name); + ret = write_packet_burst(test_ch, curr_burst_size); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s write burst failed (%d), ch %s\n", + __func__, ret, test_ch->name); + goto exit_err; + } + if (i > 0) { + /* read from channel */ + if (test_ch->ch->is_packet_mode) + ret = read_data_from_packet_ch(test_ch, + size, + total_packet_count); + else + ret = read_data_from_stream_ch(test_ch, + size, + total_packet_count); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s read" + " failed:%d, chan %s\n", + __func__, ret, + test_ch->name); + goto exit_err; + } + } + TEST_DBG(TEST_MODULE_NAME ":%s before close, ch %s\n", + __func__, test_ch->name); + ret = close_sdio_ch(test_ch); + if (ret) { + pr_err(TEST_MODULE_NAME":%s close channel %s" + " failed (%d)\n", + __func__, test_ch->name, ret); + goto exit_err; + } else { + TEST_DBG(TEST_MODULE_NAME":%s close channel %s" + " success\n", __func__, + test_ch->name); + total_packet_count += curr_burst_size; + atomic_set(&test_ch->rx_notify_count, 0); + atomic_set(&test_ch->tx_notify_count, 0); + atomic_set(&test_ch->any_notify_count, 0); + } + TEST_DBG(TEST_MODULE_NAME ":%s before open, ch %s\n", + __func__, test_ch->name); + ret = open_sdio_ch(test_ch); + if (ret) { + pr_err(TEST_MODULE_NAME":%s open channel %s" + " failed (%d)\n", + __func__, test_ch->name, ret); + goto exit_err; + } else { + read_avail = sdio_read_avail(test_ch->ch); + if (read_avail > 0) { + pr_err(TEST_MODULE_NAME": after open" + " ch %s read_availis not zero" + " (%d bytes)\n", + test_ch->name, read_avail); + goto exit_err; + } + } + TEST_DBG(TEST_MODULE_NAME ":%s total tx = %d," + " packet# = %d, size = %d for ch %s\n", + __func__, test_ch->tx_bytes, + total_packet_count, size, + test_ch->name); + } /* end of while */ + } + pr_info(TEST_MODULE_NAME ":%s Test end: total rx bytes = 0x%x," + " total tx bytes = 0x%x for chan %s\n", __func__, + test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name); + pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__, + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_PASSED; + check_test_completion(); + return; +exit_err: + pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__, + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + +/** + * sender Test + */ +static void sender_test(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 read_avail = 0; + u32 write_avail = 0; + int packet_count = 0; + int size = 512; + u16 *buf16 = (u16 *) test_ch->buf; + int i; + int max_packet_count = 10000; + int random_num = 0; + + max_packet_count = test_ch->config_msg.num_packets; + + for (i = 0 ; i < size / 2 ; i++) + buf16[i] = (u16) (i & 0xFFFF); + + + pr_info(TEST_MODULE_NAME + ":SENDER TEST START for chan %s\n", test_ch->name); + + while (packet_count < max_packet_count) { + + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + + random_num = get_random_int(); + size = (random_num % test_ch->packet_length) + 1; + + TEST_DBG(TEST_MODULE_NAME "SENDER WAIT FOR EVENT for chan %s\n", + test_ch->name); + + /* wait for data ready event */ + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail); + if (write_avail < size) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->tx_notify_count)); + atomic_dec(&test_ch->tx_notify_count); + } + + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail); + if (write_avail < size) { + pr_info(TEST_MODULE_NAME ":not enough write avail.\n"); + continue; + } + + test_ch->buf[0] = packet_count; + + ret = sdio_write(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n", + -ret); + goto exit_err; + } + + /* wait for read data ready event */ + TEST_DBG(TEST_MODULE_NAME ":sender wait for rx data for " + "chan %s\n", + test_ch->name); + read_avail = sdio_read_avail(test_ch->ch); + wait_event(test_ch->wait_q, + atomic_read(&test_ch->rx_notify_count)); + atomic_dec(&test_ch->rx_notify_count); + + read_avail = sdio_read_avail(test_ch->ch); + + if (read_avail != size) { + pr_info(TEST_MODULE_NAME + ":read_avail size %d for chan %s not as " + "expected size %d.\n", + read_avail, test_ch->name, size); + goto exit_err; + } + + memset(test_ch->buf, 0x00, size); + + ret = sdio_read(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_info(TEST_MODULE_NAME ":sender sdio_read for chan %s" + " err=%d.\n", + test_ch->name, -ret); + goto exit_err; + } + + + if ((test_ch->buf[0] != packet_count) && (size != 1)) { + pr_info(TEST_MODULE_NAME ":sender sdio_read WRONG DATA" + " for chan %s, size=%d\n", + test_ch->name, size); + goto exit_err; + } + + test_ch->tx_bytes += size; + test_ch->rx_bytes += size; + packet_count++; + + TEST_DBG(TEST_MODULE_NAME + ":sender total rx bytes = 0x%x , packet#=%d, size=%d" + " for chan %s\n", + test_ch->rx_bytes, packet_count, size, test_ch->name); + TEST_DBG(TEST_MODULE_NAME + ":sender total tx bytes = 0x%x , packet#=%d, size=%d" + " for chan %s\n", + test_ch->tx_bytes, packet_count, size, test_ch->name); + + } /* end of while */ + + pr_info(TEST_MODULE_NAME + ":SENDER TEST END: total rx bytes = 0x%x, " + " total tx bytes = 0x%x for chan %s\n", + test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name); + + pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n", + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_PASSED; + check_test_completion(); + return; + +exit_err: + pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n", + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + +/** + * A2 Perf Test + */ +static void a2_performance_test(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 read_avail = 0; + u32 write_avail = 0; + int tx_packet_count = 0; + int rx_packet_count = 0; + int size = 0; + u16 *buf16 = (u16 *) test_ch->buf; + int i; + int total_bytes = 0; + int max_packets = 10000; + u32 packet_size = test_ch->buf_size; + int rand_size = 0; + + u64 start_jiffy, end_jiffy, delta_jiffies; + unsigned int time_msec = 0; + u32 throughput = 0; + + max_packets = test_ch->config_msg.num_packets; + packet_size = test_ch->packet_length; + + for (i = 0; i < packet_size / 2; i++) + buf16[i] = (u16) (i & 0xFFFF); + + pr_info(TEST_MODULE_NAME ": A2 PERFORMANCE TEST START for chan %s\n", + test_ch->name); + + start_jiffy = get_jiffies_64(); /* read the current time */ + + while (tx_packet_count < max_packets) { + + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + + if (test_ch->random_packet_size) { + rand_size = get_random_int(); + packet_size = (rand_size % test_ch->packet_length) + 1; + if (packet_size < A2_MIN_PACKET_SIZE) + packet_size = A2_MIN_PACKET_SIZE; + } + + /* wait for data ready event */ + /* use a func to avoid compiler optimizations */ + write_avail = sdio_write_avail(test_ch->ch); + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, " + "read_avail=%d for chan %s\n", + test_ch->name, write_avail, read_avail, + test_ch->name); + if ((write_avail == 0) && (read_avail == 0)) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->any_notify_count)); + atomic_set(&test_ch->any_notify_count, 0); + } + + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n", + test_ch->name, write_avail); + if (write_avail > 0) { + size = min(packet_size, write_avail) ; + TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n", + size, test_ch->name); + test_ch->buf[0] = tx_packet_count; + test_ch->buf[(size/4)-1] = tx_packet_count; + + ret = sdio_write(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_info(TEST_MODULE_NAME ":sdio_write err=%d" + " for chan %s\n", + -ret, test_ch->name); + goto exit_err; + } + tx_packet_count++; + test_ch->tx_bytes += size; + } + + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n", + test_ch->name, read_avail); + if (read_avail > 0) { + size = min(packet_size, read_avail); + pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size); + ret = sdio_read(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_info(TEST_MODULE_NAME ": sdio_read size %d " + " err=%d" + " for chan %s\n", + size, -ret, test_ch->name); + goto exit_err; + } + rx_packet_count++; + test_ch->rx_bytes += size; + } + + TEST_DBG(TEST_MODULE_NAME + ":total rx bytes = %d , rx_packet#=%d" + " for chan %s\n", + test_ch->rx_bytes, rx_packet_count, test_ch->name); + TEST_DBG(TEST_MODULE_NAME + ":total tx bytes = %d , tx_packet#=%d" + " for chan %s\n", + test_ch->tx_bytes, tx_packet_count, test_ch->name); + + } /* while (tx_packet_count < max_packets ) */ + + end_jiffy = get_jiffies_64(); /* read the current time */ + + delta_jiffies = end_jiffy - start_jiffy; + time_msec = jiffies_to_msecs(delta_jiffies); + + pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for" + " chan %s.\n", + test_ch->rx_bytes, rx_packet_count, test_ch->name); + pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d" + " for chan %s.\n", + test_ch->tx_bytes, tx_packet_count, test_ch->name); + + total_bytes = (test_ch->tx_bytes + test_ch->rx_bytes); + pr_err(TEST_MODULE_NAME ":total bytes = %d, time msec = %d" + " for chan %s\n", + total_bytes , (int) time_msec, test_ch->name); + + if (!test_ch->random_packet_size) { + if (time_msec) { + throughput = (total_bytes / time_msec) * 8 / 1000; + pr_err(TEST_MODULE_NAME ": %s - Performance = " + "%d Mbit/sec for chan %s\n", + __func__, throughput, test_ch->name); + } else { + pr_err(TEST_MODULE_NAME ": %s - time_msec = 0 Couldn't " + "calculate performence for chan %s\n", + __func__, test_ch->name); + } + + } + +#ifdef CONFIG_DEBUG_FS + switch (test_ch->ch_id) { + case SDIO_DUN: + test_ctx->debug.dun_throughput = throughput; + break; + case SDIO_RMNT: + test_ctx->debug.rmnt_throughput = throughput; + break; + default: + pr_err(TEST_MODULE_NAME "No debugfs for this channel " + "throughput"); + } +#endif + + pr_err(TEST_MODULE_NAME ": A2 PERFORMANCE TEST END for chan %s.\n", + test_ch->name); + + pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_PASSED; + check_test_completion(); + return; + +exit_err: + pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + +/** + * rx_cleanup + * This function reads all the messages sent by the modem until + * the read_avail is 0 after 1 second of sleep. + * The function returns the number of packets that was received. + */ +static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count) +{ + int read_avail = 0; + int ret = 0; + int counter = 0; + + if (!test_ch || !test_ch->ch) { + pr_err(TEST_MODULE_NAME ":%s NULL channel\n", + __func__); + return; + } + + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n", + test_ch->name, read_avail); + + /* If no pending messages, wait to see if the modem sends data */ + if (read_avail == 0) { + msleep(1000); + read_avail = sdio_read_avail(test_ch->ch); + } + + while ((read_avail > 0) && (counter < 10)) { + TEST_DBG(TEST_MODULE_NAME ": read_avail=%d for ch %s\n", + read_avail, test_ch->name); + + ret = sdio_read(test_ch->ch, test_ch->buf, read_avail); + if (ret) { + pr_info(TEST_MODULE_NAME ": sdio_read size %d " + " err=%d for chan %s\n", + read_avail, -ret, test_ch->name); + break; + } + (*rx_packet_count)++; + test_ch->rx_bytes += read_avail; + read_avail = sdio_read_avail(test_ch->ch); + if (read_avail == 0) { + msleep(1000); + counter++; + read_avail = sdio_read_avail(test_ch->ch); + } + } + pr_info(TEST_MODULE_NAME ": finished cleanup for ch %s, " + "rx_packet_count=%d, total rx bytes=%d\n", + test_ch->name, *rx_packet_count, test_ch->rx_bytes); +} + + +/** + * A2 RTT Test + * This function sends a packet and calculate the RTT time of + * this packet. + * The test also calculte Min, Max and Average RTT + */ +static void a2_rtt_test(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 read_avail = 0; + u32 write_avail = 0; + int tx_packet_count = 0; + int rx_packet_count = 0; + u16 *buf16 = NULL; + int i; + int max_packets = 0; + u32 packet_size = 0; + s64 start_time, end_time; + int delta_usec = 0; + int time_average = 0; + int min_delta_usec = 0xFFFF; + int max_delta_usec = 0; + int total_time = 0; + int expected_read_size = 0; + int delay_ms = 0; + int slow_rtt_counter = 0; + int read_avail_so_far = 0; + + if (test_ch) { + /* + * Cleanup the pending RX data (such as loopback of the + * config msg) + */ + rx_cleanup(test_ch, &rx_packet_count); + rx_packet_count = 0; + } else { + return; + } + + max_packets = test_ch->config_msg.num_packets; + packet_size = test_ch->packet_length; + buf16 = (u16 *) test_ch->buf; + + for (i = 0; i < packet_size / 2; i++) + buf16[i] = (u16) (i & 0xFFFF); + + pr_info(TEST_MODULE_NAME ": A2 RTT TEST START for chan %s\n", + test_ch->name); + + switch (test_ch->ch_id) { + case SDIO_RMNT: + delay_ms = 100; + break; + case SDIO_CSVT: + delay_ms = 0; + break; + default: + pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n", + __func__); + return; + } + + while (tx_packet_count < max_packets) { + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + start_time = 0; + end_time = 0; + read_avail_so_far = 0; + + if (delay_ms) + msleep(delay_ms); + + /* wait for data ready event */ + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":ch %s: write_avail=%d\n", + test_ch->name, write_avail); + if (write_avail == 0) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->tx_notify_count)); + atomic_dec(&test_ch->tx_notify_count); + } + + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n", + test_ch->name, write_avail); + if (write_avail > 0) { + TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n", + packet_size, test_ch->name); + test_ch->buf[0] = tx_packet_count; + + start_time = ktime_to_us(ktime_get()); + ret = sdio_write(test_ch->ch, test_ch->buf, + packet_size); + if (ret) { + pr_err(TEST_MODULE_NAME ":sdio_write err=%d" + " for chan %s\n", + -ret, test_ch->name); + goto exit_err; + } + tx_packet_count++; + test_ch->tx_bytes += packet_size; + } else { + pr_err(TEST_MODULE_NAME ": Invalid write_avail" + " %d for chan %s\n", + write_avail, test_ch->name); + goto exit_err; + } + + expected_read_size = packet_size + A2_HEADER_OVERHEAD; + + while (read_avail_so_far < expected_read_size) { + + read_avail = sdio_read_avail(test_ch->ch); + + if (!read_avail) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch-> + rx_notify_count)); + + atomic_dec(&test_ch->rx_notify_count); + continue; + } + + read_avail_so_far += read_avail; + + if (read_avail_so_far > expected_read_size) { + pr_err(TEST_MODULE_NAME ": %s - Invalid " + "read_avail(%d) read_avail_so_far(%d) " + "can't be larger than " + "expected_read_size(%d).", + __func__, + read_avail, + read_avail_so_far, + expected_read_size); + goto exit_err; + } + + /* + * must read entire pending bytes, so later, we will + * get a notification when more data arrives + */ + ret = sdio_read(test_ch->ch, test_ch->buf, + read_avail); + + if (ret) { + pr_info(TEST_MODULE_NAME ": sdio_read size %d " + " err=%d for chan %s\n", + read_avail, -ret, + test_ch->name); + goto exit_err; + } + } + + end_time = ktime_to_us(ktime_get()); + rx_packet_count++; + test_ch->rx_bytes += expected_read_size; + + delta_usec = (int)(end_time - start_time); + total_time += delta_usec; + if (delta_usec < min_delta_usec) + min_delta_usec = delta_usec; + if (delta_usec > max_delta_usec) + max_delta_usec = delta_usec; + + /* checking the RTT per channel criteria */ + if (delta_usec > MAX_AVG_RTT_TIME_USEC) { + pr_err(TEST_MODULE_NAME ": %s - " + "msg # %d - rtt time (%d usec) is " + "longer than %d usec\n", + __func__, + tx_packet_count, + delta_usec, + MAX_AVG_RTT_TIME_USEC); + slow_rtt_counter++; + } + + TEST_DBG(TEST_MODULE_NAME + ":RTT time=%d for packet #%d for chan %s\n", + delta_usec, tx_packet_count, test_ch->name); + } /* while (tx_packet_count < max_packets ) */ + + pr_info(TEST_MODULE_NAME ": %s - tx_packet_count = %d\n", + __func__, tx_packet_count); + + pr_info(TEST_MODULE_NAME ": %s - total rx bytes = 0x%x, " + "rx_packet# = %d for chan %s.\n", + __func__, test_ch->rx_bytes, rx_packet_count, test_ch->name); + + pr_info(TEST_MODULE_NAME ": %s - total tx bytes = 0x%x, " + "tx_packet# = %d for chan %s.\n", + __func__, test_ch->tx_bytes, tx_packet_count, test_ch->name); + + pr_info(TEST_MODULE_NAME ": %s - slow_rtt_counter = %d for " + "chan %s.\n", + __func__, slow_rtt_counter, test_ch->name); + + if (tx_packet_count) { + time_average = total_time / tx_packet_count; + pr_info(TEST_MODULE_NAME ":Average RTT time = %d for chan %s\n", + time_average, test_ch->name); + } else { + pr_err(TEST_MODULE_NAME ": %s - tx_packet_count=0. couldn't " + "calculate average rtt time", __func__); + } + + pr_info(TEST_MODULE_NAME ":MIN RTT time = %d for chan %s\n", + min_delta_usec, test_ch->name); + pr_info(TEST_MODULE_NAME ":MAX RTT time = %d for chan %s\n", + max_delta_usec, test_ch->name); + + pr_info(TEST_MODULE_NAME ": A2 RTT TEST END for chan %s.\n", + test_ch->name); + + if (ret) + goto exit_err; + + if (time_average == 0 || time_average > MAX_AVG_RTT_TIME_USEC) { + pr_err(TEST_MODULE_NAME ": %s - average_time = %d. Invalid " + "value", + __func__, time_average); + goto exit_err; + + } + + pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_PASSED; + check_test_completion(); + return; + +exit_err: + pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + +/** + * Process Rx Data - Helper for A2 Validation Test + * @test_ch(in/out) : Test channel that contains Rx data buffer to process. + * + * @rx_unprocessed_bytes(in) : Number of bytes to process in the buffer. + * + * @rx_process_packet_state(in/out) : + * Current processing state (used to identify what to process + * next in a partial packet) + * + * @rx_packet_size(in/out) : + * Number of bytes remaining in the packet to be processed. + * + * @rx_packet_count(in/out) : + * Number of packets processed. + */ +static int process_rx_data(struct test_channel *test_ch, + u32 rx_unprocessed_bytes, + int *rx_process_packet_state, + u16 *rx_packet_size, + int *rx_packet_count) +{ + u8 *buf = (u8 *)test_ch->buf; + int eop = 0; + int i = 0; + int ret = 0; + u32 *ptr = 0; + u16 size = 0; + + /* process rx data */ + while (rx_unprocessed_bytes) { + TEST_DBG(TEST_MODULE_NAME ": unprocessed bytes : %u\n", + rx_unprocessed_bytes); + + switch (*rx_process_packet_state) { + case RX_PROCESS_PACKET_INIT: + /* process the A2 header */ + TEST_DBG(TEST_MODULE_NAME ": " + "RX_PROCESS_PACKET_INIT\n"); + *rx_process_packet_state = RX_PROCESS_PACKET_INIT; + if (rx_unprocessed_bytes < 4) + break; + + i += 4; + rx_unprocessed_bytes -= 4; + + case RX_PROCESS_A2_HEADER: + /* process the rest of A2 header */ + TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_A2_HEADER\n"); + *rx_process_packet_state = RX_PROCESS_A2_HEADER; + if (rx_unprocessed_bytes < 4) + break; + + ptr = (u32 *)&buf[i]; + /* + * upper 2 bytes of the last 4 bytes of A2 header + * contains the size of the packet + */ + *rx_packet_size = *ptr >> 0x10; + + i += 4; + rx_unprocessed_bytes -= 4; + + case RX_PROCESS_PACKET_DATA: + /* process the2_2_ packet data */ + TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_PACKET_DATA " + "- packet size - %u\n", *rx_packet_size); + *rx_process_packet_state = RX_PROCESS_PACKET_DATA; + + size = *rx_packet_size; + if (*rx_packet_size <= rx_unprocessed_bytes) { + eop = *rx_packet_size; + *rx_packet_size = 0; + } else { + eop = rx_unprocessed_bytes; + *rx_packet_size = *rx_packet_size - + rx_unprocessed_bytes; + } + + /* no more bytes available to process */ + if (!eop) + break; + /* + * end of packet is starting from + * the current position + */ + eop = eop + i; + TEST_DBG(TEST_MODULE_NAME ": size - %u, " + "packet size - %u eop - %d\n", + size, *rx_packet_size, eop); + + /* validate the data */ + for (; i < eop; i++) { + if (buf[i] != (test_ch->rx_bytes % 256)) { + pr_err(TEST_MODULE_NAME ": " + "Corrupt data. buf:%u, " + "data:%u\n", buf[i], + test_ch->rx_bytes % 256); + ret = -EINVAL; + goto err; + } + rx_unprocessed_bytes--; + test_ch->rx_bytes++; + } + + /* have more data to be processed */ + if (*rx_packet_size) + break; + + /* + * A2 sends data in 4 byte alignment, + * skip the padding + */ + if (size % 4) { + i += 4 - (size % 4); + rx_unprocessed_bytes -= 4 - (size % 4); + } + *rx_packet_count = *rx_packet_count + 1; + + /* re init the state to process new packet */ + *rx_process_packet_state = RX_PROCESS_PACKET_INIT; + break; + default: + pr_err(TEST_MODULE_NAME ": Invalid case: %d\n", + *rx_process_packet_state); + ret = -EINVAL; + goto err; + } + TEST_DBG(TEST_MODULE_NAME ": Continue processing " + "if more data is available\n"); + } + +err: + return ret; +} + +/** + * A2 Validation Test + * Send packets and validate the returned packets. + * Transmit one packet at a time, while process multiple rx + * packets in a single transaction. + * A transaction is of size min(random number, write_avail). + * A packet consists of a min of 1 byte to channel supported max. + */ +static void a2_validation_test(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 read_avail = 0; + u32 write_avail = 0; + int tx_packet_count = 0; + int rx_packet_count = 0; + int initial_rx_packet_count = 0; + u32 size = 0; + u8 *buf8 = (u8 *)test_ch->buf; + int i = 0; + int max_packets = test_ch->config_msg.num_packets; + u16 tx_packet_size = 0; + u16 rx_packet_size = 0; + u32 random_num = 0; + int rx_process_packet_state = RX_PROCESS_PACKET_INIT; + + pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST START for chan %s\n", + test_ch->name); + + /* Wait for the initial rx messages before starting the test. */ + rx_cleanup(test_ch, &initial_rx_packet_count); + + test_ch->tx_bytes = 0; + test_ch->rx_bytes = 0; + + /* Continue till we have transmitted and received all packets */ + while ((tx_packet_count < max_packets) || + (rx_packet_count < max_packets)) { + + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + + random_num = get_random_int(); + size = (random_num % test_ch->packet_length) + 1; + TEST_DBG(TEST_MODULE_NAME ": Random tx packet size =%u", size); + + /* + * wait for data ready event + * use a func to avoid compiler optimizations + */ + write_avail = sdio_write_avail(test_ch->ch); + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ": write_avail=%d, " + "read_avail=%d for chan %s\n", + write_avail, read_avail, test_ch->name); + + if ((write_avail == 0) && (read_avail == 0)) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->any_notify_count)); + atomic_set(&test_ch->any_notify_count, 0); + } + + /* Transmit data */ + write_avail = sdio_write_avail(test_ch->ch); + if ((tx_packet_count < max_packets) && (write_avail > 0)) { + tx_packet_size = min(size, write_avail) ; + TEST_DBG(TEST_MODULE_NAME ": tx size = %u, " + "write_avail = %u tx_packet# = %d\n", + tx_packet_size, write_avail, + tx_packet_count); + memset(test_ch->buf, 0, test_ch->buf_size); + /* populate the buffer */ + for (i = 0; i < tx_packet_size; i++) { + buf8[i] = test_ch->tx_bytes % 256; + test_ch->tx_bytes++; + } + + ret = sdio_write(test_ch->ch, test_ch->buf, + tx_packet_size); + if (ret) { + pr_err(TEST_MODULE_NAME ":sdio_write err=%d" + " for chan %s\n", + -ret, test_ch->name); + goto exit_err; + } + tx_packet_count++; + } + + /* Receive data */ + read_avail = sdio_read_avail(test_ch->ch); + if (read_avail > 0) { + TEST_DBG(TEST_MODULE_NAME ": rx size = %u, " + "rx_packet#=%d.\n", + read_avail, rx_packet_count); + memset(test_ch->buf, 0, test_ch->buf_size); + + ret = sdio_read(test_ch->ch, test_ch->buf, + read_avail); + if (ret) { + pr_err(TEST_MODULE_NAME ": sdio_read " + "size %d err=%d for chan %s\n", + size, -ret, test_ch->name); + goto exit_err; + } + + /* Process data */ + ret = process_rx_data(test_ch, read_avail, + &rx_process_packet_state, + &rx_packet_size, + &rx_packet_count); + + if (ret != 0) + goto exit_err; + } + TEST_DBG(TEST_MODULE_NAME ": Continue loop ...\n"); + } + + if (test_ch->tx_bytes != test_ch->rx_bytes) { + pr_err(TEST_MODULE_NAME ": Total number of bytes " + "transmitted (%u) does not match the total " + "number of bytes received (%u).", test_ch->tx_bytes, + test_ch->rx_bytes); + goto exit_err; + } + + pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST END for chan %s.\n", + test_ch->name); + + pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_PASSED; + check_test_completion(); + return; + +exit_err: + pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + +/** + * sender No loopback Test + */ +static void sender_no_loopback_test(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 write_avail = 0; + int packet_count = 0; + int size = 512; + u16 *buf16 = (u16 *) test_ch->buf; + int i; + int max_packet_count = 10000; + unsigned int random_num = 0; + + max_packet_count = test_ch->config_msg.num_packets; + + for (i = 0 ; i < size / 2 ; i++) + buf16[i] = (u16) (i & 0xFFFF); + + pr_info(TEST_MODULE_NAME + ":SENDER NO LP TEST START for chan %s\n", test_ch->name); + + while (packet_count < max_packet_count) { + + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + + random_num = get_random_int(); + size = (random_num % test_ch->packet_length) + 1; + + TEST_DBG(TEST_MODULE_NAME ":SENDER WAIT FOR EVENT " + "for chan %s\n", + test_ch->name); + + /* wait for data ready event */ + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail); + if (write_avail < size) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->tx_notify_count)); + atomic_dec(&test_ch->tx_notify_count); + } + + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail); + if (write_avail < size) { + pr_info(TEST_MODULE_NAME ":not enough write avail.\n"); + continue; + } + + test_ch->buf[0] = packet_count; + + ret = sdio_write(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n", + -ret); + goto exit_err; + } + + test_ch->tx_bytes += size; + packet_count++; + + TEST_DBG(TEST_MODULE_NAME + ":sender total tx bytes = 0x%x , packet#=%d, size=%d" + " for chan %s\n", + test_ch->tx_bytes, packet_count, size, test_ch->name); + + } /* end of while */ + + pr_info(TEST_MODULE_NAME + ":SENDER TEST END: total tx bytes = 0x%x, " + " for chan %s\n", + test_ch->tx_bytes, test_ch->name); + + test_ch->modem_result_per_chan = wait_for_result_msg(test_ch); + + if (test_ch->modem_result_per_chan) { + pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n", + test_ch->name); + test_ch->test_result = TEST_PASSED; + } else { + pr_info(TEST_MODULE_NAME ": TEST FAILURE for chan %s.\n", + test_ch->name); + test_ch->test_result = TEST_FAILED; + } + test_ch->test_completed = 1; + check_test_completion(); + return; + +exit_err: + pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n", + test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + + +/** + * Modem reset Test + * The test verifies that it finished sending all the packets + * while there might be modem reset in the middle + */ +static void modem_reset_test(struct test_channel *test_ch) +{ + int ret = 0 ; + u32 read_avail = 0; + u32 write_avail = 0; + int tx_packet_count = 0; + int rx_packet_count = 0; + int size = 0; + u16 *buf16 = (u16 *) test_ch->buf; + int i; + int max_packets = 10000; + u32 packet_size = test_ch->buf_size; + int is_err = 0; + + max_packets = test_ch->config_msg.num_packets; + packet_size = test_ch->packet_length; + + for (i = 0; i < packet_size / 2; i++) + buf16[i] = (u16) (i & 0xFFFF); + + pr_info(TEST_MODULE_NAME ": Modem Reset TEST START for chan %s\n", + test_ch->name); + + while (tx_packet_count < max_packets) { + + if (test_ctx->exit_flag) { + pr_info(TEST_MODULE_NAME ":Exit Test.\n"); + return; + } + + if (test_ch->card_removed) { + pr_info(TEST_MODULE_NAME ": card removal was detected " + "for chan %s, tx_total=0x%x\n", + test_ch->name, test_ch->tx_bytes); + wait_event(test_ch->wait_q, + atomic_read(&test_ch->card_detected_event)); + atomic_set(&test_ch->card_detected_event, 0); + pr_info(TEST_MODULE_NAME ": card_detected_event " + "for chan %s\n", test_ch->name); + if (test_ch->card_removed) + continue; + is_err = 0; + /* Need to wait for the modem to be ready */ + msleep(5000); + pr_info(TEST_MODULE_NAME ": sending the config message " + "for chan %s\n", test_ch->name); + send_config_msg(test_ch); + } + + /* wait for data ready event */ + /* use a func to avoid compiler optimizations */ + write_avail = sdio_write_avail(test_ch->ch); + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, " + "read_avail=%d for chan %s\n", + test_ch->name, write_avail, read_avail, + test_ch->name); + if ((write_avail == 0) && (read_avail == 0)) { + wait_event(test_ch->wait_q, + atomic_read(&test_ch->any_notify_count)); + atomic_set(&test_ch->any_notify_count, 0); + } + if (atomic_read(&test_ch->card_detected_event)) { + atomic_set(&test_ch->card_detected_event, 0); + pr_info(TEST_MODULE_NAME ": card_detected_event " + "for chan %s, tx_total=0x%x\n", + test_ch->name, test_ch->tx_bytes); + if (test_ch->card_removed) + continue; + /* Need to wait for the modem to be ready */ + msleep(5000); + is_err = 0; + pr_info(TEST_MODULE_NAME ": sending the config message " + "for chan %s\n", test_ch->name); + send_config_msg(test_ch); + } + + write_avail = sdio_write_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n", + test_ch->name, write_avail); + if (write_avail > 0) { + size = min(packet_size, write_avail) ; + pr_debug(TEST_MODULE_NAME ":tx size = %d for chan %s\n", + size, test_ch->name); + test_ch->buf[0] = tx_packet_count; + test_ch->buf[(size/4)-1] = tx_packet_count; + + TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_write, " + "size=%d\n", test_ch->name, size); + if (is_err) { + msleep(100); + continue; + } + ret = sdio_write(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_info(TEST_MODULE_NAME ":sdio_write err=%d" + " for chan %s\n", + -ret, test_ch->name); + is_err = 1; + msleep(20); + continue; + } + tx_packet_count++; + test_ch->tx_bytes += size; + test_ch->config_msg.num_packets--; + } + + read_avail = sdio_read_avail(test_ch->ch); + TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n", + test_ch->name, read_avail); + if (read_avail > 0) { + size = min(packet_size, read_avail); + pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size); + TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_read, " + "size=%d\n", test_ch->name, size); + if (is_err) { + msleep(100); + continue; + } + ret = sdio_read(test_ch->ch, test_ch->buf, size); + if (ret) { + pr_info(TEST_MODULE_NAME ": sdio_read size %d " + " err=%d" + " for chan %s\n", + size, -ret, test_ch->name); + is_err = 1; + msleep(20); + continue; + } + rx_packet_count++; + test_ch->rx_bytes += size; + } + + TEST_DBG(TEST_MODULE_NAME + ":total rx bytes = %d , rx_packet#=%d" + " for chan %s\n", + test_ch->rx_bytes, rx_packet_count, test_ch->name); + TEST_DBG(TEST_MODULE_NAME + ":total tx bytes = %d , tx_packet#=%d" + " for chan %s\n", + test_ch->tx_bytes, tx_packet_count, test_ch->name); + + udelay(500); + + } /* while (tx_packet_count < max_packets ) */ + + pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for" + " chan %s.\n", + test_ch->rx_bytes, rx_packet_count, test_ch->name); + pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d" + " for chan %s.\n", + test_ch->tx_bytes, tx_packet_count, test_ch->name); + + pr_err(TEST_MODULE_NAME ": Modem Reset TEST END for chan %s.\n", + test_ch->name); + + pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name); + test_ch->test_completed = 1; + test_ch->test_result = TEST_PASSED; + check_test_completion(); + return; +} + +/** + * Worker thread to handle the tests types + */ +static void worker(struct work_struct *work) +{ + struct test_channel *test_ch = NULL; + struct test_work *test_work = container_of(work, + struct test_work, + work); + int test_type = 0; + + test_ch = test_work->test_ch; + + if (test_ch == NULL) { + pr_err(TEST_MODULE_NAME ":NULL test_ch\n"); + return; + } + + test_type = test_ch->test_type; + + switch (test_type) { + case SDIO_TEST_LOOPBACK_HOST: + loopback_test(test_ch); + break; + case SDIO_TEST_LOOPBACK_CLIENT: + sender_test(test_ch); + break; + case SDIO_TEST_PERF: + a2_performance_test(test_ch); + break; + case SDIO_TEST_LPM_CLIENT_WAKER: + lpm_test(test_ch); + break; + case SDIO_TEST_LPM_HOST_WAKER: + lpm_test_host_waker(test_ch); + break; + case SDIO_TEST_HOST_SENDER_NO_LP: + sender_no_loopback_test(test_ch); + break; + case SDIO_TEST_LPM_RANDOM: + lpm_continuous_rand_test(test_ch); + break; + case SDIO_TEST_RTT: + a2_rtt_test(test_ch); + break; + case SDIO_TEST_CLOSE_CHANNEL: + if (test_ch->ch_id != SDIO_SMEM) + open_close_test(test_ch); + break; + case SDIO_TEST_MODEM_RESET: + modem_reset_test(test_ch); + break; + case SDIO_TEST_A2_VALIDATION: + a2_validation_test(test_ch); + break; + default: + pr_err(TEST_MODULE_NAME ":Bad Test type = %d.\n", + (int) test_type); + } +} + + +/** + * Notification Callback + * + * Notify the worker + * + */ +static void notify(void *priv, unsigned channel_event) +{ + struct test_channel *test_ch = (struct test_channel *) priv; + + pr_debug(TEST_MODULE_NAME ": %s - notify event=%d.\n", + __func__, channel_event); + + if (test_ch->ch == NULL) { + pr_info(TEST_MODULE_NAME ": %s - notify before ch ready.\n", + __func__); + return; + } + + switch (channel_event) { + case SDIO_EVENT_DATA_READ_AVAIL: + atomic_inc(&test_ch->rx_notify_count); + atomic_set(&test_ch->any_notify_count, 1); + TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_READ_AVAIL, " + "any_notify_count=%d, rx_notify_count=%d\n", + __func__, + atomic_read(&test_ch->any_notify_count), + atomic_read(&test_ch->rx_notify_count)); + /* + * when there is pending data on a channel we would like to + * turn on the bit mask that implies that there is pending + * data for that channel on that deivce + */ + if (test_ch->test_device != NULL && + test_ch->test_type == SDIO_TEST_LPM_RANDOM) { + spin_lock_irqsave(&test_ch->test_device->lpm_array_lock, + test_ch->test_device-> + lpm_array_lock_flags); + test_ch->test_device->read_avail_mask |= + test_ch->channel_mask_id; + test_ch->notify_counter_per_chan++; + + lpm_test_update_entry(test_ch, LPM_NOTIFY, "NOTIFY", 0); + spin_unlock_irqrestore(&test_ch->test_device-> + lpm_array_lock, + test_ch->test_device-> + lpm_array_lock_flags); + } + break; + + case SDIO_EVENT_DATA_WRITE_AVAIL: + atomic_inc(&test_ch->tx_notify_count); + atomic_set(&test_ch->any_notify_count, 1); + TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_WRITE_AVAIL, " + "any_notify_count=%d, tx_notify_count=%d\n", + __func__, + atomic_read(&test_ch->any_notify_count), + atomic_read(&test_ch->tx_notify_count)); + break; + + default: + BUG(); + } + wake_up(&test_ch->wait_q); + +} + +#ifdef CONFIG_MSM_SDIO_SMEM +static int sdio_smem_test_cb(int event) +{ + struct test_channel *tch = test_ctx->test_ch_arr[SDIO_SMEM]; + int i; + int *smem_buf = (int *)test_ctx->smem_buf; + uint32_t val = 0; + int ret = 0; + + pr_debug(TEST_MODULE_NAME ":%s: Received event %d\n", __func__, event); + + if (!tch) { + pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__); + return -EINVAL; + } + + switch (event) { + case SDIO_SMEM_EVENT_READ_DONE: + tch->rx_bytes += SMEM_MAX_XFER_SIZE; + for (i = 0; i < SMEM_MAX_XFER_SIZE;) { + val = (int)*smem_buf; + if ((val != test_ctx->smem_counter) && tch->is_used) { + pr_err(TEST_MODULE_NAME ":%s: Invalid value %d " + "expected %d in smem arr", + __func__, val, test_ctx->smem_counter); + pr_err(TEST_MODULE_NAME ":SMEM test FAILED\n"); + tch->test_completed = 1; + tch->test_result = TEST_FAILED; + check_test_completion(); + ret = -EINVAL; + goto exit; + } + i += 4; + smem_buf++; + test_ctx->smem_counter++; + } + if (tch->rx_bytes >= 40000000) { + if ((!tch->test_completed) && tch->is_used) { + pr_info(TEST_MODULE_NAME ":SMEM test PASSED\n"); + tch->test_completed = 1; + tch->test_result = TEST_PASSED; + check_test_completion(); + } + } + break; + case SDIO_SMEM_EVENT_READ_ERR: + if (tch->is_used) { + pr_err(TEST_MODULE_NAME ":Read overflow, " + "SMEM test FAILED\n"); + tch->test_completed = 1; + tch->test_result = TEST_FAILED; + ret = -EIO; + } + break; + default: + if (tch->is_used) { + pr_err(TEST_MODULE_NAME ":Unhandled event %d\n", event); + ret = -EINVAL; + } + break; + } +exit: + return ret; +} + +static int sdio_smem_open(struct sdio_smem_client *sdio_smem) +{ + int ret = 0; + + if (!sdio_smem) { + pr_info(TEST_MODULE_NAME "%s: NULL sdio_smem_client\n", + __func__); + return -EINVAL; + } + + if (test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready) { + pr_info(TEST_MODULE_NAME "%s: SDIO_SMEM channel is already opened\n", + __func__); + return 0; + } + + test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready = 1; + sdio_smem->buf = test_ctx->smem_buf; + sdio_smem->size = SMEM_MAX_XFER_SIZE; + sdio_smem->cb_func = sdio_smem_test_cb; + ret = sdio_smem_register_client(); + if (ret) + pr_info(TEST_MODULE_NAME "%s: Error (%d) registering sdio_smem " + "test client\n", + __func__, ret); + + return ret; +} + +static int sdio_smem_test_probe(struct platform_device *pdev) +{ + test_ctx->sdio_smem = container_of(pdev, struct sdio_smem_client, + plat_dev); + + return sdio_smem_open(test_ctx->sdio_smem); +} + +static struct platform_driver sdio_smem_client_drv = { + .probe = sdio_smem_test_probe, + .driver = { + .name = "SDIO_SMEM_CLIENT", + .owner = THIS_MODULE, + }, +}; +#endif + +static void sdio_test_lpm_timeout_handler(unsigned long data) +{ + struct test_channel *tch = (struct test_channel *)data; + + pr_info(TEST_MODULE_NAME ": %s - LPM TEST TIMEOUT Expired after " + "%d ms\n", __func__, tch->timeout_ms); + tch->test_completed = 1; + pr_info(TEST_MODULE_NAME ": %s - tch->test_result = TEST_FAILED\n", + __func__); + tch->test_completed = 1; + tch->test_result = TEST_FAILED; + check_test_completion(); + return; +} + +static void sdio_test_lpm_timer_handler(unsigned long data) +{ + struct test_channel *tch = (struct test_channel *)data; + + pr_info(TEST_MODULE_NAME ": %s - LPM TEST Timer Expired after " + "%d ms\n", __func__, tch->timer_interval_ms); + + if (!tch) { + pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. " + "tch is NULL\n", __func__); + return; + } + + if (!tch->ch) { + pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. tch->ch " + "is NULL\n", __func__); + tch->test_result = TEST_FAILED; + return; + } + + /* Verfiy that we voted for sleep */ + if (tch->is_ok_to_sleep) { + tch->test_result = TEST_PASSED; + pr_info(TEST_MODULE_NAME ": %s - 8K voted for sleep\n", + __func__); + } else { + tch->test_result = TEST_FAILED; + pr_info(TEST_MODULE_NAME ": %s - 8K voted against sleep\n", + __func__); + + } + + sdio_al_unregister_lpm_cb(tch->sdio_al_device); + + if (tch->test_type == SDIO_TEST_LPM_HOST_WAKER) { + atomic_set(&tch->wakeup_client, 1); + wake_up(&tch->wait_q); + } +} + +int sdio_test_wakeup_callback(void *device_handle, int is_vote_for_sleep) +{ + int i = 0; + + TEST_DBG(TEST_MODULE_NAME ": %s is_vote_for_sleep=%d!!!", + __func__, is_vote_for_sleep); + + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + + if ((!tch) || (!tch->is_used) || (!tch->ch_ready)) + continue; + if (tch->sdio_al_device == device_handle) { + tch->is_ok_to_sleep = is_vote_for_sleep; + + if (tch->test_type == SDIO_TEST_LPM_RANDOM) { + spin_lock_irqsave(&tch->test_device-> + lpm_array_lock, + tch->test_device-> + lpm_array_lock_flags); + if (is_vote_for_sleep == 1) + lpm_test_update_entry(tch, + LPM_SLEEP, + "SLEEP ", 0); + else + lpm_test_update_entry(tch, + LPM_WAKEUP, + "WAKEUP", 0); + + spin_unlock_irqrestore(&tch->test_device-> + lpm_array_lock, + tch->test_device-> + lpm_array_lock_flags); + break; + } + } + } + + return 0; +} + +static int sdio_test_find_dev(struct test_channel *tch) +{ + int j; + int null_index = -1; + + for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES; ++j) { + + struct sdio_test_device *test_dev = + &test_ctx->test_dev_arr[j]; + + if (test_dev->sdio_al_device == NULL) { + if (null_index == -1) + null_index = j; + continue; + } + + if (test_dev->sdio_al_device == + tch->ch->sdio_al_dev) { + test_dev->open_channels_counter_to_recv++; + test_dev->open_channels_counter_to_send++; + tch->test_device = test_dev; + /* setting mask id for pending data for + this channel */ + tch->channel_mask_id = test_dev->next_mask_id; + test_dev->next_mask_id *= 2; + pr_info(TEST_MODULE_NAME ": %s - channel %s " + "got read_mask_id = 0x%x. device " + "next_mask_id=0x%x", + __func__, tch->name, tch->channel_mask_id, + test_dev->next_mask_id); + break; + } + } + + /* + * happens ones a new device is "discovered" while testing. i.e + * if testing a few channels, a new deivce will be "discovered" once + * the first channel of a device is being tested + */ + if (j == MAX_NUM_OF_SDIO_DEVICES) { + + struct sdio_test_device *test_dev = + &test_ctx-> + test_dev_arr[null_index]; + test_dev->sdio_al_device = + tch->ch->sdio_al_dev; + + test_ctx->number_of_active_devices++; + test_ctx->max_number_of_devices++; + test_dev->open_channels_counter_to_recv++; + test_dev->open_channels_counter_to_send++; + test_dev->next_avail_entry_in_array = 0; + tch->test_device = test_dev; + tch->test_device->array_size = + LPM_ARRAY_SIZE; + test_dev->modem_result_per_dev = 1; + tch->modem_result_per_chan = 0; + test_dev->next_avail_entry_in_array = 0; + + spin_lock_init(&test_dev-> + lpm_array_lock); + + if (tch->test_type == SDIO_TEST_LPM_RANDOM) { + pr_err(MODULE_NAME ": %s - " + "Allocating Msg Array for " + "Maximum open channels for device (%d) " + "Channels. Array has %d entries", + __func__, + LPM_MAX_OPEN_CHAN_PER_DEV, + test_dev->array_size); + + test_dev->lpm_arr = + kzalloc(sizeof( + struct lpm_entry_type) * + tch-> + test_device->array_size, + GFP_KERNEL); + + if (!test_dev->lpm_arr) { + pr_err(MODULE_NAME ": %s - " + "lpm_arr is NULL", + __func__); + return -ENOMEM; + } + } + + /* + * in new device, initialize next_mask_id, and setting + * mask_id to the channel + */ + test_dev->next_mask_id = 0x1; + tch->channel_mask_id = test_dev->next_mask_id; + test_dev->next_mask_id *= 2; + pr_info(TEST_MODULE_NAME ": %s - channel %s got " + "read_mask_id = 0x%x. device next_mask_id=0x%x", + __func__, + tch->name, + tch->channel_mask_id, + test_dev->next_mask_id); + } + + return 0; +} + +static void check_test_result(void) +{ + int result = 1; + int i = 0; + + test_ctx->max_number_of_devices = 0; + + pr_info(TEST_MODULE_NAME ": %s - Woke Up\n", __func__); + + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + + if ((!tch) || (!tch->is_used) || (!tch->ch_ready)) + continue; + + if (tch->test_type == SDIO_TEST_LPM_RANDOM) + result &= tch->test_device->final_result_per_dev; + else + if (tch->test_result == TEST_FAILED) { + pr_info(TEST_MODULE_NAME ": %s - " + "Test FAILED\n", __func__); + test_ctx->test_result = TEST_FAILED; + pr_err(TEST_MODULE_NAME ": %s - " + "test_result %d", + __func__, test_ctx->test_result); + return; + } + } + + if (result == 0) { + pr_info(TEST_MODULE_NAME ": %s - Test FAILED\n", __func__); + test_ctx->test_result = TEST_FAILED; + pr_err(TEST_MODULE_NAME ": %s - " + "test_result %d", + __func__, test_ctx->test_result); + return; + } + + pr_info(TEST_MODULE_NAME ": %s - Test PASSED", __func__); + test_ctx->test_result = TEST_PASSED; + pr_err(TEST_MODULE_NAME ": %s - " + "test_result %d", + __func__, test_ctx->test_result); + return; +} + +/** + * Test Main + */ +static int test_start(void) +{ + int ret = -ENOMEM; + int i; + + pr_debug(TEST_MODULE_NAME ":Starting Test ....\n"); + + test_ctx->test_completed = 0; + test_ctx->test_result = TEST_NO_RESULT; + test_ctx->debug.dun_throughput = 0; + test_ctx->debug.rmnt_throughput = 0; + test_ctx->number_of_active_devices = 0; + + pr_err(TEST_MODULE_NAME ": %s - test_result %d", + __func__, test_ctx->test_result); + + memset(test_ctx->test_dev_arr, 0, + sizeof(struct sdio_test_device)*MAX_NUM_OF_SDIO_DEVICES); + + /* Open The Channels */ + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + + if ((!tch) || (!tch->is_used)) + continue; + + tch->rx_bytes = 0; + tch->tx_bytes = 0; + + atomic_set(&tch->tx_notify_count, 0); + atomic_set(&tch->rx_notify_count, 0); + atomic_set(&tch->any_notify_count, 0); + atomic_set(&tch->wakeup_client, 0); + + /* in case there are values left from previous tests */ + tch->notify_counter_per_chan = 0; + tch->next_index_in_sent_msg_per_chan = 0; + + memset(tch->buf, 0x00, tch->buf_size); + tch->test_result = TEST_NO_RESULT; + + tch->test_completed = 0; + + ret = open_sdio_ch(tch); + if (ret) + continue; + + if (tch->ch_id != SDIO_SMEM) { + ret = sdio_test_find_dev(tch); + + if (ret) { + pr_err(TEST_MODULE_NAME ": %s - " + "sdio_test_find_dev() returned with " + "error", __func__); + return -ENODEV; + } + + tch->sdio_al_device = tch->ch->sdio_al_dev; + } + + if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) || + (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) || + (tch->test_type == SDIO_TEST_LPM_RANDOM)) + sdio_al_register_lpm_cb(tch->sdio_al_device, + sdio_test_wakeup_callback); + } + + /* + * make some space between opening the channels and sending the + * config messages + */ + msleep(100); + + /* + * try to delay send_config_msg of all channels to after the point + * when we open them all + */ + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + + if ((!tch) || (!tch->is_used)) + continue; + + if ((tch->ch_ready) && (tch->ch_id != SDIO_SMEM)) + send_config_msg(tch); + + if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) || + (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) || + (tch->test_type == SDIO_TEST_LPM_RANDOM)) { + if (tch->timer_interval_ms > 0) { + pr_info(TEST_MODULE_NAME ": %s - init timer, " + "ms=%d\n", + __func__, tch->timer_interval_ms); + init_timer(&tch->timer); + tch->timer.data = (unsigned long)tch; + tch->timer.function = + sdio_test_lpm_timer_handler; + tch->timer.expires = jiffies + + msecs_to_jiffies(tch->timer_interval_ms); + add_timer(&tch->timer); + } + } + } + + pr_debug(TEST_MODULE_NAME ":queue_work..\n"); + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + + if ((!tch) || (!tch->is_used) || (!tch->ch_ready)) + continue; + + if (tch->ch_id == SDIO_SMEM) { +#ifdef CONFIG_MSM_SDIO_SMEM + if (tch->test_type == SDIO_TEST_CLOSE_CHANNEL) + open_close_smem_test(tch); +#endif + } else { + queue_work(tch->workqueue, &tch->test_work.work); + } + + } + + pr_info(TEST_MODULE_NAME ": %s - Waiting for the test completion\n", + __func__); + + wait_event(test_ctx->wait_q, test_ctx->test_completed); + check_test_result(); + + /* + * Close the channels and zero the is_used flag so that if the modem + * will be reset after the test completion we won't re-open + * the channels + */ + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + + if ((!tch) || (!tch->is_used)) + continue; + if (!tch->ch_ready) { + tch->is_used = 0; + continue; + } + + close_sdio_ch(tch); + tch->is_used = 0; + } + + if (test_ctx->test_result == TEST_PASSED) + return 0; + else + return -EINVAL; +} + +static int set_params_loopback_9k(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_LOOPBACK_CLIENT; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT; + tch->config_msg.num_packets = 10000; + tch->config_msg.num_iterations = 1; + + tch->packet_length = 512; + if (tch->ch_id == SDIO_RPC) + tch->packet_length = 128; + tch->timer_interval_ms = 0; + + return 0; +} +static int set_params_loopback_9k_close(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_CLOSE_CHANNEL; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT; + tch->config_msg.num_packets = 5000; + tch->config_msg.num_iterations = 1; + tch->max_burst_size = 10; + switch (tch->ch_id) { + case SDIO_DUN: + case SDIO_RPC: + tch->packet_length = 128; /* max is 2K*/ + break; + case SDIO_DIAG: + case SDIO_RMNT: + default: + tch->packet_length = 512; /* max is 4k */ + } + tch->timer_interval_ms = 0; + return 0; +} +static int set_params_a2_perf(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_PERF; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT; + + switch (tch->ch_id) { + case SDIO_DIAG: + tch->packet_length = 512; + break; + case SDIO_DUN: + tch->packet_length = DUN_PACKET_SIZE; + break; + case SDIO_CSVT: + tch->packet_length = CSVT_PACKET_SIZE; + break; + default: + tch->packet_length = MAX_XFER_SIZE; + break; + } + + pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__, + tch->packet_length); + + tch->config_msg.num_packets = 10000; + tch->config_msg.num_iterations = 1; + tch->random_packet_size = 0; + + tch->timer_interval_ms = 0; + + return 0; +} + +static int set_params_rtt(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_RTT; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT; + + switch (tch->ch_id) { + case SDIO_RMNT: + tch->packet_length = SDIO_RMNT_RTT_PACKET_SIZE; + break; + case SDIO_CSVT: + tch->packet_length = SDIO_CSVT_RTT_PACKET_SIZE; + break; + default: + pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n", __func__); + return -EINVAL; + } + + pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__, + tch->packet_length); + + tch->config_msg.num_packets = 200; + tch->config_msg.num_iterations = 1; + tch->random_packet_size = 0; + + tch->timer_interval_ms = 0; + + return 0; +} + +static int set_params_a2_small_pkts(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_PERF; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT; + tch->packet_length = 128; + + tch->config_msg.num_packets = 1000000; + tch->config_msg.num_iterations = 1; + tch->random_packet_size = 1; + + tch->timer_interval_ms = 0; + + return 0; +} + +static int set_params_modem_reset(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_MODEM_RESET; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT; + tch->packet_length = 512; + if (tch->ch_id == SDIO_RPC) + tch->packet_length = 128; + else if ((tch->ch_id == SDIO_RMNT) || (tch->ch_id == SDIO_DUN)) + tch->packet_length = MAX_XFER_SIZE; + + tch->config_msg.num_packets = 50000; + tch->config_msg.num_iterations = 1; + + tch->timer_interval_ms = 0; + + return 0; +} + +static int set_params_a2_validation(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_A2_VALIDATION; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT; + + if (tch->ch_id == SDIO_RMNT) + tch->packet_length = RMNT_PACKET_SIZE; + else if (tch->ch_id == SDIO_DUN) + tch->packet_length = DUN_PACKET_SIZE; + else + tch->packet_length = MAX_XFER_SIZE; + + tch->config_msg.num_packets = 10000; + tch->config_msg.num_iterations = 1; + tch->timer_interval_ms = 0; + + return 0; +} + +static int set_params_smem_test(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->timer_interval_ms = 0; + + return 0; +} + +static int set_params_lpm_test(struct test_channel *tch, + enum sdio_test_case_type test, + int timer_interval_ms) +{ + static int first_time = 1; + if (!tch) { + pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__); + return -EINVAL; + } + + tch->is_used = 1; + tch->test_type = test; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = test; + tch->config_msg.num_packets = LPM_TEST_NUM_OF_PACKETS; + tch->config_msg.num_iterations = 1; + tch->timer_interval_ms = timer_interval_ms; + tch->timeout_ms = 10000; + + tch->packet_length = 0; + if (test != SDIO_TEST_LPM_RANDOM) { + init_timer(&tch->timeout_timer); + tch->timeout_timer.data = (unsigned long)tch; + tch->timeout_timer.function = sdio_test_lpm_timeout_handler; + tch->timeout_timer.expires = jiffies + + msecs_to_jiffies(tch->timeout_ms); + add_timer(&tch->timeout_timer); + pr_info(TEST_MODULE_NAME ": %s - Initiated LPM TIMEOUT TIMER." + "set to %d ms\n", + __func__, tch->timeout_ms); + } + + if (first_time) { + pr_info(TEST_MODULE_NAME ": %s - wake_lock_init() called\n", + __func__); + wake_lock_init(&test_ctx->wake_lock, + WAKE_LOCK_SUSPEND, TEST_MODULE_NAME); + first_time = 0; + } + + pr_info(TEST_MODULE_NAME ": %s - wake_lock() for the TEST is " + "called channel %s. to prevent real sleeping\n", + __func__, tch->name); + wake_lock(&test_ctx->wake_lock); + + return 0; +} + +static int set_params_8k_sender_no_lp(struct test_channel *tch) +{ + if (!tch) { + pr_err(TEST_MODULE_NAME ":NULL channel\n"); + return -EINVAL; + } + tch->is_used = 1; + tch->test_type = SDIO_TEST_HOST_SENDER_NO_LP; + tch->config_msg.signature = TEST_CONFIG_SIGNATURE; + tch->config_msg.test_case = SDIO_TEST_HOST_SENDER_NO_LP; + tch->config_msg.num_packets = 1000; + tch->config_msg.num_iterations = 1; + + tch->packet_length = 512; + if (tch->ch_id == SDIO_RPC) + tch->packet_length = 128; + tch->timer_interval_ms = 0; + + return 0; +} + +static void set_pseudo_random_seed(void) +{ + /* Set the seed accoring to the kernel command parameters if any or + get a random value */ + if (seed != 0) { + test_ctx->lpm_pseudo_random_seed = seed; + } else { + test_ctx->lpm_pseudo_random_seed = + (unsigned int)(get_jiffies_64() & 0xFFFF); + test_ctx->lpm_pseudo_random_seed = + pseudo_random_seed(&test_ctx->lpm_pseudo_random_seed); + } + + pr_info(TEST_MODULE_NAME ":%s: seed is %u", + __func__, test_ctx->lpm_pseudo_random_seed); +} + +/* + for each channel + 1. open channel + 2. close channel +*/ +static int close_channel_lpm_test(int channel_num) +{ + int ret = 0; + struct test_channel *tch = NULL; + tch = test_ctx->test_ch_arr[channel_num]; + + if (!tch) { + pr_info(TEST_MODULE_NAME ":%s ch#%d is NULL\n", + __func__, channel_num); + return 0; + } + + ret = open_sdio_ch(tch); + if (ret) { + pr_err(TEST_MODULE_NAME":%s open channel %s" + " failed\n", __func__, tch->name); + return ret; + } else { + pr_info(TEST_MODULE_NAME":%s open channel %s" + " success\n", __func__, tch->name); + } + ret = close_sdio_ch(tch); + if (ret) { + pr_err(TEST_MODULE_NAME":%s close channel %s" + " failed\n", __func__, tch->name); + return ret; + } else { + pr_info(TEST_MODULE_NAME":%s close channel %s" + " success\n", __func__, tch->name); + } + + tch->is_used = 0; + + return ret; +} + +/** + * Write File. + * + * @note Trigger the test from user space by: + * echo 1 > /dev/sdio_al_test + * + */ +ssize_t test_write(struct file *filp, const char __user *buf, size_t size, + loff_t *f_pos) +{ + sdio_al_test_initial_dev_and_chan(test_ctx); + + if (strict_strtol(buf, 10, &test_ctx->testcase)) + return -EINVAL; + + switch (test_ctx->testcase) { + case 98: + pr_info(TEST_MODULE_NAME " set runtime debug on"); + test_ctx->runtime_debug = 1; + return size; + case 99: + pr_info(TEST_MODULE_NAME " set runtime debug off"); + test_ctx->runtime_debug = 0; + return size; + default: + pr_info(TEST_MODULE_NAME ":Bad Test number = %d.\n", + (int)test_ctx->testcase); + return size; + } + + return size; +} + +/** + * Test Channel Init. + */ +int test_channel_init(char *name) +{ + struct test_channel *test_ch; + int ch_id = 0; + int ret; + + pr_debug(TEST_MODULE_NAME ":%s.\n", __func__); + pr_info(TEST_MODULE_NAME ": init test channel %s.\n", name); + + ch_id = channel_name_to_id(name); + pr_debug(TEST_MODULE_NAME ":id = %d.\n", ch_id); + if (test_ctx->test_ch_arr[ch_id] == NULL) { + test_ch = kzalloc(sizeof(*test_ch), GFP_KERNEL); + if (test_ch == NULL) { + pr_err(TEST_MODULE_NAME ":kzalloc err for allocating " + "test_ch %s.\n", + name); + return -ENOMEM; + } + test_ctx->test_ch_arr[ch_id] = test_ch; + + test_ch->ch_id = ch_id; + + strncpy(test_ch->name, name, + strnlen(name, TEST_CH_NAME_SIZE)-SDIO_TEST_POSTFIX_SIZE); + + test_ch->buf_size = MAX_XFER_SIZE; + + test_ch->buf = kzalloc(test_ch->buf_size, GFP_KERNEL); + if (test_ch->buf == NULL) { + kfree(test_ch); + test_ctx->test_ch = NULL; + return -ENOMEM; + } + + if (test_ch->ch_id == SDIO_SMEM) { + test_ctx->smem_buf = kzalloc(SMEM_MAX_XFER_SIZE, + GFP_KERNEL); + if (test_ctx->smem_buf == NULL) { + pr_err(TEST_MODULE_NAME ":%s: Unable to " + "allocate smem buf\n", + __func__); + kfree(test_ch); + test_ctx->test_ch = NULL; + return -ENOMEM; + } + +#ifdef CONFIG_MSM_SDIO_SMEM + ret = platform_driver_register(&sdio_smem_client_drv); + if (ret) { + pr_err(TEST_MODULE_NAME ":%s: Unable to " + "register sdio smem " + "test client\n", + __func__); + return ret; + } +#endif + } else { + test_ch->workqueue = + create_singlethread_workqueue(test_ch->name); + test_ch->test_work.test_ch = test_ch; + INIT_WORK(&test_ch->test_work.work, worker); + + init_waitqueue_head(&test_ch->wait_q); + } + } else { + test_ch = test_ctx->test_ch_arr[ch_id]; + pr_info(TEST_MODULE_NAME ":%s: ch %s was detected again\n", + __func__, test_ch->name); + test_ch->card_removed = 0; + if ((test_ch->is_used) && + (test_ch->test_type == SDIO_TEST_MODEM_RESET)) { + if (test_ch->ch_id == SDIO_SMEM) { +#ifdef CONFIG_MSM_SDIO_SMEM + ret = add_sdio_smem(); + if (ret) { + test_ch->ch_ready = false; + return 0; + } +#endif + } else { + ret = open_sdio_ch(test_ch); + if (ret) { + pr_info(TEST_MODULE_NAME + ":%s: open channel %s failed\n", + __func__, test_ch->name); + return 0; + } + ret = sdio_test_find_dev(test_ch); + + if (ret) { + pr_err(TEST_MODULE_NAME ": %s - " + "sdio_test_find_dev() returned " + "with error", __func__); + return -ENODEV; + } + + test_ch->sdio_al_device = + test_ch->ch->sdio_al_dev; + } + atomic_set(&test_ch->card_detected_event, 1); + wake_up(&test_ch->wait_q); + } + } + + return 0; +} + +static int sdio_test_channel_probe(struct platform_device *pdev) +{ + if (!pdev) + return -EIO; + return test_channel_init((char *)pdev->name); +} + +static int sdio_test_channel_remove(struct platform_device *pdev) +{ + int ch_id; + + if (!pdev) + return -EIO; + + ch_id = channel_name_to_id((char *)pdev->name); + if (test_ctx->test_ch_arr[ch_id] == NULL) + return 0; + + pr_info(TEST_MODULE_NAME "%s: remove ch %s\n", + __func__, test_ctx->test_ch_arr[ch_id]->name); + + if ((ch_id == SDIO_SMEM) && (test_ctx->smem_pdev)) { + platform_device_unregister(test_ctx->smem_pdev); + test_ctx->smem_pdev = NULL; + } + + test_ctx->test_ch_arr[ch_id]->ch_ready = 0; + test_ctx->test_ch_arr[ch_id]->card_removed = 1; + + return 0; + +} + +static int sdio_test_channel_csvt_probe(struct platform_device *pdev) +{ + int ret = 0; + + if (!pdev) + return -ENODEV; + + test_ctx->csvt_app_pdev = platform_device_alloc("SDIO_CSVT_TEST_APP", + -1); + ret = platform_device_add(test_ctx->csvt_app_pdev); + if (ret) { + pr_err(MODULE_NAME ":platform_device_add failed, " + "ret=%d\n", ret); + return ret; + } + + return sdio_test_channel_probe(pdev); +} + +static int sdio_test_channel_csvt_remove(struct platform_device *pdev) +{ + if (!pdev) + return -ENODEV; + + platform_device_unregister(test_ctx->csvt_app_pdev); + + return sdio_test_channel_remove(pdev); +} + +static struct platform_driver sdio_rpc_drv = { + .probe = sdio_test_channel_probe, + .remove = sdio_test_channel_remove, + .driver = { + .name = "SDIO_RPC_TEST", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver sdio_qmi_drv = { + .probe = sdio_test_channel_probe, + .remove = sdio_test_channel_remove, + .driver = { + .name = "SDIO_QMI_TEST", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver sdio_diag_drv = { + .probe = sdio_test_channel_probe, + .remove = sdio_test_channel_remove, + .driver = { + .name = "SDIO_DIAG_TEST", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver sdio_smem_drv = { + .probe = sdio_test_channel_probe, + .remove = sdio_test_channel_remove, + .driver = { + .name = "SDIO_SMEM_TEST", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver sdio_rmnt_drv = { + .probe = sdio_test_channel_probe, + .remove = sdio_test_channel_remove, + .driver = { + .name = "SDIO_RMNT_TEST", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver sdio_dun_drv = { + .probe = sdio_test_channel_probe, + .remove = sdio_test_channel_remove, + .driver = { + .name = "SDIO_DUN_TEST", + .owner = THIS_MODULE, + }, +}; + +static struct platform_driver sdio_csvt_drv = { + .probe = sdio_test_channel_csvt_probe, + .remove = sdio_test_channel_csvt_remove, + .driver = { + .name = "SDIO_CSVT_TEST", + .owner = THIS_MODULE, + }, +}; + +static struct class *test_class; + +const struct file_operations test_fops = { + .owner = THIS_MODULE, + .write = test_write, +}; + +/** + * Module Init. + */ +static int __init test_init(void) +{ + int ret; + + pr_debug(TEST_MODULE_NAME ":test_init.\n"); + + test_ctx = kzalloc(sizeof(struct test_context), GFP_KERNEL); + + if (test_ctx == NULL) { + pr_err(TEST_MODULE_NAME ":kzalloc err.\n"); + return -ENOMEM; + } + test_ctx->test_ch = NULL; + test_ctx->signature = TEST_SIGNATURE; + + test_ctx->name = "UNKNOWN"; + + init_waitqueue_head(&test_ctx->wait_q); + +#ifdef CONFIG_DEBUG_FS + sdio_al_test_debugfs_init(); +#endif + + test_class = class_create(THIS_MODULE, TEST_MODULE_NAME); + + ret = alloc_chrdev_region(&test_ctx->dev_num, 0, 1, TEST_MODULE_NAME); + if (ret) { + pr_err(TEST_MODULE_NAME "alloc_chrdev_region err.\n"); + return -ENODEV; + } + + test_ctx->dev = device_create(test_class, NULL, test_ctx->dev_num, + test_ctx, TEST_MODULE_NAME); + if (IS_ERR(test_ctx->dev)) { + pr_err(TEST_MODULE_NAME ":device_create err.\n"); + return -ENODEV; + } + + test_ctx->cdev = cdev_alloc(); + if (test_ctx->cdev == NULL) { + pr_err(TEST_MODULE_NAME ":cdev_alloc err.\n"); + return -ENODEV; + } + cdev_init(test_ctx->cdev, &test_fops); + test_ctx->cdev->owner = THIS_MODULE; + + ret = cdev_add(test_ctx->cdev, test_ctx->dev_num, 1); + if (ret) + pr_err(TEST_MODULE_NAME ":cdev_add err=%d\n", -ret); + else + pr_debug(TEST_MODULE_NAME ":SDIO-AL-Test init OK..\n"); + + platform_driver_register(&sdio_rpc_drv); + platform_driver_register(&sdio_qmi_drv); + platform_driver_register(&sdio_diag_drv); + platform_driver_register(&sdio_smem_drv); + platform_driver_register(&sdio_rmnt_drv); + platform_driver_register(&sdio_dun_drv); + platform_driver_register(&sdio_csvt_drv); + + return ret; +} + +/** + * Module Exit. + */ +static void __exit test_exit(void) +{ + int i; + + pr_debug(TEST_MODULE_NAME ":test_exit.\n"); + + test_ctx->exit_flag = true; + + msleep(100); /* allow gracefully exit of the worker thread */ + + cdev_del(test_ctx->cdev); + device_destroy(test_class, test_ctx->dev_num); + unregister_chrdev_region(test_ctx->dev_num, 1); + + platform_driver_unregister(&sdio_rpc_drv); + platform_driver_unregister(&sdio_qmi_drv); + platform_driver_unregister(&sdio_diag_drv); + platform_driver_unregister(&sdio_smem_drv); + platform_driver_unregister(&sdio_rmnt_drv); + platform_driver_unregister(&sdio_dun_drv); + platform_driver_unregister(&sdio_csvt_drv); + + for (i = 0; i < SDIO_MAX_CHANNELS; i++) { + struct test_channel *tch = test_ctx->test_ch_arr[i]; + if (!tch) + continue; + kfree(tch->buf); + kfree(tch); + } + +#ifdef CONFIG_DEBUG_FS + sdio_al_test_debugfs_cleanup(); +#endif + + kfree(test_ctx); + + pr_debug(TEST_MODULE_NAME ":test_exit complete.\n"); +} + +module_init(test_init); +module_exit(test_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SDIO_AL Test"); +MODULE_AUTHOR("Amir Samuelov "); + + diff --git a/arch/arm/mach-msm/sdio_cmux.c b/arch/arm/mach-msm/sdio_cmux.c new file mode 100644 index 00000000..70935b27 --- /dev/null +++ b/arch/arm/mach-msm/sdio_cmux.c @@ -0,0 +1,885 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "modem_notifier.h" + +#define MAX_WRITE_RETRY 5 +#define MAGIC_NO_V1 0x33FC + +static int msm_sdio_cmux_debug_mask; +module_param_named(debug_mask, msm_sdio_cmux_debug_mask, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +enum cmd_type { + DATA = 0, + OPEN, + CLOSE, + STATUS, + NUM_CMDS +}; + +#define DSR_POS 0x1 +#define CTS_POS 0x2 +#define RI_POS 0x4 +#define CD_POS 0x8 + +struct sdio_cmux_ch { + int lc_id; + + struct mutex lc_lock; + wait_queue_head_t open_wait_queue; + int is_remote_open; + int is_local_open; + int is_channel_reset; + + char local_status; + char remote_status; + + struct mutex tx_lock; + struct list_head tx_list; + + void *priv; + void (*receive_cb)(void *, int, void *); + void (*write_done)(void *, int, void *); + void (*status_callback)(int, void *); +} logical_ch[SDIO_CMUX_NUM_CHANNELS]; + +struct sdio_cmux_hdr { + uint16_t magic_no; + uint8_t status; /* This field is reserved for commands other + * than STATUS */ + uint8_t cmd; + uint8_t pad_bytes; + uint8_t lc_id; + uint16_t pkt_len; +}; + +struct sdio_cmux_pkt { + struct sdio_cmux_hdr *hdr; + void *data; +}; + +struct sdio_cmux_list_elem { + struct list_head list; + struct sdio_cmux_pkt cmux_pkt; +}; + +#define logical_ch_is_local_open(x) \ + (logical_ch[(x)].is_local_open) + +#define logical_ch_is_remote_open(x) \ + (logical_ch[(x)].is_remote_open) + +static void sdio_cdemux_fn(struct work_struct *work); +static DECLARE_WORK(sdio_cdemux_work, sdio_cdemux_fn); +static struct workqueue_struct *sdio_cdemux_wq; + +static DEFINE_MUTEX(write_lock); +static uint32_t bytes_to_write; +static DEFINE_MUTEX(temp_rx_lock); +static LIST_HEAD(temp_rx_list); + +static void sdio_cmux_fn(struct work_struct *work); +static DECLARE_WORK(sdio_cmux_work, sdio_cmux_fn); +static struct workqueue_struct *sdio_cmux_wq; + +static struct sdio_channel *sdio_qmi_chl; +static uint32_t sdio_cmux_inited; + +static uint32_t abort_tx; +static DEFINE_MUTEX(modem_reset_lock); + +static DEFINE_MUTEX(probe_lock); + +enum { + MSM_SDIO_CMUX_DEBUG = 1U << 0, + MSM_SDIO_CMUX_DUMP_BUFFER = 1U << 1, +}; + +static struct platform_device sdio_ctl_dev = { + .name = "SDIO_CTL", + .id = -1, +}; + +#if defined(DEBUG) +#define D_DUMP_BUFFER(prestr, cnt, buf) \ +do { \ + if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DUMP_BUFFER) { \ + int i; \ + pr_debug("%s", prestr); \ + for (i = 0; i < cnt; i++) \ + pr_info("%.2x", buf[i]); \ + pr_debug("\n"); \ + } \ +} while (0) + +#define D(x...) \ +do { \ + if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DEBUG) \ + pr_debug(x); \ +} while (0) + +#else +#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0) +#define D(x...) do {} while (0) +#endif + +static int sdio_cmux_ch_alloc(int id) +{ + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) { + pr_err("%s: Invalid lc_id - %d\n", __func__, id); + return -EINVAL; + } + + logical_ch[id].lc_id = id; + mutex_init(&logical_ch[id].lc_lock); + init_waitqueue_head(&logical_ch[id].open_wait_queue); + logical_ch[id].is_remote_open = 0; + logical_ch[id].is_local_open = 0; + logical_ch[id].is_channel_reset = 0; + + INIT_LIST_HEAD(&logical_ch[id].tx_list); + mutex_init(&logical_ch[id].tx_lock); + + logical_ch[id].priv = NULL; + logical_ch[id].receive_cb = NULL; + logical_ch[id].write_done = NULL; + return 0; +} + +static int sdio_cmux_ch_clear_and_signal(int id) +{ + struct sdio_cmux_list_elem *list_elem; + + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) { + pr_err("%s: Invalid lc_id - %d\n", __func__, id); + return -EINVAL; + } + + mutex_lock(&logical_ch[id].lc_lock); + logical_ch[id].is_remote_open = 0; + mutex_lock(&logical_ch[id].tx_lock); + while (!list_empty(&logical_ch[id].tx_list)) { + list_elem = list_first_entry(&logical_ch[id].tx_list, + struct sdio_cmux_list_elem, + list); + list_del(&list_elem->list); + kfree(list_elem->cmux_pkt.hdr); + kfree(list_elem); + } + mutex_unlock(&logical_ch[id].tx_lock); + if (logical_ch[id].receive_cb) + logical_ch[id].receive_cb(NULL, 0, logical_ch[id].priv); + if (logical_ch[id].write_done) + logical_ch[id].write_done(NULL, 0, logical_ch[id].priv); + mutex_unlock(&logical_ch[id].lc_lock); + wake_up(&logical_ch[id].open_wait_queue); + return 0; +} + +static int sdio_cmux_write_cmd(const int id, enum cmd_type type) +{ + int write_size = 0; + void *write_data = NULL; + struct sdio_cmux_list_elem *list_elem; + + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) { + pr_err("%s: Invalid lc_id - %d\n", __func__, id); + return -EINVAL; + } + + if (type < 0 || type > NUM_CMDS) { + pr_err("%s: Invalid cmd - %d\n", __func__, type); + return -EINVAL; + } + + write_size = sizeof(struct sdio_cmux_hdr); + list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL); + if (!list_elem) { + pr_err("%s: list_elem alloc failed\n", __func__); + return -ENOMEM; + } + + write_data = kmalloc(write_size, GFP_KERNEL); + if (!write_data) { + pr_err("%s: write_data alloc failed\n", __func__); + kfree(list_elem); + return -ENOMEM; + } + + list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data; + list_elem->cmux_pkt.data = NULL; + + list_elem->cmux_pkt.hdr->lc_id = (uint8_t)id; + list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)0; + list_elem->cmux_pkt.hdr->cmd = (uint8_t)type; + list_elem->cmux_pkt.hdr->status = (uint8_t)0; + if (type == STATUS) + list_elem->cmux_pkt.hdr->status = logical_ch[id].local_status; + list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0; + list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1; + + mutex_lock(&logical_ch[id].tx_lock); + list_add_tail(&list_elem->list, &logical_ch[id].tx_list); + mutex_unlock(&logical_ch[id].tx_lock); + + mutex_lock(&write_lock); + bytes_to_write += write_size; + mutex_unlock(&write_lock); + queue_work(sdio_cmux_wq, &sdio_cmux_work); + + return 0; +} + +int sdio_cmux_open(const int id, + void (*receive_cb)(void *, int, void *), + void (*write_done)(void *, int, void *), + void (*status_callback)(int, void *), + void *priv) +{ + int r; + struct sdio_cmux_list_elem *list_elem, *list_elem_tmp; + + if (!sdio_cmux_inited) + return -ENODEV; + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) { + pr_err("%s: Invalid id - %d\n", __func__, id); + return -EINVAL; + } + + r = wait_event_timeout(logical_ch[id].open_wait_queue, + logical_ch[id].is_remote_open, (1 * HZ)); + if (r < 0) { + pr_err("ERROR %s: wait_event_timeout() failed for" + " ch%d with rc %d\n", __func__, id, r); + return r; + } + if (r == 0) { + pr_err("ERROR %s: Wait Timed Out for ch%d\n", __func__, id); + return -ETIMEDOUT; + } + + mutex_lock(&logical_ch[id].lc_lock); + if (!logical_ch[id].is_remote_open) { + pr_err("%s: Remote ch%d not opened\n", __func__, id); + mutex_unlock(&logical_ch[id].lc_lock); + return -EINVAL; + } + if (logical_ch[id].is_local_open) { + mutex_unlock(&logical_ch[id].lc_lock); + return 0; + } + logical_ch[id].is_local_open = 1; + logical_ch[id].priv = priv; + logical_ch[id].receive_cb = receive_cb; + logical_ch[id].write_done = write_done; + logical_ch[id].status_callback = status_callback; + if (logical_ch[id].receive_cb) { + mutex_lock(&temp_rx_lock); + list_for_each_entry_safe(list_elem, list_elem_tmp, + &temp_rx_list, list) { + if ((int)list_elem->cmux_pkt.hdr->lc_id == id) { + logical_ch[id].receive_cb( + list_elem->cmux_pkt.data, + (int)list_elem->cmux_pkt.hdr->pkt_len, + logical_ch[id].priv); + list_del(&list_elem->list); + kfree(list_elem->cmux_pkt.hdr); + kfree(list_elem); + } + } + mutex_unlock(&temp_rx_lock); + } + mutex_unlock(&logical_ch[id].lc_lock); + sdio_cmux_write_cmd(id, OPEN); + return 0; +} +EXPORT_SYMBOL(sdio_cmux_open); + +int sdio_cmux_close(int id) +{ + struct sdio_cmux_ch *ch; + + if (!sdio_cmux_inited) + return -ENODEV; + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) { + pr_err("%s: Invalid channel close\n", __func__); + return -EINVAL; + } + + ch = &logical_ch[id]; + mutex_lock(&ch->lc_lock); + ch->receive_cb = NULL; + mutex_lock(&ch->tx_lock); + ch->write_done = NULL; + mutex_unlock(&ch->tx_lock); + ch->is_local_open = 0; + ch->priv = NULL; + mutex_unlock(&ch->lc_lock); + sdio_cmux_write_cmd(ch->lc_id, CLOSE); + return 0; +} +EXPORT_SYMBOL(sdio_cmux_close); + +int sdio_cmux_write_avail(int id) +{ + int write_avail; + + mutex_lock(&logical_ch[id].lc_lock); + if (logical_ch[id].is_channel_reset) { + mutex_unlock(&logical_ch[id].lc_lock); + return -ENETRESET; + } + mutex_unlock(&logical_ch[id].lc_lock); + write_avail = sdio_write_avail(sdio_qmi_chl); + return write_avail - bytes_to_write; +} +EXPORT_SYMBOL(sdio_cmux_write_avail); + +int sdio_cmux_write(int id, void *data, int len) +{ + struct sdio_cmux_list_elem *list_elem; + uint32_t write_size; + void *write_data = NULL; + struct sdio_cmux_ch *ch; + int ret; + + if (!sdio_cmux_inited) + return -ENODEV; + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) { + pr_err("%s: Invalid channel id %d\n", __func__, id); + return -ENODEV; + } + + ch = &logical_ch[id]; + if (len <= 0) { + pr_err("%s: Invalid len %d bytes to write\n", + __func__, len); + return -EINVAL; + } + + write_size = sizeof(struct sdio_cmux_hdr) + len; + list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL); + if (!list_elem) { + pr_err("%s: list_elem alloc failed\n", __func__); + return -ENOMEM; + } + + write_data = kmalloc(write_size, GFP_KERNEL); + if (!write_data) { + pr_err("%s: write_data alloc failed\n", __func__); + kfree(list_elem); + return -ENOMEM; + } + + list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data; + list_elem->cmux_pkt.data = (void *)((char *)write_data + + sizeof(struct sdio_cmux_hdr)); + memcpy(list_elem->cmux_pkt.data, data, len); + + list_elem->cmux_pkt.hdr->lc_id = (uint8_t)ch->lc_id; + list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)len; + list_elem->cmux_pkt.hdr->cmd = (uint8_t)DATA; + list_elem->cmux_pkt.hdr->status = (uint8_t)0; + list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0; + list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1; + + mutex_lock(&ch->lc_lock); + if (!ch->is_remote_open || !ch->is_local_open) { + pr_err("%s: Local ch%d sending data before sending/receiving" + " OPEN command\n", __func__, ch->lc_id); + if (ch->is_channel_reset) + ret = -ENETRESET; + else + ret = -ENODEV; + mutex_unlock(&ch->lc_lock); + kfree(write_data); + kfree(list_elem); + return ret; + } + mutex_lock(&ch->tx_lock); + list_add_tail(&list_elem->list, &ch->tx_list); + mutex_unlock(&ch->tx_lock); + mutex_unlock(&ch->lc_lock); + + mutex_lock(&write_lock); + bytes_to_write += write_size; + mutex_unlock(&write_lock); + queue_work(sdio_cmux_wq, &sdio_cmux_work); + + return len; +} +EXPORT_SYMBOL(sdio_cmux_write); + +int is_remote_open(int id) +{ + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) + return -ENODEV; + + return logical_ch_is_remote_open(id); +} +EXPORT_SYMBOL(is_remote_open); + +int sdio_cmux_is_channel_reset(int id) +{ + int ret; + if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) + return -ENODEV; + + mutex_lock(&logical_ch[id].lc_lock); + ret = logical_ch[id].is_channel_reset; + mutex_unlock(&logical_ch[id].lc_lock); + return ret; +} +EXPORT_SYMBOL(sdio_cmux_is_channel_reset); + +int sdio_cmux_tiocmget(int id) +{ + int ret = (logical_ch[id].remote_status & DSR_POS ? TIOCM_DSR : 0) | + (logical_ch[id].remote_status & CTS_POS ? TIOCM_CTS : 0) | + (logical_ch[id].remote_status & CD_POS ? TIOCM_CD : 0) | + (logical_ch[id].remote_status & RI_POS ? TIOCM_RI : 0) | + (logical_ch[id].local_status & CTS_POS ? TIOCM_RTS : 0) | + (logical_ch[id].local_status & DSR_POS ? TIOCM_DTR : 0); + return ret; +} +EXPORT_SYMBOL(sdio_cmux_tiocmget); + +int sdio_cmux_tiocmset(int id, unsigned int set, unsigned int clear) +{ + if (set & TIOCM_DTR) + logical_ch[id].local_status |= DSR_POS; + + if (set & TIOCM_RTS) + logical_ch[id].local_status |= CTS_POS; + + if (clear & TIOCM_DTR) + logical_ch[id].local_status &= ~DSR_POS; + + if (clear & TIOCM_RTS) + logical_ch[id].local_status &= ~CTS_POS; + + sdio_cmux_write_cmd(id, STATUS); + return 0; +} +EXPORT_SYMBOL(sdio_cmux_tiocmset); + +static int copy_packet(void *pkt, int size) +{ + struct sdio_cmux_list_elem *list_elem = NULL; + void *temp_pkt = NULL; + + list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL); + if (!list_elem) { + pr_err("%s: list_elem alloc failed\n", __func__); + return -ENOMEM; + } + temp_pkt = kmalloc(size, GFP_KERNEL); + if (!temp_pkt) { + pr_err("%s: temp_pkt alloc failed\n", __func__); + kfree(list_elem); + return -ENOMEM; + } + + memcpy(temp_pkt, pkt, size); + list_elem->cmux_pkt.hdr = temp_pkt; + list_elem->cmux_pkt.data = (void *)((char *)temp_pkt + + sizeof(struct sdio_cmux_hdr)); + mutex_lock(&temp_rx_lock); + list_add_tail(&list_elem->list, &temp_rx_list); + mutex_unlock(&temp_rx_lock); + return 0; +} + +static int process_cmux_pkt(void *pkt, int size) +{ + struct sdio_cmux_hdr *mux_hdr; + uint32_t id, data_size; + void *data; + char *dump_buf = (char *)pkt; + + D_DUMP_BUFFER("process_cmux_pkt:", size, dump_buf); + mux_hdr = (struct sdio_cmux_hdr *)pkt; + switch (mux_hdr->cmd) { + case OPEN: + id = (uint32_t)(mux_hdr->lc_id); + D("%s: Received OPEN command for ch%d\n", __func__, id); + mutex_lock(&logical_ch[id].lc_lock); + logical_ch[id].is_remote_open = 1; + if (logical_ch[id].is_channel_reset) { + sdio_cmux_write_cmd(id, OPEN); + logical_ch[id].is_channel_reset = 0; + } + mutex_unlock(&logical_ch[id].lc_lock); + wake_up(&logical_ch[id].open_wait_queue); + break; + + case CLOSE: + id = (uint32_t)(mux_hdr->lc_id); + D("%s: Received CLOSE command for ch%d\n", __func__, id); + sdio_cmux_ch_clear_and_signal(id); + break; + + case DATA: + id = (uint32_t)(mux_hdr->lc_id); + D("%s: Received DATA for ch%d\n", __func__, id); + /*Channel is not locally open & if single packet received + then drop it*/ + mutex_lock(&logical_ch[id].lc_lock); + if (!logical_ch[id].is_remote_open) { + mutex_unlock(&logical_ch[id].lc_lock); + pr_err("%s: Remote Ch%d sent data before sending/" + "receiving OPEN command\n", __func__, id); + return -ENODEV; + } + + data = (void *)((char *)pkt + sizeof(struct sdio_cmux_hdr)); + data_size = (int)(((struct sdio_cmux_hdr *)pkt)->pkt_len); + if (logical_ch[id].receive_cb) + logical_ch[id].receive_cb(data, data_size, + logical_ch[id].priv); + else + copy_packet(pkt, size); + mutex_unlock(&logical_ch[id].lc_lock); + break; + + case STATUS: + id = (uint32_t)(mux_hdr->lc_id); + D("%s: Received STATUS command for ch%d\n", __func__, id); + if (logical_ch[id].remote_status != mux_hdr->status) { + mutex_lock(&logical_ch[id].lc_lock); + logical_ch[id].remote_status = mux_hdr->status; + mutex_unlock(&logical_ch[id].lc_lock); + if (logical_ch[id].status_callback) + logical_ch[id].status_callback( + sdio_cmux_tiocmget(id), + logical_ch[id].priv); + } + break; + } + return 0; +} + +static void parse_cmux_data(void *data, int size) +{ + int data_parsed = 0, pkt_size; + char *temp_ptr; + + D("Entered %s\n", __func__); + temp_ptr = (char *)data; + while (data_parsed < size) { + pkt_size = sizeof(struct sdio_cmux_hdr) + + (int)(((struct sdio_cmux_hdr *)temp_ptr)->pkt_len); + D("Parsed %d bytes, Current Pkt Size %d bytes," + " Total size %d bytes\n", data_parsed, pkt_size, size); + process_cmux_pkt((void *)temp_ptr, pkt_size); + data_parsed += pkt_size; + temp_ptr += pkt_size; + } + + kfree(data); +} + +static void sdio_cdemux_fn(struct work_struct *work) +{ + int r = 0, read_avail = 0; + void *cmux_data; + + while (1) { + read_avail = sdio_read_avail(sdio_qmi_chl); + if (read_avail < 0) { + pr_err("%s: sdio_read_avail failed with rc %d\n", + __func__, read_avail); + return; + } + + if (read_avail == 0) { + D("%s: Nothing to read\n", __func__); + return; + } + + D("%s: kmalloc %d bytes\n", __func__, read_avail); + cmux_data = kmalloc(read_avail, GFP_KERNEL); + if (!cmux_data) { + pr_err("%s: kmalloc Failed\n", __func__); + return; + } + + D("%s: sdio_read %d bytes\n", __func__, read_avail); + r = sdio_read(sdio_qmi_chl, cmux_data, read_avail); + if (r < 0) { + pr_err("%s: sdio_read failed with rc %d\n", + __func__, r); + kfree(cmux_data); + return; + } + + parse_cmux_data(cmux_data, read_avail); + } + return; +} + +static void sdio_cmux_fn(struct work_struct *work) +{ + int i, r = 0; + void *write_data; + uint32_t write_size, write_avail, write_retry = 0; + int bytes_written; + struct sdio_cmux_list_elem *list_elem = NULL; + struct sdio_cmux_ch *ch; + + for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) { + ch = &logical_ch[i]; + bytes_written = 0; + mutex_lock(&ch->tx_lock); + while (!list_empty(&ch->tx_list)) { + list_elem = list_first_entry(&ch->tx_list, + struct sdio_cmux_list_elem, + list); + list_del(&list_elem->list); + mutex_unlock(&ch->tx_lock); + + write_data = (void *)list_elem->cmux_pkt.hdr; + write_size = sizeof(struct sdio_cmux_hdr) + + (uint32_t)list_elem->cmux_pkt.hdr->pkt_len; + + mutex_lock(&modem_reset_lock); + while (!(abort_tx) && + ((write_avail = sdio_write_avail(sdio_qmi_chl)) + < write_size)) { + mutex_unlock(&modem_reset_lock); + pr_err("%s: sdio_write_avail %d bytes, " + "write size %d bytes. Waiting...\n", + __func__, write_avail, write_size); + msleep(250); + mutex_lock(&modem_reset_lock); + } + while (!(abort_tx) && + ((r = sdio_write(sdio_qmi_chl, + write_data, write_size)) < 0) + && (r != -ENODEV) + && (write_retry++ < MAX_WRITE_RETRY)) { + mutex_unlock(&modem_reset_lock); + pr_err("%s: sdio_write failed with rc %d." + "Retrying...", __func__, r); + msleep(250); + mutex_lock(&modem_reset_lock); + } + if (!r && !abort_tx) { + D("%s: sdio_write_completed %dbytes\n", + __func__, write_size); + bytes_written += write_size; + } else if (r == -ENODEV) { + pr_err("%s: aborting_tx because sdio_write" + " returned %d\n", __func__, r); + r = 0; + abort_tx = 1; + } + mutex_unlock(&modem_reset_lock); + kfree(list_elem->cmux_pkt.hdr); + kfree(list_elem); + mutex_lock(&write_lock); + bytes_to_write -= write_size; + mutex_unlock(&write_lock); + mutex_lock(&ch->tx_lock); + } + if (ch->write_done) + ch->write_done(NULL, bytes_written, ch->priv); + mutex_unlock(&ch->tx_lock); + } + return; +} + +static void sdio_qmi_chl_notify(void *priv, unsigned event) +{ + if (event == SDIO_EVENT_DATA_READ_AVAIL) { + D("%s: Received SDIO_EVENT_DATA_READ_AVAIL\n", __func__); + queue_work(sdio_cdemux_wq, &sdio_cdemux_work); + } +} + +#ifdef CONFIG_DEBUG_FS + +static int debug_tbl(char *buf, int max) +{ + int i = 0; + int j; + + for (j = 0; j < SDIO_CMUX_NUM_CHANNELS; ++j) { + i += scnprintf(buf + i, max - i, + "ch%02d local open=%s remote open=%s\n", + j, logical_ch_is_local_open(j) ? "Y" : "N", + logical_ch_is_remote_open(j) ? "Y" : "N"); + } + + return i; +} + +#define DEBUG_BUFMAX 4096 +static char debug_buffer[DEBUG_BUFMAX]; + +static ssize_t debug_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int (*fill)(char *buf, int max) = file->private_data; + int bsize = fill(debug_buffer, DEBUG_BUFMAX); + return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); +} + +static int debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + + +static const struct file_operations debug_ops = { + .read = debug_read, + .open = debug_open, +}; + +static void debug_create(const char *name, mode_t mode, + struct dentry *dent, + int (*fill)(char *buf, int max)) +{ + debugfs_create_file(name, mode, dent, fill, &debug_ops); +} + +#endif + +static int sdio_cmux_probe(struct platform_device *pdev) +{ + int i, r; + + mutex_lock(&probe_lock); + D("%s Begins\n", __func__); + if (sdio_cmux_inited) { + mutex_lock(&modem_reset_lock); + r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL, + sdio_qmi_chl_notify); + if (r < 0) { + mutex_unlock(&modem_reset_lock); + pr_err("%s: sdio_open() failed\n", __func__); + goto error0; + } + abort_tx = 0; + mutex_unlock(&modem_reset_lock); + mutex_unlock(&probe_lock); + return 0; + } + + for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) + sdio_cmux_ch_alloc(i); + INIT_LIST_HEAD(&temp_rx_list); + + sdio_cmux_wq = create_singlethread_workqueue("sdio_cmux"); + if (IS_ERR(sdio_cmux_wq)) { + pr_err("%s: create_singlethread_workqueue() ENOMEM\n", + __func__); + r = -ENOMEM; + goto error0; + } + + sdio_cdemux_wq = create_singlethread_workqueue("sdio_cdemux"); + if (IS_ERR(sdio_cdemux_wq)) { + pr_err("%s: create_singlethread_workqueue() ENOMEM\n", + __func__); + r = -ENOMEM; + goto error1; + } + + r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL, sdio_qmi_chl_notify); + if (r < 0) { + pr_err("%s: sdio_open() failed\n", __func__); + goto error2; + } + + platform_device_register(&sdio_ctl_dev); + sdio_cmux_inited = 1; + D("SDIO Control MUX Driver Initialized.\n"); + mutex_unlock(&probe_lock); + return 0; + +error2: + destroy_workqueue(sdio_cdemux_wq); +error1: + destroy_workqueue(sdio_cmux_wq); +error0: + mutex_unlock(&probe_lock); + return r; +} + +static int sdio_cmux_remove(struct platform_device *pdev) +{ + int i; + + mutex_lock(&modem_reset_lock); + abort_tx = 1; + + for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) { + mutex_lock(&logical_ch[i].lc_lock); + logical_ch[i].is_channel_reset = 1; + mutex_unlock(&logical_ch[i].lc_lock); + sdio_cmux_ch_clear_and_signal(i); + } + sdio_qmi_chl = NULL; + mutex_unlock(&modem_reset_lock); + + return 0; +} + +static struct platform_driver sdio_cmux_driver = { + .probe = sdio_cmux_probe, + .remove = sdio_cmux_remove, + .driver = { + .name = "SDIO_QMI", + .owner = THIS_MODULE, + }, +}; + +static int __init sdio_cmux_init(void) +{ +#ifdef CONFIG_DEBUG_FS + struct dentry *dent; + + dent = debugfs_create_dir("sdio_cmux", 0); + if (!IS_ERR(dent)) + debug_create("tbl", 0444, dent, debug_tbl); +#endif + + msm_sdio_cmux_debug_mask = 0; + return platform_driver_register(&sdio_cmux_driver); +} + +module_init(sdio_cmux_init); +MODULE_DESCRIPTION("MSM SDIO Control MUX"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/sdio_ctl.c b/arch/arm/mach-msm/sdio_ctl.c new file mode 100644 index 00000000..cacdce98 --- /dev/null +++ b/arch/arm/mach-msm/sdio_ctl.c @@ -0,0 +1,575 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * SDIO Control Driver -- Provides a binary SDIO muxed control port + * interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "modem_notifier.h" +#include + +#define MAX_WRITE_RETRY 5 +#define MAGIC_NO_V1 0x33FC +#define NUM_SDIO_CTL_PORTS 10 +#define DEVICE_NAME "sdioctl" +#define MAX_BUF_SIZE 2048 +#define DEBUG + +static int msm_sdio_ctl_debug_mask; +module_param_named(debug_mask, msm_sdio_ctl_debug_mask, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +struct sdio_ctl_dev { + int id; + char name[9]; + struct cdev cdev; + struct device *devicep; + struct mutex dev_lock; + int ref_count; + + struct mutex rx_lock; + uint32_t read_avail; + struct list_head rx_list; + + wait_queue_head_t read_wait_queue; + wait_queue_head_t write_wait_queue; +} *sdio_ctl_devp[NUM_SDIO_CTL_PORTS]; + +struct sdio_ctl_pkt { + int data_size; + void *data; +}; + +struct sdio_ctl_list_elem { + struct list_head list; + struct sdio_ctl_pkt ctl_pkt; +}; + +struct class *sdio_ctl_classp; +static dev_t sdio_ctl_number; +static uint32_t sdio_ctl_inited; + +enum { + MSM_SDIO_CTL_DEBUG = 1U << 0, + MSM_SDIO_CTL_DUMP_BUFFER = 1U << 1, +}; + +#if defined(DEBUG) +#define D_DUMP_BUFFER(prestr, cnt, buf) \ +do { \ + if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DUMP_BUFFER) { \ + int i; \ + pr_info("%s", prestr); \ + for (i = 0; i < cnt; i++) \ + pr_info("%.2x", buf[i]); \ + pr_info("\n"); \ + } \ +} while (0) + +#define D(x...) \ +do { \ + if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DEBUG) \ + pr_info(x); \ +} while (0) + +#else +#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0) +#define D(x...) do {} while (0) +#endif + +static uint32_t cmux_ch_id[] = { + SDIO_CMUX_DATA_CTL_0, + SDIO_CMUX_DATA_CTL_1, + SDIO_CMUX_DATA_CTL_2, + SDIO_CMUX_DATA_CTL_3, + SDIO_CMUX_DATA_CTL_4, + SDIO_CMUX_DATA_CTL_5, + SDIO_CMUX_DATA_CTL_6, + SDIO_CMUX_DATA_CTL_7, + SDIO_CMUX_USB_CTL_0, + SDIO_CMUX_CSVT_CTL_0 +}; + +static int get_ctl_dev_index(int id) +{ + int dev_index; + for (dev_index = 0; dev_index < NUM_SDIO_CTL_PORTS; dev_index++) { + if (cmux_ch_id[dev_index] == id) + return dev_index; + } + return -ENODEV; +} + +static void sdio_ctl_receive_cb(void *data, int size, void *priv) +{ + struct sdio_ctl_list_elem *list_elem = NULL; + int id = ((struct sdio_ctl_dev *)(priv))->id; + int dev_index; + + if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1]) + return; + dev_index = get_ctl_dev_index(id); + if (dev_index < 0) { + pr_err("%s: Ch%d is not exported to user-space\n", + __func__, id); + return; + } + + if (!data || size <= 0) { + wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue); + return; + } + + list_elem = kmalloc(sizeof(struct sdio_ctl_list_elem), GFP_KERNEL); + if (!list_elem) { + pr_err("%s: list_elem alloc failed\n", __func__); + return; + } + + list_elem->ctl_pkt.data = kmalloc(size, GFP_KERNEL); + if (!list_elem->ctl_pkt.data) { + pr_err("%s: list_elem->data alloc failed\n", __func__); + kfree(list_elem); + return; + } + memcpy(list_elem->ctl_pkt.data, data, size); + list_elem->ctl_pkt.data_size = size; + mutex_lock(&sdio_ctl_devp[dev_index]->rx_lock); + list_add_tail(&list_elem->list, &sdio_ctl_devp[dev_index]->rx_list); + sdio_ctl_devp[dev_index]->read_avail += size; + mutex_unlock(&sdio_ctl_devp[dev_index]->rx_lock); + wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue); +} + +static void sdio_ctl_write_done(void *data, int size, void *priv) +{ + int id = ((struct sdio_ctl_dev *)(priv))->id; + int dev_index; + if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1]) + return; + + dev_index = get_ctl_dev_index(id); + if (dev_index < 0) { + pr_err("%s: Ch%d is not exported to user-space\n", + __func__, id); + return; + } + wake_up(&sdio_ctl_devp[dev_index]->write_wait_queue); +} + +static long sdio_ctl_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct sdio_ctl_dev *sdio_ctl_devp; + + sdio_ctl_devp = file->private_data; + if (!sdio_ctl_devp) + return -ENODEV; + + switch (cmd) { + case TIOCMGET: + ret = sdio_cmux_tiocmget(sdio_ctl_devp->id); + break; + case TIOCMSET: + ret = sdio_cmux_tiocmset(sdio_ctl_devp->id, arg, ~arg); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static unsigned int sdio_ctl_poll(struct file *file, poll_table *wait) +{ + struct sdio_ctl_dev *sdio_ctl_devp; + unsigned int mask = 0; + + sdio_ctl_devp = file->private_data; + if (!sdio_ctl_devp) { + pr_err("%s: on a NULL device\n", __func__); + return POLLERR; + } + + poll_wait(file, &sdio_ctl_devp->read_wait_queue, wait); + mutex_lock(&sdio_ctl_devp->rx_lock); + if (sdio_cmux_is_channel_reset(sdio_ctl_devp->id)) { + mutex_unlock(&sdio_ctl_devp->rx_lock); + pr_err("%s notifying reset for sdio_ctl_dev id:%d\n", + __func__, sdio_ctl_devp->id); + return POLLERR; + } + + if (sdio_ctl_devp->read_avail > 0) + mask |= POLLIN | POLLRDNORM; + + mutex_unlock(&sdio_ctl_devp->rx_lock); + + return mask; +} + +ssize_t sdio_ctl_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + int r = 0, id, bytes_to_read; + struct sdio_ctl_dev *sdio_ctl_devp; + struct sdio_ctl_list_elem *list_elem = NULL; + + sdio_ctl_devp = file->private_data; + + if (!sdio_ctl_devp) + return -ENODEV; + + D("%s: read from ch%d\n", __func__, sdio_ctl_devp->id); + + id = sdio_ctl_devp->id; + mutex_lock(&sdio_ctl_devp->rx_lock); + while (sdio_ctl_devp->read_avail <= 0) { + mutex_unlock(&sdio_ctl_devp->rx_lock); + r = wait_event_interruptible(sdio_ctl_devp->read_wait_queue, + sdio_ctl_devp->read_avail > 0 || + !is_remote_open(id)); + if (sdio_cmux_is_channel_reset(id)) + return -ENETRESET; + + if (!is_remote_open(id)) + return -ENODEV; + + if (r < 0) { + /* qualify error message */ + /* we get this anytime a signal comes in */ + if (r != -ERESTARTSYS) + pr_err("ERROR:%s: wait_event_interruptible " + "ret %i\n", __func__, r); + return r; + } + mutex_lock(&sdio_ctl_devp->rx_lock); + } + + if (list_empty(&sdio_ctl_devp->rx_list)) { + mutex_unlock(&sdio_ctl_devp->rx_lock); + D("%s: Nothing in ch%d's rx_list\n", __func__, + sdio_ctl_devp->id); + return -EAGAIN; + } + + list_elem = list_first_entry(&sdio_ctl_devp->rx_list, + struct sdio_ctl_list_elem, list); + bytes_to_read = (uint32_t)(list_elem->ctl_pkt.data_size); + if (bytes_to_read > count) { + mutex_unlock(&sdio_ctl_devp->rx_lock); + pr_err("%s: Packet size %d > buf size %d\n", __func__, + bytes_to_read, count); + return -ENOMEM; + } + + if (copy_to_user(buf, list_elem->ctl_pkt.data, bytes_to_read)) { + mutex_unlock(&sdio_ctl_devp->rx_lock); + pr_err("%s: copy_to_user failed for ch%d\n", __func__, + sdio_ctl_devp->id); + return -EFAULT; + } + sdio_ctl_devp->read_avail -= bytes_to_read; + list_del(&list_elem->list); + kfree(list_elem->ctl_pkt.data); + kfree(list_elem); + mutex_unlock(&sdio_ctl_devp->rx_lock); + D("%s: Returning %d bytes to ch%d\n", __func__, + bytes_to_read, sdio_ctl_devp->id); + return bytes_to_read; +} + + +ssize_t sdio_ctl_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int r = 0, id; + char *temp_buf; + struct sdio_ctl_dev *sdio_ctl_devp; + + if (count <= 0) + return -EINVAL; + + sdio_ctl_devp = file->private_data; + if (!sdio_ctl_devp) + return -ENODEV; + + D("%s: writing %i bytes on ch%d\n", + __func__, count, sdio_ctl_devp->id); + id = sdio_ctl_devp->id; + mutex_lock(&sdio_ctl_devp->dev_lock); + while (sdio_cmux_write_avail(id) < count) { + mutex_unlock(&sdio_ctl_devp->dev_lock); + r = wait_event_interruptible(sdio_ctl_devp->write_wait_queue, + sdio_cmux_write_avail(id) >= count + || !is_remote_open(id)); + + if (sdio_cmux_is_channel_reset(id)) + return -ENETRESET; + + if (!is_remote_open(id)) + return -ENODEV; + + if (r < 0) { + /* qualify error message */ + /* we get this anytime a signal comes in */ + if (r != -ERESTARTSYS) + pr_err("ERROR:%s: wait_event_interruptible " + "ret %i\n", __func__, r); + return r; + } + mutex_lock(&sdio_ctl_devp->dev_lock); + } + + temp_buf = kmalloc(count, GFP_KERNEL); + if (!temp_buf) { + mutex_unlock(&sdio_ctl_devp->dev_lock); + pr_err("%s: temp_buf alloc failed\n", __func__); + return -ENOMEM; + } + + if (copy_from_user(temp_buf, buf, count)) { + mutex_unlock(&sdio_ctl_devp->dev_lock); + pr_err("%s: copy_from_user failed\n", __func__); + kfree(temp_buf); + return -EFAULT; + } + + r = sdio_cmux_write(id, (void *)temp_buf, count); + kfree(temp_buf); + mutex_unlock(&sdio_ctl_devp->dev_lock); + return r; +} + + +int sdio_ctl_open(struct inode *inode, struct file *file) +{ + int r = 0; + struct sdio_ctl_dev *sdio_ctl_devp; + + if (!sdio_ctl_inited) + return -EIO; + + sdio_ctl_devp = container_of(inode->i_cdev, struct sdio_ctl_dev, cdev); + + if (!sdio_ctl_devp) + return -ENODEV; + + D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id); + r = sdio_cmux_open(sdio_ctl_devp->id, sdio_ctl_receive_cb, + sdio_ctl_write_done, NULL, + sdio_ctl_devp); + if (r < 0) { + pr_err("ERROR %s: sdio_cmux_open failed with rc %d\n", + __func__, r); + return r; + } + + mutex_lock(&sdio_ctl_devp->dev_lock); + sdio_ctl_devp->ref_count++; + mutex_unlock(&sdio_ctl_devp->dev_lock); + + file->private_data = sdio_ctl_devp; + return 0; +} + +int sdio_ctl_release(struct inode *inode, struct file *file) +{ + struct sdio_ctl_dev *sdio_ctl_devp; + struct sdio_ctl_list_elem *list_elem = NULL; + + sdio_ctl_devp = file->private_data; + if (!sdio_ctl_devp) + return -EINVAL; + + D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id); + + mutex_lock(&sdio_ctl_devp->dev_lock); + if (sdio_ctl_devp->ref_count > 0) { + sdio_ctl_devp->ref_count--; + if (!sdio_ctl_devp->ref_count) { + mutex_lock(&sdio_ctl_devp->rx_lock); + while (!list_empty(&sdio_ctl_devp->rx_list)) { + list_elem = list_first_entry( + &sdio_ctl_devp->rx_list, + struct sdio_ctl_list_elem, + list); + list_del(&list_elem->list); + kfree(list_elem->ctl_pkt.data); + kfree(list_elem); + } + sdio_ctl_devp->read_avail = 0; + mutex_unlock(&sdio_ctl_devp->rx_lock); + sdio_cmux_close(sdio_ctl_devp->id); + } + } + mutex_unlock(&sdio_ctl_devp->dev_lock); + + file->private_data = NULL; + return 0; +} + +static const struct file_operations sdio_ctl_fops = { + .owner = THIS_MODULE, + .open = sdio_ctl_open, + .release = sdio_ctl_release, + .read = sdio_ctl_read, + .write = sdio_ctl_write, + .poll = sdio_ctl_poll, + .unlocked_ioctl = sdio_ctl_ioctl, +}; + +static int sdio_ctl_probe(struct platform_device *pdev) +{ + int i; + int r; + + pr_info("%s Begins\n", __func__); + for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) { + sdio_ctl_devp[i] = kzalloc(sizeof(struct sdio_ctl_dev), + GFP_KERNEL); + if (IS_ERR(sdio_ctl_devp[i])) { + pr_err("ERROR:%s kmalloc() ENOMEM\n", __func__); + r = -ENOMEM; + goto error0; + } + + sdio_ctl_devp[i]->id = cmux_ch_id[i]; + sdio_ctl_devp[i]->ref_count = 0; + + mutex_init(&sdio_ctl_devp[i]->dev_lock); + init_waitqueue_head(&sdio_ctl_devp[i]->read_wait_queue); + init_waitqueue_head(&sdio_ctl_devp[i]->write_wait_queue); + mutex_init(&sdio_ctl_devp[i]->rx_lock); + INIT_LIST_HEAD(&sdio_ctl_devp[i]->rx_list); + sdio_ctl_devp[i]->read_avail = 0; + } + + r = alloc_chrdev_region(&sdio_ctl_number, 0, NUM_SDIO_CTL_PORTS, + DEVICE_NAME); + if (IS_ERR_VALUE(r)) { + pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n", + __func__, r); + goto error0; + } + + sdio_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(sdio_ctl_classp)) { + pr_err("ERROR:%s: class_create() ENOMEM\n", __func__); + r = -ENOMEM; + goto error1; + } + + for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) { + cdev_init(&sdio_ctl_devp[i]->cdev, &sdio_ctl_fops); + sdio_ctl_devp[i]->cdev.owner = THIS_MODULE; + + r = cdev_add(&sdio_ctl_devp[i]->cdev, (sdio_ctl_number + i), + 1); + + if (IS_ERR_VALUE(r)) { + pr_err("%s: cdev_add() ret %i\n", __func__, r); + kfree(sdio_ctl_devp[i]); + goto error2; + } + + sdio_ctl_devp[i]->devicep = + device_create(sdio_ctl_classp, NULL, + (sdio_ctl_number + i), NULL, + DEVICE_NAME "%d", cmux_ch_id[i]); + + if (IS_ERR(sdio_ctl_devp[i]->devicep)) { + pr_err("%s: device_create() ENOMEM\n", __func__); + r = -ENOMEM; + cdev_del(&sdio_ctl_devp[i]->cdev); + kfree(sdio_ctl_devp[i]); + goto error2; + } + } + + sdio_ctl_inited = 1; + D("SDIO Control Port Driver Initialized.\n"); + return 0; + +error2: + while (--i >= 0) { + cdev_del(&sdio_ctl_devp[i]->cdev); + device_destroy(sdio_ctl_classp, + MKDEV(MAJOR(sdio_ctl_number), i)); + } + + class_destroy(sdio_ctl_classp); + i = NUM_SDIO_CTL_PORTS; +error1: + unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS); +error0: + while (--i >= 0) + kfree(sdio_ctl_devp[i]); + return r; +} + +static int sdio_ctl_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) { + cdev_del(&sdio_ctl_devp[i]->cdev); + kfree(sdio_ctl_devp[i]); + device_destroy(sdio_ctl_classp, + MKDEV(MAJOR(sdio_ctl_number), i)); + } + class_destroy(sdio_ctl_classp); + unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS); + + return 0; +} + +static struct platform_driver sdio_ctl_driver = { + .probe = sdio_ctl_probe, + .remove = sdio_ctl_remove, + .driver = { + .name = "SDIO_CTL", + .owner = THIS_MODULE, + }, +}; + +static int __init sdio_ctl_init(void) +{ + msm_sdio_ctl_debug_mask = 0; + return platform_driver_register(&sdio_ctl_driver); +} + +module_init(sdio_ctl_init); +MODULE_DESCRIPTION("MSM SDIO Control Port"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/sdio_dmux.c b/arch/arm/mach-msm/sdio_dmux.c new file mode 100644 index 00000000..c6d665d9 --- /dev/null +++ b/arch/arm/mach-msm/sdio_dmux.c @@ -0,0 +1,925 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * SDIO DMUX module. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SDIO_CH_LOCAL_OPEN 0x1 +#define SDIO_CH_REMOTE_OPEN 0x2 +#define SDIO_CH_IN_RESET 0x4 + +#define SDIO_MUX_HDR_MAGIC_NO 0x33fc + +#define SDIO_MUX_HDR_CMD_DATA 0 +#define SDIO_MUX_HDR_CMD_OPEN 1 +#define SDIO_MUX_HDR_CMD_CLOSE 2 + +#define LOW_WATERMARK 2 +#define HIGH_WATERMARK 4 + +static int msm_sdio_dmux_debug_enable; +module_param_named(debug_enable, msm_sdio_dmux_debug_enable, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +#if defined(DEBUG) +static uint32_t sdio_dmux_read_cnt; +static uint32_t sdio_dmux_write_cnt; +static uint32_t sdio_dmux_write_cpy_cnt; +static uint32_t sdio_dmux_write_cpy_bytes; + +#define DBG(x...) do { \ + if (msm_sdio_dmux_debug_enable) \ + pr_debug(x); \ + } while (0) + +#define DBG_INC_READ_CNT(x) do { \ + sdio_dmux_read_cnt += (x); \ + if (msm_sdio_dmux_debug_enable) \ + pr_debug("%s: total read bytes %u\n", \ + __func__, sdio_dmux_read_cnt); \ + } while (0) + +#define DBG_INC_WRITE_CNT(x) do { \ + sdio_dmux_write_cnt += (x); \ + if (msm_sdio_dmux_debug_enable) \ + pr_debug("%s: total written bytes %u\n", \ + __func__, sdio_dmux_write_cnt); \ + } while (0) + +#define DBG_INC_WRITE_CPY(x) do { \ + sdio_dmux_write_cpy_bytes += (x); \ + sdio_dmux_write_cpy_cnt++; \ + if (msm_sdio_dmux_debug_enable) \ + pr_debug("%s: total write copy cnt %u, bytes %u\n", \ + __func__, sdio_dmux_write_cpy_cnt, \ + sdio_dmux_write_cpy_bytes); \ + } while (0) +#else +#define DBG(x...) do { } while (0) +#define DBG_INC_READ_CNT(x...) do { } while (0) +#define DBG_INC_WRITE_CNT(x...) do { } while (0) +#define DBG_INC_WRITE_CPY(x...) do { } while (0) +#endif + +struct sdio_ch_info { + uint32_t status; + void (*receive_cb)(void *, struct sk_buff *); + void (*write_done)(void *, struct sk_buff *); + void *priv; + spinlock_t lock; + int num_tx_pkts; + int use_wm; +}; + +static struct sk_buff_head sdio_mux_write_pool; +static spinlock_t sdio_mux_write_lock; + +static struct sdio_channel *sdio_mux_ch; +static struct sdio_ch_info sdio_ch[SDIO_DMUX_NUM_CHANNELS]; +struct wake_lock sdio_mux_ch_wakelock; +static int sdio_mux_initialized; +static int fatal_error; + +struct sdio_mux_hdr { + uint16_t magic_num; + uint8_t reserved; + uint8_t cmd; + uint8_t pad_len; + uint8_t ch_id; + uint16_t pkt_len; +}; + +struct sdio_partial_pkt_info { + uint32_t valid; + struct sk_buff *skb; + struct sdio_mux_hdr *hdr; +}; + +static void sdio_mux_read_data(struct work_struct *work); +static void sdio_mux_write_data(struct work_struct *work); +static void sdio_mux_send_open_cmd(uint32_t id); + +static DEFINE_MUTEX(sdio_mux_lock); +static DECLARE_WORK(work_sdio_mux_read, sdio_mux_read_data); +static DECLARE_WORK(work_sdio_mux_write, sdio_mux_write_data); +static DECLARE_DELAYED_WORK(delayed_work_sdio_mux_write, sdio_mux_write_data); + +static struct workqueue_struct *sdio_mux_workqueue; +static struct sdio_partial_pkt_info sdio_partial_pkt; + +#define sdio_ch_is_open(x) \ + (sdio_ch[(x)].status == (SDIO_CH_LOCAL_OPEN | SDIO_CH_REMOTE_OPEN)) + +#define sdio_ch_is_local_open(x) \ + (sdio_ch[(x)].status & SDIO_CH_LOCAL_OPEN) + +#define sdio_ch_is_remote_open(x) \ + (sdio_ch[(x)].status & SDIO_CH_REMOTE_OPEN) + +#define sdio_ch_is_in_reset(x) \ + (sdio_ch[(x)].status & SDIO_CH_IN_RESET) + +static inline void skb_set_data(struct sk_buff *skb, + unsigned char *data, + unsigned int len) +{ + /* panic if tail > end */ + skb->data = data; + skb->tail = skb->data + len; + skb->len = len; + skb->truesize = len + sizeof(struct sk_buff); +} + +static void sdio_mux_save_partial_pkt(struct sdio_mux_hdr *hdr, + struct sk_buff *skb_mux) +{ + struct sk_buff *skb; + + /* i think we can avoid cloning here */ + skb = skb_clone(skb_mux, GFP_KERNEL); + if (!skb) { + pr_err("%s: cannot clone skb\n", __func__); + return; + } + + /* protect? */ + skb_set_data(skb, (unsigned char *)hdr, + skb->tail - (unsigned char *)hdr); + sdio_partial_pkt.skb = skb; + sdio_partial_pkt.valid = 1; + DBG("%s: head %p data %p tail %p end %p len %d\n", __func__, + skb->head, skb->data, skb->tail, skb->end, skb->len); + return; +} + +static void *handle_sdio_mux_data(struct sdio_mux_hdr *hdr, + struct sk_buff *skb_mux) +{ + struct sk_buff *skb; + void *rp = (void *)hdr; + unsigned long flags; + + /* protect? */ + rp += sizeof(*hdr); + if (rp < (void *)skb_mux->tail) + rp += (hdr->pkt_len + hdr->pad_len); + + if (rp > (void *)skb_mux->tail) { + /* partial packet */ + sdio_mux_save_partial_pkt(hdr, skb_mux); + goto packet_done; + } + + DBG("%s: hdr %p next %p tail %p pkt_size %d\n", + __func__, hdr, rp, skb_mux->tail, hdr->pkt_len + hdr->pad_len); + + skb = skb_clone(skb_mux, GFP_KERNEL); + if (!skb) { + pr_err("%s: cannot clone skb\n", __func__); + goto packet_done; + } + + skb_set_data(skb, (unsigned char *)(hdr + 1), hdr->pkt_len); + DBG("%s: head %p data %p tail %p end %p len %d\n", + __func__, skb->head, skb->data, skb->tail, skb->end, skb->len); + + /* probably we should check channel status */ + /* discard packet early if local side not open */ + spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags); + if (sdio_ch[hdr->ch_id].receive_cb) + sdio_ch[hdr->ch_id].receive_cb(sdio_ch[hdr->ch_id].priv, skb); + else + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags); + +packet_done: + return rp; +} + +static void *handle_sdio_mux_command(struct sdio_mux_hdr *hdr, + struct sk_buff *skb_mux) +{ + void *rp; + unsigned long flags; + int send_open = 0; + + DBG("%s: cmd %d ch %d\n", __func__, hdr->cmd, hdr->ch_id); + switch (hdr->cmd) { + case SDIO_MUX_HDR_CMD_DATA: + rp = handle_sdio_mux_data(hdr, skb_mux); + break; + case SDIO_MUX_HDR_CMD_OPEN: + spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags); + sdio_ch[hdr->ch_id].status |= SDIO_CH_REMOTE_OPEN; + sdio_ch[hdr->ch_id].num_tx_pkts = 0; + + if (sdio_ch_is_in_reset(hdr->ch_id)) { + DBG("%s: in reset - sending open cmd\n", __func__); + sdio_ch[hdr->ch_id].status &= ~SDIO_CH_IN_RESET; + send_open = 1; + } + + /* notify client so it can update its status */ + if (sdio_ch[hdr->ch_id].receive_cb) + sdio_ch[hdr->ch_id].receive_cb( + sdio_ch[hdr->ch_id].priv, NULL); + + if (sdio_ch[hdr->ch_id].write_done) + sdio_ch[hdr->ch_id].write_done( + sdio_ch[hdr->ch_id].priv, NULL); + spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags); + rp = hdr + 1; + if (send_open) + sdio_mux_send_open_cmd(hdr->ch_id); + + break; + case SDIO_MUX_HDR_CMD_CLOSE: + /* probably should drop pending write */ + spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags); + sdio_ch[hdr->ch_id].status &= ~SDIO_CH_REMOTE_OPEN; + spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags); + rp = hdr + 1; + break; + default: + rp = hdr + 1; + } + + return rp; +} + +static void *handle_sdio_partial_pkt(struct sk_buff *skb_mux) +{ + struct sk_buff *p_skb; + struct sdio_mux_hdr *p_hdr; + void *ptr, *rp = skb_mux->data; + + /* protoect? */ + if (sdio_partial_pkt.valid) { + p_skb = sdio_partial_pkt.skb; + + ptr = skb_push(skb_mux, p_skb->len); + memcpy(ptr, p_skb->data, p_skb->len); + sdio_partial_pkt.skb = NULL; + sdio_partial_pkt.valid = 0; + dev_kfree_skb_any(p_skb); + + DBG("%s: head %p data %p tail %p end %p len %d\n", __func__, + skb_mux->head, skb_mux->data, skb_mux->tail, + skb_mux->end, skb_mux->len); + + p_hdr = (struct sdio_mux_hdr *)skb_mux->data; + rp = handle_sdio_mux_command(p_hdr, skb_mux); + } + return rp; +} + +static void sdio_mux_read_data(struct work_struct *work) +{ + struct sk_buff *skb_mux; + void *ptr = 0; + int sz, rc, len = 0; + struct sdio_mux_hdr *hdr; + static int workqueue_pinned; + + if (!workqueue_pinned) { + struct cpumask cpus; + + cpumask_clear(&cpus); + cpumask_set_cpu(0, &cpus); + + if (sched_setaffinity(current->pid, &cpus)) + pr_err("%s: sdio_dmux set CPU affinity failed\n", + __func__); + workqueue_pinned = 1; + } + + DBG("%s: reading\n", __func__); + /* should probably have a separate read lock */ + mutex_lock(&sdio_mux_lock); + sz = sdio_read_avail(sdio_mux_ch); + DBG("%s: read avail %d\n", __func__, sz); + if (sz <= 0) { + if (sz) + pr_err("%s: read avail failed %d\n", __func__, sz); + mutex_unlock(&sdio_mux_lock); + return; + } + + /* net_ip_aling is probably not required */ + if (sdio_partial_pkt.valid) + len = sdio_partial_pkt.skb->len; + + /* If allocation fails attempt to get a smaller chunk of mem */ + do { + skb_mux = __dev_alloc_skb(sz + NET_IP_ALIGN + len, GFP_KERNEL); + if (skb_mux) + break; + + pr_err("%s: cannot allocate skb of size:%d + " + "%d (NET_SKB_PAD)\n", __func__, + sz + NET_IP_ALIGN + len, NET_SKB_PAD); + /* the skb structure adds NET_SKB_PAD bytes to the memory + * request, which may push the actual request above PAGE_SIZE + * in that case, we need to iterate one more time to make sure + * we get the memory request under PAGE_SIZE + */ + if (sz + NET_IP_ALIGN + len + NET_SKB_PAD <= PAGE_SIZE) { + pr_err("%s: allocation failed\n", __func__); + mutex_unlock(&sdio_mux_lock); + return; + } + sz /= 2; + } while (1); + + skb_reserve(skb_mux, NET_IP_ALIGN + len); + ptr = skb_put(skb_mux, sz); + + /* half second wakelock is fine? */ + wake_lock_timeout(&sdio_mux_ch_wakelock, HZ / 2); + rc = sdio_read(sdio_mux_ch, ptr, sz); + DBG("%s: read %d\n", __func__, rc); + if (rc) { + pr_err("%s: sdio read failed %d\n", __func__, rc); + dev_kfree_skb_any(skb_mux); + mutex_unlock(&sdio_mux_lock); + queue_work(sdio_mux_workqueue, &work_sdio_mux_read); + return; + } + mutex_unlock(&sdio_mux_lock); + + DBG_INC_READ_CNT(sz); + DBG("%s: head %p data %p tail %p end %p len %d\n", __func__, + skb_mux->head, skb_mux->data, skb_mux->tail, + skb_mux->end, skb_mux->len); + + /* move to a separate function */ + /* probably do skb_pull instead of pointer adjustment */ + hdr = handle_sdio_partial_pkt(skb_mux); + while ((void *)hdr < (void *)skb_mux->tail) { + + if (((void *)hdr + sizeof(*hdr)) > (void *)skb_mux->tail) { + /* handle partial header */ + sdio_mux_save_partial_pkt(hdr, skb_mux); + break; + } + + if (hdr->magic_num != SDIO_MUX_HDR_MAGIC_NO) { + pr_err("%s: packet error\n", __func__); + break; + } + + hdr = handle_sdio_mux_command(hdr, skb_mux); + } + dev_kfree_skb_any(skb_mux); + + DBG("%s: read done\n", __func__); + queue_work(sdio_mux_workqueue, &work_sdio_mux_read); +} + +static int sdio_mux_write(struct sk_buff *skb) +{ + int rc, sz; + + mutex_lock(&sdio_mux_lock); + sz = sdio_write_avail(sdio_mux_ch); + DBG("%s: avail %d len %d\n", __func__, sz, skb->len); + if (skb->len <= sz) { + rc = sdio_write(sdio_mux_ch, skb->data, skb->len); + DBG("%s: write returned %d\n", __func__, rc); + if (rc == 0) + DBG_INC_WRITE_CNT(skb->len); + } else + rc = -ENOMEM; + + mutex_unlock(&sdio_mux_lock); + return rc; +} + +static int sdio_mux_write_cmd(void *data, uint32_t len) +{ + int avail, rc; + for (;;) { + mutex_lock(&sdio_mux_lock); + avail = sdio_write_avail(sdio_mux_ch); + DBG("%s: avail %d len %d\n", __func__, avail, len); + if (avail >= len) { + rc = sdio_write(sdio_mux_ch, data, len); + DBG("%s: write returned %d\n", __func__, rc); + if (!rc) { + DBG_INC_WRITE_CNT(len); + break; + } + } + mutex_unlock(&sdio_mux_lock); + msleep(250); + } + mutex_unlock(&sdio_mux_lock); + return 0; +} + +static void sdio_mux_send_open_cmd(uint32_t id) +{ + struct sdio_mux_hdr hdr = { + .magic_num = SDIO_MUX_HDR_MAGIC_NO, + .cmd = SDIO_MUX_HDR_CMD_OPEN, + .reserved = 0, + .ch_id = id, + .pkt_len = 0, + .pad_len = 0 + }; + + sdio_mux_write_cmd((void *)&hdr, sizeof(hdr)); +} + +static void sdio_mux_write_data(struct work_struct *work) +{ + int rc, reschedule = 0; + int notify = 0; + struct sk_buff *skb; + unsigned long flags; + int avail; + int ch_id; + + spin_lock_irqsave(&sdio_mux_write_lock, flags); + while ((skb = __skb_dequeue(&sdio_mux_write_pool))) { + ch_id = ((struct sdio_mux_hdr *)skb->data)->ch_id; + + avail = sdio_write_avail(sdio_mux_ch); + if (avail < skb->len) { + /* we may have to wait for write avail + * notification from sdio al + */ + DBG("%s: sdio_write_avail(%d) < skb->len(%d)\n", + __func__, avail, skb->len); + + reschedule = 1; + break; + } + spin_unlock_irqrestore(&sdio_mux_write_lock, flags); + rc = sdio_mux_write(skb); + spin_lock_irqsave(&sdio_mux_write_lock, flags); + if (rc == 0) { + + spin_lock(&sdio_ch[ch_id].lock); + sdio_ch[ch_id].num_tx_pkts--; + spin_unlock(&sdio_ch[ch_id].lock); + + if (sdio_ch[ch_id].write_done) + sdio_ch[ch_id].write_done( + sdio_ch[ch_id].priv, skb); + else + dev_kfree_skb_any(skb); + } else if (rc == -EAGAIN || rc == -ENOMEM) { + /* recoverable error - retry again later */ + reschedule = 1; + break; + } else if (rc == -ENODEV) { + /* + * sdio_al suffered some kind of fatal error + * prevent future writes and clean up pending ones + */ + fatal_error = 1; + do { + ch_id = ((struct sdio_mux_hdr *) + skb->data)->ch_id; + spin_lock(&sdio_ch[ch_id].lock); + sdio_ch[ch_id].num_tx_pkts--; + spin_unlock(&sdio_ch[ch_id].lock); + dev_kfree_skb_any(skb); + } while ((skb = __skb_dequeue(&sdio_mux_write_pool))); + spin_unlock_irqrestore(&sdio_mux_write_lock, flags); + return; + } else { + /* unknown error condition - drop the + * skb and reschedule for the + * other skb's + */ + pr_err("%s: sdio_mux_write error %d" + " for ch %d, skb=%p\n", + __func__, rc, ch_id, skb); + notify = 1; + break; + } + } + + if (reschedule) { + if (sdio_ch_is_in_reset(ch_id)) { + notify = 1; + } else { + __skb_queue_head(&sdio_mux_write_pool, skb); + queue_delayed_work(sdio_mux_workqueue, + &delayed_work_sdio_mux_write, + msecs_to_jiffies(250) + ); + } + } + + if (notify) { + spin_lock(&sdio_ch[ch_id].lock); + sdio_ch[ch_id].num_tx_pkts--; + spin_unlock(&sdio_ch[ch_id].lock); + + if (sdio_ch[ch_id].write_done) + sdio_ch[ch_id].write_done( + sdio_ch[ch_id].priv, skb); + else + dev_kfree_skb_any(skb); + } + spin_unlock_irqrestore(&sdio_mux_write_lock, flags); +} + +int msm_sdio_is_channel_in_reset(uint32_t id) +{ + int rc = 0; + + if (id >= SDIO_DMUX_NUM_CHANNELS) + return -EINVAL; + + if (sdio_ch_is_in_reset(id)) + rc = 1; + + return rc; +} + +int msm_sdio_dmux_write(uint32_t id, struct sk_buff *skb) +{ + int rc = 0; + struct sdio_mux_hdr *hdr; + unsigned long flags; + struct sk_buff *new_skb; + + if (id >= SDIO_DMUX_NUM_CHANNELS) + return -EINVAL; + if (!skb) + return -EINVAL; + if (!sdio_mux_initialized) + return -ENODEV; + if (fatal_error) + return -ENODEV; + + DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len); + spin_lock_irqsave(&sdio_ch[id].lock, flags); + if (sdio_ch_is_in_reset(id)) { + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + pr_err("%s: port is in reset: %d\n", __func__, + sdio_ch[id].status); + return -ENETRESET; + } + if (!sdio_ch_is_local_open(id)) { + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status); + return -ENODEV; + } + if (sdio_ch[id].use_wm && + (sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK)) { + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + pr_err("%s: watermark exceeded: %d\n", __func__, id); + return -EAGAIN; + } + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + + spin_lock_irqsave(&sdio_mux_write_lock, flags); + /* if skb do not have any tailroom for padding, + copy the skb into a new expanded skb */ + if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) { + /* revisit, probably dev_alloc_skb and memcpy is effecient */ + new_skb = skb_copy_expand(skb, skb_headroom(skb), + 4 - (skb->len & 0x3), GFP_ATOMIC); + if (new_skb == NULL) { + pr_err("%s: cannot allocate skb\n", __func__); + rc = -ENOMEM; + goto write_done; + } + dev_kfree_skb_any(skb); + skb = new_skb; + DBG_INC_WRITE_CPY(skb->len); + } + + hdr = (struct sdio_mux_hdr *)skb_push(skb, sizeof(struct sdio_mux_hdr)); + + /* caller should allocate for hdr and padding + hdr is fine, padding is tricky */ + hdr->magic_num = SDIO_MUX_HDR_MAGIC_NO; + hdr->cmd = SDIO_MUX_HDR_CMD_DATA; + hdr->reserved = 0; + hdr->ch_id = id; + hdr->pkt_len = skb->len - sizeof(struct sdio_mux_hdr); + if (skb->len & 0x3) + skb_put(skb, 4 - (skb->len & 0x3)); + + hdr->pad_len = skb->len - (sizeof(struct sdio_mux_hdr) + hdr->pkt_len); + + DBG("%s: data %p, tail %p skb len %d pkt len %d pad len %d\n", + __func__, skb->data, skb->tail, skb->len, + hdr->pkt_len, hdr->pad_len); + __skb_queue_tail(&sdio_mux_write_pool, skb); + + spin_lock(&sdio_ch[id].lock); + sdio_ch[id].num_tx_pkts++; + spin_unlock(&sdio_ch[id].lock); + + queue_work(sdio_mux_workqueue, &work_sdio_mux_write); + +write_done: + spin_unlock_irqrestore(&sdio_mux_write_lock, flags); + return rc; +} + +int msm_sdio_dmux_open(uint32_t id, void *priv, + void (*receive_cb)(void *, struct sk_buff *), + void (*write_done)(void *, struct sk_buff *)) +{ + unsigned long flags; + + DBG("%s: opening ch %d\n", __func__, id); + if (!sdio_mux_initialized) + return -ENODEV; + if (id >= SDIO_DMUX_NUM_CHANNELS) + return -EINVAL; + + spin_lock_irqsave(&sdio_ch[id].lock, flags); + if (sdio_ch_is_local_open(id)) { + pr_info("%s: Already opened %d\n", __func__, id); + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + goto open_done; + } + + sdio_ch[id].receive_cb = receive_cb; + sdio_ch[id].write_done = write_done; + sdio_ch[id].priv = priv; + sdio_ch[id].status |= SDIO_CH_LOCAL_OPEN; + sdio_ch[id].num_tx_pkts = 0; + sdio_ch[id].use_wm = 0; + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + + sdio_mux_send_open_cmd(id); + +open_done: + pr_info("%s: opened ch %d\n", __func__, id); + return 0; +} + +int msm_sdio_dmux_close(uint32_t id) +{ + struct sdio_mux_hdr hdr; + unsigned long flags; + + if (id >= SDIO_DMUX_NUM_CHANNELS) + return -EINVAL; + DBG("%s: closing ch %d\n", __func__, id); + if (!sdio_mux_initialized) + return -ENODEV; + spin_lock_irqsave(&sdio_ch[id].lock, flags); + + sdio_ch[id].receive_cb = NULL; + sdio_ch[id].priv = NULL; + sdio_ch[id].status &= ~SDIO_CH_LOCAL_OPEN; + sdio_ch[id].status &= ~SDIO_CH_IN_RESET; + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + + hdr.magic_num = SDIO_MUX_HDR_MAGIC_NO; + hdr.cmd = SDIO_MUX_HDR_CMD_CLOSE; + hdr.reserved = 0; + hdr.ch_id = id; + hdr.pkt_len = 0; + hdr.pad_len = 0; + + sdio_mux_write_cmd((void *)&hdr, sizeof(hdr)); + + pr_info("%s: closed ch %d\n", __func__, id); + return 0; +} + +static void sdio_mux_notify(void *_dev, unsigned event) +{ + DBG("%s: event %d notified\n", __func__, event); + + /* write avail may not be enouogh for a packet, but should be fine */ + if ((event == SDIO_EVENT_DATA_WRITE_AVAIL) && + sdio_write_avail(sdio_mux_ch)) + queue_work(sdio_mux_workqueue, &work_sdio_mux_write); + + if ((event == SDIO_EVENT_DATA_READ_AVAIL) && + sdio_read_avail(sdio_mux_ch)) + queue_work(sdio_mux_workqueue, &work_sdio_mux_read); +} + +int msm_sdio_dmux_is_ch_full(uint32_t id) +{ + unsigned long flags; + int ret; + + if (id >= SDIO_DMUX_NUM_CHANNELS) + return -EINVAL; + + spin_lock_irqsave(&sdio_ch[id].lock, flags); + sdio_ch[id].use_wm = 1; + ret = sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK; + DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__, + id, sdio_ch[id].num_tx_pkts, ret); + if (!sdio_ch_is_local_open(id)) { + ret = -ENODEV; + pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status); + } + spin_unlock_irqrestore(&sdio_ch[id].lock, flags); + + return ret; +} + +int msm_sdio_dmux_is_ch_low(uint32_t id) +{ + int ret; + + if (id >= SDIO_DMUX_NUM_CHANNELS) + return -EINVAL; + + sdio_ch[id].use_wm = 1; + ret = sdio_ch[id].num_tx_pkts <= LOW_WATERMARK; + DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__, + id, sdio_ch[id].num_tx_pkts, ret); + if (!sdio_ch_is_local_open(id)) { + ret = -ENODEV; + pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status); + } + + return ret; +} + +#ifdef CONFIG_DEBUG_FS + +static int debug_tbl(char *buf, int max) +{ + int i = 0; + int j; + + for (j = 0; j < SDIO_DMUX_NUM_CHANNELS; ++j) { + i += scnprintf(buf + i, max - i, + "ch%02d local open=%s remote open=%s\n", + j, sdio_ch_is_local_open(j) ? "Y" : "N", + sdio_ch_is_remote_open(j) ? "Y" : "N"); + } + + return i; +} + +#define DEBUG_BUFMAX 4096 +static char debug_buffer[DEBUG_BUFMAX]; + +static ssize_t debug_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int (*fill)(char *buf, int max) = file->private_data; + int bsize = fill(debug_buffer, DEBUG_BUFMAX); + return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); +} + +static int debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + + +static const struct file_operations debug_ops = { + .read = debug_read, + .open = debug_open, +}; + +static void debug_create(const char *name, mode_t mode, + struct dentry *dent, + int (*fill)(char *buf, int max)) +{ + debugfs_create_file(name, mode, dent, fill, &debug_ops); +} + +#endif + +static int sdio_dmux_probe(struct platform_device *pdev) +{ + int rc; + + DBG("%s probe called\n", __func__); + + if (!sdio_mux_initialized) { + sdio_mux_workqueue = create_singlethread_workqueue("sdio_dmux"); + if (!sdio_mux_workqueue) + return -ENOMEM; + + skb_queue_head_init(&sdio_mux_write_pool); + spin_lock_init(&sdio_mux_write_lock); + + for (rc = 0; rc < SDIO_DMUX_NUM_CHANNELS; ++rc) + spin_lock_init(&sdio_ch[rc].lock); + + + wake_lock_init(&sdio_mux_ch_wakelock, WAKE_LOCK_SUSPEND, + "sdio_dmux"); + } + + rc = sdio_open("SDIO_RMNT", &sdio_mux_ch, NULL, sdio_mux_notify); + if (rc < 0) { + pr_err("%s: sido open failed %d\n", __func__, rc); + wake_lock_destroy(&sdio_mux_ch_wakelock); + destroy_workqueue(sdio_mux_workqueue); + sdio_mux_initialized = 0; + return rc; + } + + fatal_error = 0; + sdio_mux_initialized = 1; + return 0; +} + +static int sdio_dmux_remove(struct platform_device *pdev) +{ + int i; + unsigned long ch_lock_flags; + unsigned long write_lock_flags; + struct sk_buff *skb; + + DBG("%s remove called\n", __func__); + if (!sdio_mux_initialized) + return 0; + + /* set reset state for any open channels */ + for (i = 0; i < SDIO_DMUX_NUM_CHANNELS; ++i) { + spin_lock_irqsave(&sdio_ch[i].lock, ch_lock_flags); + if (sdio_ch_is_open(i)) { + sdio_ch[i].status |= SDIO_CH_IN_RESET; + sdio_ch[i].status &= ~SDIO_CH_REMOTE_OPEN; + + /* notify client so it can update its status */ + if (sdio_ch[i].receive_cb) + sdio_ch[i].receive_cb( + sdio_ch[i].priv, NULL); + } + spin_unlock_irqrestore(&sdio_ch[i].lock, ch_lock_flags); + } + + /* cancel any pending writes */ + spin_lock_irqsave(&sdio_mux_write_lock, write_lock_flags); + while ((skb = __skb_dequeue(&sdio_mux_write_pool))) { + i = ((struct sdio_mux_hdr *)skb->data)->ch_id; + if (sdio_ch[i].write_done) + sdio_ch[i].write_done( + sdio_ch[i].priv, skb); + else + dev_kfree_skb_any(skb); + } + spin_unlock_irqrestore(&sdio_mux_write_lock, + write_lock_flags); + + return 0; +} + +static struct platform_driver sdio_dmux_driver = { + .probe = sdio_dmux_probe, + .remove = sdio_dmux_remove, + .driver = { + .name = "SDIO_RMNT", + .owner = THIS_MODULE, + }, +}; + +static int __init sdio_dmux_init(void) +{ +#ifdef CONFIG_DEBUG_FS + struct dentry *dent; + + dent = debugfs_create_dir("sdio_dmux", 0); + if (!IS_ERR(dent)) + debug_create("tbl", 0444, dent, debug_tbl); +#endif + return platform_driver_register(&sdio_dmux_driver); +} + +module_init(sdio_dmux_init); +MODULE_DESCRIPTION("MSM SDIO DMUX"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/sdio_smem.c b/arch/arm/mach-msm/sdio_smem.c new file mode 100644 index 00000000..edc0d23e --- /dev/null +++ b/arch/arm/mach-msm/sdio_smem.c @@ -0,0 +1,175 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include + +static void sdio_smem_read(struct work_struct *work); + +static struct sdio_channel *channel; +static struct workqueue_struct *workq; +static DECLARE_WORK(work_read, sdio_smem_read); +static DECLARE_WAIT_QUEUE_HEAD(waitq); +static int bytes_avail; +static int sdio_ch_opened; + +static void sdio_smem_release(struct device *dev) +{ + pr_debug("sdio smem released\n"); +} + +static struct sdio_smem_client client; + +static void sdio_smem_read(struct work_struct *work) +{ + int err; + int read_avail; + char *data = client.buf; + + if (!sdio_ch_opened) + return; + + read_avail = sdio_read_avail(channel); + if (read_avail > bytes_avail || + read_avail < 0) { + pr_err("Error: read_avail=%d bytes_avail=%d\n", + read_avail, bytes_avail); + goto read_err; + } + + if (read_avail == 0) + return; + + err = sdio_read(channel, + &data[client.size - bytes_avail], + read_avail); + if (err) { + pr_err("sdio_read error (%d)", err); + goto read_err; + } + + bytes_avail -= read_avail; + pr_debug("read %d bytes (bytes_avail = %d)\n", + read_avail, bytes_avail); + + if (!bytes_avail) { + bytes_avail = client.size; + err = client.cb_func(SDIO_SMEM_EVENT_READ_DONE); + } + if (err) + pr_err("error (%d) on callback\n", err); + + return; + +read_err: + if (sdio_ch_opened) + client.cb_func(SDIO_SMEM_EVENT_READ_ERR); + return; +} + +static void sdio_smem_notify(void *priv, unsigned event) +{ + pr_debug("%d event received\n", event); + + if (event == SDIO_EVENT_DATA_READ_AVAIL || + event == SDIO_EVENT_DATA_WRITE_AVAIL) + queue_work(workq, &work_read); +} + +int sdio_smem_register_client(void) +{ + int err = 0; + + if (!client.buf || !client.size || !client.cb_func) + return -EINVAL; + + pr_debug("buf = %p\n", client.buf); + pr_debug("size = 0x%x\n", client.size); + + bytes_avail = client.size; + workq = create_singlethread_workqueue("sdio_smem"); + if (!workq) + return -ENOMEM; + + sdio_ch_opened = 1; + err = sdio_open("SDIO_SMEM", &channel, NULL, sdio_smem_notify); + if (err) { + sdio_ch_opened = 0; + pr_err("sdio_open error (%d)\n", err); + destroy_workqueue(workq); + return err; + } + pr_debug("SDIO SMEM channel opened\n"); + return err; +} + +int sdio_smem_unregister_client(void) +{ + int err = 0; + + sdio_ch_opened = 0; + err = sdio_close(channel); + if (err) { + pr_err("sdio_close error (%d)\n", err); + return err; + } + pr_debug("SDIO SMEM channel closed\n"); + flush_workqueue(workq); + destroy_workqueue(workq); + bytes_avail = 0; + client.buf = NULL; + client.cb_func = NULL; + client.size = 0; + + return 0; +} + +static int sdio_smem_probe(struct platform_device *pdev) +{ + client.plat_dev.name = "SDIO_SMEM_CLIENT"; + client.plat_dev.id = -1; + client.plat_dev.dev.release = sdio_smem_release; + + return platform_device_register(&client.plat_dev); +} + +static int sdio_smem_remove(struct platform_device *pdev) +{ + platform_device_unregister(&client.plat_dev); + memset(&client, 0, sizeof(client)); + sdio_ch_opened = 0; + return 0; +} +static struct platform_driver sdio_smem_drv = { + .probe = sdio_smem_probe, + .remove = sdio_smem_remove, + .driver = { + .name = "SDIO_SMEM", + .owner = THIS_MODULE, + }, +}; + +static int __init sdio_smem_init(void) +{ + return platform_driver_register(&sdio_smem_drv); +}; + +module_init(sdio_smem_init); + +MODULE_DESCRIPTION("SDIO SMEM"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c new file mode 100644 index 00000000..c4b76733 --- /dev/null +++ b/arch/arm/mach-msm/sdio_tty.c @@ -0,0 +1,824 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INPUT_SPEED 4800 +#define OUTPUT_SPEED 4800 +#define SDIO_TTY_MODULE_NAME "sdio_tty" +#define SDIO_TTY_MAX_PACKET_SIZE 4096 +#define MAX_SDIO_TTY_DRV 1 +#define MAX_SDIO_TTY_DEVS 2 +#define MAX_SDIO_TTY_DEV_NAME_SIZE 25 + +/* Configurations per channel device */ +/* CSVT */ +#define SDIO_TTY_CSVT_DEV "sdio_tty_csvt_0" +#define SDIO_TTY_CSVT_TEST_DEV "sdio_tty_csvt_test_0" +#define SDIO_TTY_CH_CSVT "SDIO_CSVT" + +enum sdio_tty_state { + TTY_INITIAL = 0, + TTY_REGISTERED = 1, + TTY_OPENED = 2, + TTY_CLOSED = 3, +}; + +enum sdio_tty_devices { + SDIO_CSVT, + SDIO_CSVT_TEST_APP, +}; + +static const struct platform_device_id sdio_tty_id_table[] = { + { "SDIO_CSVT", SDIO_CSVT }, + { "SDIO_CSVT_TEST_APP", SDIO_CSVT_TEST_APP }, + { }, +}; +MODULE_DEVICE_TABLE(platform, sdio_tty_id_table); + +struct sdio_tty { + struct sdio_channel *ch; + char *sdio_ch_name; + char tty_dev_name[MAX_SDIO_TTY_DEV_NAME_SIZE]; + int device_id; + struct workqueue_struct *workq; + struct work_struct work_read; + wait_queue_head_t waitq; + struct tty_driver *tty_drv; + struct tty_struct *tty_str; + int debug_msg_on; + char *read_buf; + enum sdio_tty_state sdio_tty_state; + int is_sdio_open; + int tty_open_count; + int total_rx; + int total_tx; +}; + +static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS]; + +#ifdef CONFIG_DEBUG_FS +struct dentry *sdio_tty_debug_root; +struct dentry *sdio_tty_debug_info; +#endif + +#define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x) + +/* + * Enable sdio_tty debug messages + * By default the sdio_tty debug messages are turned off + */ +static int csvt_debug_msg_on; +module_param(csvt_debug_msg_on, int, 0); + +static void sdio_tty_read(struct work_struct *work) +{ + int ret = 0; + int read_avail = 0; + int left = 0; + int total_push = 0; + int num_push = 0; + struct sdio_tty *sdio_tty_drv = NULL; + + sdio_tty_drv = container_of(work, struct sdio_tty, work_read); + + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty", __func__); + return ; + } + + if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d", + __func__, sdio_tty_drv->sdio_tty_state); + return; + } + + if (!sdio_tty_drv->read_buf) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf for dev %s", + __func__, sdio_tty_drv->tty_dev_name); + return; + } + + /* Read the data from the SDIO channel as long as there is available + data */ + while (1) { + if (test_bit(TTY_THROTTLED, &sdio_tty_drv->tty_str->flags)) { + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME + ": %s: TTY_THROTTLED bit is set for " + "dev %s, exit", __func__, + sdio_tty_drv->tty_dev_name); + return; + } + + total_push = 0; + read_avail = sdio_read_avail(sdio_tty_drv->ch); + + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME + ": %s: read_avail is %d for dev %s", __func__, + read_avail, sdio_tty_drv->tty_dev_name); + + if (read_avail == 0) { + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME + ": %s: read_avail is 0 for dev %s", + __func__, sdio_tty_drv->tty_dev_name); + return; + } + + if (read_avail > SDIO_TTY_MAX_PACKET_SIZE) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: read_avail(%d) is " + "bigger than SDIO_TTY_MAX_PACKET_SIZE(%d) " + "for dev %s", __func__, read_avail, + SDIO_TTY_MAX_PACKET_SIZE, + sdio_tty_drv->tty_dev_name); + return; + } + + ret = sdio_read(sdio_tty_drv->ch, + sdio_tty_drv->read_buf, + read_avail); + if (ret < 0) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d) " + "for dev %s", __func__, ret, + sdio_tty_drv->tty_dev_name); + return; + } + + left = read_avail; + do { + num_push = tty_insert_flip_string( + sdio_tty_drv->tty_str, + sdio_tty_drv->read_buf+total_push, + left); + total_push += num_push; + left -= num_push; + tty_flip_buffer_push(sdio_tty_drv->tty_str); + } while (left != 0); + + if (total_push != read_avail) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: failed, total_push" + "(%d) != read_avail(%d) for dev %s\n", + __func__, total_push, read_avail, + sdio_tty_drv->tty_dev_name); + } + + tty_flip_buffer_push(sdio_tty_drv->tty_str); + sdio_tty_drv->total_rx += read_avail; + + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Rx: %d, " + "Total Rx = %d bytes for dev %s", __func__, + read_avail, sdio_tty_drv->total_rx, + sdio_tty_drv->tty_dev_name); + } +} + +/** + * sdio_tty_write_room + * + * This is the write_room function of the tty driver. + * + * @tty: pointer to tty struct. + * @return free bytes for write. + * + */ +static int sdio_tty_write_room(struct tty_struct *tty) +{ + int write_avail = 0; + struct sdio_tty *sdio_tty_drv = NULL; + + if (!tty) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__); + return -ENODEV; + } + sdio_tty_drv = tty->driver_data; + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + return -ENODEV; + } + + if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d", + __func__, sdio_tty_drv->sdio_tty_state); + return -EPERM; + } + + write_avail = sdio_write_avail(sdio_tty_drv->ch); + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: write_avail=%d " + "for dev %s", __func__, write_avail, + sdio_tty_drv->tty_dev_name); + + return write_avail; +} + +/** + * sdio_tty_write_callback + * this is the write callback of the tty driver. + * + * @tty: pointer to tty struct. + * @buf: buffer to write from. + * @count: number of bytes to write. + * @return bytes written or negative value on error. + * + * if destination buffer has not enough room for the incoming + * data, writes the possible amount of bytes . + */ +static int sdio_tty_write_callback(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + int write_avail = 0; + int len = count; + int ret = 0; + struct sdio_tty *sdio_tty_drv = NULL; + + if (!tty) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__); + return -ENODEV; + } + sdio_tty_drv = tty->driver_data; + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + return -ENODEV; + } + + if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d", + __func__, sdio_tty_drv->sdio_tty_state); + return -EPERM; + } + + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Write Callback " + "called with %d bytes for dev %s\n", __func__, count, + sdio_tty_drv->tty_dev_name); + write_avail = sdio_write_avail(sdio_tty_drv->ch); + if (write_avail == 0) { + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: " + "write_avail is 0 for dev %s\n", + __func__, sdio_tty_drv->tty_dev_name); + return 0; + } + if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) { + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: " + "write_avail(%d) is bigger than max packet " + "size(%d) for dev %s, setting to " + "max_packet_size\n", __func__, write_avail, + SDIO_TTY_MAX_PACKET_SIZE, + sdio_tty_drv->tty_dev_name); + write_avail = SDIO_TTY_MAX_PACKET_SIZE; + } + if (write_avail < count) { + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: " + "write_avail(%d) is smaller than required(%d) " + "for dev %s, writing only %d bytes\n", + __func__, write_avail, count, + sdio_tty_drv->tty_dev_name, write_avail); + len = write_avail; + } + ret = sdio_write(sdio_tty_drv->ch, buf, len); + if (ret) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed for " + "dev %s, ret=%d\n", __func__, + sdio_tty_drv->tty_dev_name, ret); + return 0; + } + + sdio_tty_drv->total_tx += len; + + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Tx: %d, " + "Total Tx = %d for dev %s", __func__, len, + sdio_tty_drv->total_tx, sdio_tty_drv->tty_dev_name); + return len; +} + +static void sdio_tty_notify(void *priv, unsigned event) +{ + struct sdio_tty *sdio_tty_drv = priv; + + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + } + + if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d", + __func__, sdio_tty_drv->sdio_tty_state); + return; + } + + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: event %d " + "received for dev %s\n", __func__, event, + sdio_tty_drv->tty_dev_name); + + if (event == SDIO_EVENT_DATA_READ_AVAIL) + queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read); +} + +/** + * sdio_tty_open + * This is the open callback of the tty driver. it opens + * the sdio channel, and creates the workqueue. + * + * @tty: a pointer to the tty struct. + * @file: file descriptor. + * @return 0 on success or negative value on error. + */ +static int sdio_tty_open(struct tty_struct *tty, struct file *file) +{ + int ret = 0; + int i = 0; + struct sdio_tty *sdio_tty_drv = NULL; + + if (!tty) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__); + return -ENODEV; + } + + for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) { + if (sdio_tty[i] == NULL) + continue; + if (!strncmp(sdio_tty[i]->tty_dev_name, tty->name, + MAX_SDIO_TTY_DEV_NAME_SIZE)) { + sdio_tty_drv = sdio_tty[i]; + break; + } + } + + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + return -ENODEV; + } + + sdio_tty_drv->tty_open_count++; + if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) is already open", + __func__, sdio_tty_drv->tty_dev_name); + return -EBUSY; + } + + tty->driver_data = sdio_tty_drv; + + sdio_tty_drv->tty_str = tty; + sdio_tty_drv->tty_str->low_latency = 1; + sdio_tty_drv->tty_str->icanon = 0; + set_bit(TTY_NO_WRITE_SPLIT, &sdio_tty_drv->tty_str->flags); + + sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL); + if (sdio_tty_drv->read_buf == NULL) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf " + "for dev %s", __func__, sdio_tty_drv->tty_dev_name); + return -ENOMEM; + } + + sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read"); + if (!sdio_tty_drv->workq) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq " + "for dev %s", __func__, sdio_tty_drv->tty_dev_name); + return -ENOMEM; + } + + if (!sdio_tty_drv->is_sdio_open) { + ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch, + sdio_tty_drv, sdio_tty_notify); + if (ret < 0) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d " + "for dev %s\n", __func__, ret, + sdio_tty_drv->tty_dev_name); + destroy_workqueue(sdio_tty_drv->workq); + return ret; + } + + pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) " + "opened\n", __func__, sdio_tty_drv->sdio_ch_name); + + sdio_tty_drv->is_sdio_open = 1; + } else { + /* If SDIO channel is already open try to read the data + * from the modem + */ + queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read); + + } + + sdio_tty_drv->sdio_tty_state = TTY_OPENED; + + pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device(%s) opened\n", + __func__, sdio_tty_drv->tty_dev_name); + + return ret; +} + +/** + * sdio_tty_close + * This is the close callback of the tty driver. it requests + * the main thread to exit, and waits for notification of it. + * it also de-allocates the buffers, and unregisters the tty + * driver and device. + * + * @tty: a pointer to the tty struct. + * @file: file descriptor. + * @return None. + */ +static void sdio_tty_close(struct tty_struct *tty, struct file *file) +{ + struct sdio_tty *sdio_tty_drv = NULL; + + if (!tty) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__); + return; + } + sdio_tty_drv = tty->driver_data; + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + return; + } + if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a " + "TTY device that was not opened\n", __func__); + return; + } + if (--sdio_tty_drv->tty_open_count != 0) + return; + + flush_workqueue(sdio_tty_drv->workq); + destroy_workqueue(sdio_tty_drv->workq); + + kfree(sdio_tty_drv->read_buf); + sdio_tty_drv->read_buf = NULL; + + sdio_tty_drv->sdio_tty_state = TTY_CLOSED; + + pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY device(%s) closed\n", + __func__, sdio_tty_drv->tty_dev_name); +} + +static void sdio_tty_unthrottle(struct tty_struct *tty) +{ + struct sdio_tty *sdio_tty_drv = NULL; + + if (!tty) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__); + return; + } + sdio_tty_drv = tty->driver_data; + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + return; + } + + if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d", + __func__, sdio_tty_drv->sdio_tty_state); + return; + } + + queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read); + return; +} + +static const struct tty_operations sdio_tty_ops = { + .open = sdio_tty_open, + .close = sdio_tty_close, + .write = sdio_tty_write_callback, + .write_room = sdio_tty_write_room, + .unthrottle = sdio_tty_unthrottle, +}; + +int sdio_tty_init_tty(char *tty_name, char *sdio_ch_name, + enum sdio_tty_devices device_id, int debug_msg_on) +{ + int ret = 0; + int i = 0; + struct device *tty_dev = NULL; + struct sdio_tty *sdio_tty_drv = NULL; + + sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL); + if (sdio_tty_drv == NULL) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate sdio_tty " + "for dev %s", __func__, tty_name); + return -ENOMEM; + } + + for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) { + if (sdio_tty[i] == NULL) { + sdio_tty[i] = sdio_tty_drv; + break; + } + } + + if (i == MAX_SDIO_TTY_DEVS) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) creation failed," + " max limit(%d) reached.", __func__, tty_name, + MAX_SDIO_TTY_DEVS); + kfree(sdio_tty_drv); + return -ENODEV; + } + + snprintf(sdio_tty_drv->tty_dev_name, MAX_SDIO_TTY_DEV_NAME_SIZE, + "%s%d", tty_name, 0); + sdio_tty_drv->sdio_ch_name = sdio_ch_name; + sdio_tty_drv->device_id = device_id; + pr_info(SDIO_TTY_MODULE_NAME ": %s: dev=%s, id=%d, channel=%s\n", + __func__, sdio_tty_drv->tty_dev_name, sdio_tty_drv->device_id, + sdio_tty_drv->sdio_ch_name); + + INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read); + + sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV); + + if (!sdio_tty_drv->tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL for dev %s", + __func__, sdio_tty_drv->tty_dev_name); + kfree(sdio_tty_drv); + return -ENODEV; + } + + sdio_tty_drv->tty_drv->name = tty_name; + sdio_tty_drv->tty_drv->owner = THIS_MODULE; + sdio_tty_drv->tty_drv->driver_name = "SDIO_tty"; + /* uses dynamically assigned dev_t values */ + sdio_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL; + sdio_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL; + sdio_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW + | TTY_DRIVER_DYNAMIC_DEV + | TTY_DRIVER_RESET_TERMIOS; + + /* initializing the tty driver */ + sdio_tty_drv->tty_drv->init_termios = tty_std_termios; + sdio_tty_drv->tty_drv->init_termios.c_cflag = + B4800 | CS8 | CREAD | HUPCL | CLOCAL; + sdio_tty_drv->tty_drv->init_termios.c_ispeed = INPUT_SPEED; + sdio_tty_drv->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED; + + tty_set_operations(sdio_tty_drv->tty_drv, &sdio_tty_ops); + + ret = tty_register_driver(sdio_tty_drv->tty_drv); + if (ret) { + put_tty_driver(sdio_tty_drv->tty_drv); + pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() " + "failed for dev %s\n", __func__, + sdio_tty_drv->tty_dev_name); + + sdio_tty_drv->tty_drv = NULL; + kfree(sdio_tty_drv); + return -ENODEV; + } + + tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL); + if (IS_ERR(tty_dev)) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() " + "failed for dev %s\n", __func__, + sdio_tty_drv->tty_dev_name); + tty_unregister_driver(sdio_tty_drv->tty_drv); + put_tty_driver(sdio_tty_drv->tty_drv); + kfree(sdio_tty_drv); + return -ENODEV; + } + + sdio_tty_drv->sdio_tty_state = TTY_REGISTERED; + if (debug_msg_on) { + pr_info(SDIO_TTY_MODULE_NAME ": %s: turn on debug msg for %s", + __func__, sdio_tty_drv->tty_dev_name); + sdio_tty_drv->debug_msg_on = debug_msg_on; + } + return 0; +} + +int sdio_tty_uninit_tty(void *sdio_tty_handle) +{ + int ret = 0; + int i = 0; + struct sdio_tty *sdio_tty_drv = sdio_tty_handle; + + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + return -ENODEV; + } + if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) { + flush_workqueue(sdio_tty_drv->workq); + destroy_workqueue(sdio_tty_drv->workq); + + kfree(sdio_tty_drv->read_buf); + sdio_tty_drv->read_buf = NULL; + } + + if (sdio_tty_drv->sdio_tty_state != TTY_INITIAL) { + tty_unregister_device(sdio_tty_drv->tty_drv, 0); + + ret = tty_unregister_driver(sdio_tty_drv->tty_drv); + if (ret) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: " + "tty_unregister_driver() failed for dev %s\n", + __func__, sdio_tty_drv->tty_dev_name); + } + put_tty_driver(sdio_tty_drv->tty_drv); + sdio_tty_drv->sdio_tty_state = TTY_INITIAL; + sdio_tty_drv->tty_drv = NULL; + } + + for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) { + if (sdio_tty[i] == NULL) + continue; + if (sdio_tty[i]->device_id == sdio_tty_drv->device_id) { + sdio_tty[i] = NULL; + break; + } + } + + DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty " + "structure, dev=%s", __func__, + sdio_tty_drv->tty_dev_name); + kfree(sdio_tty_drv); + + return 0; +} + +static int sdio_tty_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + enum sdio_tty_devices device_id = id->driver_data; + char *device_name = NULL; + char *channel_name = NULL; + int debug_msg_on = 0; + int ret = 0; + + pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name); + + switch (device_id) { + case SDIO_CSVT: + device_name = SDIO_TTY_CSVT_DEV; + channel_name = SDIO_TTY_CH_CSVT; + debug_msg_on = csvt_debug_msg_on; + break; + case SDIO_CSVT_TEST_APP: + device_name = SDIO_TTY_CSVT_TEST_DEV; + channel_name = SDIO_TTY_CH_CSVT; + debug_msg_on = csvt_debug_msg_on; + break; + default: + pr_err(SDIO_TTY_MODULE_NAME ": %s Invalid device:%s, id:%d", + __func__, pdev->name, device_id); + ret = -ENODEV; + break; + } + + if (device_name) { + ret = sdio_tty_init_tty(device_name, channel_name, + device_id, debug_msg_on); + if (ret) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_init_tty " + "failed for dev:%s", __func__, device_name); + } + } + return ret; +} + +static int sdio_tty_remove(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + enum sdio_tty_devices device_id = id->driver_data; + struct sdio_tty *sdio_tty_drv = NULL; + int i = 0; + int ret = 0; + + pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name); + + for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) { + if (sdio_tty[i] == NULL) + continue; + if (sdio_tty[i]->device_id == device_id) { + sdio_tty_drv = sdio_tty[i]; + break; + } + } + + if (!sdio_tty_drv) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv", + __func__); + return -ENODEV; + } + + ret = sdio_tty_uninit_tty(sdio_tty_drv); + if (ret) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_uninit_tty " + "failed for %s", __func__, pdev->name); + } + return ret; +} + +static struct platform_driver sdio_tty_pdrv = { + .probe = sdio_tty_probe, + .remove = sdio_tty_remove, + .id_table = sdio_tty_id_table, + .driver = { + .name = "SDIO_TTY", + .owner = THIS_MODULE, + }, +}; + +#ifdef CONFIG_DEBUG_FS +void sdio_tty_print_info(void) +{ + int i = 0; + + for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) { + if (sdio_tty[i] == NULL) + continue; + pr_info(SDIO_TTY_MODULE_NAME ": %s: Total Rx=%d, Tx = %d " + "for dev %s", __func__, sdio_tty[i]->total_rx, + sdio_tty[i]->total_tx, sdio_tty[i]->tty_dev_name); + } +} + +static int tty_debug_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t tty_debug_info_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + sdio_tty_print_info(); + return count; +} + +const struct file_operations tty_debug_info_ops = { + .open = tty_debug_info_open, + .write = tty_debug_info_write, +}; +#endif + +/* + * Module Init. + * + * Register SDIO TTY driver. + * + */ +static int __init sdio_tty_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&sdio_tty_pdrv); + if (ret) { + pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register " + "failed", __func__); + } +#ifdef CONFIG_DEBUG_FS + else { + sdio_tty_debug_root = debugfs_create_dir("sdio_tty", NULL); + if (sdio_tty_debug_root) { + sdio_tty_debug_info = debugfs_create_file( + "sdio_tty_debug", + S_IRUGO | S_IWUGO, + sdio_tty_debug_root, + NULL, + &tty_debug_info_ops); + } + } +#endif + return ret; +}; + +/* + * Module Exit. + * + * Unregister SDIO TTY driver. + * + */ +static void __exit sdio_tty_exit(void) +{ +#ifdef CONFIG_DEBUG_FS + debugfs_remove(sdio_tty_debug_info); + debugfs_remove(sdio_tty_debug_root); +#endif + platform_driver_unregister(&sdio_tty_pdrv); +} + +module_init(sdio_tty_init); +module_exit(sdio_tty_exit); + +MODULE_DESCRIPTION("SDIO TTY"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Maya Erez "); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index ce65979a..324dd312 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -284,7 +284,7 @@ void __init dma_contiguous_remap(void) if (end > arm_lowmem_limit) end = arm_lowmem_limit; if (start >= end) - continue; + return; map.pfn = __phys_to_pfn(start); map.virtual = __phys_to_virt(start); diff --git a/arch/arm/mm/dma-mapping.cd b/arch/arm/mm/dma-mapping.cd new file mode 100644 index 00000000..517c5a2e --- /dev/null +++ b/arch/arm/mm/dma-mapping.cd @@ -0,0 +1,989 @@ +/* + * linux/arch/arm/mm/dma-mapping.c + * + * Copyright (C) 2000-2004 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * DMA uncached mapping support. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mm.h" + +static u64 get_coherent_dma_mask(struct device *dev) +{ + u64 mask = (u64)arm_dma_limit; + + if (dev) { + mask = dev->coherent_dma_mask; + + /* + * Sanity check the DMA mask - it must be non-zero, and + * must be able to be satisfied by a DMA allocation. + */ + if (mask == 0) { + dev_warn(dev, "coherent DMA mask is unset\n"); + return 0; + } + + if ((~mask) & (u64)arm_dma_limit) { + dev_warn(dev, "coherent DMA mask %#llx is smaller " + "than system GFP_DMA mask %#llx\n", + mask, (u64)arm_dma_limit); + return 0; + } + } + + return mask; +} + +static void __dma_clear_buffer(struct page *page, size_t size) +{ + void *ptr; + /* + * Ensure that the allocated pages are zeroed, and that any data + * lurking in the kernel direct-mapped region is invalidated. + */ + ptr = page_address(page); + memset(ptr, 0, size); + dmac_flush_range(ptr, ptr + size); + outer_flush_range(__pa(ptr), __pa(ptr) + size); +} + +/* + * Allocate a DMA buffer for 'dev' of size 'size' using the + * specified gfp mask. Note that 'size' must be page aligned. + */ +static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp) +{ + unsigned long order = get_order(size); + struct page *page, *p, *e; + + page = alloc_pages(gfp, order); + if (!page) + return NULL; + + /* + * Now split the huge page and free the excess pages + */ + split_page(page, order); + for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++) + __free_page(p); + + __dma_clear_buffer(page, size); + + return page; +} + +/* + * Free a DMA buffer. 'size' must be page aligned. + */ +static void __dma_free_buffer(struct page *page, size_t size) +{ + struct page *e = page + (size >> PAGE_SHIFT); + + while (page < e) { + __free_page(page); + page++; + } +} + +#ifdef CONFIG_MMU + +#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - consistent_base) >> PAGE_SHIFT) +#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - consistent_base) >> PMD_SHIFT) + +/* + * These are the page tables (2MB each) covering uncached, DMA consistent allocations + */ +static pte_t **consistent_pte; + +#define DEFAULT_CONSISTENT_DMA_SIZE (7*SZ_2M) + +unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE; + +void __init init_consistent_dma_size(unsigned long size) +{ + unsigned long base = CONSISTENT_END - ALIGN(size, SZ_2M); + + BUG_ON(consistent_pte); /* Check we're called before DMA region init */ + BUG_ON(base < VMALLOC_END); + + /* Grow region to accommodate specified size */ + if (base < consistent_base) + consistent_base = base; +} + +#include "vmregion.h" + +static struct arm_vmregion_head consistent_head = { + .vm_lock = __SPIN_LOCK_UNLOCKED(&consistent_head.vm_lock), + .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), + .vm_end = CONSISTENT_END, +}; + +#ifdef CONFIG_HUGETLB_PAGE +#error ARM Coherent DMA allocator does not (yet) support huge TLB +#endif + +/* + * Initialise the consistent memory allocation. + */ +static int __init consistent_init(void) +{ + int ret = 0; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + int i = 0; + unsigned long base = consistent_base; + unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT; + + if (IS_ENABLED(CONFIG_CMA) && !IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) + return 0; + + consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL); + if (!consistent_pte) { + pr_err("%s: no memory\n", __func__); + return -ENOMEM; + } + + pr_debug("DMA memory: 0x%08lx - 0x%08lx:\n", base, CONSISTENT_END); + consistent_head.vm_start = base; + + do { + pgd = pgd_offset(&init_mm, base); + + pud = pud_alloc(&init_mm, pgd, base); + if (!pud) { + printk(KERN_ERR "%s: no pud tables\n", __func__); + ret = -ENOMEM; + break; + } + + pmd = pmd_alloc(&init_mm, pud, base); + if (!pmd) { + printk(KERN_ERR "%s: no pmd tables\n", __func__); + ret = -ENOMEM; + break; + } + WARN_ON(!pmd_none(*pmd)); + + pte = pte_alloc_kernel(pmd, base); + if (!pte) { + printk(KERN_ERR "%s: no pte tables\n", __func__); + ret = -ENOMEM; + break; + } + + consistent_pte[i++] = pte; + base += PMD_SIZE; + } while (base < CONSISTENT_END); + + return ret; +} +core_initcall(consistent_init); + +static void *__alloc_from_contiguous(struct device *dev, size_t size, + pgprot_t prot, struct page **ret_page); + +static struct arm_vmregion_head coherent_head = { + .vm_lock = __SPIN_LOCK_UNLOCKED(&coherent_head.vm_lock), + .vm_list = LIST_HEAD_INIT(coherent_head.vm_list), +}; + +size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8; + +static int __init early_coherent_pool(char *p) +{ + coherent_pool_size = memparse(p, &p); + return 0; +} +early_param("coherent_pool", early_coherent_pool); + +/* + * Initialise the coherent pool for atomic allocations. + */ +static int __init coherent_init(void) +{ + pgprot_t prot = pgprot_dmacoherent(pgprot_kernel); + size_t size = coherent_pool_size; + struct page *page; + void *ptr; + + if (!IS_ENABLED(CONFIG_CMA)) + return 0; + + ptr = __alloc_from_contiguous(NULL, size, prot, &page); + if (ptr) { + coherent_head.vm_start = (unsigned long) ptr; + coherent_head.vm_end = (unsigned long) ptr + size; + printk(KERN_INFO "DMA: preallocated %u KiB pool for atomic coherent allocations\n", + (unsigned)size / 1024); + return 0; + } + printk(KERN_ERR "DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", + (unsigned)size / 1024); + return -ENOMEM; +} +/* + * CMA is activated by core_initcall, so we must be called after it. + */ +postcore_initcall(coherent_init); + +struct dma_contig_early_reserve { + phys_addr_t base; + unsigned long size; +}; + +static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS] __initdata; + +static int dma_mmu_remap_num __initdata; + +void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) +{ + dma_mmu_remap[dma_mmu_remap_num].base = base; + dma_mmu_remap[dma_mmu_remap_num].size = size; + dma_mmu_remap_num++; +} + +void __init dma_contiguous_remap(void) +{ + int i; + for (i = 0; i < dma_mmu_remap_num; i++) { + phys_addr_t start = dma_mmu_remap[i].base; + phys_addr_t end = start + dma_mmu_remap[i].size; + struct map_desc map; + unsigned long addr; + + if (end > arm_lowmem_limit) + end = arm_lowmem_limit; + if (start >= end) + return; + + map.pfn = __phys_to_pfn(start); + map.virtual = __phys_to_virt(start); + map.length = end - start; + map.type = MT_MEMORY_DMA_READY; + + /* + * Clear previous low-memory mapping + */ + for (addr = __phys_to_virt(start); addr < __phys_to_virt(end); + addr += PGDIR_SIZE) + pmd_clear(pmd_off_k(addr)); + + iotable_init(&map, 1); + } +} + +static void * +__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, + const void *caller) +{ + struct arm_vmregion *c; + size_t align; + int bit; + + if (!consistent_pte) { + printk(KERN_ERR "%s: not initialised\n", __func__); + dump_stack(); + return NULL; + } + + /* + * Align the virtual region allocation - maximum alignment is + * a section size, minimum is a page size. This helps reduce + * fragmentation of the DMA space, and also prevents allocations + * smaller than a section from crossing a section boundary. + */ + bit = fls(size - 1); + if (bit > SECTION_SHIFT) + bit = SECTION_SHIFT; + align = 1 << bit; + + /* + * Allocate a virtual address in the consistent mapping region. + */ + c = arm_vmregion_alloc(&consistent_head, align, size, + gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller); + if (c) { + pte_t *pte; + int idx = CONSISTENT_PTE_INDEX(c->vm_start); + u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); + + pte = consistent_pte[idx] + off; + c->vm_pages = page; + + do { + BUG_ON(!pte_none(*pte)); + + set_pte_ext(pte, mk_pte(page, prot), 0); + page++; + pte++; + off++; + if (off >= PTRS_PER_PTE) { + off = 0; + pte = consistent_pte[++idx]; + } + } while (size -= PAGE_SIZE); + + dsb(); + + return (void *)c->vm_start; + } + return NULL; +} + +static void __dma_free_remap(void *cpu_addr, size_t size) +{ + struct arm_vmregion *c; + unsigned long addr; + pte_t *ptep; + int idx; + u32 off; + + c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr); + if (!c) { + printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n", + __func__, cpu_addr); + dump_stack(); + return; + } + + if ((c->vm_end - c->vm_start) != size) { + printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", + __func__, c->vm_end - c->vm_start, size); + dump_stack(); + size = c->vm_end - c->vm_start; + } + + idx = CONSISTENT_PTE_INDEX(c->vm_start); + off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); + ptep = consistent_pte[idx] + off; + addr = c->vm_start; + do { + pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); + + ptep++; + addr += PAGE_SIZE; + off++; + if (off >= PTRS_PER_PTE) { + off = 0; + ptep = consistent_pte[++idx]; + } + + if (pte_none(pte) || !pte_present(pte)) + printk(KERN_CRIT "%s: bad page in kernel page table\n", + __func__); + } while (size -= PAGE_SIZE); + + flush_tlb_kernel_range(c->vm_start, c->vm_end); + + arm_vmregion_free(&consistent_head, c); +} + +static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, + void *data) +{ + struct page *page = virt_to_page(addr); + pgprot_t prot = *(pgprot_t *)data; + + set_pte_ext(pte, mk_pte(page, prot), 0); + return 0; +} + +static void __dma_remap(struct page *page, size_t size, pgprot_t prot) +{ + unsigned long start = (unsigned long) page_address(page); + unsigned end = start + size; + + apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot); + dsb(); + flush_tlb_kernel_range(start, end); +} + +static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, + pgprot_t prot, struct page **ret_page, + const void *caller) +{ + struct page *page; + void *ptr; + page = __dma_alloc_buffer(dev, size, gfp); + if (!page) + return NULL; + + ptr = __dma_alloc_remap(page, size, gfp, prot, caller); + if (!ptr) { + __dma_free_buffer(page, size); + return NULL; + } + + *ret_page = page; + return ptr; +} + +static void *__alloc_from_pool(struct device *dev, size_t size, + struct page **ret_page, const void *caller) +{ + struct arm_vmregion *c; + size_t align; + + if (!coherent_head.vm_start) { + printk(KERN_ERR "%s: coherent pool not initialised!\n", + __func__); + dump_stack(); + return NULL; + } + + /* + * Align the region allocation - allocations from pool are rather + * small, so align them to their order in pages, minimum is a page + * size. This helps reduce fragmentation of the DMA space. + */ + align = PAGE_SIZE << get_order(size); + c = arm_vmregion_alloc(&coherent_head, align, size, 0, caller); + if (c) { + void *ptr = (void *)c->vm_start; + struct page *page = virt_to_page(ptr); + *ret_page = page; + return ptr; + } + return NULL; +} + +static int __free_from_pool(void *cpu_addr, size_t size) +{ + unsigned long start = (unsigned long)cpu_addr; + unsigned long end = start + size; + struct arm_vmregion *c; + + if (start < coherent_head.vm_start || end > coherent_head.vm_end) + return 0; + + c = arm_vmregion_find_remove(&coherent_head, (unsigned long)start); + + if ((c->vm_end - c->vm_start) != size) { + printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", + __func__, c->vm_end - c->vm_start, size); + dump_stack(); + size = c->vm_end - c->vm_start; + } + + arm_vmregion_free(&coherent_head, c); + return 1; +} + +static void *__alloc_from_contiguous(struct device *dev, size_t size, + pgprot_t prot, struct page **ret_page) +{ + unsigned long order = get_order(size); + size_t count = size >> PAGE_SHIFT; + struct page *page; + + page = dma_alloc_from_contiguous(dev, count, order); + if (!page) + return NULL; + + __dma_clear_buffer(page, size); + __dma_remap(page, size, prot); + + *ret_page = page; + return page_address(page); +} + +static void __free_from_contiguous(struct device *dev, struct page *page, + size_t size) +{ + __dma_remap(page, size, pgprot_kernel); + dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); +} + +static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot) +{ + if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs)) + prot = pgprot_writecombine(prot); + else if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs)) + prot = pgprot_stronglyordered(prot); + /* if non-consistent just pass back what was given */ + else if (!dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) + prot = pgprot_dmacoherent(prot); + + return prot; +} + +#define nommu() 0 + +#else /* !CONFIG_MMU */ + +#define nommu() 1 + +#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c) NULL +#define __alloc_from_pool(dev, size, ret_page, c) NULL +#define __alloc_from_contiguous(dev, size, prot, ret) NULL +#define __free_from_pool(cpu_addr, size) 0 +#define __free_from_contiguous(dev, page, size) do { } while (0) +#define __dma_free_remap(cpu_addr, size) do { } while (0) + +#endif /* CONFIG_MMU */ + +static void *__alloc_simple_buffer(struct device *dev, size_t size, gfp_t gfp, + struct page **ret_page) +{ + struct page *page; + page = __dma_alloc_buffer(dev, size, gfp); + if (!page) + return NULL; + + *ret_page = page; + return page_address(page); +} + + + +static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, + gfp_t gfp, pgprot_t prot, const void *caller) +{ + u64 mask = get_coherent_dma_mask(dev); + struct page *page; + void *addr; + +#ifdef CONFIG_DMA_API_DEBUG + u64 limit = (mask + 1) & ~mask; + if (limit && size >= limit) { + dev_warn(dev, "coherent allocation too big (requested %#x mask %#llx)\n", + size, mask); + return NULL; + } +#endif + + if (!mask) + return NULL; + + if (mask < 0xffffffffULL) + gfp |= GFP_DMA; + + /* + * Following is a work-around (a.k.a. hack) to prevent pages + * with __GFP_COMP being passed to split_page() which cannot + * handle them. The real problem is that this flag probably + * should be 0 on ARM as it is not supported on this + * platform; see CONFIG_HUGETLBFS. + */ + gfp &= ~(__GFP_COMP); + + *handle = ~0; + size = PAGE_ALIGN(size); + + if (arch_is_coherent() || nommu()) + addr = __alloc_simple_buffer(dev, size, gfp, &page); + else if (!IS_ENABLED(CONFIG_CMA)) + addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); + else if (gfp & GFP_ATOMIC) + addr = __alloc_from_pool(dev, size, &page, caller); + else + addr = __alloc_from_contiguous(dev, size, prot, &page); + + if (addr) + *handle = pfn_to_dma(dev, page_to_pfn(page)); + + return addr; +} + +/* + * Allocate DMA-coherent memory space and return both the kernel remapped + * virtual and bus address for that space. + */ +void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, + gfp_t gfp) +{ + void *memory; + + if (dma_alloc_from_coherent(dev, size, handle, &memory)) + return memory; + + return __dma_alloc(dev, size, handle, gfp, + pgprot_dmacoherent(pgprot_kernel), + __builtin_return_address(0)); +} +EXPORT_SYMBOL(dma_alloc_coherent); + +/* + * Allocate a writecombining region, in much the same way as + * dma_alloc_coherent above. + */ +void * +dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) +{ + return __dma_alloc(dev, size, handle, gfp, + pgprot_writecombine(pgprot_kernel), + __builtin_return_address(0)); +} +EXPORT_SYMBOL(dma_alloc_writecombine); + +static int dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + int ret = -ENXIO; +#ifdef CONFIG_MMU + unsigned long pfn = dma_to_pfn(dev, dma_addr); + ret = remap_pfn_range(vma, vma->vm_start, + pfn + vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +#endif /* CONFIG_MMU */ + + return ret; +} + +int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot); + return dma_mmap(dev, vma, cpu_addr, dma_addr, size); +} +EXPORT_SYMBOL(dma_mmap_coherent); + +int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return dma_mmap(dev, vma, cpu_addr, dma_addr, size); +} +EXPORT_SYMBOL(dma_mmap_writecombine); + + +/* + * Free a buffer as defined by the above mapping. + */ +void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle) +{ + struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); + + if (dma_release_from_coherent(dev, get_order(size), cpu_addr)) + return; + + size = PAGE_ALIGN(size); + + if (arch_is_coherent() || nommu()) { + __dma_free_buffer(page, size); + } else if (!IS_ENABLED(CONFIG_CMA)) { + __dma_free_remap(cpu_addr, size); + __dma_free_buffer(page, size); + } else { + if (__free_from_pool(cpu_addr, size)) + return; + /* + * Non-atomic allocations cannot be freed with IRQs disabled + */ + WARN_ON(irqs_disabled()); + __free_from_contiguous(dev, page, size); + } +} +EXPORT_SYMBOL(dma_free_coherent); + +/* + * Make an area consistent for devices. + * Note: Drivers should NOT use this function directly, as it will break + * platforms with CONFIG_DMABOUNCE. + * Use the driver DMA support - see dma-mapping.h (dma_sync_*) + */ +void ___dma_single_cpu_to_dev(const void *kaddr, size_t size, + enum dma_data_direction dir) +{ +#ifdef CONFIG_OUTER_CACHE + unsigned long paddr; + + BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); +#endif + + dmac_map_area(kaddr, size, dir); + +#ifdef CONFIG_OUTER_CACHE + paddr = __pa(kaddr); + if (dir == DMA_FROM_DEVICE) { + outer_inv_range(paddr, paddr + size); + } else { + outer_clean_range(paddr, paddr + size); + } +#endif + /* FIXME: non-speculating: flush on bidirectional mappings? */ +} +EXPORT_SYMBOL(___dma_single_cpu_to_dev); + +void ___dma_single_dev_to_cpu(const void *kaddr, size_t size, + enum dma_data_direction dir) +{ +#ifdef CONFIG_OUTER_CACHE + BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); + + /* FIXME: non-speculating: not required */ + /* don't bother invalidating if DMA to device */ + if (dir != DMA_TO_DEVICE) { + unsigned long paddr = __pa(kaddr); + outer_inv_range(paddr, paddr + size); + } +#endif + dmac_unmap_area(kaddr, size, dir); +} +EXPORT_SYMBOL(___dma_single_dev_to_cpu); + +static void dma_cache_maint_page(struct page *page, unsigned long offset, + size_t size, enum dma_data_direction dir, + void (*op)(const void *, size_t, int)) +{ + /* + * A single sg entry may refer to multiple physically contiguous + * pages. But we still need to process highmem pages individually. + * If highmem is not configured then the bulk of this loop gets + * optimized out. + */ + size_t left = size; + do { + size_t len = left; + void *vaddr; + + if (PageHighMem(page)) { + if (len + offset > PAGE_SIZE) { + if (offset >= PAGE_SIZE) { + page += offset / PAGE_SIZE; + offset %= PAGE_SIZE; + } + len = PAGE_SIZE - offset; + } + vaddr = kmap_high_get(page); + if (vaddr) { + vaddr += offset; + op(vaddr, len, dir); + kunmap_high(page); + } else if (cache_is_vipt()) { + /* unmapped pages might still be cached */ + vaddr = kmap_atomic(page); + op(vaddr + offset, len, dir); + kunmap_atomic(vaddr); + } + } else { + vaddr = page_address(page) + offset; + op(vaddr, len, dir); + } + offset = 0; + page++; + left -= len; + } while (left); +} + +void ___dma_page_cpu_to_dev(struct page *page, unsigned long off, + size_t size, enum dma_data_direction dir) +{ + unsigned long paddr; + + dma_cache_maint_page(page, off, size, dir, dmac_map_area); + + paddr = page_to_phys(page) + off; + if (dir == DMA_FROM_DEVICE) { + outer_inv_range(paddr, paddr + size); + } else { + outer_clean_range(paddr, paddr + size); + } + /* FIXME: non-speculating: flush on bidirectional mappings? */ +} +EXPORT_SYMBOL(___dma_page_cpu_to_dev); + +void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, + size_t size, enum dma_data_direction dir) +{ + unsigned long paddr = page_to_phys(page) + off; + + /* FIXME: non-speculating: not required */ + /* don't bother invalidating if DMA to device */ + if (dir != DMA_TO_DEVICE) + outer_inv_range(paddr, paddr + size); + + dma_cache_maint_page(page, off, size, dir, dmac_unmap_area); + + /* + * Mark the D-cache clean for this page to avoid extra flushing. + */ + if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE) + set_bit(PG_dcache_clean, &page->flags); +} +EXPORT_SYMBOL(___dma_page_dev_to_cpu); + +/** + * dma_map_sg - map a set of SG buffers for streaming mode DMA + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @sg: list of buffers + * @nents: number of buffers to map + * @dir: DMA transfer direction + * + * Map a set of buffers described by scatterlist in streaming mode for DMA. + * This is the scatter-gather version of the dma_map_single interface. + * Here the scatter gather list elements are each tagged with the + * appropriate dma address and length. They are obtained via + * sg_dma_{address,length}. + * + * Device ownership issues as mentioned for dma_map_single are the same + * here. + */ +int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + struct scatterlist *s; + int i, j; + + BUG_ON(!valid_dma_direction(dir)); + + for_each_sg(sg, s, nents, i) { + s->dma_address = __dma_map_page(dev, sg_page(s), s->offset, + s->length, dir); + if (dma_mapping_error(dev, s->dma_address)) + goto bad_mapping; + } + debug_dma_map_sg(dev, sg, nents, nents, dir); + return nents; + + bad_mapping: + for_each_sg(sg, s, i, j) + __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); + return 0; +} +EXPORT_SYMBOL(dma_map_sg); + +/** + * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @sg: list of buffers + * @nents: number of buffers to unmap (same as was passed to dma_map_sg) + * @dir: DMA transfer direction (same as was passed to dma_map_sg) + * + * Unmap a set of streaming mode DMA translations. Again, CPU access + * rules concerning calls here are the same as for dma_unmap_single(). + */ +void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + struct scatterlist *s; + int i; + + debug_dma_unmap_sg(dev, sg, nents, dir); + + for_each_sg(sg, s, nents, i) + __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); +} +EXPORT_SYMBOL(dma_unmap_sg); + +/** + * dma_sync_sg_for_cpu + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @sg: list of buffers + * @nents: number of buffers to map (returned from dma_map_sg) + * @dir: DMA transfer direction (same as was passed to dma_map_sg) + */ +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) { + if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0, + sg_dma_len(s), dir)) + continue; + + __dma_page_dev_to_cpu(sg_page(s), s->offset, + s->length, dir); + } + + debug_dma_sync_sg_for_cpu(dev, sg, nents, dir); +} +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + +/** + * dma_sync_sg_for_device + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @sg: list of buffers + * @nents: number of buffers to map (returned from dma_map_sg) + * @dir: DMA transfer direction (same as was passed to dma_map_sg) + */ +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) { + if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0, + sg_dma_len(s), dir)) + continue; + + __dma_page_cpu_to_dev(sg_page(s), s->offset, + s->length, dir); + } + + debug_dma_sync_sg_for_device(dev, sg, nents, dir); +} +EXPORT_SYMBOL(dma_sync_sg_for_device); + +/* + * Return whether the given device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during bus mastering, then you would pass 0x00ffffff as the mask + * to this function. + */ +int dma_supported(struct device *dev, u64 mask) +{ + if (mask < (u64)arm_dma_limit) + return 0; + return 1; +} +EXPORT_SYMBOL(dma_supported); + +int dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + +#ifndef CONFIG_DMABOUNCE + *dev->dma_mask = dma_mask; +#endif + + return 0; +} +EXPORT_SYMBOL(dma_set_mask); + +#define PREALLOC_DMA_DEBUG_ENTRIES 4096 + +static int __init dma_debug_do_init(void) +{ +#ifdef CONFIG_MMU + arm_vmregion_create_proc("dma-mappings", &consistent_head); +#endif + dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); + return 0; +} +fs_initcall(dma_debug_do_init); diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 8877dddc..802611b0 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -62,6 +62,9 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page #define VM_ARM_MTYPE(mt) ((mt) << 20) #define VM_ARM_MTYPE_MASK (0x1f << 20) +/* consistent regions used by dma_alloc_attrs() */ +#define VM_ARM_DMA_CONSISTENT 0x20000000 + #endif #ifdef CONFIG_ZONE_DMA diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched index 3066f240..4e534631 100644 --- a/block/Kconfig.iosched +++ b/block/Kconfig.iosched @@ -2,26 +2,49 @@ if BLOCK menu "IO Schedulers" -config IOSCHED_NOOP - bool +config IOSCHED_BFQ + tristate "BFQ I/O scheduler" + depends on EXPERIMENTAL + default n + ---help--- + The BFQ I/O scheduler tries to distribute bandwidth among + all processes according to their weights. + It aims at distributing the bandwidth as desired, independently of + the disk parameters and with any workload. It also tries to + guarantee low latency to interactive and soft real-time + applications. If compiled built-in (saying Y here), BFQ can + be configured to support hierarchical scheduling. + +config CGROUP_BFQIO + bool "BFQ hierarchical scheduling support" + depends on CGROUPS && IOSCHED_BFQ=y + default n + ---help--- + Enable hierarchical scheduling in BFQ, using the cgroups + filesystem interface. The name of the subsystem will be + bfqio. + +config IOSCHED_CFQ + tristate "CFQ I/O scheduler" + # If BLK_CGROUP is a module, CFQ has to be built as module. + depends on (BLK_CGROUP=m && m) || !BLK_CGROUP || BLK_CGROUP=y default y ---help--- - The no-op I/O scheduler is a minimal scheduler that does basic merging - and sorting. Its main uses include non-disk based block devices like - memory devices, and specialised software or hardware environments - that do their own scheduling and require only minimal assistance from - the kernel. + The CFQ I/O scheduler tries to distribute bandwidth equally + among all processes in the system. It should provide a fair + and low latency working environment, suitable for both desktop + and server systems. -config IOSCHED_TEST - tristate "Test I/O scheduler" - depends on DEBUG_FS - default m + This is the default I/O scheduler. + + Note: If BLK_CGROUP=m, then CFQ can be built only as module. + +config CFQ_GROUP_IOSCHED + bool "CFQ Group Scheduling support" + depends on IOSCHED_CFQ && BLK_CGROUP + default n ---help--- - The test I/O scheduler is a duplicate of the noop scheduler with - addition of test utlity. - It allows testing a block device by dispatching specific requests - according to the test case and declare PASS/FAIL according to the - requests completion error code. + Enable group IO scheduling in CFQ. config IOSCHED_DEADLINE tristate "Deadline I/O scheduler" @@ -40,27 +63,71 @@ config IOSCHED_FIOPS IOPS equally among all processes in the system. It's mainly for Flash based storage. -config IOSCHED_CFQ - tristate "CFQ I/O scheduler" - # If BLK_CGROUP is a module, CFQ has to be built as module. - depends on (BLK_CGROUP=m && m) || !BLK_CGROUP || BLK_CGROUP=y +config IOSCHED_NOOP + bool default y ---help--- - The CFQ I/O scheduler tries to distribute bandwidth equally - among all processes in the system. It should provide a fair - and low latency working environment, suitable for both desktop - and server systems. + The no-op I/O scheduler is a minimal scheduler that does basic merging + and sorting. Its main uses include non-disk based block devices like + memory devices, and specialised software or hardware environments + that do their own scheduling and require only minimal assistance from + the kernel. - This is the default I/O scheduler. +config IOSCHED_ROW + tristate "ROW I/O scheduler" + default y + ---help--- + The ROW I/O scheduler gives priority to READ requests over the + WRITE requests when dispatching, without starving WRITE requests. + Requests are kept in priority queues. Dispatching is done in a RR + manner when the dispatch quantum for each queue is calculated + according to queue priority. + Most suitable for mobile devices. + +config IOSCHED_SIO + tristate "Simple I/O scheduler" + default y + ---help--- + The Simple I/O scheduler is an extremely simple scheduler, + based on noop and deadline, that relies on deadlines to + ensure fairness. The algorithm does not do any sorting but + basic merging, trying to keep a minimum overhead. It is aimed + mainly for aleatory access devices (eg: flash devices). + +config IOSCHED_SIOPLUS + tristate "Simple I/O scheduler plus" + default y + ---help--- + The Simple I/O scheduler is an extremely simple scheduler, + based on noop and deadline, that relies on deadlines to + ensure fairness. The algorithm does not do any sorting but + basic merging, trying to keep a minimum overhead. It is aimed + mainly for aleatory access devices (eg: flash devices). - Note: If BLK_CGROUP=m, then CFQ can be built only as module. +config IOSCHED_TEST + tristate "Test I/O scheduler" + depends on DEBUG_FS + default m + ---help--- + The test I/O scheduler is a duplicate of the noop scheduler with + addition of test utlity. + It allows testing a block device by dispatching specific requests + according to the test case and declare PASS/FAIL according to the + requests completion error code. -config CFQ_GROUP_IOSCHED - bool "CFQ Group Scheduling support" - depends on IOSCHED_CFQ && BLK_CGROUP +config IOSCHED_VR + tristate "V(R) I/O scheduler" default n - ---help--- - Enable group IO scheduling in CFQ. + ---help--- + Requests are chosen according to SSTF with a penalty of rev_penalty + for switching head direction. + +config IOSCHED_ZEN + tristate "Zen I/O scheduler" + default y + ---help--- + FCFS, dispatches are back-inserted, deadlines ensure fairness. + Should work best with devices where there is no travel delay. choice prompt "Default I/O scheduler" @@ -69,26 +136,64 @@ choice Select the I/O scheduler which will be used by default for all block devices. + config DEFAULT_BFQ + bool "BFQ" if IOSCHED_BFQ=y + help + Selects BFQ as the default I/O scheduler which will be + used by default for all block devices. + The BFQ I/O scheduler aims at distributing the bandwidth + as desired, independently of the disk parameters and with + any workload. It also tries to guarantee low latency to + interactive and soft real-time applications. + + config DEFAULT_CFQ + bool "CFQ" if IOSCHED_CFQ=y + config DEFAULT_DEADLINE bool "Deadline" if IOSCHED_DEADLINE=y config DEFAULT_FIOPS bool "FIOPS" if IOSCHED_FIOPS=y - config DEFAULT_CFQ - bool "CFQ" if IOSCHED_CFQ=y - config DEFAULT_NOOP bool "No-op" + config DEFAULT_ROW + bool "ROW" if IOSCHED_ROW=y + help + The ROW I/O scheduler gives priority to READ requests + over the WRITE requests when dispatching, without starving + WRITE requests. Requests are kept in priority queues. + Dispatching is done in a RR manner when the dispatch quantum + for each queue is defined according to queue priority. + Most suitable for mobile devices. + + config DEFAULT_SIO + bool "SIO" if IOSCHED_SIO=y + + config DEFAULT_SIOPLUS + bool "SIOPLUS" if IOSCHED_SIOPLUS=y + + config DEFAULT_VR + bool "VR" if IOSCHED_VR=y + + config DEFAULT_ZEN + bool "ZEN" if IOSCHED_ZEN=y + endchoice config DEFAULT_IOSCHED string + default "bfq" if DEFAULT_BFQ + default "cfq" if DEFAULT_CFQ default "deadline" if DEFAULT_DEADLINE default "fiops" if DEFAULT_FIOPS - default "cfq" if DEFAULT_CFQ default "noop" if DEFAULT_NOOP + default "row" if DEFAULT_ROW + default "sio" if DEFAULT_SIO + default "sioplus" if DEFAULT_SIOPLUS + default "vr" if DEFAULT_VR + default "zen" if DEFAULT_ZEN endmenu diff --git a/block/Makefile b/block/Makefile index a91fda5d..e4a5e913 100644 --- a/block/Makefile +++ b/block/Makefile @@ -12,11 +12,17 @@ obj-$(CONFIG_BLK_DEV_BSG) += bsg.o obj-$(CONFIG_BLK_DEV_BSGLIB) += bsg-lib.o obj-$(CONFIG_BLK_CGROUP) += blk-cgroup.o obj-$(CONFIG_BLK_DEV_THROTTLING) += blk-throttle.o -obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o +obj-$(CONFIG_IOSCHED_BFQ) += bfq-iosched.o +obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o obj-$(CONFIG_IOSCHED_FIOPS) += fiops-iosched.o -obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o +obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o +obj-$(CONFIG_IOSCHED_ROW) += row-iosched.o +obj-$(CONFIG_IOSCHED_SIO) += sio-iosched.o +obj-$(CONFIG_IOSCHED_SIOPLUS) += sioplus-iosched.o obj-$(CONFIG_IOSCHED_TEST) += test-iosched.o +obj-$(CONFIG_IOSCHED_VR) += vr-iosched.o +obj-$(CONFIG_IOSCHED_ZEN) += zen-iosched.o obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c new file mode 100644 index 00000000..8399c920 --- /dev/null +++ b/block/bfq-cgroup.c @@ -0,0 +1,908 @@ +/* + * BFQ: CGROUPS support. + * + * Based on ideas and code from CFQ: + * Copyright (C) 2003 Jens Axboe + * + * Copyright (C) 2008 Fabio Checconi + * Paolo Valente + * + * Copyright (C) 2010 Paolo Valente + * + * Licensed under the GPL-2 as detailed in the accompanying COPYING.BFQ + * file. + */ + +#ifdef CONFIG_CGROUP_BFQIO +static struct bfqio_cgroup bfqio_root_cgroup = { + .weight = BFQ_DEFAULT_GRP_WEIGHT, + .ioprio = BFQ_DEFAULT_GRP_IOPRIO, + .ioprio_class = BFQ_DEFAULT_GRP_CLASS, +}; + +static inline void bfq_init_entity(struct bfq_entity *entity, + struct bfq_group *bfqg) +{ + entity->weight = entity->new_weight; + entity->orig_weight = entity->new_weight; + entity->ioprio = entity->new_ioprio; + entity->ioprio_class = entity->new_ioprio_class; + entity->parent = bfqg->my_entity; + entity->sched_data = &bfqg->sched_data; +} + +static struct bfqio_cgroup *cgroup_to_bfqio(struct cgroup *cgroup) +{ + return container_of(cgroup_subsys_state(cgroup, bfqio_subsys_id), + struct bfqio_cgroup, css); +} + +/* + * Search the bfq_group for bfqd into the hash table (by now only a list) + * of bgrp. Must be called under rcu_read_lock(). + */ +static struct bfq_group *bfqio_lookup_group(struct bfqio_cgroup *bgrp, + struct bfq_data *bfqd) +{ + struct bfq_group *bfqg; + struct hlist_node *n; + void *key; + + hlist_for_each_entry_rcu(bfqg, n, &bgrp->group_data, group_node) { + key = rcu_dereference(bfqg->bfqd); + if (key == bfqd) + return bfqg; + } + + return NULL; +} + +static inline void bfq_group_init_entity(struct bfqio_cgroup *bgrp, + struct bfq_group *bfqg) +{ + struct bfq_entity *entity = &bfqg->entity; + + /* + * If the weight of the entity has never been set via the sysfs + * interface, then bgrp->weight == 0. In this case we initialize + * the weight from the current ioprio value. Otherwise, the group + * weight, if set, has priority over the ioprio value. + */ + if (bgrp->weight == 0) { + entity->new_weight = bfq_ioprio_to_weight(bgrp->ioprio); + entity->new_ioprio = bgrp->ioprio; + } else { + if (bgrp->weight < BFQ_MIN_WEIGHT || + bgrp->weight > BFQ_MAX_WEIGHT) { + printk(KERN_CRIT "bfq_group_init_entity: " + "bgrp->weight %d\n", bgrp->weight); + BUG(); + } + entity->new_weight = bgrp->weight; + entity->new_ioprio = bfq_weight_to_ioprio(bgrp->weight); + } + entity->orig_weight = entity->weight = entity->new_weight; + entity->ioprio = entity->new_ioprio; + entity->ioprio_class = entity->new_ioprio_class = bgrp->ioprio_class; + entity->my_sched_data = &bfqg->sched_data; + bfqg->active_entities = 0; +} + +static inline void bfq_group_set_parent(struct bfq_group *bfqg, + struct bfq_group *parent) +{ + struct bfq_entity *entity; + + BUG_ON(parent == NULL); + BUG_ON(bfqg == NULL); + + entity = &bfqg->entity; + entity->parent = parent->my_entity; + entity->sched_data = &parent->sched_data; +} + +/** + * bfq_group_chain_alloc - allocate a chain of groups. + * @bfqd: queue descriptor. + * @cgroup: the leaf cgroup this chain starts from. + * + * Allocate a chain of groups starting from the one belonging to + * @cgroup up to the root cgroup. Stop if a cgroup on the chain + * to the root has already an allocated group on @bfqd. + */ +static struct bfq_group *bfq_group_chain_alloc(struct bfq_data *bfqd, + struct cgroup *cgroup) +{ + struct bfqio_cgroup *bgrp; + struct bfq_group *bfqg, *prev = NULL, *leaf = NULL; + + for (; cgroup != NULL; cgroup = cgroup->parent) { + bgrp = cgroup_to_bfqio(cgroup); + + bfqg = bfqio_lookup_group(bgrp, bfqd); + if (bfqg != NULL) { + /* + * All the cgroups in the path from there to the + * root must have a bfq_group for bfqd, so we don't + * need any more allocations. + */ + break; + } + + bfqg = kzalloc(sizeof(*bfqg), GFP_ATOMIC); + if (bfqg == NULL) + goto cleanup; + + bfq_group_init_entity(bgrp, bfqg); + bfqg->my_entity = &bfqg->entity; + + if (leaf == NULL) { + leaf = bfqg; + prev = leaf; + } else { + bfq_group_set_parent(prev, bfqg); + /* + * Build a list of allocated nodes using the bfqd + * filed, that is still unused and will be + * initialized only after the node will be + * connected. + */ + prev->bfqd = bfqg; + prev = bfqg; + } + } + + return leaf; + +cleanup: + while (leaf != NULL) { + prev = leaf; + leaf = leaf->bfqd; + kfree(prev); + } + + return NULL; +} + +/** + * bfq_group_chain_link - link an allocated group chain to a cgroup + * hierarchy. + * @bfqd: the queue descriptor. + * @cgroup: the leaf cgroup to start from. + * @leaf: the leaf group (to be associated to @cgroup). + * + * Try to link a chain of groups to a cgroup hierarchy, connecting the + * nodes bottom-up, so we can be sure that when we find a cgroup in the + * hierarchy that already as a group associated to @bfqd all the nodes + * in the path to the root cgroup have one too. + * + * On locking: the queue lock protects the hierarchy (there is a hierarchy + * per device) while the bfqio_cgroup lock protects the list of groups + * belonging to the same cgroup. + */ +static void bfq_group_chain_link(struct bfq_data *bfqd, struct cgroup *cgroup, + struct bfq_group *leaf) +{ + struct bfqio_cgroup *bgrp; + struct bfq_group *bfqg, *next, *prev = NULL; + unsigned long flags; + + assert_spin_locked(bfqd->queue->queue_lock); + + for (; cgroup != NULL && leaf != NULL; cgroup = cgroup->parent) { + bgrp = cgroup_to_bfqio(cgroup); + next = leaf->bfqd; + + bfqg = bfqio_lookup_group(bgrp, bfqd); + BUG_ON(bfqg != NULL); + + spin_lock_irqsave(&bgrp->lock, flags); + + rcu_assign_pointer(leaf->bfqd, bfqd); + hlist_add_head_rcu(&leaf->group_node, &bgrp->group_data); + hlist_add_head(&leaf->bfqd_node, &bfqd->group_list); + + spin_unlock_irqrestore(&bgrp->lock, flags); + + prev = leaf; + leaf = next; + } + + BUG_ON(cgroup == NULL && leaf != NULL); + if (cgroup != NULL && prev != NULL) { + bgrp = cgroup_to_bfqio(cgroup); + bfqg = bfqio_lookup_group(bgrp, bfqd); + bfq_group_set_parent(prev, bfqg); + } +} + +/** + * bfq_find_alloc_group - return the group associated to @bfqd in @cgroup. + * @bfqd: queue descriptor. + * @cgroup: cgroup being searched for. + * + * Return a group associated to @bfqd in @cgroup, allocating one if + * necessary. When a group is returned all the cgroups in the path + * to the root have a group associated to @bfqd. + * + * If the allocation fails, return the root group: this breaks guarantees + * but is a safe fallback. If this loss becomes a problem it can be + * mitigated using the equivalent weight (given by the product of the + * weights of the groups in the path from @group to the root) in the + * root scheduler. + * + * We allocate all the missing nodes in the path from the leaf cgroup + * to the root and we connect the nodes only after all the allocations + * have been successful. + */ +static struct bfq_group *bfq_find_alloc_group(struct bfq_data *bfqd, + struct cgroup *cgroup) +{ + struct bfqio_cgroup *bgrp = cgroup_to_bfqio(cgroup); + struct bfq_group *bfqg; + + bfqg = bfqio_lookup_group(bgrp, bfqd); + if (bfqg != NULL) + return bfqg; + + bfqg = bfq_group_chain_alloc(bfqd, cgroup); + if (bfqg != NULL) + bfq_group_chain_link(bfqd, cgroup, bfqg); + else + bfqg = bfqd->root_group; + + return bfqg; +} + +/** + * bfq_bfqq_move - migrate @bfqq to @bfqg. + * @bfqd: queue descriptor. + * @bfqq: the queue to move. + * @entity: @bfqq's entity. + * @bfqg: the group to move to. + * + * Move @bfqq to @bfqg, deactivating it from its old group and reactivating + * it on the new one. Avoid putting the entity on the old group idle tree. + * + * Must be called under the queue lock; the cgroup owning @bfqg must + * not disappear (by now this just means that we are called under + * rcu_read_lock()). + */ +static void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq, + struct bfq_entity *entity, struct bfq_group *bfqg) +{ + int busy, resume; + + busy = bfq_bfqq_busy(bfqq); + resume = !RB_EMPTY_ROOT(&bfqq->sort_list); + + BUG_ON(resume && !entity->on_st); + BUG_ON(busy && !resume && entity->on_st && + bfqq != bfqd->in_service_queue); + + if (busy) { + BUG_ON(atomic_read(&bfqq->ref) < 2); + + if (!resume) + bfq_del_bfqq_busy(bfqd, bfqq, 0); + else + bfq_deactivate_bfqq(bfqd, bfqq, 0); + } else if (entity->on_st) + bfq_put_idle_entity(bfq_entity_service_tree(entity), entity); + + /* + * Here we use a reference to bfqg. We don't need a refcounter + * as the cgroup reference will not be dropped, so that its + * destroy() callback will not be invoked. + */ + entity->parent = bfqg->my_entity; + entity->sched_data = &bfqg->sched_data; + + if (busy && resume) + bfq_activate_bfqq(bfqd, bfqq); + + if (bfqd->in_service_queue == NULL && !bfqd->rq_in_driver) + bfq_schedule_dispatch(bfqd); +} + +/** + * __bfq_bic_change_cgroup - move @bic to @cgroup. + * @bfqd: the queue descriptor. + * @bic: the bic to move. + * @cgroup: the cgroup to move to. + * + * Move bic to cgroup, assuming that bfqd->queue is locked; the caller + * has to make sure that the reference to cgroup is valid across the call. + * + * NOTE: an alternative approach might have been to store the current + * cgroup in bfqq and getting a reference to it, reducing the lookup + * time here, at the price of slightly more complex code. + */ +static struct bfq_group *__bfq_bic_change_cgroup(struct bfq_data *bfqd, + struct bfq_io_cq *bic, + struct cgroup *cgroup) +{ + struct bfq_queue *async_bfqq = bic_to_bfqq(bic, 0); + struct bfq_queue *sync_bfqq = bic_to_bfqq(bic, 1); + struct bfq_entity *entity; + struct bfq_group *bfqg; + struct bfqio_cgroup *bgrp; + + bgrp = cgroup_to_bfqio(cgroup); + + bfqg = bfq_find_alloc_group(bfqd, cgroup); + if (async_bfqq != NULL) { + entity = &async_bfqq->entity; + + if (entity->sched_data != &bfqg->sched_data) { + bic_set_bfqq(bic, NULL, 0); + bfq_log_bfqq(bfqd, async_bfqq, + "bic_change_group: %p %d", + async_bfqq, atomic_read(&async_bfqq->ref)); + bfq_put_queue(async_bfqq); + } + } + + if (sync_bfqq != NULL) { + entity = &sync_bfqq->entity; + if (entity->sched_data != &bfqg->sched_data) + bfq_bfqq_move(bfqd, sync_bfqq, entity, bfqg); + } + + return bfqg; +} + +/** + * bfq_bic_change_cgroup - move @bic to @cgroup. + * @bic: the bic being migrated. + * @cgroup: the destination cgroup. + * + * When the task owning @bic is moved to @cgroup, @bic is immediately + * moved into its new parent group. + */ +static void bfq_bic_change_cgroup(struct bfq_io_cq *bic, + struct cgroup *cgroup) +{ + struct bfq_data *bfqd; + unsigned long uninitialized_var(flags); + + bfqd = bfq_get_bfqd_locked(&(bic->icq.q->elevator->elevator_data), + &flags); + if (bfqd != NULL) { + __bfq_bic_change_cgroup(bfqd, bic, cgroup); + bfq_put_bfqd_unlock(bfqd, &flags); + } +} + +/** + * bfq_bic_update_cgroup - update the cgroup of @bic. + * @bic: the @bic to update. + * + * Make sure that @bic is enqueued in the cgroup of the current task. + * We need this in addition to moving bics during the cgroup attach + * phase because the task owning @bic could be at its first disk + * access or we may end up in the root cgroup as the result of a + * memory allocation failure and here we try to move to the right + * group. + * + * Must be called under the queue lock. It is safe to use the returned + * value even after the rcu_read_unlock() as the migration/destruction + * paths act under the queue lock too. IOW it is impossible to race with + * group migration/destruction and end up with an invalid group as: + * a) here cgroup has not yet been destroyed, nor its destroy callback + * has started execution, as current holds a reference to it, + * b) if it is destroyed after rcu_read_unlock() [after current is + * migrated to a different cgroup] its attach() callback will have + * taken care of remove all the references to the old cgroup data. + */ +static struct bfq_group *bfq_bic_update_cgroup(struct bfq_io_cq *bic) +{ + struct bfq_data *bfqd = bic_to_bfqd(bic); + struct bfq_group *bfqg; + struct cgroup *cgroup; + + BUG_ON(bfqd == NULL); + + rcu_read_lock(); + cgroup = task_cgroup(current, bfqio_subsys_id); + bfqg = __bfq_bic_change_cgroup(bfqd, bic, cgroup); + rcu_read_unlock(); + + return bfqg; +} + +/** + * bfq_flush_idle_tree - deactivate any entity on the idle tree of @st. + * @st: the service tree being flushed. + */ +static inline void bfq_flush_idle_tree(struct bfq_service_tree *st) +{ + struct bfq_entity *entity = st->first_idle; + + for (; entity != NULL; entity = st->first_idle) + __bfq_deactivate_entity(entity, 0); +} + +/** + * bfq_reparent_leaf_entity - move leaf entity to the root_group. + * @bfqd: the device data structure with the root group. + * @entity: the entity to move. + */ +static inline void bfq_reparent_leaf_entity(struct bfq_data *bfqd, + struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + + BUG_ON(bfqq == NULL); + bfq_bfqq_move(bfqd, bfqq, entity, bfqd->root_group); + return; +} + +/** + * bfq_reparent_active_entities - move to the root group all active + * entities. + * @bfqd: the device data structure with the root group. + * @bfqg: the group to move from. + * @st: the service tree with the entities. + * + * Needs queue_lock to be taken and reference to be valid over the call. + */ +static inline void bfq_reparent_active_entities(struct bfq_data *bfqd, + struct bfq_group *bfqg, + struct bfq_service_tree *st) +{ + struct rb_root *active = &st->active; + struct bfq_entity *entity = NULL; + + if (!RB_EMPTY_ROOT(&st->active)) + entity = bfq_entity_of(rb_first(active)); + + for (; entity != NULL; entity = bfq_entity_of(rb_first(active))) + bfq_reparent_leaf_entity(bfqd, entity); + + if (bfqg->sched_data.in_service_entity != NULL) + bfq_reparent_leaf_entity(bfqd, + bfqg->sched_data.in_service_entity); + + return; +} + +/** + * bfq_destroy_group - destroy @bfqg. + * @bgrp: the bfqio_cgroup containing @bfqg. + * @bfqg: the group being destroyed. + * + * Destroy @bfqg, making sure that it is not referenced from its parent. + */ +static void bfq_destroy_group(struct bfqio_cgroup *bgrp, struct bfq_group *bfqg) +{ + struct bfq_data *bfqd; + struct bfq_service_tree *st; + struct bfq_entity *entity = bfqg->my_entity; + unsigned long uninitialized_var(flags); + int i; + + hlist_del(&bfqg->group_node); + + /* + * Empty all service_trees belonging to this group before + * deactivating the group itself. + */ + for (i = 0; i < BFQ_IOPRIO_CLASSES; i++) { + st = bfqg->sched_data.service_tree + i; + + /* + * The idle tree may still contain bfq_queues belonging + * to exited task because they never migrated to a different + * cgroup from the one being destroyed now. No one else + * can access them so it's safe to act without any lock. + */ + bfq_flush_idle_tree(st); + + /* + * It may happen that some queues are still active + * (busy) upon group destruction (if the corresponding + * processes have been forced to terminate). We move + * all the leaf entities corresponding to these queues + * to the root_group. + * Also, it may happen that the group has an entity + * in service, which is disconnected from the active + * tree: it must be moved, too. + * There is no need to put the sync queues, as the + * scheduler has taken no reference. + */ + bfqd = bfq_get_bfqd_locked(&bfqg->bfqd, &flags); + if (bfqd != NULL) { + bfq_reparent_active_entities(bfqd, bfqg, st); + bfq_put_bfqd_unlock(bfqd, &flags); + } + BUG_ON(!RB_EMPTY_ROOT(&st->active)); + BUG_ON(!RB_EMPTY_ROOT(&st->idle)); + } + BUG_ON(bfqg->sched_data.next_in_service != NULL); + BUG_ON(bfqg->sched_data.in_service_entity != NULL); + + /* + * We may race with device destruction, take extra care when + * dereferencing bfqg->bfqd. + */ + bfqd = bfq_get_bfqd_locked(&bfqg->bfqd, &flags); + if (bfqd != NULL) { + hlist_del(&bfqg->bfqd_node); + __bfq_deactivate_entity(entity, 0); + bfq_put_async_queues(bfqd, bfqg); + bfq_put_bfqd_unlock(bfqd, &flags); + } + BUG_ON(entity->tree != NULL); + + /* + * No need to defer the kfree() to the end of the RCU grace + * period: we are called from the destroy() callback of our + * cgroup, so we can be sure that no one is a) still using + * this cgroup or b) doing lookups in it. + */ + kfree(bfqg); +} + +static void bfq_end_wr_async(struct bfq_data *bfqd) +{ + struct hlist_node *pos, *n; + struct bfq_group *bfqg; + + hlist_for_each_entry_safe(bfqg, pos, n, &bfqd->group_list, bfqd_node) + bfq_end_wr_async_queues(bfqd, bfqg); + bfq_end_wr_async_queues(bfqd, bfqd->root_group); +} + +/** + * bfq_disconnect_groups - disconnect @bfqd from all its groups. + * @bfqd: the device descriptor being exited. + * + * When the device exits we just make sure that no lookup can return + * the now unused group structures. They will be deallocated on cgroup + * destruction. + */ +static void bfq_disconnect_groups(struct bfq_data *bfqd) +{ + struct hlist_node *pos, *n; + struct bfq_group *bfqg; + + bfq_log(bfqd, "disconnect_groups beginning"); + hlist_for_each_entry_safe(bfqg, pos, n, &bfqd->group_list, bfqd_node) { + hlist_del(&bfqg->bfqd_node); + + __bfq_deactivate_entity(bfqg->my_entity, 0); + + /* + * Don't remove from the group hash, just set an + * invalid key. No lookups can race with the + * assignment as bfqd is being destroyed; this + * implies also that new elements cannot be added + * to the list. + */ + rcu_assign_pointer(bfqg->bfqd, NULL); + + bfq_log(bfqd, "disconnect_groups: put async for group %p", + bfqg); + bfq_put_async_queues(bfqd, bfqg); + } +} + +static inline void bfq_free_root_group(struct bfq_data *bfqd) +{ + struct bfqio_cgroup *bgrp = &bfqio_root_cgroup; + struct bfq_group *bfqg = bfqd->root_group; + + bfq_put_async_queues(bfqd, bfqg); + + spin_lock_irq(&bgrp->lock); + hlist_del_rcu(&bfqg->group_node); + spin_unlock_irq(&bgrp->lock); + + /* + * No need to synchronize_rcu() here: since the device is gone + * there cannot be any read-side access to its root_group. + */ + kfree(bfqg); +} + +static struct bfq_group *bfq_alloc_root_group(struct bfq_data *bfqd, int node) +{ + struct bfq_group *bfqg; + struct bfqio_cgroup *bgrp; + int i; + + bfqg = kzalloc_node(sizeof(*bfqg), GFP_KERNEL, node); + if (bfqg == NULL) + return NULL; + + bfqg->entity.parent = NULL; + for (i = 0; i < BFQ_IOPRIO_CLASSES; i++) + bfqg->sched_data.service_tree[i] = BFQ_SERVICE_TREE_INIT; + + bgrp = &bfqio_root_cgroup; + spin_lock_irq(&bgrp->lock); + rcu_assign_pointer(bfqg->bfqd, bfqd); + hlist_add_head_rcu(&bfqg->group_node, &bgrp->group_data); + spin_unlock_irq(&bgrp->lock); + + return bfqg; +} + +#define SHOW_FUNCTION(__VAR) \ +static u64 bfqio_cgroup_##__VAR##_read(struct cgroup *cgroup, \ + struct cftype *cftype) \ +{ \ + struct bfqio_cgroup *bgrp; \ + u64 ret; \ + \ + if (!cgroup_lock_live_group(cgroup)) \ + return -ENODEV; \ + \ + bgrp = cgroup_to_bfqio(cgroup); \ + spin_lock_irq(&bgrp->lock); \ + ret = bgrp->__VAR; \ + spin_unlock_irq(&bgrp->lock); \ + \ + cgroup_unlock(); \ + \ + return ret; \ +} + +SHOW_FUNCTION(weight); +SHOW_FUNCTION(ioprio); +SHOW_FUNCTION(ioprio_class); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__VAR, __MIN, __MAX) \ +static int bfqio_cgroup_##__VAR##_write(struct cgroup *cgroup, \ + struct cftype *cftype, \ + u64 val) \ +{ \ + struct bfqio_cgroup *bgrp; \ + struct bfq_group *bfqg; \ + struct hlist_node *n; \ + \ + if (val < (__MIN) || val > (__MAX)) \ + return -EINVAL; \ + \ + if (!cgroup_lock_live_group(cgroup)) \ + return -ENODEV; \ + \ + bgrp = cgroup_to_bfqio(cgroup); \ + \ + spin_lock_irq(&bgrp->lock); \ + bgrp->__VAR = (unsigned short)val; \ + hlist_for_each_entry(bfqg, n, &bgrp->group_data, group_node) { \ + /* \ + * Setting the ioprio_changed flag of the entity \ + * to 1 with new_##__VAR == ##__VAR would re-set \ + * the value of the weight to its ioprio mapping. \ + * Set the flag only if necessary. \ + */ \ + if ((unsigned short)val != bfqg->entity.new_##__VAR) { \ + bfqg->entity.new_##__VAR = (unsigned short)val; \ + /* \ + * Make sure that the above new value has been \ + * stored in bfqg->entity.new_##__VAR before \ + * setting the ioprio_changed flag. In fact, \ + * this flag may be read asynchronously (in \ + * critical sections protected by a different \ + * lock than that held here), and finding this \ + * flag set may cause the execution of the code \ + * for updating parameters whose value may \ + * depend also on bfqg->entity.new_##__VAR (in \ + * __bfq_entity_update_weight_prio). \ + * This barrier makes sure that the new value \ + * of bfqg->entity.new_##__VAR is correctly \ + * seen in that code. \ + */ \ + smp_wmb(); \ + bfqg->entity.ioprio_changed = 1; \ + } \ + } \ + spin_unlock_irq(&bgrp->lock); \ + \ + cgroup_unlock(); \ + \ + return 0; \ +} + +STORE_FUNCTION(weight, BFQ_MIN_WEIGHT, BFQ_MAX_WEIGHT); +STORE_FUNCTION(ioprio, 0, IOPRIO_BE_NR - 1); +STORE_FUNCTION(ioprio_class, IOPRIO_CLASS_RT, IOPRIO_CLASS_IDLE); +#undef STORE_FUNCTION + +static struct cftype bfqio_files[] = { + { + .name = "weight", + .read_u64 = bfqio_cgroup_weight_read, + .write_u64 = bfqio_cgroup_weight_write, + }, + { + .name = "ioprio", + .read_u64 = bfqio_cgroup_ioprio_read, + .write_u64 = bfqio_cgroup_ioprio_write, + }, + { + .name = "ioprio_class", + .read_u64 = bfqio_cgroup_ioprio_class_read, + .write_u64 = bfqio_cgroup_ioprio_class_write, + }, +}; + +static int bfqio_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup) +{ + return cgroup_add_files(cgroup, subsys, bfqio_files, + ARRAY_SIZE(bfqio_files)); +} + +static struct cgroup_subsys_state *bfqio_create(struct cgroup *cgroup) +{ + struct bfqio_cgroup *bgrp; + + if (cgroup->parent != NULL) { + bgrp = kzalloc(sizeof(*bgrp), GFP_KERNEL); + if (bgrp == NULL) + return ERR_PTR(-ENOMEM); + } else + bgrp = &bfqio_root_cgroup; + + spin_lock_init(&bgrp->lock); + INIT_HLIST_HEAD(&bgrp->group_data); + bgrp->ioprio = BFQ_DEFAULT_GRP_IOPRIO; + bgrp->ioprio_class = BFQ_DEFAULT_GRP_CLASS; + + return &bgrp->css; +} + +/* + * We cannot support shared io contexts, as we have no means to support + * two tasks with the same ioc in two different groups without major rework + * of the main bic/bfqq data structures. By now we allow a task to change + * its cgroup only if it's the only owner of its ioc; the drawback of this + * behavior is that a group containing a task that forked using CLONE_IO + * will not be destroyed until the tasks sharing the ioc die. + */ +static int bfqio_can_attach(struct cgroup *cgroup, struct cgroup_taskset *tset) +{ + struct task_struct *task; + struct io_context *ioc; + int ret = 0; + + cgroup_taskset_for_each(task, cgroup, tset) { + /* task_lock() is needed to avoid races with exit_io_context() */ + task_lock(task); + ioc = task->io_context; + if (ioc != NULL && atomic_read(&ioc->nr_tasks) > 1) + /* + * ioc == NULL means that the task is either too + * young or exiting: if it has still no ioc the + * ioc can't be shared, if the task is exiting the + * attach will fail anyway, no matter what we + * return here. + */ + ret = -EINVAL; + task_unlock(task); + if (ret) + break; + } + + return ret; +} + +static void bfqio_attach(struct cgroup *cgroup, struct cgroup_taskset *tset) +{ + struct task_struct *task; + struct io_context *ioc; + struct io_cq *icq; + struct hlist_node *n; + + /* + * IMPORTANT NOTE: The move of more than one process at a time to a + * new group has not yet been tested. + */ + cgroup_taskset_for_each(task, cgroup, tset) { + ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); + if (ioc) { + /* + * Handle cgroup change here. + */ + rcu_read_lock(); + hlist_for_each_entry_rcu(icq, n, &ioc->icq_list, ioc_node) + if (!strncmp( + icq->q->elevator->type->elevator_name, + "bfq", ELV_NAME_MAX)) + bfq_bic_change_cgroup(icq_to_bic(icq), + cgroup); + rcu_read_unlock(); + put_io_context(ioc); + } + } +} + +static void bfqio_destroy(struct cgroup *cgroup) +{ + struct bfqio_cgroup *bgrp = cgroup_to_bfqio(cgroup); + struct hlist_node *n, *tmp; + struct bfq_group *bfqg; + + /* + * Since we are destroying the cgroup, there are no more tasks + * referencing it, and all the RCU grace periods that may have + * referenced it are ended (as the destruction of the parent + * cgroup is RCU-safe); bgrp->group_data will not be accessed by + * anything else and we don't need any synchronization. + */ + hlist_for_each_entry_safe(bfqg, n, tmp, &bgrp->group_data, group_node) + bfq_destroy_group(bgrp, bfqg); + + BUG_ON(!hlist_empty(&bgrp->group_data)); + + kfree(bgrp); +} + +struct cgroup_subsys bfqio_subsys = { + .name = "bfqio", + .create = bfqio_create, + .can_attach = bfqio_can_attach, + .attach = bfqio_attach, + .destroy = bfqio_destroy, + .populate = bfqio_populate, + .subsys_id = bfqio_subsys_id, +}; +#else +static inline void bfq_init_entity(struct bfq_entity *entity, + struct bfq_group *bfqg) +{ + entity->weight = entity->new_weight; + entity->orig_weight = entity->new_weight; + entity->ioprio = entity->new_ioprio; + entity->ioprio_class = entity->new_ioprio_class; + entity->sched_data = &bfqg->sched_data; +} + +static inline struct bfq_group * +bfq_bic_update_cgroup(struct bfq_io_cq *bic) +{ + struct bfq_data *bfqd = bic_to_bfqd(bic); + return bfqd->root_group; +} + +static inline void bfq_bfqq_move(struct bfq_data *bfqd, + struct bfq_queue *bfqq, + struct bfq_entity *entity, + struct bfq_group *bfqg) +{ +} + +static void bfq_end_wr_async(struct bfq_data *bfqd) +{ + bfq_end_wr_async_queues(bfqd, bfqd->root_group); +} + +static inline void bfq_disconnect_groups(struct bfq_data *bfqd) +{ + bfq_put_async_queues(bfqd, bfqd->root_group); +} + +static inline void bfq_free_root_group(struct bfq_data *bfqd) +{ + kfree(bfqd->root_group); +} + +static struct bfq_group *bfq_alloc_root_group(struct bfq_data *bfqd, int node) +{ + struct bfq_group *bfqg; + int i; + + bfqg = kmalloc_node(sizeof(*bfqg), GFP_KERNEL | __GFP_ZERO, node); + if (bfqg == NULL) + return NULL; + + for (i = 0; i < BFQ_IOPRIO_CLASSES; i++) + bfqg->sched_data.service_tree[i] = BFQ_SERVICE_TREE_INIT; + + return bfqg; +} +#endif diff --git a/block/bfq-ioc.c b/block/bfq-ioc.c new file mode 100644 index 00000000..7f6b0004 --- /dev/null +++ b/block/bfq-ioc.c @@ -0,0 +1,36 @@ +/* + * BFQ: I/O context handling. + * + * Based on ideas and code from CFQ: + * Copyright (C) 2003 Jens Axboe + * + * Copyright (C) 2008 Fabio Checconi + * Paolo Valente + * + * Copyright (C) 2010 Paolo Valente + */ + +/** + * icq_to_bic - convert iocontext queue structure to bfq_io_cq. + * @icq: the iocontext queue. + */ +static inline struct bfq_io_cq *icq_to_bic(struct io_cq *icq) +{ + /* bic->icq is the first member, %NULL will convert to %NULL */ + return container_of(icq, struct bfq_io_cq, icq); +} + +/** + * bfq_bic_lookup - search into @ioc a bic associated to @bfqd. + * @bfqd: the lookup key. + * @ioc: the io_context of the process doing I/O. + * + * Queue lock must be held. + */ +static inline struct bfq_io_cq *bfq_bic_lookup(struct bfq_data *bfqd, + struct io_context *ioc) +{ + if (ioc) + return icq_to_bic(ioc_lookup_icq(ioc, bfqd->queue)); + return NULL; +} diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c new file mode 100644 index 00000000..ab55091e --- /dev/null +++ b/block/bfq-iosched.c @@ -0,0 +1,4207 @@ +/* + * Budget Fair Queueing (BFQ) disk scheduler. + * + * Based on ideas and code from CFQ: + * Copyright (C) 2003 Jens Axboe + * + * Copyright (C) 2008 Fabio Checconi + * Paolo Valente + * + * Copyright (C) 2010 Paolo Valente + * + * Licensed under the GPL-2 as detailed in the accompanying COPYING.BFQ + * file. + * + * BFQ is a proportional-share storage-I/O scheduling algorithm based on + * the slice-by-slice service scheme of CFQ. But BFQ assigns budgets, + * measured in number of sectors, to processes instead of time slices. The + * device is not granted to the in-service process for a given time slice, + * but until it has exhausted its assigned budget. This change from the time + * to the service domain allows BFQ to distribute the device throughput + * among processes as desired, without any distortion due to ZBR, workload + * fluctuations or other factors. BFQ uses an ad hoc internal scheduler, + * called B-WF2Q+, to schedule processes according to their budgets. More + * precisely, BFQ schedules queues associated to processes. Thanks to the + * accurate policy of B-WF2Q+, BFQ can afford to assign high budgets to + * I/O-bound processes issuing sequential requests (to boost the + * throughput), and yet guarantee a low latency to interactive and soft + * real-time applications. + * + * BFQ is described in [1], where also a reference to the initial, more + * theoretical paper on BFQ can be found. The interested reader can find + * in the latter paper full details on the main algorithm, as well as + * formulas of the guarantees and formal proofs of all the properties. + * With respect to the version of BFQ presented in these papers, this + * implementation adds a few more heuristics, such as the one that + * guarantees a low latency to soft real-time applications, and a + * hierarchical extension based on H-WF2Q+. + * + * B-WF2Q+ is based on WF2Q+, that is described in [2], together with + * H-WF2Q+, while the augmented tree used to implement B-WF2Q+ with O(log N) + * complexity derives from the one introduced with EEVDF in [3]. + * + * [1] P. Valente and M. Andreolini, ``Improving Application Responsiveness + * with the BFQ Disk I/O Scheduler'', + * Proceedings of the 5th Annual International Systems and Storage + * Conference (SYSTOR '12), June 2012. + * + * http://algogroup.unimo.it/people/paolo/disk_sched/bf1-v1-suite-results.pdf + * + * [2] Jon C.R. Bennett and H. Zhang, ``Hierarchical Packet Fair Queueing + * Algorithms,'' IEEE/ACM Transactions on Networking, 5(5):675-689, + * Oct 1997. + * + * http://www.cs.cmu.edu/~hzhang/papers/TON-97-Oct.ps.gz + * + * [3] I. Stoica and H. Abdel-Wahab, ``Earliest Eligible Virtual Deadline + * First: A Flexible and Accurate Mechanism for Proportional Share + * Resource Allocation,'' technical report. + * + * http://www.cs.berkeley.edu/~istoica/papers/eevdf-tr-95.pdf + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bfq.h" +#include "blk.h" + +/* Expiration time of sync (0) and async (1) requests, in jiffies. */ +static const int bfq_fifo_expire[2] = { HZ / 4, HZ / 8 }; + +/* Maximum backwards seek, in KiB. */ +static const int bfq_back_max = 16 * 1024; + +/* Penalty of a backwards seek, in number of sectors. */ +static const int bfq_back_penalty = 2; + +/* Idling period duration, in jiffies. */ +static int bfq_slice_idle = 0; + +/* Default maximum budget values, in sectors and number of requests. */ +static const int bfq_default_max_budget = 16 * 1024; +static const int bfq_max_budget_async_rq = 4; + +/* + * Async to sync throughput distribution is controlled as follows: + * when an async request is served, the entity is charged the number + * of sectors of the request, multiplied by the factor below + */ +static const int bfq_async_charge_factor = 10; + +/* Default timeout values, in jiffies, approximating CFQ defaults. */ +static const int bfq_timeout_sync = HZ / 8; +static int bfq_timeout_async = HZ / 25; + +struct kmem_cache *bfq_pool; + +/* Below this threshold (in ms), we consider thinktime immediate. */ +#define BFQ_MIN_TT 2 + +/* hw_tag detection: parallel requests threshold and min samples needed. */ +#define BFQ_HW_QUEUE_THRESHOLD 4 +#define BFQ_HW_QUEUE_SAMPLES 32 + +#define BFQQ_SEEK_THR (sector_t)(8 * 1024) +#define BFQQ_SEEKY(bfqq) ((bfqq)->seek_mean > BFQQ_SEEK_THR) + +/* Min samples used for peak rate estimation (for autotuning). */ +#define BFQ_PEAK_RATE_SAMPLES 32 + +/* Shift used for peak rate fixed precision calculations. */ +#define BFQ_RATE_SHIFT 16 + +/* + * By default, BFQ computes the duration of the weight raising for + * interactive applications automatically, using the following formula: + * duration = (R / r) * T, where r is the peak rate of the device, and + * R and T are two reference parameters. + * In particular, R is the peak rate of the reference device (see below), + * and T is a reference time: given the systems that are likely to be + * installed on the reference device according to its speed class, T is + * about the maximum time needed, under BFQ and while reading two files in + * parallel, to load typical large applications on these systems. + * In practice, the slower/faster the device at hand is, the more/less it + * takes to load applications with respect to the reference device. + * Accordingly, the longer/shorter BFQ grants weight raising to interactive + * applications. + * + * BFQ uses four different reference pairs (R, T), depending on: + * . whether the device is rotational or non-rotational; + * . whether the device is slow, such as old or portable HDDs, as well as + * SD cards, or fast, such as newer HDDs and SSDs. + * + * The device's speed class is dynamically (re)detected in + * bfq_update_peak_rate() every time the estimated peak rate is updated. + * + * In the following definitions, R_slow[0]/R_fast[0] and T_slow[0]/T_fast[0] + * are the reference values for a slow/fast rotational device, whereas + * R_slow[1]/R_fast[1] and T_slow[1]/T_fast[1] are the reference values for + * a slow/fast non-rotational device. Finally, device_speed_thresh are the + * thresholds used to switch between speed classes. + * Both the reference peak rates and the thresholds are measured in + * sectors/usec, left-shifted by BFQ_RATE_SHIFT. + */ +static int R_slow[2] = {1536, 10752}; +static int R_fast[2] = {17415, 34791}; +/* + * To improve readability, a conversion function is used to initialize the + * following arrays, which entails that they can be initialized only in a + * function. + */ +static int T_slow[2]; +static int T_fast[2]; +static int device_speed_thresh[2]; + +#define BFQ_SERVICE_TREE_INIT ((struct bfq_service_tree) \ + { RB_ROOT, RB_ROOT, NULL, NULL, 0, 0 }) + +#define RQ_BIC(rq) ((struct bfq_io_cq *) (rq)->elv.priv[0]) +#define RQ_BFQQ(rq) ((rq)->elv.priv[1]) + +static inline void bfq_schedule_dispatch(struct bfq_data *bfqd); + +#include "bfq-ioc.c" +#include "bfq-sched.c" +#include "bfq-cgroup.c" + +#define bfq_class_idle(bfqq) ((bfqq)->entity.ioprio_class ==\ + IOPRIO_CLASS_IDLE) +#define bfq_class_rt(bfqq) ((bfqq)->entity.ioprio_class ==\ + IOPRIO_CLASS_RT) + +#define bfq_sample_valid(samples) ((samples) > 80) + +/* + * The following macro groups conditions that need to be evaluated when + * checking if existing queues and groups form a symmetric scenario + * and therefore idling can be reduced or disabled for some of the + * queues. See the comment to the function bfq_bfqq_must_not_expire() + * for further details. + */ +#ifdef CONFIG_CGROUP_BFQIO +#define symmetric_scenario (!bfqd->active_numerous_groups && \ + !bfq_differentiated_weights(bfqd)) +#else +#define symmetric_scenario (!bfq_differentiated_weights(bfqd)) +#endif + +/* + * We regard a request as SYNC, if either it's a read or has the SYNC bit + * set (in which case it could also be a direct WRITE). + */ +static inline int bfq_bio_sync(struct bio *bio) +{ + if (bio_data_dir(bio) == READ || (bio->bi_rw & REQ_SYNC)) + return 1; + + return 0; +} + +/* + * Scheduler run of queue, if there are requests pending and no one in the + * driver that will restart queueing. + */ +static inline void bfq_schedule_dispatch(struct bfq_data *bfqd) +{ + if (bfqd->queued != 0) { + bfq_log(bfqd, "schedule dispatch"); + kblockd_schedule_work(bfqd->queue, &bfqd->unplug_work); + } +} + +/* + * Lifted from AS - choose which of rq1 and rq2 that is best served now. + * We choose the request that is closesr to the head right now. Distance + * behind the head is penalized and only allowed to a certain extent. + */ +static struct request *bfq_choose_req(struct bfq_data *bfqd, + struct request *rq1, + struct request *rq2, + sector_t last) +{ + sector_t s1, s2, d1 = 0, d2 = 0; + unsigned long back_max; +#define BFQ_RQ1_WRAP 0x01 /* request 1 wraps */ +#define BFQ_RQ2_WRAP 0x02 /* request 2 wraps */ + unsigned wrap = 0; /* bit mask: requests behind the disk head? */ + + if (rq1 == NULL || rq1 == rq2) + return rq2; + if (rq2 == NULL) + return rq1; + + if (rq_is_sync(rq1) && !rq_is_sync(rq2)) + return rq1; + else if (rq_is_sync(rq2) && !rq_is_sync(rq1)) + return rq2; + if ((rq1->cmd_flags & REQ_META) && !(rq2->cmd_flags & REQ_META)) + return rq1; + else if ((rq2->cmd_flags & REQ_META) && !(rq1->cmd_flags & REQ_META)) + return rq2; + + s1 = blk_rq_pos(rq1); + s2 = blk_rq_pos(rq2); + + /* + * By definition, 1KiB is 2 sectors. + */ + back_max = bfqd->bfq_back_max * 2; + + /* + * Strict one way elevator _except_ in the case where we allow + * short backward seeks which are biased as twice the cost of a + * similar forward seek. + */ + if (s1 >= last) + d1 = s1 - last; + else if (s1 + back_max >= last) + d1 = (last - s1) * bfqd->bfq_back_penalty; + else + wrap |= BFQ_RQ1_WRAP; + + if (s2 >= last) + d2 = s2 - last; + else if (s2 + back_max >= last) + d2 = (last - s2) * bfqd->bfq_back_penalty; + else + wrap |= BFQ_RQ2_WRAP; + + /* Found required data */ + + /* + * By doing switch() on the bit mask "wrap" we avoid having to + * check two variables for all permutations: --> faster! + */ + switch (wrap) { + case 0: /* common case for CFQ: rq1 and rq2 not wrapped */ + if (d1 < d2) + return rq1; + else if (d2 < d1) + return rq2; + else { + if (s1 >= s2) + return rq1; + else + return rq2; + } + + case BFQ_RQ2_WRAP: + return rq1; + case BFQ_RQ1_WRAP: + return rq2; + case (BFQ_RQ1_WRAP|BFQ_RQ2_WRAP): /* both rqs wrapped */ + default: + /* + * Since both rqs are wrapped, + * start with the one that's further behind head + * (--> only *one* back seek required), + * since back seek takes more time than forward. + */ + if (s1 <= s2) + return rq1; + else + return rq2; + } +} + +static struct bfq_queue * +bfq_rq_pos_tree_lookup(struct bfq_data *bfqd, struct rb_root *root, + sector_t sector, struct rb_node **ret_parent, + struct rb_node ***rb_link) +{ + struct rb_node **p, *parent; + struct bfq_queue *bfqq = NULL; + + parent = NULL; + p = &root->rb_node; + while (*p) { + struct rb_node **n; + + parent = *p; + bfqq = rb_entry(parent, struct bfq_queue, pos_node); + + /* + * Sort strictly based on sector. Smallest to the left, + * largest to the right. + */ + if (sector > blk_rq_pos(bfqq->next_rq)) + n = &(*p)->rb_right; + else if (sector < blk_rq_pos(bfqq->next_rq)) + n = &(*p)->rb_left; + else + break; + p = n; + bfqq = NULL; + } + + *ret_parent = parent; + if (rb_link) + *rb_link = p; + + bfq_log(bfqd, "rq_pos_tree_lookup %llu: returning %d", + (long long unsigned)sector, + bfqq != NULL ? bfqq->pid : 0); + + return bfqq; +} + +static void bfq_rq_pos_tree_add(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + struct rb_node **p, *parent; + struct bfq_queue *__bfqq; + + if (bfqq->pos_root != NULL) { + rb_erase(&bfqq->pos_node, bfqq->pos_root); + bfqq->pos_root = NULL; + } + + if (bfq_class_idle(bfqq)) + return; + if (!bfqq->next_rq) + return; + + bfqq->pos_root = &bfqd->rq_pos_tree; + __bfqq = bfq_rq_pos_tree_lookup(bfqd, bfqq->pos_root, + blk_rq_pos(bfqq->next_rq), &parent, &p); + if (__bfqq == NULL) { + rb_link_node(&bfqq->pos_node, parent, p); + rb_insert_color(&bfqq->pos_node, bfqq->pos_root); + } else + bfqq->pos_root = NULL; +} + +/* + * Tell whether there are active queues or groups with differentiated weights. + */ +static inline bool bfq_differentiated_weights(struct bfq_data *bfqd) +{ + /* + * For weights to differ, at least one of the trees must contain + * at least two nodes. + */ + return (!RB_EMPTY_ROOT(&bfqd->queue_weights_tree) && + (bfqd->queue_weights_tree.rb_node->rb_left || + bfqd->queue_weights_tree.rb_node->rb_right) +#ifdef CONFIG_CGROUP_BFQIO + ) || + (!RB_EMPTY_ROOT(&bfqd->group_weights_tree) && + (bfqd->group_weights_tree.rb_node->rb_left || + bfqd->group_weights_tree.rb_node->rb_right) +#endif + ); +} + +/* + * If the weight-counter tree passed as input contains no counter for + * the weight of the input entity, then add that counter; otherwise just + * increment the existing counter. + * + * Note that weight-counter trees contain few nodes in mostly symmetric + * scenarios. For example, if all queues have the same weight, then the + * weight-counter tree for the queues may contain at most one node. + * This holds even if low_latency is on, because weight-raised queues + * are not inserted in the tree. + * In most scenarios, the rate at which nodes are created/destroyed + * should be low too. + */ +static void bfq_weights_tree_add(struct bfq_data *bfqd, + struct bfq_entity *entity, + struct rb_root *root) +{ + struct rb_node **new = &(root->rb_node), *parent = NULL; + + /* + * Do not insert if the entity is already associated with a + * counter, which happens if: + * 1) the entity is associated with a queue, + * 2) a request arrival has caused the queue to become both + * non-weight-raised, and hence change its weight, and + * backlogged; in this respect, each of the two events + * causes an invocation of this function, + * 3) this is the invocation of this function caused by the + * second event. This second invocation is actually useless, + * and we handle this fact by exiting immediately. More + * efficient or clearer solutions might possibly be adopted. + */ + if (entity->weight_counter) + return; + + while (*new) { + struct bfq_weight_counter *__counter = container_of(*new, + struct bfq_weight_counter, + weights_node); + parent = *new; + + if (entity->weight == __counter->weight) { + entity->weight_counter = __counter; + goto inc_counter; + } + if (entity->weight < __counter->weight) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); + } + + entity->weight_counter = kzalloc(sizeof(struct bfq_weight_counter), + GFP_ATOMIC); + entity->weight_counter->weight = entity->weight; + rb_link_node(&entity->weight_counter->weights_node, parent, new); + rb_insert_color(&entity->weight_counter->weights_node, root); + +inc_counter: + entity->weight_counter->num_active++; +} + +/* + * Decrement the weight counter associated with the entity, and, if the + * counter reaches 0, remove the counter from the tree. + * See the comments to the function bfq_weights_tree_add() for considerations + * about overhead. + */ +static void bfq_weights_tree_remove(struct bfq_data *bfqd, + struct bfq_entity *entity, + struct rb_root *root) +{ + if (!entity->weight_counter) + return; + + BUG_ON(RB_EMPTY_ROOT(root)); + BUG_ON(entity->weight_counter->weight != entity->weight); + + BUG_ON(!entity->weight_counter->num_active); + entity->weight_counter->num_active--; + if (entity->weight_counter->num_active > 0) + goto reset_entity_pointer; + + rb_erase(&entity->weight_counter->weights_node, root); + kfree(entity->weight_counter); + +reset_entity_pointer: + entity->weight_counter = NULL; +} + +static struct request *bfq_find_next_rq(struct bfq_data *bfqd, + struct bfq_queue *bfqq, + struct request *last) +{ + struct rb_node *rbnext = rb_next(&last->rb_node); + struct rb_node *rbprev = rb_prev(&last->rb_node); + struct request *next = NULL, *prev = NULL; + + BUG_ON(RB_EMPTY_NODE(&last->rb_node)); + + if (rbprev != NULL) + prev = rb_entry_rq(rbprev); + + if (rbnext != NULL) + next = rb_entry_rq(rbnext); + else { + rbnext = rb_first(&bfqq->sort_list); + if (rbnext && rbnext != &last->rb_node) + next = rb_entry_rq(rbnext); + } + + return bfq_choose_req(bfqd, next, prev, blk_rq_pos(last)); +} + +/* see the definition of bfq_async_charge_factor for details */ +static inline unsigned long bfq_serv_to_charge(struct request *rq, + struct bfq_queue *bfqq) +{ + return blk_rq_sectors(rq) * + (1 + ((!bfq_bfqq_sync(bfqq)) * (bfqq->wr_coeff == 1) * + bfq_async_charge_factor)); +} + +/** + * bfq_updated_next_req - update the queue after a new next_rq selection. + * @bfqd: the device data the queue belongs to. + * @bfqq: the queue to update. + * + * If the first request of a queue changes we make sure that the queue + * has enough budget to serve at least its first request (if the + * request has grown). We do this because if the queue has not enough + * budget for its first request, it has to go through two dispatch + * rounds to actually get it dispatched. + */ +static void bfq_updated_next_req(struct bfq_data *bfqd, + struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + struct bfq_service_tree *st = bfq_entity_service_tree(entity); + struct request *next_rq = bfqq->next_rq; + unsigned long new_budget; + + if (next_rq == NULL) + return; + + if (bfqq == bfqd->in_service_queue) + /* + * In order not to break guarantees, budgets cannot be + * changed after an entity has been selected. + */ + return; + + BUG_ON(entity->tree != &st->active); + BUG_ON(entity == entity->sched_data->in_service_entity); + + new_budget = max_t(unsigned long, bfqq->max_budget, + bfq_serv_to_charge(next_rq, bfqq)); + if (entity->budget != new_budget) { + entity->budget = new_budget; + bfq_log_bfqq(bfqd, bfqq, "updated next rq: new budget %lu", + new_budget); + bfq_activate_bfqq(bfqd, bfqq); + } +} + +static inline unsigned int bfq_wr_duration(struct bfq_data *bfqd) +{ + u64 dur; + + if (bfqd->bfq_wr_max_time > 0) + return bfqd->bfq_wr_max_time; + + dur = bfqd->RT_prod; + do_div(dur, bfqd->peak_rate); + + return dur; +} + +static inline unsigned +bfq_bfqq_cooperations(struct bfq_queue *bfqq) +{ + return bfqq->bic ? bfqq->bic->cooperations : 0; +} + +static inline void +bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic) +{ + if (bic->saved_idle_window) + bfq_mark_bfqq_idle_window(bfqq); + else + bfq_clear_bfqq_idle_window(bfqq); + if (bic->saved_IO_bound) + bfq_mark_bfqq_IO_bound(bfqq); + else + bfq_clear_bfqq_IO_bound(bfqq); + /* Assuming that the flag in_large_burst is already correctly set */ + if (bic->wr_time_left && bfqq->bfqd->low_latency && + !bfq_bfqq_in_large_burst(bfqq) && + bic->cooperations < bfqq->bfqd->bfq_coop_thresh) { + /* + * Start a weight raising period with the duration given by + * the raising_time_left snapshot. + */ + if (bfq_bfqq_busy(bfqq)) + bfqq->bfqd->wr_busy_queues++; + bfqq->wr_coeff = bfqq->bfqd->bfq_wr_coeff; + bfqq->wr_cur_max_time = bic->wr_time_left; + bfqq->last_wr_start_finish = jiffies; + bfqq->entity.ioprio_changed = 1; + } + /* + * Clear wr_time_left to prevent bfq_bfqq_save_state() from + * getting confused about the queue's need of a weight-raising + * period. + */ + bic->wr_time_left = 0; +} + +/* Must be called with the queue_lock held. */ +static int bfqq_process_refs(struct bfq_queue *bfqq) +{ + int process_refs, io_refs; + + io_refs = bfqq->allocated[READ] + bfqq->allocated[WRITE]; + process_refs = atomic_read(&bfqq->ref) - io_refs - bfqq->entity.on_st; + BUG_ON(process_refs < 0); + return process_refs; +} + +/* Empty burst list and add just bfqq (see comments to bfq_handle_burst) */ +static inline void bfq_reset_burst_list(struct bfq_data *bfqd, + struct bfq_queue *bfqq) +{ + struct bfq_queue *item; + struct hlist_node *pos, *n; + + hlist_for_each_entry_safe(item, pos, n, + &bfqd->burst_list, burst_list_node) + hlist_del_init(&item->burst_list_node); + hlist_add_head(&bfqq->burst_list_node, &bfqd->burst_list); + bfqd->burst_size = 1; +} + +/* Add bfqq to the list of queues in current burst (see bfq_handle_burst) */ +static void bfq_add_to_burst(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + /* Increment burst size to take into account also bfqq */ + bfqd->burst_size++; + + if (bfqd->burst_size == bfqd->bfq_large_burst_thresh) { + struct bfq_queue *pos, *bfqq_item; + struct hlist_node *p, *n; + + /* + * Enough queues have been activated shortly after each + * other to consider this burst as large. + */ + bfqd->large_burst = true; + + /* + * We can now mark all queues in the burst list as + * belonging to a large burst. + */ + hlist_for_each_entry(bfqq_item, n, &bfqd->burst_list, + burst_list_node) + bfq_mark_bfqq_in_large_burst(bfqq_item); + bfq_mark_bfqq_in_large_burst(bfqq); + + /* + * From now on, and until the current burst finishes, any + * new queue being activated shortly after the last queue + * was inserted in the burst can be immediately marked as + * belonging to a large burst. So the burst list is not + * needed any more. Remove it. + */ + hlist_for_each_entry_safe(pos, p, n, &bfqd->burst_list, + burst_list_node) + hlist_del_init(&pos->burst_list_node); + } else /* burst not yet large: add bfqq to the burst list */ + hlist_add_head(&bfqq->burst_list_node, &bfqd->burst_list); +} + +/* + * If many queues happen to become active shortly after each other, then, + * to help the processes associated to these queues get their job done as + * soon as possible, it is usually better to not grant either weight-raising + * or device idling to these queues. In this comment we describe, firstly, + * the reasons why this fact holds, and, secondly, the next function, which + * implements the main steps needed to properly mark these queues so that + * they can then be treated in a different way. + * + * As for the terminology, we say that a queue becomes active, i.e., + * switches from idle to backlogged, either when it is created (as a + * consequence of the arrival of an I/O request), or, if already existing, + * when a new request for the queue arrives while the queue is idle. + * Bursts of activations, i.e., activations of different queues occurring + * shortly after each other, are typically caused by services or applications + * that spawn or reactivate many parallel threads/processes. Examples are + * systemd during boot or git grep. + * + * These services or applications benefit mostly from a high throughput: + * the quicker the requests of the activated queues are cumulatively served, + * the sooner the target job of these queues gets completed. As a consequence, + * weight-raising any of these queues, which also implies idling the device + * for it, is almost always counterproductive: in most cases it just lowers + * throughput. + * + * On the other hand, a burst of activations may be also caused by the start + * of an application that does not consist in a lot of parallel I/O-bound + * threads. In fact, with a complex application, the burst may be just a + * consequence of the fact that several processes need to be executed to + * start-up the application. To start an application as quickly as possible, + * the best thing to do is to privilege the I/O related to the application + * with respect to all other I/O. Therefore, the best strategy to start as + * quickly as possible an application that causes a burst of activations is + * to weight-raise all the queues activated during the burst. This is the + * exact opposite of the best strategy for the other type of bursts. + * + * In the end, to take the best action for each of the two cases, the two + * types of bursts need to be distinguished. Fortunately, this seems + * relatively easy to do, by looking at the sizes of the bursts. In + * particular, we found a threshold such that bursts with a larger size + * than that threshold are apparently caused only by services or commands + * such as systemd or git grep. For brevity, hereafter we call just 'large' + * these bursts. BFQ *does not* weight-raise queues whose activations occur + * in a large burst. In addition, for each of these queues BFQ performs or + * does not perform idling depending on which choice boosts the throughput + * most. The exact choice depends on the device and request pattern at + * hand. + * + * Turning back to the next function, it implements all the steps needed + * to detect the occurrence of a large burst and to properly mark all the + * queues belonging to it (so that they can then be treated in a different + * way). This goal is achieved by maintaining a special "burst list" that + * holds, temporarily, the queues that belong to the burst in progress. The + * list is then used to mark these queues as belonging to a large burst if + * the burst does become large. The main steps are the following. + * + * . when the very first queue is activated, the queue is inserted into the + * list (as it could be the first queue in a possible burst) + * + * . if the current burst has not yet become large, and a queue Q that does + * not yet belong to the burst is activated shortly after the last time + * at which a new queue entered the burst list, then the function appends + * Q to the burst list + * + * . if, as a consequence of the previous step, the burst size reaches + * the large-burst threshold, then + * + * . all the queues in the burst list are marked as belonging to a + * large burst + * + * . the burst list is deleted; in fact, the burst list already served + * its purpose (keeping temporarily track of the queues in a burst, + * so as to be able to mark them as belonging to a large burst in the + * previous sub-step), and now is not needed any more + * + * . the device enters a large-burst mode + * + * . if a queue Q that does not belong to the burst is activated while + * the device is in large-burst mode and shortly after the last time + * at which a queue either entered the burst list or was marked as + * belonging to the current large burst, then Q is immediately marked + * as belonging to a large burst. + * + * . if a queue Q that does not belong to the burst is activated a while + * later, i.e., not shortly after, than the last time at which a queue + * either entered the burst list or was marked as belonging to the + * current large burst, then the current burst is deemed as finished and: + * + * . the large-burst mode is reset if set + * + * . the burst list is emptied + * + * . Q is inserted in the burst list, as Q may be the first queue + * in a possible new burst (then the burst list contains just Q + * after this step). + */ +static void bfq_handle_burst(struct bfq_data *bfqd, struct bfq_queue *bfqq, + bool idle_for_long_time) +{ + /* + * If bfqq happened to be activated in a burst, but has been idle + * for at least as long as an interactive queue, then we assume + * that, in the overall I/O initiated in the burst, the I/O + * associated to bfqq is finished. So bfqq does not need to be + * treated as a queue belonging to a burst anymore. Accordingly, + * we reset bfqq's in_large_burst flag if set, and remove bfqq + * from the burst list if it's there. We do not decrement instead + * burst_size, because the fact that bfqq does not need to belong + * to the burst list any more does not invalidate the fact that + * bfqq may have been activated during the current burst. + */ + if (idle_for_long_time) { + hlist_del_init(&bfqq->burst_list_node); + bfq_clear_bfqq_in_large_burst(bfqq); + } + + /* + * If bfqq is already in the burst list or is part of a large + * burst, then there is nothing else to do. + */ + if (!hlist_unhashed(&bfqq->burst_list_node) || + bfq_bfqq_in_large_burst(bfqq)) + return; + + /* + * If bfqq's activation happens late enough, then the current + * burst is finished, and related data structures must be reset. + * + * In this respect, consider the special case where bfqq is the very + * first queue being activated. In this case, last_ins_in_burst is + * not yet significant when we get here. But it is easy to verify + * that, whether or not the following condition is true, bfqq will + * end up being inserted into the burst list. In particular the + * list will happen to contain only bfqq. And this is exactly what + * has to happen, as bfqq may be the first queue in a possible + * burst. + */ + if (time_is_before_jiffies(bfqd->last_ins_in_burst + + bfqd->bfq_burst_interval)) { + bfqd->large_burst = false; + bfq_reset_burst_list(bfqd, bfqq); + return; + } + + /* + * If we get here, then bfqq is being activated shortly after the + * last queue. So, if the current burst is also large, we can mark + * bfqq as belonging to this large burst immediately. + */ + if (bfqd->large_burst) { + bfq_mark_bfqq_in_large_burst(bfqq); + return; + } + + /* + * If we get here, then a large-burst state has not yet been + * reached, but bfqq is being activated shortly after the last + * queue. Then we add bfqq to the burst. + */ + bfq_add_to_burst(bfqd, bfqq); +} + +static void bfq_add_request(struct request *rq) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq); + struct bfq_entity *entity = &bfqq->entity; + struct bfq_data *bfqd = bfqq->bfqd; + struct request *next_rq, *prev; + unsigned long old_wr_coeff = bfqq->wr_coeff; + bool interactive = false; + + bfq_log_bfqq(bfqd, bfqq, "add_request %d", rq_is_sync(rq)); + bfqq->queued[rq_is_sync(rq)]++; + bfqd->queued++; + + elv_rb_add(&bfqq->sort_list, rq); + + /* + * Check if this request is a better next-serve candidate. + */ + prev = bfqq->next_rq; + next_rq = bfq_choose_req(bfqd, bfqq->next_rq, rq, bfqd->last_position); + BUG_ON(next_rq == NULL); + bfqq->next_rq = next_rq; + + /* + * Adjust priority tree position, if next_rq changes. + */ + if (prev != bfqq->next_rq) + bfq_rq_pos_tree_add(bfqd, bfqq); + + if (!bfq_bfqq_busy(bfqq)) { + bool soft_rt, coop_or_in_burst, + idle_for_long_time = time_is_before_jiffies( + bfqq->budget_timeout + + bfqd->bfq_wr_min_idle_time); + + if (bfq_bfqq_sync(bfqq)) { + bool already_in_burst = + !hlist_unhashed(&bfqq->burst_list_node) || + bfq_bfqq_in_large_burst(bfqq); + bfq_handle_burst(bfqd, bfqq, idle_for_long_time); + /* + * If bfqq was not already in the current burst, + * then, at this point, bfqq either has been + * added to the current burst or has caused the + * current burst to terminate. In particular, in + * the second case, bfqq has become the first + * queue in a possible new burst. + * In both cases last_ins_in_burst needs to be + * moved forward. + */ + if (!already_in_burst) + bfqd->last_ins_in_burst = jiffies; + } + + coop_or_in_burst = bfq_bfqq_in_large_burst(bfqq) || + bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh; + soft_rt = bfqd->bfq_wr_max_softrt_rate > 0 && + !coop_or_in_burst && + time_is_before_jiffies(bfqq->soft_rt_next_start); + interactive = !coop_or_in_burst && idle_for_long_time; + entity->budget = max_t(unsigned long, bfqq->max_budget, + bfq_serv_to_charge(next_rq, bfqq)); + + if (!bfq_bfqq_IO_bound(bfqq)) { + if (time_before(jiffies, + RQ_BIC(rq)->ttime.last_end_request + + bfqd->bfq_slice_idle)) { + bfqq->requests_within_timer++; + if (bfqq->requests_within_timer >= + bfqd->bfq_requests_within_timer) + bfq_mark_bfqq_IO_bound(bfqq); + } else + bfqq->requests_within_timer = 0; + } + + if (!bfqd->low_latency) + goto add_bfqq_busy; + + if (bfq_bfqq_just_split(bfqq)) + goto set_ioprio_changed; + + /* + * If the queue: + * - is not being boosted, + * - has been idle for enough time, + * - is not a sync queue or is linked to a bfq_io_cq (it is + * shared "for its nature" or it is not shared and its + * requests have not been redirected to a shared queue) + * start a weight-raising period. + */ + if (old_wr_coeff == 1 && (interactive || soft_rt) && + (!bfq_bfqq_sync(bfqq) || bfqq->bic != NULL)) { + bfqq->wr_coeff = bfqd->bfq_wr_coeff; + if (interactive) + bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); + else + bfqq->wr_cur_max_time = + bfqd->bfq_wr_rt_max_time; + bfq_log_bfqq(bfqd, bfqq, + "wrais starting at %lu, rais_max_time %u", + jiffies, + jiffies_to_msecs(bfqq->wr_cur_max_time)); + } else if (old_wr_coeff > 1) { + if (interactive) + bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); + else if (coop_or_in_burst || + (bfqq->wr_cur_max_time == + bfqd->bfq_wr_rt_max_time && + !soft_rt)) { + bfqq->wr_coeff = 1; + bfq_log_bfqq(bfqd, bfqq, + "wrais ending at %lu, rais_max_time %u", + jiffies, + jiffies_to_msecs(bfqq-> + wr_cur_max_time)); + } else if (time_before( + bfqq->last_wr_start_finish + + bfqq->wr_cur_max_time, + jiffies + + bfqd->bfq_wr_rt_max_time) && + soft_rt) { + /* + * + * The remaining weight-raising time is lower + * than bfqd->bfq_wr_rt_max_time, which means + * that the application is enjoying weight + * raising either because deemed soft-rt in + * the near past, or because deemed interactive + * a long ago. + * In both cases, resetting now the current + * remaining weight-raising time for the + * application to the weight-raising duration + * for soft rt applications would not cause any + * latency increase for the application (as the + * new duration would be higher than the + * remaining time). + * + * In addition, the application is now meeting + * the requirements for being deemed soft rt. + * In the end we can correctly and safely + * (re)charge the weight-raising duration for + * the application with the weight-raising + * duration for soft rt applications. + * + * In particular, doing this recharge now, i.e., + * before the weight-raising period for the + * application finishes, reduces the probability + * of the following negative scenario: + * 1) the weight of a soft rt application is + * raised at startup (as for any newly + * created application), + * 2) since the application is not interactive, + * at a certain time weight-raising is + * stopped for the application, + * 3) at that time the application happens to + * still have pending requests, and hence + * is destined to not have a chance to be + * deemed soft rt before these requests are + * completed (see the comments to the + * function bfq_bfqq_softrt_next_start() + * for details on soft rt detection), + * 4) these pending requests experience a high + * latency because the application is not + * weight-raised while they are pending. + */ + bfqq->last_wr_start_finish = jiffies; + bfqq->wr_cur_max_time = + bfqd->bfq_wr_rt_max_time; + } + } +set_ioprio_changed: + if (old_wr_coeff != bfqq->wr_coeff) + entity->ioprio_changed = 1; +add_bfqq_busy: + bfqq->last_idle_bklogged = jiffies; + bfqq->service_from_backlogged = 0; + bfq_clear_bfqq_softrt_update(bfqq); + bfq_add_bfqq_busy(bfqd, bfqq); + } else { + if (bfqd->low_latency && old_wr_coeff == 1 && !rq_is_sync(rq) && + time_is_before_jiffies( + bfqq->last_wr_start_finish + + bfqd->bfq_wr_min_inter_arr_async)) { + bfqq->wr_coeff = bfqd->bfq_wr_coeff; + bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); + + bfqd->wr_busy_queues++; + entity->ioprio_changed = 1; + bfq_log_bfqq(bfqd, bfqq, + "non-idle wrais starting at %lu, rais_max_time %u", + jiffies, + jiffies_to_msecs(bfqq->wr_cur_max_time)); + } + if (prev != bfqq->next_rq) + bfq_updated_next_req(bfqd, bfqq); + } + + if (bfqd->low_latency && + (old_wr_coeff == 1 || bfqq->wr_coeff == 1 || interactive)) + bfqq->last_wr_start_finish = jiffies; +} + +static struct request *bfq_find_rq_fmerge(struct bfq_data *bfqd, + struct bio *bio) +{ + struct task_struct *tsk = current; + struct bfq_io_cq *bic; + struct bfq_queue *bfqq; + + bic = bfq_bic_lookup(bfqd, tsk->io_context); + if (bic == NULL) + return NULL; + + bfqq = bic_to_bfqq(bic, bfq_bio_sync(bio)); + if (bfqq != NULL) { + sector_t sector = bio->bi_sector + bio_sectors(bio); + + return elv_rb_find(&bfqq->sort_list, sector); + } + + return NULL; +} + +static void bfq_activate_request(struct request_queue *q, struct request *rq) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + + bfqd->rq_in_driver++; + bfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq); + bfq_log(bfqd, "activate_request: new bfqd->last_position %llu", + (long long unsigned)bfqd->last_position); +} + +static inline void bfq_deactivate_request(struct request_queue *q, + struct request *rq) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + + BUG_ON(bfqd->rq_in_driver == 0); + bfqd->rq_in_driver--; +} + +static void bfq_remove_request(struct request *rq) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq); + struct bfq_data *bfqd = bfqq->bfqd; + const int sync = rq_is_sync(rq); + + if (bfqq->next_rq == rq) { + bfqq->next_rq = bfq_find_next_rq(bfqd, bfqq, rq); + bfq_updated_next_req(bfqd, bfqq); + } + + if (rq->queuelist.prev != &rq->queuelist) + list_del_init(&rq->queuelist); + BUG_ON(bfqq->queued[sync] == 0); + bfqq->queued[sync]--; + bfqd->queued--; + elv_rb_del(&bfqq->sort_list, rq); + + if (RB_EMPTY_ROOT(&bfqq->sort_list)) { + if (bfq_bfqq_busy(bfqq) && bfqq != bfqd->in_service_queue) + bfq_del_bfqq_busy(bfqd, bfqq, 1); + /* + * Remove queue from request-position tree as it is empty. + */ + if (bfqq->pos_root != NULL) { + rb_erase(&bfqq->pos_node, bfqq->pos_root); + bfqq->pos_root = NULL; + } + } + + if (rq->cmd_flags & REQ_META) { + BUG_ON(bfqq->meta_pending == 0); + bfqq->meta_pending--; + } +} + +static int bfq_merge(struct request_queue *q, struct request **req, + struct bio *bio) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct request *__rq; + + __rq = bfq_find_rq_fmerge(bfqd, bio); + if (__rq != NULL && elv_rq_merge_ok(__rq, bio)) { + *req = __rq; + return ELEVATOR_FRONT_MERGE; + } + + return ELEVATOR_NO_MERGE; +} + +static void bfq_merged_request(struct request_queue *q, struct request *req, + int type) +{ + if (type == ELEVATOR_FRONT_MERGE && + rb_prev(&req->rb_node) && + blk_rq_pos(req) < + blk_rq_pos(container_of(rb_prev(&req->rb_node), + struct request, rb_node))) { + struct bfq_queue *bfqq = RQ_BFQQ(req); + struct bfq_data *bfqd = bfqq->bfqd; + struct request *prev, *next_rq; + + /* Reposition request in its sort_list */ + elv_rb_del(&bfqq->sort_list, req); + elv_rb_add(&bfqq->sort_list, req); + /* Choose next request to be served for bfqq */ + prev = bfqq->next_rq; + next_rq = bfq_choose_req(bfqd, bfqq->next_rq, req, + bfqd->last_position); + BUG_ON(next_rq == NULL); + bfqq->next_rq = next_rq; + /* + * If next_rq changes, update both the queue's budget to + * fit the new request and the queue's position in its + * rq_pos_tree. + */ + if (prev != bfqq->next_rq) { + bfq_updated_next_req(bfqd, bfqq); + bfq_rq_pos_tree_add(bfqd, bfqq); + } + } +} + +static void bfq_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq), *next_bfqq = RQ_BFQQ(next); + + /* + * If next and rq belong to the same bfq_queue and next is older + * than rq, then reposition rq in the fifo (by substituting next + * with rq). Otherwise, if next and rq belong to different + * bfq_queues, never reposition rq: in fact, we would have to + * reposition it with respect to next's position in its own fifo, + * which would most certainly be too expensive with respect to + * the benefits. + */ + if (bfqq == next_bfqq && + !list_empty(&rq->queuelist) && !list_empty(&next->queuelist) && + time_before(rq_fifo_time(next), rq_fifo_time(rq))) { + list_del_init(&rq->queuelist); + list_replace_init(&next->queuelist, &rq->queuelist); + rq_set_fifo_time(rq, rq_fifo_time(next)); + } + + if (bfqq->next_rq == next) + bfqq->next_rq = rq; + + bfq_remove_request(next); +} + +/* Must be called with bfqq != NULL */ +static inline void bfq_bfqq_end_wr(struct bfq_queue *bfqq) +{ + BUG_ON(bfqq == NULL); + if (bfq_bfqq_busy(bfqq)) + bfqq->bfqd->wr_busy_queues--; + bfqq->wr_coeff = 1; + bfqq->wr_cur_max_time = 0; + /* Trigger a weight change on the next activation of the queue */ + bfqq->entity.ioprio_changed = 1; +} + +static void bfq_end_wr_async_queues(struct bfq_data *bfqd, + struct bfq_group *bfqg) +{ + int i, j; + + for (i = 0; i < 2; i++) + for (j = 0; j < IOPRIO_BE_NR; j++) + if (bfqg->async_bfqq[i][j] != NULL) + bfq_bfqq_end_wr(bfqg->async_bfqq[i][j]); + if (bfqg->async_idle_bfqq != NULL) + bfq_bfqq_end_wr(bfqg->async_idle_bfqq); +} + +static void bfq_end_wr(struct bfq_data *bfqd) +{ + struct bfq_queue *bfqq; + + spin_lock_irq(bfqd->queue->queue_lock); + + list_for_each_entry(bfqq, &bfqd->active_list, bfqq_list) + bfq_bfqq_end_wr(bfqq); + list_for_each_entry(bfqq, &bfqd->idle_list, bfqq_list) + bfq_bfqq_end_wr(bfqq); + bfq_end_wr_async(bfqd); + + spin_unlock_irq(bfqd->queue->queue_lock); +} + +static inline sector_t bfq_io_struct_pos(void *io_struct, bool request) +{ + if (request) + return blk_rq_pos(io_struct); + else + return ((struct bio *)io_struct)->bi_sector; +} + +static inline sector_t bfq_dist_from(sector_t pos1, + sector_t pos2) +{ + if (pos1 >= pos2) + return pos1 - pos2; + else + return pos2 - pos1; +} + +static inline int bfq_rq_close_to_sector(void *io_struct, bool request, + sector_t sector) +{ + return bfq_dist_from(bfq_io_struct_pos(io_struct, request), sector) <= + BFQQ_SEEK_THR; +} + +static struct bfq_queue *bfqq_close(struct bfq_data *bfqd, sector_t sector) +{ + struct rb_root *root = &bfqd->rq_pos_tree; + struct rb_node *parent, *node; + struct bfq_queue *__bfqq; + + if (RB_EMPTY_ROOT(root)) + return NULL; + + /* + * First, if we find a request starting at the end of the last + * request, choose it. + */ + __bfqq = bfq_rq_pos_tree_lookup(bfqd, root, sector, &parent, NULL); + if (__bfqq != NULL) + return __bfqq; + + /* + * If the exact sector wasn't found, the parent of the NULL leaf + * will contain the closest sector (rq_pos_tree sorted by + * next_request position). + */ + __bfqq = rb_entry(parent, struct bfq_queue, pos_node); + if (bfq_rq_close_to_sector(__bfqq->next_rq, true, sector)) + return __bfqq; + + if (blk_rq_pos(__bfqq->next_rq) < sector) + node = rb_next(&__bfqq->pos_node); + else + node = rb_prev(&__bfqq->pos_node); + if (node == NULL) + return NULL; + + __bfqq = rb_entry(node, struct bfq_queue, pos_node); + if (bfq_rq_close_to_sector(__bfqq->next_rq, true, sector)) + return __bfqq; + + return NULL; +} + +/* + * bfqd - obvious + * cur_bfqq - passed in so that we don't decide that the current queue + * is closely cooperating with itself + * sector - used as a reference point to search for a close queue + */ +static struct bfq_queue *bfq_close_cooperator(struct bfq_data *bfqd, + struct bfq_queue *cur_bfqq, + sector_t sector) +{ + struct bfq_queue *bfqq; + + if (bfq_class_idle(cur_bfqq)) + return NULL; + if (!bfq_bfqq_sync(cur_bfqq)) + return NULL; + if (BFQQ_SEEKY(cur_bfqq)) + return NULL; + + /* If device has only one backlogged bfq_queue, don't search. */ + if (bfqd->busy_queues == 1) + return NULL; + + /* + * We should notice if some of the queues are cooperating, e.g. + * working closely on the same area of the disk. In that case, + * we can group them together and don't waste time idling. + */ + bfqq = bfqq_close(bfqd, sector); + if (bfqq == NULL || bfqq == cur_bfqq) + return NULL; + + /* + * Do not merge queues from different bfq_groups. + */ + if (bfqq->entity.parent != cur_bfqq->entity.parent) + return NULL; + + /* + * It only makes sense to merge sync queues. + */ + if (!bfq_bfqq_sync(bfqq)) + return NULL; + if (BFQQ_SEEKY(bfqq)) + return NULL; + + /* + * Do not merge queues of different priority classes. + */ + if (bfq_class_rt(bfqq) != bfq_class_rt(cur_bfqq)) + return NULL; + + return bfqq; +} + +static struct bfq_queue * +bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) +{ + int process_refs, new_process_refs; + struct bfq_queue *__bfqq; + + /* + * If there are no process references on the new_bfqq, then it is + * unsafe to follow the ->new_bfqq chain as other bfqq's in the chain + * may have dropped their last reference (not just their last process + * reference). + */ + if (!bfqq_process_refs(new_bfqq)) + return NULL; + + /* Avoid a circular list and skip interim queue merges. */ + while ((__bfqq = new_bfqq->new_bfqq)) { + if (__bfqq == bfqq) + return NULL; + new_bfqq = __bfqq; + } + + process_refs = bfqq_process_refs(bfqq); + new_process_refs = bfqq_process_refs(new_bfqq); + /* + * If the process for the bfqq has gone away, there is no + * sense in merging the queues. + */ + if (process_refs == 0 || new_process_refs == 0) + return NULL; + + bfq_log_bfqq(bfqq->bfqd, bfqq, "scheduling merge with queue %d", + new_bfqq->pid); + + /* + * Merging is just a redirection: the requests of the process + * owning one of the two queues are redirected to the other queue. + * The latter queue, in its turn, is set as shared if this is the + * first time that the requests of some process are redirected to + * it. + * + * We redirect bfqq to new_bfqq and not the opposite, because we + * are in the context of the process owning bfqq, hence we have + * the io_cq of this process. So we can immediately configure this + * io_cq to redirect the requests of the process to new_bfqq. + * + * NOTE, even if new_bfqq coincides with the in-service queue, the + * io_cq of new_bfqq is not available, because, if the in-service + * queue is shared, bfqd->in_service_bic may not point to the + * io_cq of the in-service queue. + * Redirecting the requests of the process owning bfqq to the + * currently in-service queue is in any case the best option, as + * we feed the in-service queue with new requests close to the + * last request served and, by doing so, hopefully increase the + * throughput. + */ + bfqq->new_bfqq = new_bfqq; + atomic_add(process_refs, &new_bfqq->ref); + return new_bfqq; +} + +/* + * Attempt to schedule a merge of bfqq with the currently in-service queue + * or with a close queue among the scheduled queues. + * Return NULL if no merge was scheduled, a pointer to the shared bfq_queue + * structure otherwise. + * + * The OOM queue is not allowed to participate to cooperation: in fact, since + * the requests temporarily redirected to the OOM queue could be redirected + * again to dedicated queues at any time, the state needed to correctly + * handle merging with the OOM queue would be quite complex and expensive + * to maintain. Besides, in such a critical condition as an out of memory, + * the benefits of queue merging may be little relevant, or even negligible. + */ +static struct bfq_queue * +bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq, + void *io_struct, bool request) +{ + struct bfq_queue *in_service_bfqq, *new_bfqq; + + if (bfqq->new_bfqq) + return bfqq->new_bfqq; + + if (!io_struct || unlikely(bfqq == &bfqd->oom_bfqq)) + return NULL; + + in_service_bfqq = bfqd->in_service_queue; + + if (in_service_bfqq == NULL || in_service_bfqq == bfqq || + !bfqd->in_service_bic || + unlikely(in_service_bfqq == &bfqd->oom_bfqq)) + goto check_scheduled; + + if (bfq_class_idle(in_service_bfqq) || bfq_class_idle(bfqq)) + goto check_scheduled; + + if (bfq_class_rt(in_service_bfqq) != bfq_class_rt(bfqq)) + goto check_scheduled; + + if (in_service_bfqq->entity.parent != bfqq->entity.parent) + goto check_scheduled; + + if (bfq_rq_close_to_sector(io_struct, request, bfqd->last_position) && + bfq_bfqq_sync(in_service_bfqq) && bfq_bfqq_sync(bfqq)) { + new_bfqq = bfq_setup_merge(bfqq, in_service_bfqq); + if (new_bfqq != NULL) + return new_bfqq; /* Merge with in-service queue */ + } + + /* + * Check whether there is a cooperator among currently scheduled + * queues. The only thing we need is that the bio/request is not + * NULL, as we need it to establish whether a cooperator exists. + */ +check_scheduled: + new_bfqq = bfq_close_cooperator(bfqd, bfqq, + bfq_io_struct_pos(io_struct, request)); + if (new_bfqq && likely(new_bfqq != &bfqd->oom_bfqq)) + return bfq_setup_merge(bfqq, new_bfqq); + + return NULL; +} + +static inline void +bfq_bfqq_save_state(struct bfq_queue *bfqq) +{ + /* + * If bfqq->bic == NULL, the queue is already shared or its requests + * have already been redirected to a shared queue; both idle window + * and weight raising state have already been saved. Do nothing. + */ + if (bfqq->bic == NULL) + return; + if (bfqq->bic->wr_time_left) + /* + * This is the queue of a just-started process, and would + * deserve weight raising: we set wr_time_left to the full + * weight-raising duration to trigger weight-raising when + * and if the queue is split and the first request of the + * queue is enqueued. + */ + bfqq->bic->wr_time_left = bfq_wr_duration(bfqq->bfqd); + else if (bfqq->wr_coeff > 1) { + unsigned long wr_duration = + jiffies - bfqq->last_wr_start_finish; + /* + * It may happen that a queue's weight raising period lasts + * longer than its wr_cur_max_time, as weight raising is + * handled only when a request is enqueued or dispatched (it + * does not use any timer). If the weight raising period is + * about to end, don't save it. + */ + if (bfqq->wr_cur_max_time <= wr_duration) + bfqq->bic->wr_time_left = 0; + else + bfqq->bic->wr_time_left = + bfqq->wr_cur_max_time - wr_duration; + /* + * The bfq_queue is becoming shared or the requests of the + * process owning the queue are being redirected to a shared + * queue. Stop the weight raising period of the queue, as in + * both cases it should not be owned by an interactive or + * soft real-time application. + */ + bfq_bfqq_end_wr(bfqq); + } else + bfqq->bic->wr_time_left = 0; + bfqq->bic->saved_idle_window = bfq_bfqq_idle_window(bfqq); + bfqq->bic->saved_IO_bound = bfq_bfqq_IO_bound(bfqq); + bfqq->bic->saved_in_large_burst = bfq_bfqq_in_large_burst(bfqq); + bfqq->bic->was_in_burst_list = !hlist_unhashed(&bfqq->burst_list_node); + bfqq->bic->cooperations++; + bfqq->bic->failed_cooperations = 0; +} + +static inline void +bfq_get_bic_reference(struct bfq_queue *bfqq) +{ + /* + * If bfqq->bic has a non-NULL value, the bic to which it belongs + * is about to begin using a shared bfq_queue. + */ + if (bfqq->bic) + atomic_long_inc(&bfqq->bic->icq.ioc->refcount); +} + +static void +bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic, + struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) +{ + bfq_log_bfqq(bfqd, bfqq, "merging with queue %lu", + (long unsigned)new_bfqq->pid); + /* Save weight raising and idle window of the merged queues */ + bfq_bfqq_save_state(bfqq); + bfq_bfqq_save_state(new_bfqq); + if (bfq_bfqq_IO_bound(bfqq)) + bfq_mark_bfqq_IO_bound(new_bfqq); + bfq_clear_bfqq_IO_bound(bfqq); + /* + * Grab a reference to the bic, to prevent it from being destroyed + * before being possibly touched by a bfq_split_bfqq(). + */ + bfq_get_bic_reference(bfqq); + bfq_get_bic_reference(new_bfqq); + /* + * Merge queues (that is, let bic redirect its requests to new_bfqq) + */ + bic_set_bfqq(bic, new_bfqq, 1); + bfq_mark_bfqq_coop(new_bfqq); + /* + * new_bfqq now belongs to at least two bics (it is a shared queue): + * set new_bfqq->bic to NULL. bfqq either: + * - does not belong to any bic any more, and hence bfqq->bic must + * be set to NULL, or + * - is a queue whose owning bics have already been redirected to a + * different queue, hence the queue is destined to not belong to + * any bic soon and bfqq->bic is already NULL (therefore the next + * assignment causes no harm). + */ + new_bfqq->bic = NULL; + bfqq->bic = NULL; + bfq_put_queue(bfqq); +} + +static inline void bfq_bfqq_increase_failed_cooperations(struct bfq_queue *bfqq) +{ + struct bfq_io_cq *bic = bfqq->bic; + struct bfq_data *bfqd = bfqq->bfqd; + + if (bic && bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh) { + bic->failed_cooperations++; + if (bic->failed_cooperations >= bfqd->bfq_failed_cooperations) + bic->cooperations = 0; + } +} + +static int bfq_allow_merge(struct request_queue *q, struct request *rq, + struct bio *bio) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct bfq_io_cq *bic; + struct bfq_queue *bfqq, *new_bfqq; + + /* + * Disallow merge of a sync bio into an async request. + */ + if (bfq_bio_sync(bio) && !rq_is_sync(rq)) + return 0; + + /* + * Lookup the bfqq that this bio will be queued with. Allow + * merge only if rq is queued there. + * Queue lock is held here. + */ + bic = bfq_bic_lookup(bfqd, current->io_context); + if (bic == NULL) + return 0; + + bfqq = bic_to_bfqq(bic, bfq_bio_sync(bio)); + /* + * We take advantage of this function to perform an early merge + * of the queues of possible cooperating processes. + */ + if (bfqq != NULL) { + new_bfqq = bfq_setup_cooperator(bfqd, bfqq, bio, false); + if (new_bfqq != NULL) { + bfq_merge_bfqqs(bfqd, bic, bfqq, new_bfqq); + /* + * If we get here, the bio will be queued in the + * shared queue, i.e., new_bfqq, so use new_bfqq + * to decide whether bio and rq can be merged. + */ + bfqq = new_bfqq; + } else + bfq_bfqq_increase_failed_cooperations(bfqq); + } + + return bfqq == RQ_BFQQ(rq); +} + +static void __bfq_set_in_service_queue(struct bfq_data *bfqd, + struct bfq_queue *bfqq) +{ + if (bfqq != NULL) { + bfq_mark_bfqq_must_alloc(bfqq); + bfq_mark_bfqq_budget_new(bfqq); + bfq_clear_bfqq_fifo_expire(bfqq); + + bfqd->budgets_assigned = (bfqd->budgets_assigned*7 + 256) / 8; + + bfq_log_bfqq(bfqd, bfqq, + "set_in_service_queue, cur-budget = %lu", + bfqq->entity.budget); + } + + bfqd->in_service_queue = bfqq; +} + +/* + * Get and set a new queue for service. + */ +static struct bfq_queue *bfq_set_in_service_queue(struct bfq_data *bfqd) +{ + struct bfq_queue *bfqq = bfq_get_next_queue(bfqd); + + __bfq_set_in_service_queue(bfqd, bfqq); + return bfqq; +} + +/* + * If enough samples have been computed, return the current max budget + * stored in bfqd, which is dynamically updated according to the + * estimated disk peak rate; otherwise return the default max budget + */ +static inline unsigned long bfq_max_budget(struct bfq_data *bfqd) +{ + if (bfqd->budgets_assigned < 194) + return bfq_default_max_budget; + else + return bfqd->bfq_max_budget; +} + +/* + * Return min budget, which is a fraction of the current or default + * max budget (trying with 1/32) + */ +static inline unsigned long bfq_min_budget(struct bfq_data *bfqd) +{ + if (bfqd->budgets_assigned < 194) + return bfq_default_max_budget / 32; + else + return bfqd->bfq_max_budget / 32; +} + +static void bfq_arm_slice_timer(struct bfq_data *bfqd) +{ + struct bfq_queue *bfqq = bfqd->in_service_queue; + struct bfq_io_cq *bic; + unsigned long sl; + + BUG_ON(!RB_EMPTY_ROOT(&bfqq->sort_list)); + + /* Processes have exited, don't wait. */ + bic = bfqd->in_service_bic; + if (bic == NULL || atomic_read(&bic->icq.ioc->nr_tasks) == 0) + return; + + bfq_mark_bfqq_wait_request(bfqq); + + /* + * We don't want to idle for seeks, but we do want to allow + * fair distribution of slice time for a process doing back-to-back + * seeks. So allow a little bit of time for him to submit a new rq. + * + * To prevent processes with (partly) seeky workloads from + * being too ill-treated, grant them a small fraction of the + * assigned budget before reducing the waiting time to + * BFQ_MIN_TT. This happened to help reduce latency. + */ + sl = bfqd->bfq_slice_idle; + /* + * Unless the queue is being weight-raised or the scenario is + * asymmetric, grant only minimum idle time if the queue either + * has been seeky for long enough or has already proved to be + * constantly seeky. + */ + if (bfq_sample_valid(bfqq->seek_samples) && + ((BFQQ_SEEKY(bfqq) && bfqq->entity.service > + bfq_max_budget(bfqq->bfqd) / 8) || + bfq_bfqq_constantly_seeky(bfqq)) && bfqq->wr_coeff == 1 && + symmetric_scenario) + sl = min(sl, msecs_to_jiffies(BFQ_MIN_TT)); + else if (bfqq->wr_coeff > 1) + sl = sl * 3; + bfqd->last_idling_start = ktime_get(); + mod_timer(&bfqd->idle_slice_timer, jiffies + sl); + bfq_log(bfqd, "arm idle: %u/%u ms", + jiffies_to_msecs(sl), jiffies_to_msecs(bfqd->bfq_slice_idle)); +} + +/* + * Set the maximum time for the in-service queue to consume its + * budget. This prevents seeky processes from lowering the disk + * throughput (always guaranteed with a time slice scheme as in CFQ). + */ +static void bfq_set_budget_timeout(struct bfq_data *bfqd) +{ + struct bfq_queue *bfqq = bfqd->in_service_queue; + unsigned int timeout_coeff; + if (bfqq->wr_cur_max_time == bfqd->bfq_wr_rt_max_time) + timeout_coeff = 1; + else + timeout_coeff = bfqq->entity.weight / bfqq->entity.orig_weight; + + bfqd->last_budget_start = ktime_get(); + + bfq_clear_bfqq_budget_new(bfqq); + bfqq->budget_timeout = jiffies + + bfqd->bfq_timeout[bfq_bfqq_sync(bfqq)] * timeout_coeff; + + bfq_log_bfqq(bfqd, bfqq, "set budget_timeout %u", + jiffies_to_msecs(bfqd->bfq_timeout[bfq_bfqq_sync(bfqq)] * + timeout_coeff)); +} + +/* + * Move request from internal lists to the request queue dispatch list. + */ +static void bfq_dispatch_insert(struct request_queue *q, struct request *rq) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct bfq_queue *bfqq = RQ_BFQQ(rq); + + /* + * For consistency, the next instruction should have been executed + * after removing the request from the queue and dispatching it. + * We execute instead this instruction before bfq_remove_request() + * (and hence introduce a temporary inconsistency), for efficiency. + * In fact, in a forced_dispatch, this prevents two counters related + * to bfqq->dispatched to risk to be uselessly decremented if bfqq + * is not in service, and then to be incremented again after + * incrementing bfqq->dispatched. + */ + bfqq->dispatched++; + bfq_remove_request(rq); + elv_dispatch_sort(q, rq); + + if (bfq_bfqq_sync(bfqq)) + bfqd->sync_flight++; +} + +/* + * Return expired entry, or NULL to just start from scratch in rbtree. + */ +static struct request *bfq_check_fifo(struct bfq_queue *bfqq) +{ + struct request *rq = NULL; + + if (bfq_bfqq_fifo_expire(bfqq)) + return NULL; + + bfq_mark_bfqq_fifo_expire(bfqq); + + if (list_empty(&bfqq->fifo)) + return NULL; + + rq = rq_entry_fifo(bfqq->fifo.next); + + if (time_before(jiffies, rq_fifo_time(rq))) + return NULL; + + return rq; +} + +static inline unsigned long bfq_bfqq_budget_left(struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + return entity->budget - entity->service; +} + +static void __bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + BUG_ON(bfqq != bfqd->in_service_queue); + + __bfq_bfqd_reset_in_service(bfqd); + + /* + * If this bfqq is shared between multiple processes, check + * to make sure that those processes are still issuing I/Os + * within the mean seek distance. If not, it may be time to + * break the queues apart again. + */ + if (bfq_bfqq_coop(bfqq) && BFQQ_SEEKY(bfqq)) + bfq_mark_bfqq_split_coop(bfqq); + + if (RB_EMPTY_ROOT(&bfqq->sort_list)) { + /* + * Overloading budget_timeout field to store the time + * at which the queue remains with no backlog; used by + * the weight-raising mechanism. + */ + bfqq->budget_timeout = jiffies; + bfq_del_bfqq_busy(bfqd, bfqq, 1); + } else { + bfq_activate_bfqq(bfqd, bfqq); + /* + * Resort priority tree of potential close cooperators. + */ + bfq_rq_pos_tree_add(bfqd, bfqq); + } +} + +/** + * __bfq_bfqq_recalc_budget - try to adapt the budget to the @bfqq behavior. + * @bfqd: device data. + * @bfqq: queue to update. + * @reason: reason for expiration. + * + * Handle the feedback on @bfqq budget. See the body for detailed + * comments. + */ +static void __bfq_bfqq_recalc_budget(struct bfq_data *bfqd, + struct bfq_queue *bfqq, + enum bfqq_expiration reason) +{ + struct request *next_rq; + unsigned long budget, min_budget; + + budget = bfqq->max_budget; + min_budget = bfq_min_budget(bfqd); + + BUG_ON(bfqq != bfqd->in_service_queue); + + bfq_log_bfqq(bfqd, bfqq, "recalc_budg: last budg %lu, budg left %lu", + bfqq->entity.budget, bfq_bfqq_budget_left(bfqq)); + bfq_log_bfqq(bfqd, bfqq, "recalc_budg: last max_budg %lu, min budg %lu", + budget, bfq_min_budget(bfqd)); + bfq_log_bfqq(bfqd, bfqq, "recalc_budg: sync %d, seeky %d", + bfq_bfqq_sync(bfqq), BFQQ_SEEKY(bfqd->in_service_queue)); + + if (bfq_bfqq_sync(bfqq)) { + switch (reason) { + /* + * Caveat: in all the following cases we trade latency + * for throughput. + */ + case BFQ_BFQQ_TOO_IDLE: + /* + * This is the only case where we may reduce + * the budget: if there is no request of the + * process still waiting for completion, then + * we assume (tentatively) that the timer has + * expired because the batch of requests of + * the process could have been served with a + * smaller budget. Hence, betting that + * process will behave in the same way when it + * becomes backlogged again, we reduce its + * next budget. As long as we guess right, + * this budget cut reduces the latency + * experienced by the process. + * + * However, if there are still outstanding + * requests, then the process may have not yet + * issued its next request just because it is + * still waiting for the completion of some of + * the still outstanding ones. So in this + * subcase we do not reduce its budget, on the + * contrary we increase it to possibly boost + * the throughput, as discussed in the + * comments to the BUDGET_TIMEOUT case. + */ + if (bfqq->dispatched > 0) /* still outstanding reqs */ + budget = min(budget * 2, bfqd->bfq_max_budget); + else { + if (budget > 5 * min_budget) + budget -= 4 * min_budget; + else + budget = min_budget; + } + break; + case BFQ_BFQQ_BUDGET_TIMEOUT: + /* + * We double the budget here because: 1) it + * gives the chance to boost the throughput if + * this is not a seeky process (which may have + * bumped into this timeout because of, e.g., + * ZBR), 2) together with charge_full_budget + * it helps give seeky processes higher + * timestamps, and hence be served less + * frequently. + */ + budget = min(budget * 2, bfqd->bfq_max_budget); + break; + case BFQ_BFQQ_BUDGET_EXHAUSTED: + /* + * The process still has backlog, and did not + * let either the budget timeout or the disk + * idling timeout expire. Hence it is not + * seeky, has a short thinktime and may be + * happy with a higher budget too. So + * definitely increase the budget of this good + * candidate to boost the disk throughput. + */ + budget = min(budget * 4, bfqd->bfq_max_budget); + break; + case BFQ_BFQQ_NO_MORE_REQUESTS: + /* + * Leave the budget unchanged. + */ + default: + return; + } + } else /* async queue */ + /* async queues get always the maximum possible budget + * (their ability to dispatch is limited by + * @bfqd->bfq_max_budget_async_rq). + */ + budget = bfqd->bfq_max_budget; + + bfqq->max_budget = budget; + + if (bfqd->budgets_assigned >= 194 && bfqd->bfq_user_max_budget == 0 && + bfqq->max_budget > bfqd->bfq_max_budget) + bfqq->max_budget = bfqd->bfq_max_budget; + + /* + * Make sure that we have enough budget for the next request. + * Since the finish time of the bfqq must be kept in sync with + * the budget, be sure to call __bfq_bfqq_expire() after the + * update. + */ + next_rq = bfqq->next_rq; + if (next_rq != NULL) + bfqq->entity.budget = max_t(unsigned long, bfqq->max_budget, + bfq_serv_to_charge(next_rq, bfqq)); + else + bfqq->entity.budget = bfqq->max_budget; + + bfq_log_bfqq(bfqd, bfqq, "head sect: %u, new budget %lu", + next_rq != NULL ? blk_rq_sectors(next_rq) : 0, + bfqq->entity.budget); +} + +static unsigned long bfq_calc_max_budget(u64 peak_rate, u64 timeout) +{ + unsigned long max_budget; + + /* + * The max_budget calculated when autotuning is equal to the + * amount of sectors transfered in timeout_sync at the + * estimated peak rate. + */ + max_budget = (unsigned long)(peak_rate * 1000 * + timeout >> BFQ_RATE_SHIFT); + + return max_budget; +} + +/* + * In addition to updating the peak rate, checks whether the process + * is "slow", and returns 1 if so. This slow flag is used, in addition + * to the budget timeout, to reduce the amount of service provided to + * seeky processes, and hence reduce their chances to lower the + * throughput. See the code for more details. + */ +static int bfq_update_peak_rate(struct bfq_data *bfqd, struct bfq_queue *bfqq, + int compensate, enum bfqq_expiration reason) +{ + u64 bw, usecs, expected, timeout; + ktime_t delta; + int update = 0; + + if (!bfq_bfqq_sync(bfqq) || bfq_bfqq_budget_new(bfqq)) + return 0; + + if (compensate) + delta = bfqd->last_idling_start; + else + delta = ktime_get(); + delta = ktime_sub(delta, bfqd->last_budget_start); + usecs = ktime_to_us(delta); + + /* Don't trust short/unrealistic values. */ + if (usecs < 100 || usecs >= LONG_MAX) + return 0; + + /* + * Calculate the bandwidth for the last slice. We use a 64 bit + * value to store the peak rate, in sectors per usec in fixed + * point math. We do so to have enough precision in the estimate + * and to avoid overflows. + */ + bw = (u64)bfqq->entity.service << BFQ_RATE_SHIFT; + do_div(bw, (unsigned long)usecs); + + timeout = jiffies_to_msecs(bfqd->bfq_timeout[BLK_RW_SYNC]); + + /* + * Use only long (> 20ms) intervals to filter out spikes for + * the peak rate estimation. + */ + if (usecs > 20000) { + if (bw > bfqd->peak_rate || + (!BFQQ_SEEKY(bfqq) && + reason == BFQ_BFQQ_BUDGET_TIMEOUT)) { + bfq_log(bfqd, "measured bw =%llu", bw); + /* + * To smooth oscillations use a low-pass filter with + * alpha=7/8, i.e., + * new_rate = (7/8) * old_rate + (1/8) * bw + */ + do_div(bw, 8); + if (bw == 0) + return 0; + bfqd->peak_rate *= 7; + do_div(bfqd->peak_rate, 8); + bfqd->peak_rate += bw; + update = 1; + bfq_log(bfqd, "new peak_rate=%llu", bfqd->peak_rate); + } + + update |= bfqd->peak_rate_samples == BFQ_PEAK_RATE_SAMPLES - 1; + + if (bfqd->peak_rate_samples < BFQ_PEAK_RATE_SAMPLES) + bfqd->peak_rate_samples++; + + if (bfqd->peak_rate_samples == BFQ_PEAK_RATE_SAMPLES && + update) { + int dev_type = blk_queue_nonrot(bfqd->queue); + if (bfqd->bfq_user_max_budget == 0) { + bfqd->bfq_max_budget = + bfq_calc_max_budget(bfqd->peak_rate, + timeout); + bfq_log(bfqd, "new max_budget=%lu", + bfqd->bfq_max_budget); + } + if (bfqd->device_speed == BFQ_BFQD_FAST && + bfqd->peak_rate < device_speed_thresh[dev_type]) { + bfqd->device_speed = BFQ_BFQD_SLOW; + bfqd->RT_prod = R_slow[dev_type] * + T_slow[dev_type]; + } else if (bfqd->device_speed == BFQ_BFQD_SLOW && + bfqd->peak_rate > device_speed_thresh[dev_type]) { + bfqd->device_speed = BFQ_BFQD_FAST; + bfqd->RT_prod = R_fast[dev_type] * + T_fast[dev_type]; + } + } + } + + /* + * If the process has been served for a too short time + * interval to let its possible sequential accesses prevail on + * the initial seek time needed to move the disk head on the + * first sector it requested, then give the process a chance + * and for the moment return false. + */ + if (bfqq->entity.budget <= bfq_max_budget(bfqd) / 8) + return 0; + + /* + * A process is considered ``slow'' (i.e., seeky, so that we + * cannot treat it fairly in the service domain, as it would + * slow down too much the other processes) if, when a slice + * ends for whatever reason, it has received service at a + * rate that would not be high enough to complete the budget + * before the budget timeout expiration. + */ + expected = bw * 1000 * timeout >> BFQ_RATE_SHIFT; + + /* + * Caveat: processes doing IO in the slower disk zones will + * tend to be slow(er) even if not seeky. And the estimated + * peak rate will actually be an average over the disk + * surface. Hence, to not be too harsh with unlucky processes, + * we keep a budget/3 margin of safety before declaring a + * process slow. + */ + return expected > (4 * bfqq->entity.budget) / 3; +} + +/* + * To be deemed as soft real-time, an application must meet two + * requirements. First, the application must not require an average + * bandwidth higher than the approximate bandwidth required to playback or + * record a compressed high-definition video. + * The next function is invoked on the completion of the last request of a + * batch, to compute the next-start time instant, soft_rt_next_start, such + * that, if the next request of the application does not arrive before + * soft_rt_next_start, then the above requirement on the bandwidth is met. + * + * The second requirement is that the request pattern of the application is + * isochronous, i.e., that, after issuing a request or a batch of requests, + * the application stops issuing new requests until all its pending requests + * have been completed. After that, the application may issue a new batch, + * and so on. + * For this reason the next function is invoked to compute + * soft_rt_next_start only for applications that meet this requirement, + * whereas soft_rt_next_start is set to infinity for applications that do + * not. + * + * Unfortunately, even a greedy application may happen to behave in an + * isochronous way if the CPU load is high. In fact, the application may + * stop issuing requests while the CPUs are busy serving other processes, + * then restart, then stop again for a while, and so on. In addition, if + * the disk achieves a low enough throughput with the request pattern + * issued by the application (e.g., because the request pattern is random + * and/or the device is slow), then the application may meet the above + * bandwidth requirement too. To prevent such a greedy application to be + * deemed as soft real-time, a further rule is used in the computation of + * soft_rt_next_start: soft_rt_next_start must be higher than the current + * time plus the maximum time for which the arrival of a request is waited + * for when a sync queue becomes idle, namely bfqd->bfq_slice_idle. + * This filters out greedy applications, as the latter issue instead their + * next request as soon as possible after the last one has been completed + * (in contrast, when a batch of requests is completed, a soft real-time + * application spends some time processing data). + * + * Unfortunately, the last filter may easily generate false positives if + * only bfqd->bfq_slice_idle is used as a reference time interval and one + * or both the following cases occur: + * 1) HZ is so low that the duration of a jiffy is comparable to or higher + * than bfqd->bfq_slice_idle. This happens, e.g., on slow devices with + * HZ=100. + * 2) jiffies, instead of increasing at a constant rate, may stop increasing + * for a while, then suddenly 'jump' by several units to recover the lost + * increments. This seems to happen, e.g., inside virtual machines. + * To address this issue, we do not use as a reference time interval just + * bfqd->bfq_slice_idle, but bfqd->bfq_slice_idle plus a few jiffies. In + * particular we add the minimum number of jiffies for which the filter + * seems to be quite precise also in embedded systems and KVM/QEMU virtual + * machines. + */ +static inline unsigned long bfq_bfqq_softrt_next_start(struct bfq_data *bfqd, + struct bfq_queue *bfqq) +{ + return max(bfqq->last_idle_bklogged + + HZ * bfqq->service_from_backlogged / + bfqd->bfq_wr_max_softrt_rate, + jiffies + bfqq->bfqd->bfq_slice_idle + 4); +} + +/* + * Return the largest-possible time instant such that, for as long as possible, + * the current time will be lower than this time instant according to the macro + * time_is_before_jiffies(). + */ +static inline unsigned long bfq_infinity_from_now(unsigned long now) +{ + return now + ULONG_MAX / 2; +} + +/** + * bfq_bfqq_expire - expire a queue. + * @bfqd: device owning the queue. + * @bfqq: the queue to expire. + * @compensate: if true, compensate for the time spent idling. + * @reason: the reason causing the expiration. + * + * + * If the process associated to the queue is slow (i.e., seeky), or in + * case of budget timeout, or, finally, if it is async, we + * artificially charge it an entire budget (independently of the + * actual service it received). As a consequence, the queue will get + * higher timestamps than the correct ones upon reactivation, and + * hence it will be rescheduled as if it had received more service + * than what it actually received. In the end, this class of processes + * will receive less service in proportion to how slowly they consume + * their budgets (and hence how seriously they tend to lower the + * throughput). + * + * In contrast, when a queue expires because it has been idling for + * too much or because it exhausted its budget, we do not touch the + * amount of service it has received. Hence when the queue will be + * reactivated and its timestamps updated, the latter will be in sync + * with the actual service received by the queue until expiration. + * + * Charging a full budget to the first type of queues and the exact + * service to the others has the effect of using the WF2Q+ policy to + * schedule the former on a timeslice basis, without violating the + * service domain guarantees of the latter. + */ +static void bfq_bfqq_expire(struct bfq_data *bfqd, + struct bfq_queue *bfqq, + int compensate, + enum bfqq_expiration reason) +{ + int slow; + BUG_ON(bfqq != bfqd->in_service_queue); + + /* Update disk peak rate for autotuning and check whether the + * process is slow (see bfq_update_peak_rate). + */ + slow = bfq_update_peak_rate(bfqd, bfqq, compensate, reason); + + /* + * As above explained, 'punish' slow (i.e., seeky), timed-out + * and async queues, to favor sequential sync workloads. + * + * Processes doing I/O in the slower disk zones will tend to be + * slow(er) even if not seeky. Hence, since the estimated peak + * rate is actually an average over the disk surface, these + * processes may timeout just for bad luck. To avoid punishing + * them we do not charge a full budget to a process that + * succeeded in consuming at least 2/3 of its budget. + */ + if (slow || (reason == BFQ_BFQQ_BUDGET_TIMEOUT && + bfq_bfqq_budget_left(bfqq) >= bfqq->entity.budget / 3)) + bfq_bfqq_charge_full_budget(bfqq); + + bfqq->service_from_backlogged += bfqq->entity.service; + + if (BFQQ_SEEKY(bfqq) && reason == BFQ_BFQQ_BUDGET_TIMEOUT && + !bfq_bfqq_constantly_seeky(bfqq)) { + bfq_mark_bfqq_constantly_seeky(bfqq); + if (!blk_queue_nonrot(bfqd->queue)) + bfqd->const_seeky_busy_in_flight_queues++; + } + + if (reason == BFQ_BFQQ_TOO_IDLE && + bfqq->entity.service <= 2 * bfqq->entity.budget / 10 ) + bfq_clear_bfqq_IO_bound(bfqq); + + if (bfqd->low_latency && bfqq->wr_coeff == 1) + bfqq->last_wr_start_finish = jiffies; + + if (bfqd->low_latency && bfqd->bfq_wr_max_softrt_rate > 0 && + RB_EMPTY_ROOT(&bfqq->sort_list)) { + /* + * If we get here, and there are no outstanding requests, + * then the request pattern is isochronous (see the comments + * to the function bfq_bfqq_softrt_next_start()). Hence we + * can compute soft_rt_next_start. If, instead, the queue + * still has outstanding requests, then we have to wait + * for the completion of all the outstanding requests to + * discover whether the request pattern is actually + * isochronous. + */ + if (bfqq->dispatched == 0) + bfqq->soft_rt_next_start = + bfq_bfqq_softrt_next_start(bfqd, bfqq); + else { + /* + * The application is still waiting for the + * completion of one or more requests: + * prevent it from possibly being incorrectly + * deemed as soft real-time by setting its + * soft_rt_next_start to infinity. In fact, + * without this assignment, the application + * would be incorrectly deemed as soft + * real-time if: + * 1) it issued a new request before the + * completion of all its in-flight + * requests, and + * 2) at that time, its soft_rt_next_start + * happened to be in the past. + */ + bfqq->soft_rt_next_start = + bfq_infinity_from_now(jiffies); + /* + * Schedule an update of soft_rt_next_start to when + * the task may be discovered to be isochronous. + */ + bfq_mark_bfqq_softrt_update(bfqq); + } + } + + bfq_log_bfqq(bfqd, bfqq, + "expire (%d, slow %d, num_disp %d, idle_win %d)", reason, + slow, bfqq->dispatched, bfq_bfqq_idle_window(bfqq)); + + /* + * Increase, decrease or leave budget unchanged according to + * reason. + */ + __bfq_bfqq_recalc_budget(bfqd, bfqq, reason); + __bfq_bfqq_expire(bfqd, bfqq); +} + +/* + * Budget timeout is not implemented through a dedicated timer, but + * just checked on request arrivals and completions, as well as on + * idle timer expirations. + */ +static int bfq_bfqq_budget_timeout(struct bfq_queue *bfqq) +{ + if (bfq_bfqq_budget_new(bfqq) || + time_before(jiffies, bfqq->budget_timeout)) + return 0; + return 1; +} + +/* + * If we expire a queue that is waiting for the arrival of a new + * request, we may prevent the fictitious timestamp back-shifting that + * allows the guarantees of the queue to be preserved (see [1] for + * this tricky aspect). Hence we return true only if this condition + * does not hold, or if the queue is slow enough to deserve only to be + * kicked off for preserving a high throughput. +*/ +static inline int bfq_may_expire_for_budg_timeout(struct bfq_queue *bfqq) +{ + bfq_log_bfqq(bfqq->bfqd, bfqq, + "may_budget_timeout: wait_request %d left %d timeout %d", + bfq_bfqq_wait_request(bfqq), + bfq_bfqq_budget_left(bfqq) >= bfqq->entity.budget / 3, + bfq_bfqq_budget_timeout(bfqq)); + + return (!bfq_bfqq_wait_request(bfqq) || + bfq_bfqq_budget_left(bfqq) >= bfqq->entity.budget / 3) + && + bfq_bfqq_budget_timeout(bfqq); +} + +/* + * Device idling is allowed only for the queues for which this function + * returns true. For this reason, the return value of this function plays a + * critical role for both throughput boosting and service guarantees. The + * return value is computed through a logical expression. In this rather + * long comment, we try to briefly describe all the details and motivations + * behind the components of this logical expression. + * + * First, the expression is false if bfqq is not sync, or if: bfqq happened + * to become active during a large burst of queue activations, and the + * pattern of requests bfqq contains boosts the throughput if bfqq is + * expired. In fact, queues that became active during a large burst benefit + * only from throughput, as discussed in the comments to bfq_handle_burst. + * In this respect, expiring bfqq certainly boosts the throughput on NCQ- + * capable flash-based devices, whereas, on rotational devices, it boosts + * the throughput only if bfqq contains random requests. + * + * On the opposite end, if (a) bfqq is sync, (b) the above burst-related + * condition does not hold, and (c) bfqq is being weight-raised, then the + * expression always evaluates to true, as device idling is instrumental + * for preserving low-latency guarantees (see [1]). If, instead, conditions + * (a) and (b) do hold, but (c) does not, then the expression evaluates to + * true only if: (1) bfqq is I/O-bound and has a non-null idle window, and + * (2) at least one of the following two conditions holds. + * The first condition is that the device is not performing NCQ, because + * idling the device most certainly boosts the throughput if this condition + * holds and bfqq is I/O-bound and has been granted a non-null idle window. + * The second compound condition is made of the logical AND of two components. + * + * The first component is true only if there is no weight-raised busy + * queue. This guarantees that the device is not idled for a sync non- + * weight-raised queue when there are busy weight-raised queues. The former + * is then expired immediately if empty. Combined with the timestamping + * rules of BFQ (see [1] for details), this causes sync non-weight-raised + * queues to get a lower number of requests served, and hence to ask for a + * lower number of requests from the request pool, before the busy weight- + * raised queues get served again. + * + * This is beneficial for the processes associated with weight-raised + * queues, when the request pool is saturated (e.g., in the presence of + * write hogs). In fact, if the processes associated with the other queues + * ask for requests at a lower rate, then weight-raised processes have a + * higher probability to get a request from the pool immediately (or at + * least soon) when they need one. Hence they have a higher probability to + * actually get a fraction of the disk throughput proportional to their + * high weight. This is especially true with NCQ-capable drives, which + * enqueue several requests in advance and further reorder internally- + * queued requests. + * + * In the end, mistreating non-weight-raised queues when there are busy + * weight-raised queues seems to mitigate starvation problems in the + * presence of heavy write workloads and NCQ, and hence to guarantee a + * higher application and system responsiveness in these hostile scenarios. + * + * If the first component of the compound condition is instead true, i.e., + * there is no weight-raised busy queue, then the second component of the + * compound condition takes into account service-guarantee and throughput + * issues related to NCQ (recall that the compound condition is evaluated + * only if the device is detected as supporting NCQ). + * + * As for service guarantees, allowing the drive to enqueue more than one + * request at a time, and hence delegating de facto final scheduling + * decisions to the drive's internal scheduler, causes loss of control on + * the actual request service order. In this respect, when the drive is + * allowed to enqueue more than one request at a time, the service + * distribution enforced by the drive's internal scheduler is likely to + * coincide with the desired device-throughput distribution only in the + * following, perfectly symmetric, scenario: + * 1) all active queues have the same weight, + * 2) all active groups at the same level in the groups tree have the same + * weight, + * 3) all active groups at the same level in the groups tree have the same + * number of children. + * + * Even in such a scenario, sequential I/O may still receive a preferential + * treatment, but this is not likely to be a big issue with flash-based + * devices, because of their non-dramatic loss of throughput with random + * I/O. Things do differ with HDDs, for which additional care is taken, as + * explained after completing the discussion for flash-based devices. + * + * Unfortunately, keeping the necessary state for evaluating exactly the + * above symmetry conditions would be quite complex and time-consuming. + * Therefore BFQ evaluates instead the following stronger sub-conditions, + * for which it is much easier to maintain the needed state: + * 1) all active queues have the same weight, + * 2) all active groups have the same weight, + * 3) all active groups have at most one active child each. + * In particular, the last two conditions are always true if hierarchical + * support and the cgroups interface are not enabled, hence no state needs + * to be maintained in this case. + * + * According to the above considerations, the second component of the + * compound condition evaluates to true if any of the above symmetry + * sub-condition does not hold, or the device is not flash-based. Therefore, + * if also the first component is true, then idling is allowed for a sync + * queue. These are the only sub-conditions considered if the device is + * flash-based, as, for such a device, it is sensible to force idling only + * for service-guarantee issues. In fact, as for throughput, idling + * NCQ-capable flash-based devices would not boost the throughput even + * with sequential I/O; rather it would lower the throughput in proportion + * to how fast the device is. In the end, (only) if all the three + * sub-conditions hold and the device is flash-based, the compound + * condition evaluates to false and therefore no idling is performed. + * + * As already said, things change with a rotational device, where idling + * boosts the throughput with sequential I/O (even with NCQ). Hence, for + * such a device the second component of the compound condition evaluates + * to true also if the following additional sub-condition does not hold: + * the queue is constantly seeky. Unfortunately, this different behavior + * with respect to flash-based devices causes an additional asymmetry: if + * some sync queues enjoy idling and some other sync queues do not, then + * the latter get a low share of the device throughput, simply because the + * former get many requests served after being set as in service, whereas + * the latter do not. As a consequence, to guarantee the desired throughput + * distribution, on HDDs the compound expression evaluates to true (and + * hence device idling is performed) also if the following last symmetry + * condition does not hold: no other queue is benefiting from idling. Also + * this last condition is actually replaced with a simpler-to-maintain and + * stronger condition: there is no busy queue which is not constantly seeky + * (and hence may also benefit from idling). + * + * To sum up, when all the required symmetry and throughput-boosting + * sub-conditions hold, the second component of the compound condition + * evaluates to false, and hence no idling is performed. This helps to + * keep the drives' internal queues full on NCQ-capable devices, and hence + * to boost the throughput, without causing 'almost' any loss of service + * guarantees. The 'almost' follows from the fact that, if the internal + * queue of one such device is filled while all the sub-conditions hold, + * but at some point in time some sub-condition stops to hold, then it may + * become impossible to let requests be served in the new desired order + * until all the requests already queued in the device have been served. + */ +static inline bool bfq_bfqq_must_not_expire(struct bfq_queue *bfqq) +{ + struct bfq_data *bfqd = bfqq->bfqd; +#define cond_for_seeky_on_ncq_hdd (bfq_bfqq_constantly_seeky(bfqq) && \ + bfqd->busy_in_flight_queues == \ + bfqd->const_seeky_busy_in_flight_queues) + +#define cond_for_expiring_in_burst (bfq_bfqq_in_large_burst(bfqq) && \ + bfqd->hw_tag && \ + (blk_queue_nonrot(bfqd->queue) || \ + bfq_bfqq_constantly_seeky(bfqq))) + +/* + * Condition for expiring a non-weight-raised queue (and hence not idling + * the device). + */ +#define cond_for_expiring_non_wr (bfqd->hw_tag && \ + (bfqd->wr_busy_queues > 0 || \ + (blk_queue_nonrot(bfqd->queue) || \ + cond_for_seeky_on_ncq_hdd))) + + return bfq_bfqq_sync(bfqq) && + !cond_for_expiring_in_burst && + (bfqq->wr_coeff > 1 || !symmetric_scenario || + (bfq_bfqq_IO_bound(bfqq) && bfq_bfqq_idle_window(bfqq) && + !cond_for_expiring_non_wr) + ); +} + +/* + * If the in-service queue is empty but sync, and the function + * bfq_bfqq_must_not_expire returns true, then: + * 1) the queue must remain in service and cannot be expired, and + * 2) the disk must be idled to wait for the possible arrival of a new + * request for the queue. + * See the comments to the function bfq_bfqq_must_not_expire for the reasons + * why performing device idling is the best choice to boost the throughput + * and preserve service guarantees when bfq_bfqq_must_not_expire itself + * returns true. + */ +static inline bool bfq_bfqq_must_idle(struct bfq_queue *bfqq) +{ + struct bfq_data *bfqd = bfqq->bfqd; + + return RB_EMPTY_ROOT(&bfqq->sort_list) && bfqd->bfq_slice_idle != 0 && + bfq_bfqq_must_not_expire(bfqq); +} + +/* + * Select a queue for service. If we have a current queue in service, + * check whether to continue servicing it, or retrieve and set a new one. + */ +static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd) +{ + struct bfq_queue *bfqq; + struct request *next_rq; + enum bfqq_expiration reason = BFQ_BFQQ_BUDGET_TIMEOUT; + + bfqq = bfqd->in_service_queue; + if (bfqq == NULL) + goto new_queue; + + bfq_log_bfqq(bfqd, bfqq, "select_queue: already in-service queue"); + + if (bfq_may_expire_for_budg_timeout(bfqq) && + !timer_pending(&bfqd->idle_slice_timer) && + !bfq_bfqq_must_idle(bfqq)) + goto expire; + + next_rq = bfqq->next_rq; + /* + * If bfqq has requests queued and it has enough budget left to + * serve them, keep the queue, otherwise expire it. + */ + if (next_rq != NULL) { + if (bfq_serv_to_charge(next_rq, bfqq) > + bfq_bfqq_budget_left(bfqq)) { + reason = BFQ_BFQQ_BUDGET_EXHAUSTED; + goto expire; + } else { + /* + * The idle timer may be pending because we may + * not disable disk idling even when a new request + * arrives. + */ + if (timer_pending(&bfqd->idle_slice_timer)) { + /* + * If we get here: 1) at least a new request + * has arrived but we have not disabled the + * timer because the request was too small, + * 2) then the block layer has unplugged + * the device, causing the dispatch to be + * invoked. + * + * Since the device is unplugged, now the + * requests are probably large enough to + * provide a reasonable throughput. + * So we disable idling. + */ + bfq_clear_bfqq_wait_request(bfqq); + del_timer(&bfqd->idle_slice_timer); + } + goto keep_queue; + } + } + + /* + * No requests pending. However, if the in-service queue is idling + * for a new request, or has requests waiting for a completion and + * may idle after their completion, then keep it anyway. + */ + if (timer_pending(&bfqd->idle_slice_timer) || + (bfqq->dispatched != 0 && bfq_bfqq_must_not_expire(bfqq))) { + bfqq = NULL; + goto keep_queue; + } + + reason = BFQ_BFQQ_NO_MORE_REQUESTS; +expire: + bfq_bfqq_expire(bfqd, bfqq, 0, reason); +new_queue: + bfqq = bfq_set_in_service_queue(bfqd); + bfq_log(bfqd, "select_queue: new queue %d returned", + bfqq != NULL ? bfqq->pid : 0); +keep_queue: + return bfqq; +} + +static void bfq_update_wr_data(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + if (bfqq->wr_coeff > 1) { /* queue is being weight-raised */ + bfq_log_bfqq(bfqd, bfqq, + "raising period dur %u/%u msec, old coeff %u, w %d(%d)", + jiffies_to_msecs(jiffies - bfqq->last_wr_start_finish), + jiffies_to_msecs(bfqq->wr_cur_max_time), + bfqq->wr_coeff, + bfqq->entity.weight, bfqq->entity.orig_weight); + + BUG_ON(bfqq != bfqd->in_service_queue && entity->weight != + entity->orig_weight * bfqq->wr_coeff); + if (entity->ioprio_changed) + bfq_log_bfqq(bfqd, bfqq, "WARN: pending prio change"); + + /* + * If the queue was activated in a burst, or + * too much time has elapsed from the beginning + * of this weight-raising period, or the queue has + * exceeded the acceptable number of cooperations, + * then end weight raising. + */ + if (bfq_bfqq_in_large_burst(bfqq) || + bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh || + time_is_before_jiffies(bfqq->last_wr_start_finish + + bfqq->wr_cur_max_time)) { + bfqq->last_wr_start_finish = jiffies; + bfq_log_bfqq(bfqd, bfqq, + "wrais ending at %lu, rais_max_time %u", + bfqq->last_wr_start_finish, + jiffies_to_msecs(bfqq->wr_cur_max_time)); + bfq_bfqq_end_wr(bfqq); + } + } + /* Update weight both if it must be raised and if it must be lowered */ + if ((entity->weight > entity->orig_weight) != (bfqq->wr_coeff > 1)) + __bfq_entity_update_weight_prio( + bfq_entity_service_tree(entity), + entity); +} + +/* + * Dispatch one request from bfqq, moving it to the request queue + * dispatch list. + */ +static int bfq_dispatch_request(struct bfq_data *bfqd, + struct bfq_queue *bfqq) +{ + int dispatched = 0; + struct request *rq; + unsigned long service_to_charge; + + BUG_ON(RB_EMPTY_ROOT(&bfqq->sort_list)); + + /* Follow expired path, else get first next available. */ + rq = bfq_check_fifo(bfqq); + if (rq == NULL) + rq = bfqq->next_rq; + service_to_charge = bfq_serv_to_charge(rq, bfqq); + + if (service_to_charge > bfq_bfqq_budget_left(bfqq)) { + /* + * This may happen if the next rq is chosen in fifo order + * instead of sector order. The budget is properly + * dimensioned to be always sufficient to serve the next + * request only if it is chosen in sector order. The reason + * is that it would be quite inefficient and little useful + * to always make sure that the budget is large enough to + * serve even the possible next rq in fifo order. + * In fact, requests are seldom served in fifo order. + * + * Expire the queue for budget exhaustion, and make sure + * that the next act_budget is enough to serve the next + * request, even if it comes from the fifo expired path. + */ + bfqq->next_rq = rq; + /* + * Since this dispatch is failed, make sure that + * a new one will be performed + */ + if (!bfqd->rq_in_driver) + bfq_schedule_dispatch(bfqd); + goto expire; + } + + /* Finally, insert request into driver dispatch list. */ + bfq_bfqq_served(bfqq, service_to_charge); + bfq_dispatch_insert(bfqd->queue, rq); + + bfq_update_wr_data(bfqd, bfqq); + + bfq_log_bfqq(bfqd, bfqq, + "dispatched %u sec req (%llu), budg left %lu", + blk_rq_sectors(rq), + (long long unsigned)blk_rq_pos(rq), + bfq_bfqq_budget_left(bfqq)); + + dispatched++; + + if (bfqd->in_service_bic == NULL) { + atomic_long_inc(&RQ_BIC(rq)->icq.ioc->refcount); + bfqd->in_service_bic = RQ_BIC(rq); + } + + if (bfqd->busy_queues > 1 && ((!bfq_bfqq_sync(bfqq) && + dispatched >= bfqd->bfq_max_budget_async_rq) || + bfq_class_idle(bfqq))) + goto expire; + + return dispatched; + +expire: + bfq_bfqq_expire(bfqd, bfqq, 0, BFQ_BFQQ_BUDGET_EXHAUSTED); + return dispatched; +} + +static int __bfq_forced_dispatch_bfqq(struct bfq_queue *bfqq) +{ + int dispatched = 0; + + while (bfqq->next_rq != NULL) { + bfq_dispatch_insert(bfqq->bfqd->queue, bfqq->next_rq); + dispatched++; + } + + BUG_ON(!list_empty(&bfqq->fifo)); + return dispatched; +} + +/* + * Drain our current requests. + * Used for barriers and when switching io schedulers on-the-fly. + */ +static int bfq_forced_dispatch(struct bfq_data *bfqd) +{ + struct bfq_queue *bfqq, *n; + struct bfq_service_tree *st; + int dispatched = 0; + + bfqq = bfqd->in_service_queue; + if (bfqq != NULL) + __bfq_bfqq_expire(bfqd, bfqq); + + /* + * Loop through classes, and be careful to leave the scheduler + * in a consistent state, as feedback mechanisms and vtime + * updates cannot be disabled during the process. + */ + list_for_each_entry_safe(bfqq, n, &bfqd->active_list, bfqq_list) { + st = bfq_entity_service_tree(&bfqq->entity); + + dispatched += __bfq_forced_dispatch_bfqq(bfqq); + bfqq->max_budget = bfq_max_budget(bfqd); + + bfq_forget_idle(st); + } + + BUG_ON(bfqd->busy_queues != 0); + + return dispatched; +} + +static int bfq_dispatch_requests(struct request_queue *q, int force) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct bfq_queue *bfqq; + int max_dispatch; + + bfq_log(bfqd, "dispatch requests: %d busy queues", bfqd->busy_queues); + if (bfqd->busy_queues == 0) + return 0; + + if (unlikely(force)) + return bfq_forced_dispatch(bfqd); + + bfqq = bfq_select_queue(bfqd); + if (bfqq == NULL) + return 0; + + if (bfq_class_idle(bfqq)) + max_dispatch = 1; + + if (!bfq_bfqq_sync(bfqq)) + max_dispatch = bfqd->bfq_max_budget_async_rq; + + if (!bfq_bfqq_sync(bfqq) && bfqq->dispatched >= max_dispatch) { + if (bfqd->busy_queues > 1) + return 0; + if (bfqq->dispatched >= 4 * max_dispatch) + return 0; + } + + if (bfqd->sync_flight != 0 && !bfq_bfqq_sync(bfqq)) + return 0; + + bfq_clear_bfqq_wait_request(bfqq); + BUG_ON(timer_pending(&bfqd->idle_slice_timer)); + + if (!bfq_dispatch_request(bfqd, bfqq)) + return 0; + + bfq_log_bfqq(bfqd, bfqq, "dispatched %s request", + bfq_bfqq_sync(bfqq) ? "sync" : "async"); + + return 1; +} + +/* + * Task holds one reference to the queue, dropped when task exits. Each rq + * in-flight on this queue also holds a reference, dropped when rq is freed. + * + * Queue lock must be held here. + */ +static void bfq_put_queue(struct bfq_queue *bfqq) +{ + struct bfq_data *bfqd = bfqq->bfqd; + + BUG_ON(atomic_read(&bfqq->ref) <= 0); + + bfq_log_bfqq(bfqd, bfqq, "put_queue: %p %d", bfqq, + atomic_read(&bfqq->ref)); + if (!atomic_dec_and_test(&bfqq->ref)) + return; + + BUG_ON(rb_first(&bfqq->sort_list) != NULL); + BUG_ON(bfqq->allocated[READ] + bfqq->allocated[WRITE] != 0); + BUG_ON(bfqq->entity.tree != NULL); + BUG_ON(bfq_bfqq_busy(bfqq)); + BUG_ON(bfqd->in_service_queue == bfqq); + + if (bfq_bfqq_sync(bfqq)) + /* + * The fact that this queue is being destroyed does not + * invalidate the fact that this queue may have been + * activated during the current burst. As a consequence, + * although the queue does not exist anymore, and hence + * needs to be removed from the burst list if there, + * the burst size has not to be decremented. + */ + hlist_del_init(&bfqq->burst_list_node); + + bfq_log_bfqq(bfqd, bfqq, "put_queue: %p freed", bfqq); + + kmem_cache_free(bfq_pool, bfqq); +} + +static void bfq_put_cooperator(struct bfq_queue *bfqq) +{ + struct bfq_queue *__bfqq, *next; + + /* + * If this queue was scheduled to merge with another queue, be + * sure to drop the reference taken on that queue (and others in + * the merge chain). See bfq_setup_merge and bfq_merge_bfqqs. + */ + __bfqq = bfqq->new_bfqq; + while (__bfqq) { + if (__bfqq == bfqq) + break; + next = __bfqq->new_bfqq; + bfq_put_queue(__bfqq); + __bfqq = next; + } +} + +static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + if (bfqq == bfqd->in_service_queue) { + __bfq_bfqq_expire(bfqd, bfqq); + bfq_schedule_dispatch(bfqd); + } + + bfq_log_bfqq(bfqd, bfqq, "exit_bfqq: %p, %d", bfqq, + atomic_read(&bfqq->ref)); + + bfq_put_cooperator(bfqq); + + bfq_put_queue(bfqq); +} + +static inline void bfq_init_icq(struct io_cq *icq) +{ + struct bfq_io_cq *bic = icq_to_bic(icq); + + bic->ttime.last_end_request = jiffies; + /* + * A newly created bic indicates that the process has just + * started doing I/O, and is probably mapping into memory its + * executable and libraries: it definitely needs weight raising. + * There is however the possibility that the process performs, + * for a while, I/O close to some other process. EQM intercepts + * this behavior and may merge the queue corresponding to the + * process with some other queue, BEFORE the weight of the queue + * is raised. Merged queues are not weight-raised (they are assumed + * to belong to processes that benefit only from high throughput). + * If the merge is basically the consequence of an accident, then + * the queue will be split soon and will get back its old weight. + * It is then important to write down somewhere that this queue + * does need weight raising, even if it did not make it to get its + * weight raised before being merged. To this purpose, we overload + * the field raising_time_left and assign 1 to it, to mark the queue + * as needing weight raising. + */ + bic->wr_time_left = 1; +} + +static void bfq_exit_icq(struct io_cq *icq) +{ + struct bfq_io_cq *bic = icq_to_bic(icq); + struct bfq_data *bfqd = bic_to_bfqd(bic); + + if (bic->bfqq[BLK_RW_ASYNC]) { + bfq_exit_bfqq(bfqd, bic->bfqq[BLK_RW_ASYNC]); + bic->bfqq[BLK_RW_ASYNC] = NULL; + } + + if (bic->bfqq[BLK_RW_SYNC]) { + /* + * If the bic is using a shared queue, put the reference + * taken on the io_context when the bic started using a + * shared bfq_queue. + */ + if (bfq_bfqq_coop(bic->bfqq[BLK_RW_SYNC])) + put_io_context(icq->ioc); + bfq_exit_bfqq(bfqd, bic->bfqq[BLK_RW_SYNC]); + bic->bfqq[BLK_RW_SYNC] = NULL; + } +} + +/* + * Update the entity prio values; note that the new values will not + * be used until the next (re)activation. + */ +static void bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic) +{ + struct task_struct *tsk = current; + struct io_context *ioc = bic->icq.ioc; + int ioprio_class; + + ioprio_class = IOPRIO_PRIO_CLASS(ioc->ioprio); + switch (ioprio_class) { + default: + dev_err(bfqq->bfqd->queue->backing_dev_info.dev, + "bfq: bad prio class %d\n", ioprio_class); + case IOPRIO_CLASS_NONE: + /* + * No prio set, inherit CPU scheduling settings. + */ + bfqq->entity.new_ioprio = task_nice_ioprio(tsk); + bfqq->entity.new_ioprio_class = task_nice_ioclass(tsk); + break; + case IOPRIO_CLASS_RT: + bfqq->entity.new_ioprio = task_ioprio(ioc); + bfqq->entity.new_ioprio_class = IOPRIO_CLASS_RT; + break; + case IOPRIO_CLASS_BE: + bfqq->entity.new_ioprio = task_ioprio(ioc); + bfqq->entity.new_ioprio_class = IOPRIO_CLASS_BE; + break; + case IOPRIO_CLASS_IDLE: + bfqq->entity.new_ioprio_class = IOPRIO_CLASS_IDLE; + bfqq->entity.new_ioprio = 7; + bfq_clear_bfqq_idle_window(bfqq); + break; + } + + if (bfqq->entity.new_ioprio < 0 || + bfqq->entity.new_ioprio >= IOPRIO_BE_NR) { + printk(KERN_CRIT "bfq_set_next_ioprio_data: new_ioprio %d\n", + bfqq->entity.new_ioprio); + BUG(); + } + + bfqq->entity.new_weight = bfq_ioprio_to_weight(bfqq->entity.new_ioprio); + bfqq->entity.ioprio_changed = 1; +} + +static void bfq_check_ioprio_change(struct io_context *ioc, + struct bfq_io_cq *bic) +{ + struct bfq_data *bfqd; + struct bfq_queue *bfqq, *new_bfqq; + struct bfq_group *bfqg; + unsigned long uninitialized_var(flags); + int ioprio = bic->icq.ioc->ioprio; + + bfqd = bfq_get_bfqd_locked(&(bic->icq.q->elevator->elevator_data), + &flags); + if (unlikely(bfqd == NULL)) + return; + + bic->ioprio = ioprio; + + bfqq = bic->bfqq[BLK_RW_ASYNC]; + if (bfqq != NULL) { + bfqg = container_of(bfqq->entity.sched_data, struct bfq_group, + sched_data); + new_bfqq = bfq_get_queue(bfqd, bfqg, BLK_RW_ASYNC, bic->icq.ioc, + GFP_ATOMIC); + if (new_bfqq != NULL) { + bic->bfqq[BLK_RW_ASYNC] = new_bfqq; + bfq_log_bfqq(bfqd, bfqq, + "check_ioprio_change: bfqq %p %d", + bfqq, atomic_read(&bfqq->ref)); + bfq_put_queue(bfqq); + } + } + + bfqq = bic->bfqq[BLK_RW_SYNC]; + if (bfqq != NULL) + bfq_set_next_ioprio_data(bfqq, bic); + + bfq_put_bfqd_unlock(bfqd, &flags); +} + +static void bfq_init_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, + struct bfq_io_cq *bic, pid_t pid, int is_sync) +{ + RB_CLEAR_NODE(&bfqq->entity.rb_node); + INIT_LIST_HEAD(&bfqq->fifo); + INIT_HLIST_NODE(&bfqq->burst_list_node); + + atomic_set(&bfqq->ref, 0); + bfqq->bfqd = bfqd; + + if (bic) + bfq_set_next_ioprio_data(bfqq, bic); + + if (is_sync) { + if (!bfq_class_idle(bfqq)) + bfq_mark_bfqq_idle_window(bfqq); + bfq_mark_bfqq_sync(bfqq); + } + bfq_mark_bfqq_IO_bound(bfqq); + + /* Tentative initial value to trade off between thr and lat */ + bfqq->max_budget = (2 * bfq_max_budget(bfqd)) / 3; + bfqq->pid = pid; + + bfqq->wr_coeff = 1; + bfqq->last_wr_start_finish = 0; + /* + * Set to the value for which bfqq will not be deemed as + * soft rt when it becomes backlogged. + */ + bfqq->soft_rt_next_start = bfq_infinity_from_now(jiffies); +} + +static struct bfq_queue *bfq_find_alloc_queue(struct bfq_data *bfqd, + struct bfq_group *bfqg, + int is_sync, + struct io_context *ioc, + gfp_t gfp_mask) +{ + struct bfq_queue *bfqq, *new_bfqq = NULL; + struct bfq_io_cq *bic; + +retry: + bic = bfq_bic_lookup(bfqd, ioc); + /* bic always exists here */ + bfqq = bic_to_bfqq(bic, is_sync); + + /* + * Always try a new alloc if we fall back to the OOM bfqq + * originally, since it should just be a temporary situation. + */ + if (bfqq == NULL || bfqq == &bfqd->oom_bfqq) { + bfqq = NULL; + if (new_bfqq != NULL) { + bfqq = new_bfqq; + new_bfqq = NULL; + } else if (gfp_mask & __GFP_WAIT) { + spin_unlock_irq(bfqd->queue->queue_lock); + new_bfqq = kmem_cache_alloc_node(bfq_pool, + gfp_mask | __GFP_ZERO, + bfqd->queue->node); + spin_lock_irq(bfqd->queue->queue_lock); + if (new_bfqq != NULL) + goto retry; + } else { + bfqq = kmem_cache_alloc_node(bfq_pool, + gfp_mask | __GFP_ZERO, + bfqd->queue->node); + } + + if (bfqq != NULL) { + bfq_init_bfqq(bfqd, bfqq, bic, current->pid, + is_sync); + bfq_init_entity(&bfqq->entity, bfqg); + bfq_log_bfqq(bfqd, bfqq, "allocated"); + } else { + bfqq = &bfqd->oom_bfqq; + bfq_log_bfqq(bfqd, bfqq, "using oom bfqq"); + } + } + + if (new_bfqq != NULL) + kmem_cache_free(bfq_pool, new_bfqq); + + return bfqq; +} + +static struct bfq_queue **bfq_async_queue_prio(struct bfq_data *bfqd, + struct bfq_group *bfqg, + int ioprio_class, int ioprio) +{ + switch (ioprio_class) { + case IOPRIO_CLASS_RT: + return &bfqg->async_bfqq[0][ioprio]; + case IOPRIO_CLASS_BE: + return &bfqg->async_bfqq[1][ioprio]; + case IOPRIO_CLASS_IDLE: + return &bfqg->async_idle_bfqq; + default: + BUG(); + } +} + +static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd, + struct bfq_group *bfqg, int is_sync, + struct io_context *ioc, gfp_t gfp_mask) +{ + const int ioprio = task_ioprio(ioc); + const int ioprio_class = task_ioprio_class(ioc); + struct bfq_queue **async_bfqq = NULL; + struct bfq_queue *bfqq = NULL; + + if (!is_sync) { + async_bfqq = bfq_async_queue_prio(bfqd, bfqg, ioprio_class, + ioprio); + bfqq = *async_bfqq; + } + + if (bfqq == NULL) + bfqq = bfq_find_alloc_queue(bfqd, bfqg, is_sync, ioc, gfp_mask); + + /* + * Pin the queue now that it's allocated, scheduler exit will + * prune it. + */ + if (!is_sync && *async_bfqq == NULL) { + atomic_inc(&bfqq->ref); + bfq_log_bfqq(bfqd, bfqq, "get_queue, bfqq not in async: %p, %d", + bfqq, atomic_read(&bfqq->ref)); + *async_bfqq = bfqq; + } + + atomic_inc(&bfqq->ref); + bfq_log_bfqq(bfqd, bfqq, "get_queue, at end: %p, %d", bfqq, + atomic_read(&bfqq->ref)); + return bfqq; +} + +static void bfq_update_io_thinktime(struct bfq_data *bfqd, + struct bfq_io_cq *bic) +{ + unsigned long elapsed = jiffies - bic->ttime.last_end_request; + unsigned long ttime = min(elapsed, 2UL * bfqd->bfq_slice_idle); + + bic->ttime.ttime_samples = (7*bic->ttime.ttime_samples + 256) / 8; + bic->ttime.ttime_total = (7*bic->ttime.ttime_total + 256*ttime) / 8; + bic->ttime.ttime_mean = (bic->ttime.ttime_total + 128) / + bic->ttime.ttime_samples; +} + +static void bfq_update_io_seektime(struct bfq_data *bfqd, + struct bfq_queue *bfqq, + struct request *rq) +{ + sector_t sdist; + u64 total; + + if (bfqq->last_request_pos < blk_rq_pos(rq)) + sdist = blk_rq_pos(rq) - bfqq->last_request_pos; + else + sdist = bfqq->last_request_pos - blk_rq_pos(rq); + + /* + * Don't allow the seek distance to get too large from the + * odd fragment, pagein, etc. + */ + if (bfqq->seek_samples == 0) /* first request, not really a seek */ + sdist = 0; + else if (bfqq->seek_samples <= 60) /* second & third seek */ + sdist = min(sdist, (bfqq->seek_mean * 4) + 2*1024*1024); + else + sdist = min(sdist, (bfqq->seek_mean * 4) + 2*1024*64); + + bfqq->seek_samples = (7*bfqq->seek_samples + 256) / 8; + bfqq->seek_total = (7*bfqq->seek_total + (u64)256*sdist) / 8; + total = bfqq->seek_total + (bfqq->seek_samples/2); + do_div(total, bfqq->seek_samples); + bfqq->seek_mean = (sector_t)total; + + bfq_log_bfqq(bfqd, bfqq, "dist=%llu mean=%llu", (u64)sdist, + (u64)bfqq->seek_mean); +} + +/* + * Disable idle window if the process thinks too long or seeks so much that + * it doesn't matter. + */ +static void bfq_update_idle_window(struct bfq_data *bfqd, + struct bfq_queue *bfqq, + struct bfq_io_cq *bic) +{ + int enable_idle; + + /* Don't idle for async or idle io prio class. */ + if (!bfq_bfqq_sync(bfqq) || bfq_class_idle(bfqq)) + return; + + /* Idle window just restored, statistics are meaningless. */ + if (bfq_bfqq_just_split(bfqq)) + return; + + enable_idle = bfq_bfqq_idle_window(bfqq); + + if (atomic_read(&bic->icq.ioc->nr_tasks) == 0 || + bfqd->bfq_slice_idle == 0 || + (bfqd->hw_tag && BFQQ_SEEKY(bfqq) && + bfqq->wr_coeff == 1)) + enable_idle = 0; + else if (bfq_sample_valid(bic->ttime.ttime_samples)) { + if (bic->ttime.ttime_mean > bfqd->bfq_slice_idle && + bfqq->wr_coeff == 1) + enable_idle = 0; + else + enable_idle = 1; + } + bfq_log_bfqq(bfqd, bfqq, "update_idle_window: enable_idle %d", + enable_idle); + + if (enable_idle) + bfq_mark_bfqq_idle_window(bfqq); + else + bfq_clear_bfqq_idle_window(bfqq); +} + +/* + * Called when a new fs request (rq) is added to bfqq. Check if there's + * something we should do about it. + */ +static void bfq_rq_enqueued(struct bfq_data *bfqd, struct bfq_queue *bfqq, + struct request *rq) +{ + struct bfq_io_cq *bic = RQ_BIC(rq); + + if (rq->cmd_flags & REQ_META) + bfqq->meta_pending++; + + bfq_update_io_thinktime(bfqd, bic); + bfq_update_io_seektime(bfqd, bfqq, rq); + if (!BFQQ_SEEKY(bfqq) && bfq_bfqq_constantly_seeky(bfqq)) { + bfq_clear_bfqq_constantly_seeky(bfqq); + if (!blk_queue_nonrot(bfqd->queue)) { + BUG_ON(!bfqd->const_seeky_busy_in_flight_queues); + bfqd->const_seeky_busy_in_flight_queues--; + } + } + if (bfqq->entity.service > bfq_max_budget(bfqd) / 8 || + !BFQQ_SEEKY(bfqq)) + bfq_update_idle_window(bfqd, bfqq, bic); + bfq_clear_bfqq_just_split(bfqq); + + bfq_log_bfqq(bfqd, bfqq, + "rq_enqueued: idle_window=%d (seeky %d, mean %llu)", + bfq_bfqq_idle_window(bfqq), BFQQ_SEEKY(bfqq), + (long long unsigned)bfqq->seek_mean); + + bfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); + + if (bfqq == bfqd->in_service_queue && bfq_bfqq_wait_request(bfqq)) { + int small_req = bfqq->queued[rq_is_sync(rq)] == 1 && + blk_rq_sectors(rq) < 32; + int budget_timeout = bfq_bfqq_budget_timeout(bfqq); + + /* + * There is just this request queued: if the request + * is small and the queue is not to be expired, then + * just exit. + * + * In this way, if the disk is being idled to wait for + * a new request from the in-service queue, we avoid + * unplugging the device and committing the disk to serve + * just a small request. On the contrary, we wait for + * the block layer to decide when to unplug the device: + * hopefully, new requests will be merged to this one + * quickly, then the device will be unplugged and + * larger requests will be dispatched. + */ + if (small_req && !budget_timeout) + return; + + /* + * A large enough request arrived, or the queue is to + * be expired: in both cases disk idling is to be + * stopped, so clear wait_request flag and reset + * timer. + */ + bfq_clear_bfqq_wait_request(bfqq); + del_timer(&bfqd->idle_slice_timer); + + /* + * The queue is not empty, because a new request just + * arrived. Hence we can safely expire the queue, in + * case of budget timeout, without risking that the + * timestamps of the queue are not updated correctly. + * See [1] for more details. + */ + if (budget_timeout) + bfq_bfqq_expire(bfqd, bfqq, 0, BFQ_BFQQ_BUDGET_TIMEOUT); + + /* + * Let the request rip immediately, or let a new queue be + * selected if bfqq has just been expired. + */ + __blk_run_queue(bfqd->queue); + } +} + +static void bfq_insert_request(struct request_queue *q, struct request *rq) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct bfq_queue *bfqq = RQ_BFQQ(rq), *new_bfqq; + + assert_spin_locked(bfqd->queue->queue_lock); + + /* + * An unplug may trigger a requeue of a request from the device + * driver: make sure we are in process context while trying to + * merge two bfq_queues. + */ + if (!in_interrupt()) { + new_bfqq = bfq_setup_cooperator(bfqd, bfqq, rq, true); + if (new_bfqq != NULL) { + if (bic_to_bfqq(RQ_BIC(rq), 1) != bfqq) + new_bfqq = bic_to_bfqq(RQ_BIC(rq), 1); + /* + * Release the request's reference to the old bfqq + * and make sure one is taken to the shared queue. + */ + new_bfqq->allocated[rq_data_dir(rq)]++; + bfqq->allocated[rq_data_dir(rq)]--; + atomic_inc(&new_bfqq->ref); + bfq_put_queue(bfqq); + if (bic_to_bfqq(RQ_BIC(rq), 1) == bfqq) + bfq_merge_bfqqs(bfqd, RQ_BIC(rq), + bfqq, new_bfqq); + rq->elv.priv[1] = new_bfqq; + bfqq = new_bfqq; + } else + bfq_bfqq_increase_failed_cooperations(bfqq); + } + + bfq_add_request(rq); + + /* + * Here a newly-created bfq_queue has already started a weight-raising + * period: clear raising_time_left to prevent bfq_bfqq_save_state() + * from assigning it a full weight-raising period. See the detailed + * comments about this field in bfq_init_icq(). + */ + if (bfqq->bic != NULL) + bfqq->bic->wr_time_left = 0; + rq_set_fifo_time(rq, jiffies + bfqd->bfq_fifo_expire[rq_is_sync(rq)]); + list_add_tail(&rq->queuelist, &bfqq->fifo); + + bfq_rq_enqueued(bfqd, bfqq, rq); +} + +static void bfq_update_hw_tag(struct bfq_data *bfqd) +{ + bfqd->max_rq_in_driver = max(bfqd->max_rq_in_driver, + bfqd->rq_in_driver); + + if (bfqd->hw_tag == 1) + return; + + /* + * This sample is valid if the number of outstanding requests + * is large enough to allow a queueing behavior. Note that the + * sum is not exact, as it's not taking into account deactivated + * requests. + */ + if (bfqd->rq_in_driver + bfqd->queued < BFQ_HW_QUEUE_THRESHOLD) + return; + + if (bfqd->hw_tag_samples++ < BFQ_HW_QUEUE_SAMPLES) + return; + + bfqd->hw_tag = bfqd->max_rq_in_driver > BFQ_HW_QUEUE_THRESHOLD; + bfqd->max_rq_in_driver = 0; + bfqd->hw_tag_samples = 0; +} + +static void bfq_completed_request(struct request_queue *q, struct request *rq) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq); + struct bfq_data *bfqd = bfqq->bfqd; + bool sync = bfq_bfqq_sync(bfqq); + + bfq_log_bfqq(bfqd, bfqq, "completed one req with %u sects left (%d)", + blk_rq_sectors(rq), sync); + + bfq_update_hw_tag(bfqd); + + BUG_ON(!bfqd->rq_in_driver); + BUG_ON(!bfqq->dispatched); + bfqd->rq_in_driver--; + bfqq->dispatched--; + + if (!bfqq->dispatched && !bfq_bfqq_busy(bfqq)) { + bfq_weights_tree_remove(bfqd, &bfqq->entity, + &bfqd->queue_weights_tree); + if (!blk_queue_nonrot(bfqd->queue)) { + BUG_ON(!bfqd->busy_in_flight_queues); + bfqd->busy_in_flight_queues--; + if (bfq_bfqq_constantly_seeky(bfqq)) { + BUG_ON(!bfqd-> + const_seeky_busy_in_flight_queues); + bfqd->const_seeky_busy_in_flight_queues--; + } + } + } + + if (sync) { + bfqd->sync_flight--; + RQ_BIC(rq)->ttime.last_end_request = jiffies; + } + + /* + * If we are waiting to discover whether the request pattern of the + * task associated with the queue is actually isochronous, and + * both requisites for this condition to hold are satisfied, then + * compute soft_rt_next_start (see the comments to the function + * bfq_bfqq_softrt_next_start()). + */ + if (bfq_bfqq_softrt_update(bfqq) && bfqq->dispatched == 0 && + RB_EMPTY_ROOT(&bfqq->sort_list)) + bfqq->soft_rt_next_start = + bfq_bfqq_softrt_next_start(bfqd, bfqq); + + /* + * If this is the in-service queue, check if it needs to be expired, + * or if we want to idle in case it has no pending requests. + */ + if (bfqd->in_service_queue == bfqq) { + if (bfq_bfqq_budget_new(bfqq)) + bfq_set_budget_timeout(bfqd); + + if (bfq_bfqq_must_idle(bfqq)) { + bfq_arm_slice_timer(bfqd); + goto out; + } else if (bfq_may_expire_for_budg_timeout(bfqq)) + bfq_bfqq_expire(bfqd, bfqq, 0, BFQ_BFQQ_BUDGET_TIMEOUT); + else if (RB_EMPTY_ROOT(&bfqq->sort_list) && + (bfqq->dispatched == 0 || + !bfq_bfqq_must_not_expire(bfqq))) + bfq_bfqq_expire(bfqd, bfqq, 0, + BFQ_BFQQ_NO_MORE_REQUESTS); + } + + if (!bfqd->rq_in_driver) + bfq_schedule_dispatch(bfqd); + +out: + return; +} + +static inline int __bfq_may_queue(struct bfq_queue *bfqq) +{ + if (bfq_bfqq_wait_request(bfqq) && bfq_bfqq_must_alloc(bfqq)) { + bfq_clear_bfqq_must_alloc(bfqq); + return ELV_MQUEUE_MUST; + } + + return ELV_MQUEUE_MAY; +} + +static int bfq_may_queue(struct request_queue *q, int rw) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct task_struct *tsk = current; + struct bfq_io_cq *bic; + struct bfq_queue *bfqq; + + /* + * Don't force setup of a queue from here, as a call to may_queue + * does not necessarily imply that a request actually will be + * queued. So just lookup a possibly existing queue, or return + * 'may queue' if that fails. + */ + bic = bfq_bic_lookup(bfqd, tsk->io_context); + if (bic == NULL) + return ELV_MQUEUE_MAY; + + bfqq = bic_to_bfqq(bic, rw_is_sync(rw)); + if (bfqq != NULL) + return __bfq_may_queue(bfqq); + + return ELV_MQUEUE_MAY; +} + +/* + * Queue lock held here. + */ +static void bfq_put_request(struct request *rq) +{ + struct bfq_queue *bfqq = RQ_BFQQ(rq); + + if (bfqq != NULL) { + const int rw = rq_data_dir(rq); + + BUG_ON(!bfqq->allocated[rw]); + bfqq->allocated[rw]--; + + rq->elv.priv[0] = NULL; + rq->elv.priv[1] = NULL; + + bfq_log_bfqq(bfqq->bfqd, bfqq, "put_request %p, %d", + bfqq, atomic_read(&bfqq->ref)); + bfq_put_queue(bfqq); + } +} + +/* + * Returns NULL if a new bfqq should be allocated, or the old bfqq if this + * was the last process referring to said bfqq. + */ +static struct bfq_queue * +bfq_split_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq) +{ + bfq_log_bfqq(bfqq->bfqd, bfqq, "splitting queue"); + + put_io_context(bic->icq.ioc); + + if (bfqq_process_refs(bfqq) == 1) { + bfqq->pid = current->pid; + bfq_clear_bfqq_coop(bfqq); + bfq_clear_bfqq_split_coop(bfqq); + return bfqq; + } + + bic_set_bfqq(bic, NULL, 1); + + bfq_put_cooperator(bfqq); + + bfq_put_queue(bfqq); + return NULL; +} + +/* + * Allocate bfq data structures associated with this request. + */ +static int bfq_set_request(struct request_queue *q, struct request *rq, + gfp_t gfp_mask) +{ + struct bfq_data *bfqd = q->elevator->elevator_data; + struct bfq_io_cq *bic = icq_to_bic(rq->elv.icq); + const int rw = rq_data_dir(rq); + const int is_sync = rq_is_sync(rq); + struct bfq_queue *bfqq; + struct bfq_group *bfqg; + unsigned long flags; + bool split = false; + + /* handle changed prio notifications; cgroup change is handled separately */ + if (unlikely(icq_get_changed(&bic->icq) & ICQ_IOPRIO_CHANGED)) + bfq_check_ioprio_change(bic->icq.ioc, bic); + + might_sleep_if(gfp_mask & __GFP_WAIT); + + spin_lock_irqsave(q->queue_lock, flags); + + if (bic == NULL) + goto queue_fail; + + bfqg = bfq_bic_update_cgroup(bic); + +new_queue: + bfqq = bic_to_bfqq(bic, is_sync); + if (bfqq == NULL || bfqq == &bfqd->oom_bfqq) { + bfqq = bfq_get_queue(bfqd, bfqg, is_sync, bic->icq.ioc, gfp_mask); + bic_set_bfqq(bic, bfqq, is_sync); + if (split && is_sync) { + if ((bic->was_in_burst_list && bfqd->large_burst) || + bic->saved_in_large_burst) + bfq_mark_bfqq_in_large_burst(bfqq); + else { + bfq_clear_bfqq_in_large_burst(bfqq); + if (bic->was_in_burst_list) + hlist_add_head(&bfqq->burst_list_node, + &bfqd->burst_list); + } + } + } else { + /* If the queue was seeky for too long, break it apart. */ + if (bfq_bfqq_coop(bfqq) && bfq_bfqq_split_coop(bfqq)) { + bfq_log_bfqq(bfqd, bfqq, "breaking apart bfqq"); + bfqq = bfq_split_bfqq(bic, bfqq); + split = true; + if (!bfqq) + goto new_queue; + } + } + + bfqq->allocated[rw]++; + atomic_inc(&bfqq->ref); + bfq_log_bfqq(bfqd, bfqq, "set_request: bfqq %p, %d", bfqq, + atomic_read(&bfqq->ref)); + + rq->elv.priv[0] = bic; + rq->elv.priv[1] = bfqq; + + /* + * If a bfq_queue has only one process reference, it is owned + * by only one bfq_io_cq: we can set the bic field of the + * bfq_queue to the address of that structure. Also, if the + * queue has just been split, mark a flag so that the + * information is available to the other scheduler hooks. + */ + if (likely(bfqq != &bfqd->oom_bfqq) && bfqq_process_refs(bfqq) == 1) { + bfqq->bic = bic; + if (split) { + bfq_mark_bfqq_just_split(bfqq); + /* + * If the queue has just been split from a shared + * queue, restore the idle window and the possible + * weight raising period. + */ + bfq_bfqq_resume_state(bfqq, bic); + } + } + + spin_unlock_irqrestore(q->queue_lock, flags); + + return 0; + +queue_fail: + bfq_schedule_dispatch(bfqd); + spin_unlock_irqrestore(q->queue_lock, flags); + + return 1; +} + +static void bfq_kick_queue(struct work_struct *work) +{ + struct bfq_data *bfqd = + container_of(work, struct bfq_data, unplug_work); + struct request_queue *q = bfqd->queue; + + spin_lock_irq(q->queue_lock); + __blk_run_queue(q); + spin_unlock_irq(q->queue_lock); +} + +/* + * Handler of the expiration of the timer running if the in-service queue + * is idling inside its time slice. + */ +static void bfq_idle_slice_timer(unsigned long data) +{ + struct bfq_data *bfqd = (struct bfq_data *)data; + struct bfq_queue *bfqq; + unsigned long flags; + enum bfqq_expiration reason; + + spin_lock_irqsave(bfqd->queue->queue_lock, flags); + + bfqq = bfqd->in_service_queue; + /* + * Theoretical race here: the in-service queue can be NULL or + * different from the queue that was idling if the timer handler + * spins on the queue_lock and a new request arrives for the + * current queue and there is a full dispatch cycle that changes + * the in-service queue. This can hardly happen, but in the worst + * case we just expire a queue too early. + */ + if (bfqq != NULL) { + bfq_log_bfqq(bfqd, bfqq, "slice_timer expired"); + if (bfq_bfqq_budget_timeout(bfqq)) + /* + * Also here the queue can be safely expired + * for budget timeout without wasting + * guarantees + */ + reason = BFQ_BFQQ_BUDGET_TIMEOUT; + else if (bfqq->queued[0] == 0 && bfqq->queued[1] == 0) + /* + * The queue may not be empty upon timer expiration, + * because we may not disable the timer when the + * first request of the in-service queue arrives + * during disk idling. + */ + reason = BFQ_BFQQ_TOO_IDLE; + else + goto schedule_dispatch; + + bfq_bfqq_expire(bfqd, bfqq, 1, reason); + } + +schedule_dispatch: + bfq_schedule_dispatch(bfqd); + + spin_unlock_irqrestore(bfqd->queue->queue_lock, flags); +} + +static void bfq_shutdown_timer_wq(struct bfq_data *bfqd) +{ + del_timer_sync(&bfqd->idle_slice_timer); + cancel_work_sync(&bfqd->unplug_work); +} + +static inline void __bfq_put_async_bfqq(struct bfq_data *bfqd, + struct bfq_queue **bfqq_ptr) +{ + struct bfq_group *root_group = bfqd->root_group; + struct bfq_queue *bfqq = *bfqq_ptr; + + bfq_log(bfqd, "put_async_bfqq: %p", bfqq); + if (bfqq != NULL) { + bfq_bfqq_move(bfqd, bfqq, &bfqq->entity, root_group); + bfq_log_bfqq(bfqd, bfqq, "put_async_bfqq: putting %p, %d", + bfqq, atomic_read(&bfqq->ref)); + bfq_put_queue(bfqq); + *bfqq_ptr = NULL; + } +} + +/* + * Release all the bfqg references to its async queues. If we are + * deallocating the group these queues may still contain requests, so + * we reparent them to the root cgroup (i.e., the only one that will + * exist for sure until all the requests on a device are gone). + */ +static void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg) +{ + int i, j; + + for (i = 0; i < 2; i++) + for (j = 0; j < IOPRIO_BE_NR; j++) + __bfq_put_async_bfqq(bfqd, &bfqg->async_bfqq[i][j]); + + __bfq_put_async_bfqq(bfqd, &bfqg->async_idle_bfqq); +} + +static void bfq_exit_queue(struct elevator_queue *e) +{ + struct bfq_data *bfqd = e->elevator_data; + struct request_queue *q = bfqd->queue; + struct bfq_queue *bfqq, *n; + + bfq_shutdown_timer_wq(bfqd); + + spin_lock_irq(q->queue_lock); + + BUG_ON(bfqd->in_service_queue != NULL); + list_for_each_entry_safe(bfqq, n, &bfqd->idle_list, bfqq_list) + bfq_deactivate_bfqq(bfqd, bfqq, 0); + + bfq_disconnect_groups(bfqd); + spin_unlock_irq(q->queue_lock); + + bfq_shutdown_timer_wq(bfqd); + + synchronize_rcu(); + + BUG_ON(timer_pending(&bfqd->idle_slice_timer)); + + bfq_free_root_group(bfqd); + kfree(bfqd); +} + +static void *bfq_init_queue(struct request_queue *q) +{ + struct bfq_group *bfqg; + struct bfq_data *bfqd; + + bfqd = kzalloc_node(sizeof(*bfqd), GFP_KERNEL, q->node); + if (bfqd == NULL) + return NULL; + + /* + * Our fallback bfqq if bfq_find_alloc_queue() runs into OOM issues. + * Grab a permanent reference to it, so that the normal code flow + * will not attempt to free it. + */ + bfq_init_bfqq(bfqd, &bfqd->oom_bfqq, NULL, 1, 0); + atomic_inc(&bfqd->oom_bfqq.ref); + bfqd->oom_bfqq.entity.new_ioprio = BFQ_DEFAULT_QUEUE_IOPRIO; + bfqd->oom_bfqq.entity.new_ioprio_class = IOPRIO_CLASS_BE; + bfqd->oom_bfqq.entity.new_weight = + bfq_ioprio_to_weight(bfqd->oom_bfqq.entity.new_ioprio); + /* + * Trigger weight initialization, according to ioprio, at the + * oom_bfqq's first activation. The oom_bfqq's ioprio and ioprio + * class won't be changed any more. + */ + bfqd->oom_bfqq.entity.ioprio_changed = 1; + + bfqd->queue = q; + + bfqg = bfq_alloc_root_group(bfqd, q->node); + if (bfqg == NULL) { + kfree(bfqd); + return NULL; + } + + bfqd->root_group = bfqg; + bfq_init_entity(&bfqd->oom_bfqq.entity, bfqd->root_group); +#ifdef CONFIG_CGROUP_BFQIO + bfqd->active_numerous_groups = 0; +#endif + + init_timer(&bfqd->idle_slice_timer); + bfqd->idle_slice_timer.function = bfq_idle_slice_timer; + bfqd->idle_slice_timer.data = (unsigned long)bfqd; + + bfqd->rq_pos_tree = RB_ROOT; + bfqd->queue_weights_tree = RB_ROOT; + bfqd->group_weights_tree = RB_ROOT; + + INIT_WORK(&bfqd->unplug_work, bfq_kick_queue); + + INIT_LIST_HEAD(&bfqd->active_list); + INIT_LIST_HEAD(&bfqd->idle_list); + INIT_HLIST_HEAD(&bfqd->burst_list); + + bfqd->hw_tag = -1; + + bfqd->bfq_max_budget = bfq_default_max_budget; + + bfqd->bfq_fifo_expire[0] = bfq_fifo_expire[0]; + bfqd->bfq_fifo_expire[1] = bfq_fifo_expire[1]; + bfqd->bfq_back_max = bfq_back_max; + bfqd->bfq_back_penalty = bfq_back_penalty; + bfqd->bfq_slice_idle = bfq_slice_idle; + bfqd->bfq_class_idle_last_service = 0; + bfqd->bfq_max_budget_async_rq = bfq_max_budget_async_rq; + bfqd->bfq_timeout[BLK_RW_ASYNC] = bfq_timeout_async; + bfqd->bfq_timeout[BLK_RW_SYNC] = bfq_timeout_sync; + + bfqd->bfq_coop_thresh = 2; + bfqd->bfq_failed_cooperations = 7000; + bfqd->bfq_requests_within_timer = 120; + + bfqd->bfq_large_burst_thresh = 11; + bfqd->bfq_burst_interval = msecs_to_jiffies(500); + + bfqd->low_latency = true; + + bfqd->bfq_wr_coeff = 20; + bfqd->bfq_wr_rt_max_time = msecs_to_jiffies(300); + bfqd->bfq_wr_max_time = 0; + bfqd->bfq_wr_min_idle_time = msecs_to_jiffies(2000); + bfqd->bfq_wr_min_inter_arr_async = msecs_to_jiffies(500); + bfqd->bfq_wr_max_softrt_rate = 7000; /* + * Approximate rate required + * to playback or record a + * high-definition compressed + * video. + */ + bfqd->wr_busy_queues = 0; + bfqd->busy_in_flight_queues = 0; + bfqd->const_seeky_busy_in_flight_queues = 0; + + /* + * Begin by assuming, optimistically, that the device peak rate is + * equal to the highest reference rate. + */ + bfqd->RT_prod = R_fast[blk_queue_nonrot(bfqd->queue)] * + T_fast[blk_queue_nonrot(bfqd->queue)]; + bfqd->peak_rate = R_fast[blk_queue_nonrot(bfqd->queue)]; + bfqd->device_speed = BFQ_BFQD_FAST; + + return bfqd; +} + +static void bfq_slab_kill(void) +{ + if (bfq_pool != NULL) + kmem_cache_destroy(bfq_pool); +} + +static int __init bfq_slab_setup(void) +{ + bfq_pool = KMEM_CACHE(bfq_queue, 0); + if (bfq_pool == NULL) + return -ENOMEM; + return 0; +} + +static ssize_t bfq_var_show(unsigned int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t bfq_var_store(unsigned long *var, const char *page, + size_t count) +{ + unsigned long new_val; + int ret = kstrtoul(page, 10, &new_val); + + if (ret == 0) + *var = new_val; + + return count; +} + +static ssize_t bfq_wr_max_time_show(struct elevator_queue *e, char *page) +{ + struct bfq_data *bfqd = e->elevator_data; + return sprintf(page, "%d\n", bfqd->bfq_wr_max_time > 0 ? + jiffies_to_msecs(bfqd->bfq_wr_max_time) : + jiffies_to_msecs(bfq_wr_duration(bfqd))); +} + +static ssize_t bfq_weights_show(struct elevator_queue *e, char *page) +{ + struct bfq_queue *bfqq; + struct bfq_data *bfqd = e->elevator_data; + ssize_t num_char = 0; + + num_char += sprintf(page + num_char, "Tot reqs queued %d\n\n", + bfqd->queued); + + spin_lock_irq(bfqd->queue->queue_lock); + + num_char += sprintf(page + num_char, "Active:\n"); + list_for_each_entry(bfqq, &bfqd->active_list, bfqq_list) { + num_char += sprintf(page + num_char, + "pid%d: weight %hu, nr_queued %d %d, dur %d/%u\n", + bfqq->pid, + bfqq->entity.weight, + bfqq->queued[0], + bfqq->queued[1], + jiffies_to_msecs(jiffies - bfqq->last_wr_start_finish), + jiffies_to_msecs(bfqq->wr_cur_max_time)); + } + + num_char += sprintf(page + num_char, "Idle:\n"); + list_for_each_entry(bfqq, &bfqd->idle_list, bfqq_list) { + num_char += sprintf(page + num_char, + "pid%d: weight %hu, dur %d/%u\n", + bfqq->pid, + bfqq->entity.weight, + jiffies_to_msecs(jiffies - + bfqq->last_wr_start_finish), + jiffies_to_msecs(bfqq->wr_cur_max_time)); + } + + spin_unlock_irq(bfqd->queue->queue_lock); + + return num_char; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ + struct bfq_data *bfqd = e->elevator_data; \ + unsigned int __data = __VAR; \ + if (__CONV) \ + __data = jiffies_to_msecs(__data); \ + return bfq_var_show(__data, (page)); \ +} +SHOW_FUNCTION(bfq_fifo_expire_sync_show, bfqd->bfq_fifo_expire[1], 1); +SHOW_FUNCTION(bfq_fifo_expire_async_show, bfqd->bfq_fifo_expire[0], 1); +SHOW_FUNCTION(bfq_back_seek_max_show, bfqd->bfq_back_max, 0); +SHOW_FUNCTION(bfq_back_seek_penalty_show, bfqd->bfq_back_penalty, 0); +SHOW_FUNCTION(bfq_slice_idle_show, bfqd->bfq_slice_idle, 1); +SHOW_FUNCTION(bfq_max_budget_show, bfqd->bfq_user_max_budget, 0); +SHOW_FUNCTION(bfq_max_budget_async_rq_show, + bfqd->bfq_max_budget_async_rq, 0); +SHOW_FUNCTION(bfq_timeout_sync_show, bfqd->bfq_timeout[BLK_RW_SYNC], 1); +SHOW_FUNCTION(bfq_timeout_async_show, bfqd->bfq_timeout[BLK_RW_ASYNC], 1); +SHOW_FUNCTION(bfq_low_latency_show, bfqd->low_latency, 0); +SHOW_FUNCTION(bfq_wr_coeff_show, bfqd->bfq_wr_coeff, 0); +SHOW_FUNCTION(bfq_wr_rt_max_time_show, bfqd->bfq_wr_rt_max_time, 1); +SHOW_FUNCTION(bfq_wr_min_idle_time_show, bfqd->bfq_wr_min_idle_time, 1); +SHOW_FUNCTION(bfq_wr_min_inter_arr_async_show, bfqd->bfq_wr_min_inter_arr_async, + 1); +SHOW_FUNCTION(bfq_wr_max_softrt_rate_show, bfqd->bfq_wr_max_softrt_rate, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +static ssize_t \ +__FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ + struct bfq_data *bfqd = e->elevator_data; \ + unsigned long uninitialized_var(__data); \ + int ret = bfq_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + if (__CONV) \ + *(__PTR) = msecs_to_jiffies(__data); \ + else \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(bfq_fifo_expire_sync_store, &bfqd->bfq_fifo_expire[1], 1, + INT_MAX, 1); +STORE_FUNCTION(bfq_fifo_expire_async_store, &bfqd->bfq_fifo_expire[0], 1, + INT_MAX, 1); +STORE_FUNCTION(bfq_back_seek_max_store, &bfqd->bfq_back_max, 0, INT_MAX, 0); +STORE_FUNCTION(bfq_back_seek_penalty_store, &bfqd->bfq_back_penalty, 1, + INT_MAX, 0); +STORE_FUNCTION(bfq_slice_idle_store, &bfqd->bfq_slice_idle, 0, INT_MAX, 1); +STORE_FUNCTION(bfq_max_budget_async_rq_store, &bfqd->bfq_max_budget_async_rq, + 1, INT_MAX, 0); +STORE_FUNCTION(bfq_timeout_async_store, &bfqd->bfq_timeout[BLK_RW_ASYNC], 0, + INT_MAX, 1); +STORE_FUNCTION(bfq_wr_coeff_store, &bfqd->bfq_wr_coeff, 1, INT_MAX, 0); +STORE_FUNCTION(bfq_wr_max_time_store, &bfqd->bfq_wr_max_time, 0, INT_MAX, 1); +STORE_FUNCTION(bfq_wr_rt_max_time_store, &bfqd->bfq_wr_rt_max_time, 0, INT_MAX, + 1); +STORE_FUNCTION(bfq_wr_min_idle_time_store, &bfqd->bfq_wr_min_idle_time, 0, + INT_MAX, 1); +STORE_FUNCTION(bfq_wr_min_inter_arr_async_store, + &bfqd->bfq_wr_min_inter_arr_async, 0, INT_MAX, 1); +STORE_FUNCTION(bfq_wr_max_softrt_rate_store, &bfqd->bfq_wr_max_softrt_rate, 0, + INT_MAX, 0); +#undef STORE_FUNCTION + +/* do nothing for the moment */ +static ssize_t bfq_weights_store(struct elevator_queue *e, + const char *page, size_t count) +{ + return count; +} + +static inline unsigned long bfq_estimated_max_budget(struct bfq_data *bfqd) +{ + u64 timeout = jiffies_to_msecs(bfqd->bfq_timeout[BLK_RW_SYNC]); + + if (bfqd->peak_rate_samples >= BFQ_PEAK_RATE_SAMPLES) + return bfq_calc_max_budget(bfqd->peak_rate, timeout); + else + return bfq_default_max_budget; +} + +static ssize_t bfq_max_budget_store(struct elevator_queue *e, + const char *page, size_t count) +{ + struct bfq_data *bfqd = e->elevator_data; + unsigned long uninitialized_var(__data); + int ret = bfq_var_store(&__data, (page), count); + + if (__data == 0) + bfqd->bfq_max_budget = bfq_estimated_max_budget(bfqd); + else { + if (__data > INT_MAX) + __data = INT_MAX; + bfqd->bfq_max_budget = __data; + } + + bfqd->bfq_user_max_budget = __data; + + return ret; +} + +static ssize_t bfq_timeout_sync_store(struct elevator_queue *e, + const char *page, size_t count) +{ + struct bfq_data *bfqd = e->elevator_data; + unsigned long uninitialized_var(__data); + int ret = bfq_var_store(&__data, (page), count); + + if (__data < 1) + __data = 1; + else if (__data > INT_MAX) + __data = INT_MAX; + + bfqd->bfq_timeout[BLK_RW_SYNC] = msecs_to_jiffies(__data); + if (bfqd->bfq_user_max_budget == 0) + bfqd->bfq_max_budget = bfq_estimated_max_budget(bfqd); + + return ret; +} + +static ssize_t bfq_low_latency_store(struct elevator_queue *e, + const char *page, size_t count) +{ + struct bfq_data *bfqd = e->elevator_data; + unsigned long uninitialized_var(__data); + int ret = bfq_var_store(&__data, (page), count); + + if (__data > 1) + __data = 1; + if (__data == 0 && bfqd->low_latency != 0) + bfq_end_wr(bfqd); + bfqd->low_latency = __data; + + return ret; +} + +#define BFQ_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, bfq_##name##_show, bfq_##name##_store) + +static struct elv_fs_entry bfq_attrs[] = { + BFQ_ATTR(fifo_expire_sync), + BFQ_ATTR(fifo_expire_async), + BFQ_ATTR(back_seek_max), + BFQ_ATTR(back_seek_penalty), + BFQ_ATTR(slice_idle), + BFQ_ATTR(max_budget), + BFQ_ATTR(max_budget_async_rq), + BFQ_ATTR(timeout_sync), + BFQ_ATTR(timeout_async), + BFQ_ATTR(low_latency), + BFQ_ATTR(wr_coeff), + BFQ_ATTR(wr_max_time), + BFQ_ATTR(wr_rt_max_time), + BFQ_ATTR(wr_min_idle_time), + BFQ_ATTR(wr_min_inter_arr_async), + BFQ_ATTR(wr_max_softrt_rate), + BFQ_ATTR(weights), + __ATTR_NULL +}; + +static struct elevator_type iosched_bfq = { + .ops = { + .elevator_merge_fn = bfq_merge, + .elevator_merged_fn = bfq_merged_request, + .elevator_merge_req_fn = bfq_merged_requests, + .elevator_allow_merge_fn = bfq_allow_merge, + .elevator_dispatch_fn = bfq_dispatch_requests, + .elevator_add_req_fn = bfq_insert_request, + .elevator_activate_req_fn = bfq_activate_request, + .elevator_deactivate_req_fn = bfq_deactivate_request, + .elevator_completed_req_fn = bfq_completed_request, + .elevator_former_req_fn = elv_rb_former_request, + .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_init_icq_fn = bfq_init_icq, + .elevator_exit_icq_fn = bfq_exit_icq, + .elevator_set_req_fn = bfq_set_request, + .elevator_put_req_fn = bfq_put_request, + .elevator_may_queue_fn = bfq_may_queue, + .elevator_init_fn = bfq_init_queue, + .elevator_exit_fn = bfq_exit_queue, + }, + .icq_size = sizeof(struct bfq_io_cq), + .icq_align = __alignof__(struct bfq_io_cq), + .elevator_attrs = bfq_attrs, + .elevator_name = "bfq", + .elevator_owner = THIS_MODULE, +}; + +static int __init bfq_init(void) +{ + /* + * Can be 0 on HZ < 1000 setups. + */ + if (bfq_slice_idle == 0) + bfq_slice_idle = 0; + + if (bfq_timeout_async == 0) + bfq_timeout_async = 1; + + if (bfq_slab_setup()) + return -ENOMEM; + + /* + * Times to load large popular applications for the typical systems + * installed on the reference devices (see the comments before the + * definitions of the two arrays). + */ + T_slow[0] = msecs_to_jiffies(2600); + T_slow[1] = msecs_to_jiffies(1000); + T_fast[0] = msecs_to_jiffies(5500); + T_fast[1] = msecs_to_jiffies(2000); + + /* + * Thresholds that determine the switch between speed classes (see + * the comments before the definition of the array). + */ + device_speed_thresh[0] = (R_fast[0] + R_slow[0]) / 2; + device_speed_thresh[1] = (R_fast[1] + R_slow[1]) / 2; + + elv_register(&iosched_bfq); + pr_info("BFQ I/O-scheduler: v7r8"); + + return 0; +} + +static void __exit bfq_exit(void) +{ + elv_unregister(&iosched_bfq); + bfq_slab_kill(); +} + +module_init(bfq_init); +module_exit(bfq_exit); + +MODULE_AUTHOR("Fabio Checconi, Paolo Valente"); +MODULE_LICENSE("GPL"); diff --git a/block/bfq-sched.c b/block/bfq-sched.c new file mode 100644 index 00000000..d0890c6d --- /dev/null +++ b/block/bfq-sched.c @@ -0,0 +1,1180 @@ +/* + * BFQ: Hierarchical B-WF2Q+ scheduler. + * + * Based on ideas and code from CFQ: + * Copyright (C) 2003 Jens Axboe + * + * Copyright (C) 2008 Fabio Checconi + * Paolo Valente + * + * Copyright (C) 2010 Paolo Valente + */ + +#ifdef CONFIG_CGROUP_BFQIO +#define for_each_entity(entity) \ + for (; entity != NULL; entity = entity->parent) + +#define for_each_entity_safe(entity, parent) \ + for (; entity && ({ parent = entity->parent; 1; }); entity = parent) + +static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd, + int extract, + struct bfq_data *bfqd); + +static inline void bfq_update_budget(struct bfq_entity *next_in_service) +{ + struct bfq_entity *bfqg_entity; + struct bfq_group *bfqg; + struct bfq_sched_data *group_sd; + + BUG_ON(next_in_service == NULL); + + group_sd = next_in_service->sched_data; + + bfqg = container_of(group_sd, struct bfq_group, sched_data); + /* + * bfq_group's my_entity field is not NULL only if the group + * is not the root group. We must not touch the root entity + * as it must never become an in-service entity. + */ + bfqg_entity = bfqg->my_entity; + if (bfqg_entity != NULL) + bfqg_entity->budget = next_in_service->budget; +} + +static int bfq_update_next_in_service(struct bfq_sched_data *sd) +{ + struct bfq_entity *next_in_service; + + if (sd->in_service_entity != NULL) + /* will update/requeue at the end of service */ + return 0; + + /* + * NOTE: this can be improved in many ways, such as returning + * 1 (and thus propagating upwards the update) only when the + * budget changes, or caching the bfqq that will be scheduled + * next from this subtree. By now we worry more about + * correctness than about performance... + */ + next_in_service = bfq_lookup_next_entity(sd, 0, NULL); + sd->next_in_service = next_in_service; + + if (next_in_service != NULL) + bfq_update_budget(next_in_service); + + return 1; +} + +static inline void bfq_check_next_in_service(struct bfq_sched_data *sd, + struct bfq_entity *entity) +{ + BUG_ON(sd->next_in_service != entity); +} +#else +#define for_each_entity(entity) \ + for (; entity != NULL; entity = NULL) + +#define for_each_entity_safe(entity, parent) \ + for (parent = NULL; entity != NULL; entity = parent) + +static inline int bfq_update_next_in_service(struct bfq_sched_data *sd) +{ + return 0; +} + +static inline void bfq_check_next_in_service(struct bfq_sched_data *sd, + struct bfq_entity *entity) +{ +} + +static inline void bfq_update_budget(struct bfq_entity *next_in_service) +{ +} +#endif + +/* + * Shift for timestamp calculations. This actually limits the maximum + * service allowed in one timestamp delta (small shift values increase it), + * the maximum total weight that can be used for the queues in the system + * (big shift values increase it), and the period of virtual time + * wraparounds. + */ +#define WFQ_SERVICE_SHIFT 22 + +/** + * bfq_gt - compare two timestamps. + * @a: first ts. + * @b: second ts. + * + * Return @a > @b, dealing with wrapping correctly. + */ +static inline int bfq_gt(u64 a, u64 b) +{ + return (s64)(a - b) > 0; +} + +static inline struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = NULL; + + BUG_ON(entity == NULL); + + if (entity->my_sched_data == NULL) + bfqq = container_of(entity, struct bfq_queue, entity); + + return bfqq; +} + + +/** + * bfq_delta - map service into the virtual time domain. + * @service: amount of service. + * @weight: scale factor (weight of an entity or weight sum). + */ +static inline u64 bfq_delta(unsigned long service, + unsigned long weight) +{ + u64 d = (u64)service << WFQ_SERVICE_SHIFT; + + do_div(d, weight); + return d; +} + +/** + * bfq_calc_finish - assign the finish time to an entity. + * @entity: the entity to act upon. + * @service: the service to be charged to the entity. + */ +static inline void bfq_calc_finish(struct bfq_entity *entity, + unsigned long service) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + + BUG_ON(entity->weight == 0); + + entity->finish = entity->start + + bfq_delta(service, entity->weight); + + if (bfqq != NULL) { + bfq_log_bfqq(bfqq->bfqd, bfqq, + "calc_finish: serv %lu, w %d", + service, entity->weight); + bfq_log_bfqq(bfqq->bfqd, bfqq, + "calc_finish: start %llu, finish %llu, delta %llu", + entity->start, entity->finish, + bfq_delta(service, entity->weight)); + } +} + +/** + * bfq_entity_of - get an entity from a node. + * @node: the node field of the entity. + * + * Convert a node pointer to the relative entity. This is used only + * to simplify the logic of some functions and not as the generic + * conversion mechanism because, e.g., in the tree walking functions, + * the check for a %NULL value would be redundant. + */ +static inline struct bfq_entity *bfq_entity_of(struct rb_node *node) +{ + struct bfq_entity *entity = NULL; + + if (node != NULL) + entity = rb_entry(node, struct bfq_entity, rb_node); + + return entity; +} + +/** + * bfq_extract - remove an entity from a tree. + * @root: the tree root. + * @entity: the entity to remove. + */ +static inline void bfq_extract(struct rb_root *root, + struct bfq_entity *entity) +{ + BUG_ON(entity->tree != root); + + entity->tree = NULL; + rb_erase(&entity->rb_node, root); +} + +/** + * bfq_idle_extract - extract an entity from the idle tree. + * @st: the service tree of the owning @entity. + * @entity: the entity being removed. + */ +static void bfq_idle_extract(struct bfq_service_tree *st, + struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + struct rb_node *next; + + BUG_ON(entity->tree != &st->idle); + + if (entity == st->first_idle) { + next = rb_next(&entity->rb_node); + st->first_idle = bfq_entity_of(next); + } + + if (entity == st->last_idle) { + next = rb_prev(&entity->rb_node); + st->last_idle = bfq_entity_of(next); + } + + bfq_extract(&st->idle, entity); + + if (bfqq != NULL) + list_del(&bfqq->bfqq_list); +} + +/** + * bfq_insert - generic tree insertion. + * @root: tree root. + * @entity: entity to insert. + * + * This is used for the idle and the active tree, since they are both + * ordered by finish time. + */ +static void bfq_insert(struct rb_root *root, struct bfq_entity *entity) +{ + struct bfq_entity *entry; + struct rb_node **node = &root->rb_node; + struct rb_node *parent = NULL; + + BUG_ON(entity->tree != NULL); + + while (*node != NULL) { + parent = *node; + entry = rb_entry(parent, struct bfq_entity, rb_node); + + if (bfq_gt(entry->finish, entity->finish)) + node = &parent->rb_left; + else + node = &parent->rb_right; + } + + rb_link_node(&entity->rb_node, parent, node); + rb_insert_color(&entity->rb_node, root); + + entity->tree = root; +} + +/** + * bfq_update_min - update the min_start field of a entity. + * @entity: the entity to update. + * @node: one of its children. + * + * This function is called when @entity may store an invalid value for + * min_start due to updates to the active tree. The function assumes + * that the subtree rooted at @node (which may be its left or its right + * child) has a valid min_start value. + */ +static inline void bfq_update_min(struct bfq_entity *entity, + struct rb_node *node) +{ + struct bfq_entity *child; + + if (node != NULL) { + child = rb_entry(node, struct bfq_entity, rb_node); + if (bfq_gt(entity->min_start, child->min_start)) + entity->min_start = child->min_start; + } +} + +/** + * bfq_update_active_node - recalculate min_start. + * @node: the node to update. + * + * @node may have changed position or one of its children may have moved, + * this function updates its min_start value. The left and right subtrees + * are assumed to hold a correct min_start value. + */ +static inline void bfq_update_active_node(struct rb_node *node) +{ + struct bfq_entity *entity = rb_entry(node, struct bfq_entity, rb_node); + + entity->min_start = entity->start; + bfq_update_min(entity, node->rb_right); + bfq_update_min(entity, node->rb_left); +} + +/** + * bfq_update_active_tree - update min_start for the whole active tree. + * @node: the starting node. + * + * @node must be the deepest modified node after an update. This function + * updates its min_start using the values held by its children, assuming + * that they did not change, and then updates all the nodes that may have + * changed in the path to the root. The only nodes that may have changed + * are the ones in the path or their siblings. + */ +static void bfq_update_active_tree(struct rb_node *node) +{ + struct rb_node *parent; + +up: + bfq_update_active_node(node); + + parent = rb_parent(node); + if (parent == NULL) + return; + + if (node == parent->rb_left && parent->rb_right != NULL) + bfq_update_active_node(parent->rb_right); + else if (parent->rb_left != NULL) + bfq_update_active_node(parent->rb_left); + + node = parent; + goto up; +} + +static void bfq_weights_tree_add(struct bfq_data *bfqd, + struct bfq_entity *entity, + struct rb_root *root); + +static void bfq_weights_tree_remove(struct bfq_data *bfqd, + struct bfq_entity *entity, + struct rb_root *root); + + +/** + * bfq_active_insert - insert an entity in the active tree of its + * group/device. + * @st: the service tree of the entity. + * @entity: the entity being inserted. + * + * The active tree is ordered by finish time, but an extra key is kept + * per each node, containing the minimum value for the start times of + * its children (and the node itself), so it's possible to search for + * the eligible node with the lowest finish time in logarithmic time. + */ +static void bfq_active_insert(struct bfq_service_tree *st, + struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + struct rb_node *node = &entity->rb_node; +#ifdef CONFIG_CGROUP_BFQIO + struct bfq_sched_data *sd = NULL; + struct bfq_group *bfqg = NULL; + struct bfq_data *bfqd = NULL; +#endif + + bfq_insert(&st->active, entity); + + if (node->rb_left != NULL) + node = node->rb_left; + else if (node->rb_right != NULL) + node = node->rb_right; + + bfq_update_active_tree(node); + +#ifdef CONFIG_CGROUP_BFQIO + sd = entity->sched_data; + bfqg = container_of(sd, struct bfq_group, sched_data); + BUG_ON(!bfqg); + bfqd = (struct bfq_data *)bfqg->bfqd; +#endif + if (bfqq != NULL) + list_add(&bfqq->bfqq_list, &bfqq->bfqd->active_list); +#ifdef CONFIG_CGROUP_BFQIO + else { /* bfq_group */ + BUG_ON(!bfqd); + bfq_weights_tree_add(bfqd, entity, &bfqd->group_weights_tree); + } + if (bfqg != bfqd->root_group) { + BUG_ON(!bfqg); + BUG_ON(!bfqd); + bfqg->active_entities++; + if (bfqg->active_entities == 2) + bfqd->active_numerous_groups++; + } +#endif +} + +/** + * bfq_ioprio_to_weight - calc a weight from an ioprio. + * @ioprio: the ioprio value to convert. + */ +static inline unsigned short bfq_ioprio_to_weight(int ioprio) +{ + BUG_ON(ioprio < 0 || ioprio >= IOPRIO_BE_NR); + return IOPRIO_BE_NR - ioprio; +} + +/** + * bfq_weight_to_ioprio - calc an ioprio from a weight. + * @weight: the weight value to convert. + * + * To preserve as mush as possible the old only-ioprio user interface, + * 0 is used as an escape ioprio value for weights (numerically) equal or + * larger than IOPRIO_BE_NR + */ +static inline unsigned short bfq_weight_to_ioprio(int weight) +{ + BUG_ON(weight < BFQ_MIN_WEIGHT || weight > BFQ_MAX_WEIGHT); + return IOPRIO_BE_NR - weight < 0 ? 0 : IOPRIO_BE_NR - weight; +} + +static inline void bfq_get_entity(struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + + if (bfqq != NULL) { + atomic_inc(&bfqq->ref); + bfq_log_bfqq(bfqq->bfqd, bfqq, "get_entity: %p %d", + bfqq, atomic_read(&bfqq->ref)); + } +} + +/** + * bfq_find_deepest - find the deepest node that an extraction can modify. + * @node: the node being removed. + * + * Do the first step of an extraction in an rb tree, looking for the + * node that will replace @node, and returning the deepest node that + * the following modifications to the tree can touch. If @node is the + * last node in the tree return %NULL. + */ +static struct rb_node *bfq_find_deepest(struct rb_node *node) +{ + struct rb_node *deepest; + + if (node->rb_right == NULL && node->rb_left == NULL) + deepest = rb_parent(node); + else if (node->rb_right == NULL) + deepest = node->rb_left; + else if (node->rb_left == NULL) + deepest = node->rb_right; + else { + deepest = rb_next(node); + if (deepest->rb_right != NULL) + deepest = deepest->rb_right; + else if (rb_parent(deepest) != node) + deepest = rb_parent(deepest); + } + + return deepest; +} + +/** + * bfq_active_extract - remove an entity from the active tree. + * @st: the service_tree containing the tree. + * @entity: the entity being removed. + */ +static void bfq_active_extract(struct bfq_service_tree *st, + struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + struct rb_node *node; +#ifdef CONFIG_CGROUP_BFQIO + struct bfq_sched_data *sd = NULL; + struct bfq_group *bfqg = NULL; + struct bfq_data *bfqd = NULL; +#endif + + node = bfq_find_deepest(&entity->rb_node); + bfq_extract(&st->active, entity); + + if (node != NULL) + bfq_update_active_tree(node); + +#ifdef CONFIG_CGROUP_BFQIO + sd = entity->sched_data; + bfqg = container_of(sd, struct bfq_group, sched_data); + BUG_ON(!bfqg); + bfqd = (struct bfq_data *)bfqg->bfqd; +#endif + if (bfqq != NULL) + list_del(&bfqq->bfqq_list); +#ifdef CONFIG_CGROUP_BFQIO + else { /* bfq_group */ + BUG_ON(!bfqd); + bfq_weights_tree_remove(bfqd, entity, + &bfqd->group_weights_tree); + } + if (bfqg != bfqd->root_group) { + BUG_ON(!bfqg); + BUG_ON(!bfqd); + BUG_ON(!bfqg->active_entities); + bfqg->active_entities--; + if (bfqg->active_entities == 1) { + BUG_ON(!bfqd->active_numerous_groups); + bfqd->active_numerous_groups--; + } + } +#endif +} + +/** + * bfq_idle_insert - insert an entity into the idle tree. + * @st: the service tree containing the tree. + * @entity: the entity to insert. + */ +static void bfq_idle_insert(struct bfq_service_tree *st, + struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + struct bfq_entity *first_idle = st->first_idle; + struct bfq_entity *last_idle = st->last_idle; + + if (first_idle == NULL || bfq_gt(first_idle->finish, entity->finish)) + st->first_idle = entity; + if (last_idle == NULL || bfq_gt(entity->finish, last_idle->finish)) + st->last_idle = entity; + + bfq_insert(&st->idle, entity); + + if (bfqq != NULL) + list_add(&bfqq->bfqq_list, &bfqq->bfqd->idle_list); +} + +/** + * bfq_forget_entity - remove an entity from the wfq trees. + * @st: the service tree. + * @entity: the entity being removed. + * + * Update the device status and forget everything about @entity, putting + * the device reference to it, if it is a queue. Entities belonging to + * groups are not refcounted. + */ +static void bfq_forget_entity(struct bfq_service_tree *st, + struct bfq_entity *entity) +{ + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + struct bfq_sched_data *sd; + + BUG_ON(!entity->on_st); + + entity->on_st = 0; + st->wsum -= entity->weight; + if (bfqq != NULL) { + sd = entity->sched_data; + bfq_log_bfqq(bfqq->bfqd, bfqq, "forget_entity: %p %d", + bfqq, atomic_read(&bfqq->ref)); + bfq_put_queue(bfqq); + } +} + +/** + * bfq_put_idle_entity - release the idle tree ref of an entity. + * @st: service tree for the entity. + * @entity: the entity being released. + */ +static void bfq_put_idle_entity(struct bfq_service_tree *st, + struct bfq_entity *entity) +{ + bfq_idle_extract(st, entity); + bfq_forget_entity(st, entity); +} + +/** + * bfq_forget_idle - update the idle tree if necessary. + * @st: the service tree to act upon. + * + * To preserve the global O(log N) complexity we only remove one entry here; + * as the idle tree will not grow indefinitely this can be done safely. + */ +static void bfq_forget_idle(struct bfq_service_tree *st) +{ + struct bfq_entity *first_idle = st->first_idle; + struct bfq_entity *last_idle = st->last_idle; + + if (RB_EMPTY_ROOT(&st->active) && last_idle != NULL && + !bfq_gt(last_idle->finish, st->vtime)) { + /* + * Forget the whole idle tree, increasing the vtime past + * the last finish time of idle entities. + */ + st->vtime = last_idle->finish; + } + + if (first_idle != NULL && !bfq_gt(first_idle->finish, st->vtime)) + bfq_put_idle_entity(st, first_idle); +} + +static struct bfq_service_tree * +__bfq_entity_update_weight_prio(struct bfq_service_tree *old_st, + struct bfq_entity *entity) +{ + struct bfq_service_tree *new_st = old_st; + + if (entity->ioprio_changed) { + struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); + unsigned short prev_weight, new_weight; + struct bfq_data *bfqd = NULL; + struct rb_root *root; +#ifdef CONFIG_CGROUP_BFQIO + struct bfq_sched_data *sd; + struct bfq_group *bfqg; +#endif + + if (bfqq != NULL) + bfqd = bfqq->bfqd; +#ifdef CONFIG_CGROUP_BFQIO + else { + sd = entity->my_sched_data; + bfqg = container_of(sd, struct bfq_group, sched_data); + BUG_ON(!bfqg); + bfqd = (struct bfq_data *)bfqg->bfqd; + BUG_ON(!bfqd); + } +#endif + + BUG_ON(old_st->wsum < entity->weight); + old_st->wsum -= entity->weight; + + if (entity->new_weight != entity->orig_weight) { + if (entity->new_weight < BFQ_MIN_WEIGHT || + entity->new_weight > BFQ_MAX_WEIGHT) { + printk(KERN_CRIT "update_weight_prio: " + "new_weight %d\n", + entity->new_weight); + BUG(); + } + entity->orig_weight = entity->new_weight; + entity->ioprio = + bfq_weight_to_ioprio(entity->orig_weight); + } + + entity->ioprio_class = entity->new_ioprio_class; + entity->ioprio_changed = 0; + + /* + * NOTE: here we may be changing the weight too early, + * this will cause unfairness. The correct approach + * would have required additional complexity to defer + * weight changes to the proper time instants (i.e., + * when entity->finish <= old_st->vtime). + */ + new_st = bfq_entity_service_tree(entity); + + prev_weight = entity->weight; + new_weight = entity->orig_weight * + (bfqq != NULL ? bfqq->wr_coeff : 1); + /* + * If the weight of the entity changes, remove the entity + * from its old weight counter (if there is a counter + * associated with the entity), and add it to the counter + * associated with its new weight. + */ + if (prev_weight != new_weight) { + root = bfqq ? &bfqd->queue_weights_tree : + &bfqd->group_weights_tree; + bfq_weights_tree_remove(bfqd, entity, root); + } + entity->weight = new_weight; + /* + * Add the entity to its weights tree only if it is + * not associated with a weight-raised queue. + */ + if (prev_weight != new_weight && + (bfqq ? bfqq->wr_coeff == 1 : 1)) + /* If we get here, root has been initialized. */ + bfq_weights_tree_add(bfqd, entity, root); + + new_st->wsum += entity->weight; + + if (new_st != old_st) + entity->start = new_st->vtime; + } + + return new_st; +} + +/** + * bfq_bfqq_served - update the scheduler status after selection for + * service. + * @bfqq: the queue being served. + * @served: bytes to transfer. + * + * NOTE: this can be optimized, as the timestamps of upper level entities + * are synchronized every time a new bfqq is selected for service. By now, + * we keep it to better check consistency. + */ +static void bfq_bfqq_served(struct bfq_queue *bfqq, unsigned long served) +{ + struct bfq_entity *entity = &bfqq->entity; + struct bfq_service_tree *st; + + for_each_entity(entity) { + st = bfq_entity_service_tree(entity); + + entity->service += served; + BUG_ON(entity->service > entity->budget); + BUG_ON(st->wsum == 0); + + st->vtime += bfq_delta(served, st->wsum); + bfq_forget_idle(st); + } + bfq_log_bfqq(bfqq->bfqd, bfqq, "bfqq_served %lu secs", served); +} + +/** + * bfq_bfqq_charge_full_budget - set the service to the entity budget. + * @bfqq: the queue that needs a service update. + * + * When it's not possible to be fair in the service domain, because + * a queue is not consuming its budget fast enough (the meaning of + * fast depends on the timeout parameter), we charge it a full + * budget. In this way we should obtain a sort of time-domain + * fairness among all the seeky/slow queues. + */ +static inline void bfq_bfqq_charge_full_budget(struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + + bfq_log_bfqq(bfqq->bfqd, bfqq, "charge_full_budget"); + + bfq_bfqq_served(bfqq, entity->budget - entity->service); +} + +/** + * __bfq_activate_entity - activate an entity. + * @entity: the entity being activated. + * + * Called whenever an entity is activated, i.e., it is not active and one + * of its children receives a new request, or has to be reactivated due to + * budget exhaustion. It uses the current budget of the entity (and the + * service received if @entity is active) of the queue to calculate its + * timestamps. + */ +static void __bfq_activate_entity(struct bfq_entity *entity) +{ + struct bfq_sched_data *sd = entity->sched_data; + struct bfq_service_tree *st = bfq_entity_service_tree(entity); + + if (entity == sd->in_service_entity) { + BUG_ON(entity->tree != NULL); + /* + * If we are requeueing the current entity we have + * to take care of not charging to it service it has + * not received. + */ + bfq_calc_finish(entity, entity->service); + entity->start = entity->finish; + sd->in_service_entity = NULL; + } else if (entity->tree == &st->active) { + /* + * Requeueing an entity due to a change of some + * next_in_service entity below it. We reuse the + * old start time. + */ + bfq_active_extract(st, entity); + } else if (entity->tree == &st->idle) { + /* + * Must be on the idle tree, bfq_idle_extract() will + * check for that. + */ + bfq_idle_extract(st, entity); + entity->start = bfq_gt(st->vtime, entity->finish) ? + st->vtime : entity->finish; + } else { + /* + * The finish time of the entity may be invalid, and + * it is in the past for sure, otherwise the queue + * would have been on the idle tree. + */ + entity->start = st->vtime; + st->wsum += entity->weight; + bfq_get_entity(entity); + + BUG_ON(entity->on_st); + entity->on_st = 1; + } + + st = __bfq_entity_update_weight_prio(st, entity); + bfq_calc_finish(entity, entity->budget); + bfq_active_insert(st, entity); +} + +/** + * bfq_activate_entity - activate an entity and its ancestors if necessary. + * @entity: the entity to activate. + * + * Activate @entity and all the entities on the path from it to the root. + */ +static void bfq_activate_entity(struct bfq_entity *entity) +{ + struct bfq_sched_data *sd; + + for_each_entity(entity) { + __bfq_activate_entity(entity); + + sd = entity->sched_data; + if (!bfq_update_next_in_service(sd)) + /* + * No need to propagate the activation to the + * upper entities, as they will be updated when + * the in-service entity is rescheduled. + */ + break; + } +} + +/** + * __bfq_deactivate_entity - deactivate an entity from its service tree. + * @entity: the entity to deactivate. + * @requeue: if false, the entity will not be put into the idle tree. + * + * Deactivate an entity, independently from its previous state. If the + * entity was not on a service tree just return, otherwise if it is on + * any scheduler tree, extract it from that tree, and if necessary + * and if the caller did not specify @requeue, put it on the idle tree. + * + * Return %1 if the caller should update the entity hierarchy, i.e., + * if the entity was in service or if it was the next_in_service for + * its sched_data; return %0 otherwise. + */ +static int __bfq_deactivate_entity(struct bfq_entity *entity, int requeue) +{ + struct bfq_sched_data *sd = entity->sched_data; + struct bfq_service_tree *st = bfq_entity_service_tree(entity); + int was_in_service = entity == sd->in_service_entity; + int ret = 0; + + if (!entity->on_st) + return 0; + + BUG_ON(was_in_service && entity->tree != NULL); + + if (was_in_service) { + bfq_calc_finish(entity, entity->service); + sd->in_service_entity = NULL; + } else if (entity->tree == &st->active) + bfq_active_extract(st, entity); + else if (entity->tree == &st->idle) + bfq_idle_extract(st, entity); + else if (entity->tree != NULL) + BUG(); + + if (was_in_service || sd->next_in_service == entity) + ret = bfq_update_next_in_service(sd); + + if (!requeue || !bfq_gt(entity->finish, st->vtime)) + bfq_forget_entity(st, entity); + else + bfq_idle_insert(st, entity); + + BUG_ON(sd->in_service_entity == entity); + BUG_ON(sd->next_in_service == entity); + + return ret; +} + +/** + * bfq_deactivate_entity - deactivate an entity. + * @entity: the entity to deactivate. + * @requeue: true if the entity can be put on the idle tree + */ +static void bfq_deactivate_entity(struct bfq_entity *entity, int requeue) +{ + struct bfq_sched_data *sd; + struct bfq_entity *parent; + + for_each_entity_safe(entity, parent) { + sd = entity->sched_data; + + if (!__bfq_deactivate_entity(entity, requeue)) + /* + * The parent entity is still backlogged, and + * we don't need to update it as it is still + * in service. + */ + break; + + if (sd->next_in_service != NULL) + /* + * The parent entity is still backlogged and + * the budgets on the path towards the root + * need to be updated. + */ + goto update; + + /* + * If we reach there the parent is no more backlogged and + * we want to propagate the dequeue upwards. + */ + requeue = 1; + } + + return; + +update: + entity = parent; + for_each_entity(entity) { + __bfq_activate_entity(entity); + + sd = entity->sched_data; + if (!bfq_update_next_in_service(sd)) + break; + } +} + +/** + * bfq_update_vtime - update vtime if necessary. + * @st: the service tree to act upon. + * + * If necessary update the service tree vtime to have at least one + * eligible entity, skipping to its start time. Assumes that the + * active tree of the device is not empty. + * + * NOTE: this hierarchical implementation updates vtimes quite often, + * we may end up with reactivated processes getting timestamps after a + * vtime skip done because we needed a ->first_active entity on some + * intermediate node. + */ +static void bfq_update_vtime(struct bfq_service_tree *st) +{ + struct bfq_entity *entry; + struct rb_node *node = st->active.rb_node; + + entry = rb_entry(node, struct bfq_entity, rb_node); + if (bfq_gt(entry->min_start, st->vtime)) { + st->vtime = entry->min_start; + bfq_forget_idle(st); + } +} + +/** + * bfq_first_active_entity - find the eligible entity with + * the smallest finish time + * @st: the service tree to select from. + * + * This function searches the first schedulable entity, starting from the + * root of the tree and going on the left every time on this side there is + * a subtree with at least one eligible (start >= vtime) entity. The path on + * the right is followed only if a) the left subtree contains no eligible + * entities and b) no eligible entity has been found yet. + */ +static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st) +{ + struct bfq_entity *entry, *first = NULL; + struct rb_node *node = st->active.rb_node; + + while (node != NULL) { + entry = rb_entry(node, struct bfq_entity, rb_node); +left: + if (!bfq_gt(entry->start, st->vtime)) + first = entry; + + BUG_ON(bfq_gt(entry->min_start, st->vtime)); + + if (node->rb_left != NULL) { + entry = rb_entry(node->rb_left, + struct bfq_entity, rb_node); + if (!bfq_gt(entry->min_start, st->vtime)) { + node = node->rb_left; + goto left; + } + } + if (first != NULL) + break; + node = node->rb_right; + } + + BUG_ON(first == NULL && !RB_EMPTY_ROOT(&st->active)); + return first; +} + +/** + * __bfq_lookup_next_entity - return the first eligible entity in @st. + * @st: the service tree. + * + * Update the virtual time in @st and return the first eligible entity + * it contains. + */ +static struct bfq_entity *__bfq_lookup_next_entity(struct bfq_service_tree *st, + bool force) +{ + struct bfq_entity *entity, *new_next_in_service = NULL; + + if (RB_EMPTY_ROOT(&st->active)) + return NULL; + + bfq_update_vtime(st); + entity = bfq_first_active_entity(st); + BUG_ON(bfq_gt(entity->start, st->vtime)); + + /* + * If the chosen entity does not match with the sched_data's + * next_in_service and we are forcedly serving the IDLE priority + * class tree, bubble up budget update. + */ + if (unlikely(force && entity != entity->sched_data->next_in_service)) { + new_next_in_service = entity; + for_each_entity(new_next_in_service) + bfq_update_budget(new_next_in_service); + } + + return entity; +} + +/** + * bfq_lookup_next_entity - return the first eligible entity in @sd. + * @sd: the sched_data. + * @extract: if true the returned entity will be also extracted from @sd. + * + * NOTE: since we cache the next_in_service entity at each level of the + * hierarchy, the complexity of the lookup can be decreased with + * absolutely no effort just returning the cached next_in_service value; + * we prefer to do full lookups to test the consistency of * the data + * structures. + */ +static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd, + int extract, + struct bfq_data *bfqd) +{ + struct bfq_service_tree *st = sd->service_tree; + struct bfq_entity *entity; + int i = 0; + + BUG_ON(sd->in_service_entity != NULL); + + if (bfqd != NULL && + jiffies - bfqd->bfq_class_idle_last_service > BFQ_CL_IDLE_TIMEOUT) { + entity = __bfq_lookup_next_entity(st + BFQ_IOPRIO_CLASSES - 1, + true); + if (entity != NULL) { + i = BFQ_IOPRIO_CLASSES - 1; + bfqd->bfq_class_idle_last_service = jiffies; + sd->next_in_service = entity; + } + } + for (; i < BFQ_IOPRIO_CLASSES; i++) { + entity = __bfq_lookup_next_entity(st + i, false); + if (entity != NULL) { + if (extract) { + bfq_check_next_in_service(sd, entity); + bfq_active_extract(st + i, entity); + sd->in_service_entity = entity; + sd->next_in_service = NULL; + } + break; + } + } + + return entity; +} + +/* + * Get next queue for service. + */ +static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd) +{ + struct bfq_entity *entity = NULL; + struct bfq_sched_data *sd; + struct bfq_queue *bfqq; + + BUG_ON(bfqd->in_service_queue != NULL); + + if (bfqd->busy_queues == 0) + return NULL; + + sd = &bfqd->root_group->sched_data; + for (; sd != NULL; sd = entity->my_sched_data) { + entity = bfq_lookup_next_entity(sd, 1, bfqd); + BUG_ON(entity == NULL); + entity->service = 0; + } + + bfqq = bfq_entity_to_bfqq(entity); + BUG_ON(bfqq == NULL); + + return bfqq; +} + +static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd) +{ + if (bfqd->in_service_bic != NULL) { + put_io_context(bfqd->in_service_bic->icq.ioc); + bfqd->in_service_bic = NULL; + } + + bfqd->in_service_queue = NULL; + del_timer(&bfqd->idle_slice_timer); +} + +static void bfq_deactivate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, + int requeue) +{ + struct bfq_entity *entity = &bfqq->entity; + + if (bfqq == bfqd->in_service_queue) + __bfq_bfqd_reset_in_service(bfqd); + + bfq_deactivate_entity(entity, requeue); +} + +static void bfq_activate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + struct bfq_entity *entity = &bfqq->entity; + + bfq_activate_entity(entity); +} + +/* + * Called when the bfqq no longer has requests pending, remove it from + * the service tree. + */ +static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq, + int requeue) +{ + BUG_ON(!bfq_bfqq_busy(bfqq)); + BUG_ON(!RB_EMPTY_ROOT(&bfqq->sort_list)); + + bfq_log_bfqq(bfqd, bfqq, "del from busy"); + + bfq_clear_bfqq_busy(bfqq); + + BUG_ON(bfqd->busy_queues == 0); + bfqd->busy_queues--; + + if (!bfqq->dispatched) { + bfq_weights_tree_remove(bfqd, &bfqq->entity, + &bfqd->queue_weights_tree); + if (!blk_queue_nonrot(bfqd->queue)) { + BUG_ON(!bfqd->busy_in_flight_queues); + bfqd->busy_in_flight_queues--; + if (bfq_bfqq_constantly_seeky(bfqq)) { + BUG_ON(!bfqd-> + const_seeky_busy_in_flight_queues); + bfqd->const_seeky_busy_in_flight_queues--; + } + } + } + if (bfqq->wr_coeff > 1) + bfqd->wr_busy_queues--; + + bfq_deactivate_bfqq(bfqd, bfqq, requeue); +} + +/* + * Called when an inactive queue receives a new request. + */ +static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq) +{ + BUG_ON(bfq_bfqq_busy(bfqq)); + BUG_ON(bfqq == bfqd->in_service_queue); + + bfq_log_bfqq(bfqd, bfqq, "add to busy"); + + bfq_activate_bfqq(bfqd, bfqq); + + bfq_mark_bfqq_busy(bfqq); + bfqd->busy_queues++; + + if (!bfqq->dispatched) { + if (bfqq->wr_coeff == 1) + bfq_weights_tree_add(bfqd, &bfqq->entity, + &bfqd->queue_weights_tree); + if (!blk_queue_nonrot(bfqd->queue)) { + bfqd->busy_in_flight_queues++; + if (bfq_bfqq_constantly_seeky(bfqq)) + bfqd->const_seeky_busy_in_flight_queues++; + } + } + if (bfqq->wr_coeff > 1) + bfqd->wr_busy_queues++; +} diff --git a/block/bfq.h b/block/bfq.h new file mode 100644 index 00000000..e6f1a88f --- /dev/null +++ b/block/bfq.h @@ -0,0 +1,806 @@ +/* + * BFQ-v7r8 for 3.4.0: data structures and common functions prototypes. + * + * Based on ideas and code from CFQ: + * Copyright (C) 2003 Jens Axboe + * + * Copyright (C) 2008 Fabio Checconi + * Paolo Valente + * + * Copyright (C) 2010 Paolo Valente + */ + +#ifndef _BFQ_H +#define _BFQ_H + +#include +#include +#include +#include + +#define BFQ_IOPRIO_CLASSES 3 +#define BFQ_CL_IDLE_TIMEOUT (HZ/5) + +#define BFQ_MIN_WEIGHT 1 +#define BFQ_MAX_WEIGHT 1000 + +#define BFQ_DEFAULT_QUEUE_IOPRIO 4 + +#define BFQ_DEFAULT_GRP_WEIGHT 10 +#define BFQ_DEFAULT_GRP_IOPRIO 0 +#define BFQ_DEFAULT_GRP_CLASS IOPRIO_CLASS_BE + +struct bfq_entity; + +/** + * struct bfq_service_tree - per ioprio_class service tree. + * @active: tree for active entities (i.e., those backlogged). + * @idle: tree for idle entities (i.e., those not backlogged, with V <= F_i). + * @first_idle: idle entity with minimum F_i. + * @last_idle: idle entity with maximum F_i. + * @vtime: scheduler virtual time. + * @wsum: scheduler weight sum; active and idle entities contribute to it. + * + * Each service tree represents a B-WF2Q+ scheduler on its own. Each + * ioprio_class has its own independent scheduler, and so its own + * bfq_service_tree. All the fields are protected by the queue lock + * of the containing bfqd. + */ +struct bfq_service_tree { + struct rb_root active; + struct rb_root idle; + + struct bfq_entity *first_idle; + struct bfq_entity *last_idle; + + u64 vtime; + unsigned long wsum; +}; + +/** + * struct bfq_sched_data - multi-class scheduler. + * @in_service_entity: entity in service. + * @next_in_service: head-of-the-line entity in the scheduler. + * @service_tree: array of service trees, one per ioprio_class. + * + * bfq_sched_data is the basic scheduler queue. It supports three + * ioprio_classes, and can be used either as a toplevel queue or as + * an intermediate queue on a hierarchical setup. + * @next_in_service points to the active entity of the sched_data + * service trees that will be scheduled next. + * + * The supported ioprio_classes are the same as in CFQ, in descending + * priority order, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE. + * Requests from higher priority queues are served before all the + * requests from lower priority queues; among requests of the same + * queue requests are served according to B-WF2Q+. + * All the fields are protected by the queue lock of the containing bfqd. + */ +struct bfq_sched_data { + struct bfq_entity *in_service_entity; + struct bfq_entity *next_in_service; + struct bfq_service_tree service_tree[BFQ_IOPRIO_CLASSES]; +}; + +/** + * struct bfq_weight_counter - counter of the number of all active entities + * with a given weight. + * @weight: weight of the entities that this counter refers to. + * @num_active: number of active entities with this weight. + * @weights_node: weights tree member (see bfq_data's @queue_weights_tree + * and @group_weights_tree). + */ +struct bfq_weight_counter { + short int weight; + unsigned int num_active; + struct rb_node weights_node; +}; + +/** + * struct bfq_entity - schedulable entity. + * @rb_node: service_tree member. + * @weight_counter: pointer to the weight counter associated with this entity. + * @on_st: flag, true if the entity is on a tree (either the active or + * the idle one of its service_tree). + * @finish: B-WF2Q+ finish timestamp (aka F_i). + * @start: B-WF2Q+ start timestamp (aka S_i). + * @tree: tree the entity is enqueued into; %NULL if not on a tree. + * @min_start: minimum start time of the (active) subtree rooted at + * this entity; used for O(log N) lookups into active trees. + * @service: service received during the last round of service. + * @budget: budget used to calculate F_i; F_i = S_i + @budget / @weight. + * @weight: weight of the queue + * @parent: parent entity, for hierarchical scheduling. + * @my_sched_data: for non-leaf nodes in the cgroup hierarchy, the + * associated scheduler queue, %NULL on leaf nodes. + * @sched_data: the scheduler queue this entity belongs to. + * @ioprio: the ioprio in use. + * @new_weight: when a weight change is requested, the new weight value. + * @orig_weight: original weight, used to implement weight boosting + * @new_ioprio: when an ioprio change is requested, the new ioprio value. + * @ioprio_class: the ioprio_class in use. + * @new_ioprio_class: when an ioprio_class change is requested, the new + * ioprio_class value. + * @ioprio_changed: flag, true when the user requested a weight, ioprio or + * ioprio_class change. + * + * A bfq_entity is used to represent either a bfq_queue (leaf node in the + * cgroup hierarchy) or a bfq_group into the upper level scheduler. Each + * entity belongs to the sched_data of the parent group in the cgroup + * hierarchy. Non-leaf entities have also their own sched_data, stored + * in @my_sched_data. + * + * Each entity stores independently its priority values; this would + * allow different weights on different devices, but this + * functionality is not exported to userspace by now. Priorities and + * weights are updated lazily, first storing the new values into the + * new_* fields, then setting the @ioprio_changed flag. As soon as + * there is a transition in the entity state that allows the priority + * update to take place the effective and the requested priority + * values are synchronized. + * + * Unless cgroups are used, the weight value is calculated from the + * ioprio to export the same interface as CFQ. When dealing with + * ``well-behaved'' queues (i.e., queues that do not spend too much + * time to consume their budget and have true sequential behavior, and + * when there are no external factors breaking anticipation) the + * relative weights at each level of the cgroups hierarchy should be + * guaranteed. All the fields are protected by the queue lock of the + * containing bfqd. + */ +struct bfq_entity { + struct rb_node rb_node; + struct bfq_weight_counter *weight_counter; + + int on_st; + + u64 finish; + u64 start; + + struct rb_root *tree; + + u64 min_start; + + unsigned long service, budget; + unsigned short weight, new_weight; + unsigned short orig_weight; + + struct bfq_entity *parent; + + struct bfq_sched_data *my_sched_data; + struct bfq_sched_data *sched_data; + + unsigned short ioprio, new_ioprio; + unsigned short ioprio_class, new_ioprio_class; + + int ioprio_changed; +}; + +struct bfq_group; + +/** + * struct bfq_queue - leaf schedulable entity. + * @ref: reference counter. + * @bfqd: parent bfq_data. + * @new_bfqq: shared bfq_queue if queue is cooperating with + * one or more other queues. + * @pos_node: request-position tree member (see bfq_data's @rq_pos_tree). + * @pos_root: request-position tree root (see bfq_data's @rq_pos_tree). + * @sort_list: sorted list of pending requests. + * @next_rq: if fifo isn't expired, next request to serve. + * @queued: nr of requests queued in @sort_list. + * @allocated: currently allocated requests. + * @meta_pending: pending metadata requests. + * @fifo: fifo list of requests in sort_list. + * @entity: entity representing this queue in the scheduler. + * @max_budget: maximum budget allowed from the feedback mechanism. + * @budget_timeout: budget expiration (in jiffies). + * @dispatched: number of requests on the dispatch list or inside driver. + * @flags: status flags. + * @bfqq_list: node for active/idle bfqq list inside our bfqd. + * @burst_list_node: node for the device's burst list. + * @seek_samples: number of seeks sampled + * @seek_total: sum of the distances of the seeks sampled + * @seek_mean: mean seek distance + * @last_request_pos: position of the last request enqueued + * @requests_within_timer: number of consecutive pairs of request completion + * and arrival, such that the queue becomes idle + * after the completion, but the next request arrives + * within an idle time slice; used only if the queue's + * IO_bound has been cleared. + * @pid: pid of the process owning the queue, used for logging purposes. + * @last_wr_start_finish: start time of the current weight-raising period if + * the @bfq-queue is being weight-raised, otherwise + * finish time of the last weight-raising period + * @wr_cur_max_time: current max raising time for this queue + * @soft_rt_next_start: minimum time instant such that, only if a new + * request is enqueued after this time instant in an + * idle @bfq_queue with no outstanding requests, then + * the task associated with the queue it is deemed as + * soft real-time (see the comments to the function + * bfq_bfqq_softrt_next_start()) + * @last_idle_bklogged: time of the last transition of the @bfq_queue from + * idle to backlogged + * @service_from_backlogged: cumulative service received from the @bfq_queue + * since the last transition from idle to + * backlogged + * @bic: pointer to the bfq_io_cq owning the bfq_queue, set to %NULL if the + * queue is shared + * + * A bfq_queue is a leaf request queue; it can be associated with an + * io_context or more, if it is async or shared between cooperating + * processes. @cgroup holds a reference to the cgroup, to be sure that it + * does not disappear while a bfqq still references it (mostly to avoid + * races between request issuing and task migration followed by cgroup + * destruction). + * All the fields are protected by the queue lock of the containing bfqd. + */ +struct bfq_queue { + atomic_t ref; + struct bfq_data *bfqd; + + /* fields for cooperating queues handling */ + struct bfq_queue *new_bfqq; + struct rb_node pos_node; + struct rb_root *pos_root; + + struct rb_root sort_list; + struct request *next_rq; + int queued[2]; + int allocated[2]; + int meta_pending; + struct list_head fifo; + + struct bfq_entity entity; + + unsigned long max_budget; + unsigned long budget_timeout; + + int dispatched; + + unsigned int flags; + + struct list_head bfqq_list; + + struct hlist_node burst_list_node; + + unsigned int seek_samples; + u64 seek_total; + sector_t seek_mean; + sector_t last_request_pos; + + unsigned int requests_within_timer; + + pid_t pid; + struct bfq_io_cq *bic; + + /* weight-raising fields */ + unsigned long wr_cur_max_time; + unsigned long soft_rt_next_start; + unsigned long last_wr_start_finish; + unsigned int wr_coeff; + unsigned long last_idle_bklogged; + unsigned long service_from_backlogged; +}; + +/** + * struct bfq_ttime - per process thinktime stats. + * @ttime_total: total process thinktime + * @ttime_samples: number of thinktime samples + * @ttime_mean: average process thinktime + */ +struct bfq_ttime { + unsigned long last_end_request; + + unsigned long ttime_total; + unsigned long ttime_samples; + unsigned long ttime_mean; +}; + +/** + * struct bfq_io_cq - per (request_queue, io_context) structure. + * @icq: associated io_cq structure + * @bfqq: array of two process queues, the sync and the async + * @ttime: associated @bfq_ttime struct + * @wr_time_left: snapshot of the time left before weight raising ends + * for the sync queue associated to this process; this + * snapshot is taken to remember this value while the weight + * raising is suspended because the queue is merged with a + * shared queue, and is used to set @raising_cur_max_time + * when the queue is split from the shared queue and its + * weight is raised again + * @saved_idle_window: same purpose as the previous field for the idle + * window + * @saved_IO_bound: same purpose as the previous two fields for the I/O + * bound classification of a queue + * @saved_in_large_burst: same purpose as the previous fields for the + * value of the field keeping the queue's belonging + * to a large burst + * @was_in_burst_list: true if the queue belonged to a burst list + * before its merge with another cooperating queue + * @cooperations: counter of consecutive successful queue merges underwent + * by any of the process' @bfq_queues + * @failed_cooperations: counter of consecutive failed queue merges of any + * of the process' @bfq_queues + */ +struct bfq_io_cq { + struct io_cq icq; /* must be the first member */ + struct bfq_queue *bfqq[2]; + struct bfq_ttime ttime; + int ioprio; + + unsigned int wr_time_left; + bool saved_idle_window; + bool saved_IO_bound; + + bool saved_in_large_burst; + bool was_in_burst_list; + + unsigned int cooperations; + unsigned int failed_cooperations; +}; + +enum bfq_device_speed { + BFQ_BFQD_FAST, + BFQ_BFQD_SLOW, +}; + +/** + * struct bfq_data - per device data structure. + * @queue: request queue for the managed device. + * @root_group: root bfq_group for the device. + * @rq_pos_tree: rbtree sorted by next_request position, used when + * determining if two or more queues have interleaving + * requests (see bfq_close_cooperator()). + * @active_numerous_groups: number of bfq_groups containing more than one + * active @bfq_entity. + * @queue_weights_tree: rbtree of weight counters of @bfq_queues, sorted by + * weight. Used to keep track of whether all @bfq_queues + * have the same weight. The tree contains one counter + * for each distinct weight associated to some active + * and not weight-raised @bfq_queue (see the comments to + * the functions bfq_weights_tree_[add|remove] for + * further details). + * @group_weights_tree: rbtree of non-queue @bfq_entity weight counters, sorted + * by weight. Used to keep track of whether all + * @bfq_groups have the same weight. The tree contains + * one counter for each distinct weight associated to + * some active @bfq_group (see the comments to the + * functions bfq_weights_tree_[add|remove] for further + * details). + * @busy_queues: number of bfq_queues containing requests (including the + * queue in service, even if it is idling). + * @busy_in_flight_queues: number of @bfq_queues containing pending or + * in-flight requests, plus the @bfq_queue in + * service, even if idle but waiting for the + * possible arrival of its next sync request. This + * field is updated only if the device is rotational, + * but used only if the device is also NCQ-capable. + * The reason why the field is updated also for non- + * NCQ-capable rotational devices is related to the + * fact that the value of @hw_tag may be set also + * later than when busy_in_flight_queues may need to + * be incremented for the first time(s). Taking also + * this possibility into account, to avoid unbalanced + * increments/decrements, would imply more overhead + * than just updating busy_in_flight_queues + * regardless of the value of @hw_tag. + * @const_seeky_busy_in_flight_queues: number of constantly-seeky @bfq_queues + * (that is, seeky queues that expired + * for budget timeout at least once) + * containing pending or in-flight + * requests, including the in-service + * @bfq_queue if constantly seeky. This + * field is updated only if the device + * is rotational, but used only if the + * device is also NCQ-capable (see the + * comments to @busy_in_flight_queues). + * @wr_busy_queues: number of weight-raised busy @bfq_queues. + * @queued: number of queued requests. + * @rq_in_driver: number of requests dispatched and waiting for completion. + * @sync_flight: number of sync requests in the driver. + * @max_rq_in_driver: max number of reqs in driver in the last + * @hw_tag_samples completed requests. + * @hw_tag_samples: nr of samples used to calculate hw_tag. + * @hw_tag: flag set to one if the driver is showing a queueing behavior. + * @budgets_assigned: number of budgets assigned. + * @idle_slice_timer: timer set when idling for the next sequential request + * from the queue in service. + * @unplug_work: delayed work to restart dispatching on the request queue. + * @in_service_queue: bfq_queue in service. + * @in_service_bic: bfq_io_cq (bic) associated with the @in_service_queue. + * @last_position: on-disk position of the last served request. + * @last_budget_start: beginning of the last budget. + * @last_idling_start: beginning of the last idle slice. + * @peak_rate: peak transfer rate observed for a budget. + * @peak_rate_samples: number of samples used to calculate @peak_rate. + * @bfq_max_budget: maximum budget allotted to a bfq_queue before + * rescheduling. + * @group_list: list of all the bfq_groups active on the device. + * @active_list: list of all the bfq_queues active on the device. + * @idle_list: list of all the bfq_queues idle on the device. + * @bfq_fifo_expire: timeout for async/sync requests; when it expires + * requests are served in fifo order. + * @bfq_back_penalty: weight of backward seeks wrt forward ones. + * @bfq_back_max: maximum allowed backward seek. + * @bfq_slice_idle: maximum idling time. + * @bfq_user_max_budget: user-configured max budget value + * (0 for auto-tuning). + * @bfq_max_budget_async_rq: maximum budget (in nr of requests) allotted to + * async queues. + * @bfq_timeout: timeout for bfq_queues to consume their budget; used to + * to prevent seeky queues to impose long latencies to well + * behaved ones (this also implies that seeky queues cannot + * receive guarantees in the service domain; after a timeout + * they are charged for the whole allocated budget, to try + * to preserve a behavior reasonably fair among them, but + * without service-domain guarantees). + * @bfq_coop_thresh: number of queue merges after which a @bfq_queue is + * no more granted any weight-raising. + * @bfq_failed_cooperations: number of consecutive failed cooperation + * chances after which weight-raising is restored + * to a queue subject to more than bfq_coop_thresh + * queue merges. + * @bfq_requests_within_timer: number of consecutive requests that must be + * issued within the idle time slice to set + * again idling to a queue which was marked as + * non-I/O-bound (see the definition of the + * IO_bound flag for further details). + * @last_ins_in_burst: last time at which a queue entered the current + * burst of queues being activated shortly after + * each other; for more details about this and the + * following parameters related to a burst of + * activations, see the comments to the function + * @bfq_handle_burst. + * @bfq_burst_interval: reference time interval used to decide whether a + * queue has been activated shortly after + * @last_ins_in_burst. + * @burst_size: number of queues in the current burst of queue activations. + * @bfq_large_burst_thresh: maximum burst size above which the current + * queue-activation burst is deemed as 'large'. + * @large_burst: true if a large queue-activation burst is in progress. + * @burst_list: head of the burst list (as for the above fields, more details + * in the comments to the function bfq_handle_burst). + * @low_latency: if set to true, low-latency heuristics are enabled. + * @bfq_wr_coeff: maximum factor by which the weight of a weight-raised + * queue is multiplied. + * @bfq_wr_max_time: maximum duration of a weight-raising period (jiffies). + * @bfq_wr_rt_max_time: maximum duration for soft real-time processes. + * @bfq_wr_min_idle_time: minimum idle period after which weight-raising + * may be reactivated for a queue (in jiffies). + * @bfq_wr_min_inter_arr_async: minimum period between request arrivals + * after which weight-raising may be + * reactivated for an already busy queue + * (in jiffies). + * @bfq_wr_max_softrt_rate: max service-rate for a soft real-time queue, + * sectors per seconds. + * @RT_prod: cached value of the product R*T used for computing the maximum + * duration of the weight raising automatically. + * @device_speed: device-speed class for the low-latency heuristic. + * @oom_bfqq: fallback dummy bfqq for extreme OOM conditions. + * + * All the fields are protected by the @queue lock. + */ +struct bfq_data { + struct request_queue *queue; + + struct bfq_group *root_group; + struct rb_root rq_pos_tree; + +#ifdef CONFIG_CGROUP_BFQIO + int active_numerous_groups; +#endif + + struct rb_root queue_weights_tree; + struct rb_root group_weights_tree; + + int busy_queues; + int busy_in_flight_queues; + int const_seeky_busy_in_flight_queues; + int wr_busy_queues; + int queued; + int rq_in_driver; + int sync_flight; + + int max_rq_in_driver; + int hw_tag_samples; + int hw_tag; + + int budgets_assigned; + + struct timer_list idle_slice_timer; + struct work_struct unplug_work; + + struct bfq_queue *in_service_queue; + struct bfq_io_cq *in_service_bic; + + sector_t last_position; + + ktime_t last_budget_start; + ktime_t last_idling_start; + int peak_rate_samples; + u64 peak_rate; + unsigned long bfq_max_budget; + + struct hlist_head group_list; + struct list_head active_list; + struct list_head idle_list; + + unsigned int bfq_fifo_expire[2]; + unsigned int bfq_back_penalty; + unsigned int bfq_back_max; + unsigned int bfq_slice_idle; + u64 bfq_class_idle_last_service; + + unsigned int bfq_user_max_budget; + unsigned int bfq_max_budget_async_rq; + unsigned int bfq_timeout[2]; + + unsigned int bfq_coop_thresh; + unsigned int bfq_failed_cooperations; + unsigned int bfq_requests_within_timer; + + unsigned long last_ins_in_burst; + unsigned long bfq_burst_interval; + int burst_size; + unsigned long bfq_large_burst_thresh; + bool large_burst; + struct hlist_head burst_list; + + bool low_latency; + + /* parameters of the low_latency heuristics */ + unsigned int bfq_wr_coeff; + unsigned int bfq_wr_max_time; + unsigned int bfq_wr_rt_max_time; + unsigned int bfq_wr_min_idle_time; + unsigned long bfq_wr_min_inter_arr_async; + unsigned int bfq_wr_max_softrt_rate; + u64 RT_prod; + enum bfq_device_speed device_speed; + + struct bfq_queue oom_bfqq; +}; + +enum bfqq_state_flags { + BFQ_BFQQ_FLAG_busy = 0, /* has requests or is in service */ + BFQ_BFQQ_FLAG_wait_request, /* waiting for a request */ + BFQ_BFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ + BFQ_BFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ + BFQ_BFQQ_FLAG_idle_window, /* slice idling enabled */ + BFQ_BFQQ_FLAG_sync, /* synchronous queue */ + BFQ_BFQQ_FLAG_budget_new, /* no completion with this budget */ + BFQ_BFQQ_FLAG_IO_bound, /* + * bfqq has timed-out at least once + * having consumed at most 2/10 of + * its budget + */ + BFQ_BFQQ_FLAG_in_large_burst, /* + * bfqq activated in a large burst, + * see comments to bfq_handle_burst. + */ + BFQ_BFQQ_FLAG_constantly_seeky, /* + * bfqq has proved to be slow and + * seeky until budget timeout + */ + BFQ_BFQQ_FLAG_softrt_update, /* + * may need softrt-next-start + * update + */ + BFQ_BFQQ_FLAG_coop, /* bfqq is shared */ + BFQ_BFQQ_FLAG_split_coop, /* shared bfqq will be split */ + BFQ_BFQQ_FLAG_just_split, /* queue has just been split */ +}; + +#define BFQ_BFQQ_FNS(name) \ +static inline void bfq_mark_bfqq_##name(struct bfq_queue *bfqq) \ +{ \ + (bfqq)->flags |= (1 << BFQ_BFQQ_FLAG_##name); \ +} \ +static inline void bfq_clear_bfqq_##name(struct bfq_queue *bfqq) \ +{ \ + (bfqq)->flags &= ~(1 << BFQ_BFQQ_FLAG_##name); \ +} \ +static inline int bfq_bfqq_##name(const struct bfq_queue *bfqq) \ +{ \ + return ((bfqq)->flags & (1 << BFQ_BFQQ_FLAG_##name)) != 0; \ +} + +BFQ_BFQQ_FNS(busy); +BFQ_BFQQ_FNS(wait_request); +BFQ_BFQQ_FNS(must_alloc); +BFQ_BFQQ_FNS(fifo_expire); +BFQ_BFQQ_FNS(idle_window); +BFQ_BFQQ_FNS(sync); +BFQ_BFQQ_FNS(budget_new); +BFQ_BFQQ_FNS(IO_bound); +BFQ_BFQQ_FNS(in_large_burst); +BFQ_BFQQ_FNS(constantly_seeky); +BFQ_BFQQ_FNS(coop); +BFQ_BFQQ_FNS(split_coop); +BFQ_BFQQ_FNS(just_split); +BFQ_BFQQ_FNS(softrt_update); +#undef BFQ_BFQQ_FNS + +/* Logging facilities. */ +#define bfq_log_bfqq(bfqd, bfqq, fmt, args...) \ + blk_add_trace_msg((bfqd)->queue, "bfq%d " fmt, (bfqq)->pid, ##args) + +#define bfq_log(bfqd, fmt, args...) \ + blk_add_trace_msg((bfqd)->queue, "bfq " fmt, ##args) + +/* Expiration reasons. */ +enum bfqq_expiration { + BFQ_BFQQ_TOO_IDLE = 0, /* + * queue has been idling for + * too long + */ + BFQ_BFQQ_BUDGET_TIMEOUT, /* budget took too long to be used */ + BFQ_BFQQ_BUDGET_EXHAUSTED, /* budget consumed */ + BFQ_BFQQ_NO_MORE_REQUESTS, /* the queue has no more requests */ +}; + +#ifdef CONFIG_CGROUP_BFQIO +/** + * struct bfq_group - per (device, cgroup) data structure. + * @entity: schedulable entity to insert into the parent group sched_data. + * @sched_data: own sched_data, to contain child entities (they may be + * both bfq_queues and bfq_groups). + * @group_node: node to be inserted into the bfqio_cgroup->group_data + * list of the containing cgroup's bfqio_cgroup. + * @bfqd_node: node to be inserted into the @bfqd->group_list list + * of the groups active on the same device; used for cleanup. + * @bfqd: the bfq_data for the device this group acts upon. + * @async_bfqq: array of async queues for all the tasks belonging to + * the group, one queue per ioprio value per ioprio_class, + * except for the idle class that has only one queue. + * @async_idle_bfqq: async queue for the idle class (ioprio is ignored). + * @my_entity: pointer to @entity, %NULL for the toplevel group; used + * to avoid too many special cases during group creation/ + * migration. + * @active_entities: number of active entities belonging to the group; + * unused for the root group. Used to know whether there + * are groups with more than one active @bfq_entity + * (see the comments to the function + * bfq_bfqq_must_not_expire()). + * + * Each (device, cgroup) pair has its own bfq_group, i.e., for each cgroup + * there is a set of bfq_groups, each one collecting the lower-level + * entities belonging to the group that are acting on the same device. + * + * Locking works as follows: + * o @group_node is protected by the bfqio_cgroup lock, and is accessed + * via RCU from its readers. + * o @bfqd is protected by the queue lock, RCU is used to access it + * from the readers. + * o All the other fields are protected by the @bfqd queue lock. + */ +struct bfq_group { + struct bfq_entity entity; + struct bfq_sched_data sched_data; + + struct hlist_node group_node; + struct hlist_node bfqd_node; + + void *bfqd; + + struct bfq_queue *async_bfqq[2][IOPRIO_BE_NR]; + struct bfq_queue *async_idle_bfqq; + + struct bfq_entity *my_entity; + + int active_entities; +}; + +/** + * struct bfqio_cgroup - bfq cgroup data structure. + * @css: subsystem state for bfq in the containing cgroup. + * @weight: cgroup weight. + * @ioprio: cgroup ioprio. + * @ioprio_class: cgroup ioprio_class. + * @lock: spinlock that protects @ioprio, @ioprio_class and @group_data. + * @group_data: list containing the bfq_group belonging to this cgroup. + * + * @group_data is accessed using RCU, with @lock protecting the updates, + * @ioprio and @ioprio_class are protected by @lock. + */ +struct bfqio_cgroup { + struct cgroup_subsys_state css; + + unsigned short weight, ioprio, ioprio_class; + + spinlock_t lock; + struct hlist_head group_data; +}; +#else +struct bfq_group { + struct bfq_sched_data sched_data; + + struct bfq_queue *async_bfqq[2][IOPRIO_BE_NR]; + struct bfq_queue *async_idle_bfqq; +}; +#endif + +static inline struct bfq_service_tree * +bfq_entity_service_tree(struct bfq_entity *entity) +{ + struct bfq_sched_data *sched_data = entity->sched_data; + unsigned int idx = entity->ioprio_class - 1; + + BUG_ON(idx >= BFQ_IOPRIO_CLASSES); + BUG_ON(sched_data == NULL); + + return sched_data->service_tree + idx; +} + +static inline struct bfq_queue *bic_to_bfqq(struct bfq_io_cq *bic, + bool is_sync) +{ + return bic->bfqq[is_sync]; +} + +static inline void bic_set_bfqq(struct bfq_io_cq *bic, + struct bfq_queue *bfqq, bool is_sync) +{ + bic->bfqq[is_sync] = bfqq; +} + +static inline struct bfq_data *bic_to_bfqd(struct bfq_io_cq *bic) +{ + return bic->icq.q->elevator->elevator_data; +} + +/** + * bfq_get_bfqd_locked - get a lock to a bfqd using a RCU protected pointer. + * @ptr: a pointer to a bfqd. + * @flags: storage for the flags to be saved. + * + * This function allows bfqg->bfqd to be protected by the + * queue lock of the bfqd they reference; the pointer is dereferenced + * under RCU, so the storage for bfqd is assured to be safe as long + * as the RCU read side critical section does not end. After the + * bfqd->queue->queue_lock is taken the pointer is rechecked, to be + * sure that no other writer accessed it. If we raced with a writer, + * the function returns NULL, with the queue unlocked, otherwise it + * returns the dereferenced pointer, with the queue locked. + */ +static inline struct bfq_data *bfq_get_bfqd_locked(void **ptr, + unsigned long *flags) +{ + struct bfq_data *bfqd; + + rcu_read_lock(); + bfqd = rcu_dereference(*(struct bfq_data **)ptr); + + if (bfqd != NULL) { + spin_lock_irqsave(bfqd->queue->queue_lock, *flags); + if (*ptr == bfqd) + goto out; + spin_unlock_irqrestore(bfqd->queue->queue_lock, *flags); + } + + bfqd = NULL; +out: + rcu_read_unlock(); + return bfqd; +} + +static inline void bfq_put_bfqd_unlock(struct bfq_data *bfqd, + unsigned long *flags) +{ + spin_unlock_irqrestore(bfqd->queue->queue_lock, *flags); +} + +static void bfq_check_ioprio_change(struct io_context *ioc, + struct bfq_io_cq *bic); +static void bfq_put_queue(struct bfq_queue *bfqq); +static void bfq_dispatch_insert(struct request_queue *q, struct request *rq); +static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd, + struct bfq_group *bfqg, int is_sync, + struct io_context *ioc, gfp_t gfp_mask); +static void bfq_end_wr_async_queues(struct bfq_data *bfqd, + struct bfq_group *bfqg); +static void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg); +static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq); + +#endif /* _BFQ_H */ diff --git a/block/fiops-iosched.c b/block/fiops-iosched.c index 671b1d33..9db7f936 100644 --- a/block/fiops-iosched.c +++ b/block/fiops-iosched.c @@ -10,19 +10,11 @@ #include #include #include -#include #include "blk.h" #define VIOS_SCALE_SHIFT 10 #define VIOS_SCALE (1 << VIOS_SCALE_SHIFT) -#define VIOS_READ_SCALE (1) -#define VIOS_WRITE_SCALE (1) -#define VIOS_SYNC_SCALE (2) -#define VIOS_ASYNC_SCALE (5) - -#define VIOS_PRIO_SCALE (5) - struct fiops_rb_root { struct rb_root rb; struct rb_node *left; @@ -32,27 +24,15 @@ struct fiops_rb_root { }; #define FIOPS_RB_ROOT (struct fiops_rb_root) { .rb = RB_ROOT} -enum wl_prio_t { - IDLE_WORKLOAD = 0, - BE_WORKLOAD = 1, - RT_WORKLOAD = 2, - FIOPS_PRIO_NR, -}; - struct fiops_data { struct request_queue *queue; - struct fiops_rb_root service_tree[FIOPS_PRIO_NR]; + struct fiops_rb_root service_tree; unsigned int busy_queues; unsigned int in_flight[2]; struct work_struct unplug_work; - - unsigned int read_scale; - unsigned int write_scale; - unsigned int sync_scale; - unsigned int async_scale; }; struct fiops_ioc { @@ -70,16 +50,13 @@ struct fiops_ioc { struct list_head fifo; pid_t pid; - unsigned short ioprio; - enum wl_prio_t wl_type; }; -#define ioc_service_tree(ioc) (&((ioc)->fiopsd->service_tree[(ioc)->wl_type])) +#define ioc_service_tree(ioc) (&((ioc)->fiopsd->service_tree)) #define RQ_CIC(rq) icq_to_cic((rq)->elv.icq) enum ioc_state_flags { FIOPS_IOC_FLAG_on_rr = 0, /* on round-robin busy list */ - FIOPS_IOC_FLAG_prio_changed, /* task priority has changed */ }; #define FIOPS_IOC_FNS(name) \ @@ -97,23 +74,8 @@ static inline int fiops_ioc_##name(const struct fiops_ioc *ioc) \ } FIOPS_IOC_FNS(on_rr); -FIOPS_IOC_FNS(prio_changed); #undef FIOPS_IOC_FNS -#define fiops_log_ioc(fiopsd, ioc, fmt, args...) \ - blk_add_trace_msg((fiopsd)->queue, "ioc%d " fmt, (ioc)->pid, ##args) -#define fiops_log(fiopsd, fmt, args...) \ - blk_add_trace_msg((fiopsd)->queue, "fiops " fmt, ##args) - -enum wl_prio_t fiops_wl_type(short prio_class) -{ - if (prio_class == IOPRIO_CLASS_RT) - return RT_WORKLOAD; - if (prio_class == IOPRIO_CLASS_BE) - return BE_WORKLOAD; - return IDLE_WORKLOAD; -} - static inline struct fiops_ioc *icq_to_cic(struct io_cq *icq) { /* cic->icq is the first member, %NULL will convert to %NULL */ @@ -194,20 +156,15 @@ static void fiops_service_tree_add(struct fiops_data *fiopsd, int left; /* New added IOC */ - if (RB_EMPTY_NODE(&ioc->rb_node)) { - if (ioc->in_flight > 0) - vios = ioc->vios; - else - vios = max_vios(service_tree->min_vios, ioc->vios); - } else { + if (RB_EMPTY_NODE(&ioc->rb_node)) + vios = max_vios(service_tree->min_vios, ioc->vios); + else { vios = ioc->vios; /* ioc->service_tree might not equal to service_tree */ fiops_rb_erase(&ioc->rb_node, ioc->service_tree); ioc->service_tree = NULL; } - fiops_log_ioc(fiopsd, ioc, "service tree add, vios %lld", vios); - left = 1; parent = NULL; ioc->service_tree = service_tree; @@ -323,17 +280,7 @@ static void fiops_remove_request(struct request *rq) static u64 fiops_scaled_vios(struct fiops_data *fiopsd, struct fiops_ioc *ioc, struct request *rq) { - int vios = VIOS_SCALE; - - if (rq_data_dir(rq) == WRITE) - vios = vios * fiopsd->write_scale / fiopsd->read_scale; - - if (!rq_is_sync(rq)) - vios = vios * fiopsd->async_scale / fiopsd->sync_scale; - - vios += vios * (ioc->ioprio - IOPRIO_NORM) / VIOS_PRIO_SCALE; - - return vios; + return VIOS_SCALE; } /* return vios dispatched */ @@ -358,19 +305,14 @@ static int fiops_forced_dispatch(struct fiops_data *fiopsd) { struct fiops_ioc *ioc; int dispatched = 0; - int i; - - for (i = RT_WORKLOAD; i >= IDLE_WORKLOAD; i--) { - while (!RB_EMPTY_ROOT(&fiopsd->service_tree[i].rb)) { - ioc = fiops_rb_first(&fiopsd->service_tree[i]); - - while (!list_empty(&ioc->fifo)) { - fiops_dispatch_request(fiopsd, ioc); - dispatched++; - } - if (fiops_ioc_on_rr(ioc)) - fiops_del_ioc_rr(fiopsd, ioc); + + while ((ioc = fiops_rb_first(&fiopsd->service_tree)) != NULL) { + while (!list_empty(&ioc->fifo)) { + fiops_dispatch_request(fiopsd, ioc); + dispatched++; } + if (fiops_ioc_on_rr(ioc)) + fiops_del_ioc_rr(fiopsd, ioc); } return dispatched; } @@ -378,36 +320,10 @@ static int fiops_forced_dispatch(struct fiops_data *fiopsd) static struct fiops_ioc *fiops_select_ioc(struct fiops_data *fiopsd) { struct fiops_ioc *ioc; - struct fiops_rb_root *service_tree = NULL; - int i; - struct request *rq; - - for (i = RT_WORKLOAD; i >= IDLE_WORKLOAD; i--) { - if (!RB_EMPTY_ROOT(&fiopsd->service_tree[i].rb)) { - service_tree = &fiopsd->service_tree[i]; - break; - } - } - - if (!service_tree) - return NULL; - - ioc = fiops_rb_first(service_tree); - rq = rq_entry_fifo(ioc->fifo.next); - /* - * we are the only async task and sync requests are in flight, delay a - * moment. If there are other tasks coming, sync tasks have no chance - * to be starved, don't delay - */ - if (!rq_is_sync(rq) && fiopsd->in_flight[1] != 0 && - service_tree->count == 1) { - fiops_log_ioc(fiopsd, ioc, - "postpone async, in_flight async %d sync %d", - fiopsd->in_flight[0], fiopsd->in_flight[1]); + if (RB_EMPTY_ROOT(&fiopsd->service_tree.rb)) return NULL; - } - + ioc = fiops_rb_first(&fiopsd->service_tree); return ioc; } @@ -417,8 +333,6 @@ static void fiops_charge_vios(struct fiops_data *fiopsd, struct fiops_rb_root *service_tree = ioc->service_tree; ioc->vios += vios; - fiops_log_ioc(fiopsd, ioc, "charge vios %lld, new vios %lld", vios, ioc->vios); - if (RB_EMPTY_ROOT(&ioc->sort_list)) fiops_del_ioc_rr(fiopsd, ioc); else @@ -446,49 +360,10 @@ static int fiops_dispatch_requests(struct request_queue *q, int force) return 1; } -static void fiops_init_prio_data(struct fiops_ioc *cic) -{ - struct task_struct *tsk = current; - struct io_context *ioc = cic->icq.ioc; - int ioprio_class; - - if (!fiops_ioc_prio_changed(cic)) - return; - - ioprio_class = IOPRIO_PRIO_CLASS(ioc->ioprio); - switch (ioprio_class) { - default: - printk(KERN_ERR "fiops: bad prio %x\n", ioprio_class); - case IOPRIO_CLASS_NONE: - /* - * no prio set, inherit CPU scheduling settings - */ - cic->ioprio = task_nice_ioprio(tsk); - cic->wl_type = fiops_wl_type(task_nice_ioclass(tsk)); - break; - case IOPRIO_CLASS_RT: - cic->ioprio = task_ioprio(ioc); - cic->wl_type = fiops_wl_type(IOPRIO_CLASS_RT); - break; - case IOPRIO_CLASS_BE: - cic->ioprio = task_ioprio(ioc); - cic->wl_type = fiops_wl_type(IOPRIO_CLASS_BE); - break; - case IOPRIO_CLASS_IDLE: - cic->wl_type = fiops_wl_type(IOPRIO_CLASS_IDLE); - cic->ioprio = 7; - break; - } - - fiops_clear_ioc_prio_changed(cic); -} - static void fiops_insert_request(struct request_queue *q, struct request *rq) { struct fiops_ioc *ioc = RQ_CIC(rq); - fiops_init_prio_data(ioc); - list_add_tail(&rq->queuelist, &ioc->fifo); fiops_add_rq_rb(rq); @@ -512,9 +387,6 @@ static void fiops_completed_request(struct request_queue *q, struct request *rq) fiopsd->in_flight[rq_is_sync(rq)]--; ioc->in_flight--; - fiops_log_ioc(fiopsd, ioc, "in_flight %d, busy queues %d", - ioc->in_flight, fiopsd->busy_queues); - if (fiopsd->in_flight[0] + fiopsd->in_flight[1] == 0) fiops_schedule_dispatch(fiopsd); } @@ -617,7 +489,6 @@ static void fiops_kick_queue(struct work_struct *work) static void *fiops_init_queue(struct request_queue *q) { struct fiops_data *fiopsd; - int i; fiopsd = kzalloc_node(sizeof(*fiopsd), GFP_KERNEL, q->node); if (!fiopsd) @@ -625,16 +496,10 @@ static void *fiops_init_queue(struct request_queue *q) fiopsd->queue = q; - for (i = IDLE_WORKLOAD; i <= RT_WORKLOAD; i++) - fiopsd->service_tree[i] = FIOPS_RB_ROOT; + fiopsd->service_tree = FIOPS_RB_ROOT; INIT_WORK(&fiopsd->unplug_work, fiops_kick_queue); - fiopsd->read_scale = VIOS_READ_SCALE; - fiopsd->write_scale = VIOS_WRITE_SCALE; - fiopsd->sync_scale = VIOS_SYNC_SCALE; - fiopsd->async_scale = VIOS_ASYNC_SCALE; - return fiopsd; } @@ -650,69 +515,8 @@ static void fiops_init_icq(struct io_cq *icq) ioc->fiopsd = fiopsd; ioc->pid = current->pid; - fiops_mark_ioc_prio_changed(ioc); } -/* - * sysfs parts below --> - */ -static ssize_t -fiops_var_show(unsigned int var, char *page) -{ - return sprintf(page, "%d\n", var); -} - -static ssize_t -fiops_var_store(unsigned int *var, const char *page, size_t count) -{ - char *p = (char *) page; - - *var = simple_strtoul(p, &p, 10); - return count; -} - -#define SHOW_FUNCTION(__FUNC, __VAR) \ -static ssize_t __FUNC(struct elevator_queue *e, char *page) \ -{ \ - struct fiops_data *fiopsd = e->elevator_data; \ - return fiops_var_show(__VAR, (page)); \ -} -SHOW_FUNCTION(fiops_read_scale_show, fiopsd->read_scale); -SHOW_FUNCTION(fiops_write_scale_show, fiopsd->write_scale); -SHOW_FUNCTION(fiops_sync_scale_show, fiopsd->sync_scale); -SHOW_FUNCTION(fiops_async_scale_show, fiopsd->async_scale); -#undef SHOW_FUNCTION - -#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ -static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ -{ \ - struct fiops_data *fiopsd = e->elevator_data; \ - unsigned int __data; \ - int ret = fiops_var_store(&__data, (page), count); \ - if (__data < (MIN)) \ - __data = (MIN); \ - else if (__data > (MAX)) \ - __data = (MAX); \ - *(__PTR) = __data; \ - return ret; \ -} -STORE_FUNCTION(fiops_read_scale_store, &fiopsd->read_scale, 1, 100); -STORE_FUNCTION(fiops_write_scale_store, &fiopsd->write_scale, 1, 100); -STORE_FUNCTION(fiops_sync_scale_store, &fiopsd->sync_scale, 1, 100); -STORE_FUNCTION(fiops_async_scale_store, &fiopsd->async_scale, 1, 100); -#undef STORE_FUNCTION - -#define FIOPS_ATTR(name) \ - __ATTR(name, S_IRUGO|S_IWUSR, fiops_##name##_show, fiops_##name##_store) - -static struct elv_fs_entry fiops_attrs[] = { - FIOPS_ATTR(read_scale), - FIOPS_ATTR(write_scale), - FIOPS_ATTR(sync_scale), - FIOPS_ATTR(async_scale), - __ATTR_NULL -}; - static struct elevator_type iosched_fiops = { .ops = { .elevator_merge_fn = fiops_merge, @@ -730,7 +534,6 @@ static struct elevator_type iosched_fiops = { }, .icq_size = sizeof(struct fiops_ioc), .icq_align = __alignof__(struct fiops_ioc), - .elevator_attrs = fiops_attrs, .elevator_name = "fiops", .elevator_owner = THIS_MODULE, }; diff --git a/block/row-iosched.c b/block/row-iosched.c new file mode 100644 index 00000000..b8c16e70 --- /dev/null +++ b/block/row-iosched.c @@ -0,0 +1,790 @@ +/* + * ROW (Read Over Write) I/O scheduler. + * + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* See Documentation/block/row-iosched.txt */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * enum row_queue_prio - Priorities of the ROW queues + * + * This enum defines the priorities (and the number of queues) + * the requests will be disptributed to. The higher priority - + * the bigger is the dispatch quantum given to that queue. + * ROWQ_PRIO_HIGH_READ - is the higher priority queue. + * + */ +enum row_queue_prio { + ROWQ_PRIO_HIGH_READ = 0, + ROWQ_PRIO_REG_READ, + ROWQ_PRIO_HIGH_SWRITE, + ROWQ_PRIO_REG_SWRITE, + ROWQ_PRIO_REG_WRITE, + ROWQ_PRIO_LOW_READ, + ROWQ_PRIO_LOW_SWRITE, + ROWQ_MAX_PRIO, +}; + +/** + * struct row_queue_params - ROW queue parameters + * @idling_enabled: Flag indicating whether idling is enable on + * the queue + * @quantum: Number of requests to be dispatched from this queue + * in a dispatch cycle + * @is_urgent: Flags indicating whether the queue can notify on + * urgent requests + * + */ +struct row_queue_params { + bool idling_enabled; + int quantum; + bool is_urgent; +}; + +/* + * This array holds the default values of the different configurables + * for each ROW queue. Each row of the array holds the following values: + * {idling_enabled, quantum, is_urgent} + * Each row corresponds to a queue with the same index (according to + * enum row_queue_prio) + */ +static const struct row_queue_params row_queues_def[] = { +/* idling_enabled, quantum, is_urgent */ + {true, 100, true}, /* ROWQ_PRIO_HIGH_READ */ + {true, 100, true}, /* ROWQ_PRIO_REG_READ */ + {false, 2, false}, /* ROWQ_PRIO_HIGH_SWRITE */ + {false, 1, false}, /* ROWQ_PRIO_REG_SWRITE */ + {false, 1, false}, /* ROWQ_PRIO_REG_WRITE */ + {false, 1, false}, /* ROWQ_PRIO_LOW_READ */ + {false, 1, false} /* ROWQ_PRIO_LOW_SWRITE */ +}; + +/* Default values for idling on read queues (in msec) */ +#define ROW_IDLE_TIME_MSEC 5 +#define ROW_READ_FREQ_MSEC 20 + +/** + * struct rowq_idling_data - parameters for idling on the queue + * @last_insert_time: time the last request was inserted + * to the queue + * @begin_idling: flag indicating wether we should idle + * + */ +struct rowq_idling_data { + ktime_t last_insert_time; + bool begin_idling; +}; + +/** + * struct row_queue - requests grouping structure + * @rdata: parent row_data structure + * @fifo: fifo of requests + * @prio: queue priority (enum row_queue_prio) + * @nr_dispatched: number of requests already dispatched in + * the current dispatch cycle + * @slice: number of requests to dispatch in a cycle + * @nr_req: number of requests in queue + * @dispatch quantum: number of requests this queue may + * dispatch in a dispatch cycle + * @idle_data: data for idling on queues + * + */ +struct row_queue { + struct row_data *rdata; + struct list_head fifo; + enum row_queue_prio prio; + + unsigned int nr_dispatched; + unsigned int slice; + + unsigned int nr_req; + int disp_quantum; + + /* used only for READ queues */ + struct rowq_idling_data idle_data; +}; + +/** + * struct idling_data - data for idling on empty rqueue + * @idle_time: idling duration (jiffies) + * @freq: min time between two requests that + * triger idling (msec) + * @idle_work: pointer to struct delayed_work + * + */ +struct idling_data { + unsigned long idle_time; + u32 freq; + + struct workqueue_struct *idle_workqueue; + struct delayed_work idle_work; +}; + +/** + * struct row_queue - Per block device rqueue structure + * @dispatch_queue: dispatch rqueue + * @row_queues: array of priority request queues + * @curr_queue: index in the row_queues array of the + * currently serviced rqueue + * @read_idle: data for idling after READ request + * @nr_reqs: nr_reqs[0] holds the number of all READ requests in + * scheduler, nr_reqs[1] holds the number of all WRITE + * requests in scheduler + * @cycle_flags: used for marking unserved queueus + * + */ +struct row_data { + struct request_queue *dispatch_queue; + + struct row_queue row_queues[ROWQ_MAX_PRIO]; + + enum row_queue_prio curr_queue; + + struct idling_data read_idle; + unsigned int nr_reqs[2]; + + unsigned int cycle_flags; +}; + +#define RQ_ROWQ(rq) ((struct row_queue *) ((rq)->elv.priv[0])) + +#define row_log(q, fmt, args...) \ + blk_add_trace_msg(q, "%s():" fmt , __func__, ##args) +#define row_log_rowq(rdata, rowq_id, fmt, args...) \ + blk_add_trace_msg(rdata->dispatch_queue, "rowq%d " fmt, \ + rowq_id, ##args) + +static inline void row_mark_rowq_unserved(struct row_data *rd, + enum row_queue_prio qnum) +{ + rd->cycle_flags |= (1 << qnum); +} + +static inline void row_clear_rowq_unserved(struct row_data *rd, + enum row_queue_prio qnum) +{ + rd->cycle_flags &= ~(1 << qnum); +} + +static inline int row_rowq_unserved(struct row_data *rd, + enum row_queue_prio qnum) +{ + return rd->cycle_flags & (1 << qnum); +} + +static inline void __maybe_unused row_dump_queues_stat(struct row_data *rd) +{ + int i; + + row_log(rd->dispatch_queue, " Queues status:"); + for (i = 0; i < ROWQ_MAX_PRIO; i++) + row_log(rd->dispatch_queue, + "queue%d: dispatched= %d, nr_req=%d", i, + rd->row_queues[i].nr_dispatched, + rd->row_queues[i].nr_req); +} + +/******************** Static helper functions ***********************/ +/* + * kick_queue() - Wake up device driver queue thread + * @work: pointer to struct work_struct + * + * This is a idling delayed work function. It's purpose is to wake up the + * device driver in order for it to start fetching requests. + * + */ +static void kick_queue(struct work_struct *work) +{ + struct delayed_work *idle_work = to_delayed_work(work); + struct idling_data *read_data = + container_of(idle_work, struct idling_data, idle_work); + struct row_data *rd = + container_of(read_data, struct row_data, read_idle); + + row_log_rowq(rd, rd->curr_queue, "Performing delayed work"); + /* Mark idling process as done */ + rd->row_queues[rd->curr_queue].idle_data.begin_idling = false; + + if (!(rd->nr_reqs[0] + rd->nr_reqs[1])) + row_log(rd->dispatch_queue, "No requests in scheduler"); + else { + spin_lock_irq(rd->dispatch_queue->queue_lock); + __blk_run_queue(rd->dispatch_queue); + spin_unlock_irq(rd->dispatch_queue->queue_lock); + } +} + +/* + * row_restart_disp_cycle() - Restart the dispatch cycle + * @rd: pointer to struct row_data + * + * This function restarts the dispatch cycle by: + * - Setting current queue to ROWQ_PRIO_HIGH_READ + * - For each queue: reset the number of requests dispatched in + * the cycle + */ +static inline void row_restart_disp_cycle(struct row_data *rd) +{ + int i; + + for (i = 0; i < ROWQ_MAX_PRIO; i++) + rd->row_queues[i].nr_dispatched = 0; + + rd->curr_queue = ROWQ_PRIO_HIGH_READ; + row_log(rd->dispatch_queue, "Restarting cycle"); +} + +static inline void row_get_next_queue(struct row_data *rd) +{ + rd->curr_queue++; + if (rd->curr_queue == ROWQ_MAX_PRIO) + row_restart_disp_cycle(rd); +} + +/******************* Elevator callback functions *********************/ + +/* + * row_add_request() - Add request to the scheduler + * @q: requests queue + * @rq: request to add + * + */ +static void row_add_request(struct request_queue *q, + struct request *rq) +{ + struct row_data *rd = (struct row_data *)q->elevator->elevator_data; + struct row_queue *rqueue = RQ_ROWQ(rq); + + list_add_tail(&rq->queuelist, &rqueue->fifo); + rd->nr_reqs[rq_data_dir(rq)]++; + rqueue->nr_req++; + rq_set_fifo_time(rq, jiffies); /* for statistics*/ + + if (row_queues_def[rqueue->prio].idling_enabled) { + if (delayed_work_pending(&rd->read_idle.idle_work)) + (void)cancel_delayed_work( + &rd->read_idle.idle_work); + if (ktime_to_ms(ktime_sub(ktime_get(), + rqueue->idle_data.last_insert_time)) < + rd->read_idle.freq) { + rqueue->idle_data.begin_idling = true; + row_log_rowq(rd, rqueue->prio, "Enable idling"); + } else { + rqueue->idle_data.begin_idling = false; + row_log_rowq(rd, rqueue->prio, "Disable idling"); + } + + rqueue->idle_data.last_insert_time = ktime_get(); + } + if (row_queues_def[rqueue->prio].is_urgent && + row_rowq_unserved(rd, rqueue->prio)) { + row_log_rowq(rd, rqueue->prio, + "added urgent request (total on queue=%d)", + rqueue->nr_req); + } else + row_log_rowq(rd, rqueue->prio, + "added request (total on queue=%d)", rqueue->nr_req); +} + +/** + * row_reinsert_req() - Reinsert request back to the scheduler + * @q: requests queue + * @rq: request to add + * + * Reinsert the given request back to the queue it was + * dispatched from as if it was never dispatched. + * + * Returns 0 on success, error code otherwise + */ +static int row_reinsert_req(struct request_queue *q, + struct request *rq) +{ + struct row_data *rd = q->elevator->elevator_data; + struct row_queue *rqueue = RQ_ROWQ(rq); + + /* Verify rqueue is legitimate */ + if (rqueue->prio >= ROWQ_MAX_PRIO) { + pr_err("\n\nROW BUG: row_reinsert_req() rqueue->prio = %d\n", + rqueue->prio); + blk_dump_rq_flags(rq, ""); + return -EIO; + } + + list_add(&rq->queuelist, &rqueue->fifo); + rd->nr_reqs[rq_data_dir(rq)]++; + rqueue->nr_req++; + + row_log_rowq(rd, rqueue->prio, + "request reinserted (total on queue=%d)", rqueue->nr_req); + + return 0; +} + +/** + * row_urgent_pending() - Return TRUE if there is an urgent + * request on scheduler + * @q: requests queue + */ +static bool row_urgent_pending(struct request_queue *q) +{ + struct row_data *rd = q->elevator->elevator_data; + int i; + + for (i = 0; i < ROWQ_MAX_PRIO; i++) + if (row_queues_def[i].is_urgent && row_rowq_unserved(rd, i) && + !list_empty(&rd->row_queues[i].fifo)) { + row_log_rowq(rd, i, + "Urgent request pending (curr=%i)", + rd->curr_queue); + return true; + } + + return false; +} + +/** + * row_remove_request() - Remove given request from scheduler + * @q: requests queue + * @rq: request to remove + * + */ +static void row_remove_request(struct request_queue *q, + struct request *rq) +{ + struct row_data *rd = (struct row_data *)q->elevator->elevator_data; + struct row_queue *rqueue = RQ_ROWQ(rq); + + rq_fifo_clear(rq); + rqueue->nr_req--; + rd->nr_reqs[rq_data_dir(rq)]--; +} + +/* + * row_dispatch_insert() - move request to dispatch queue + * @rd: pointer to struct row_data + * + * This function moves the next request to dispatch from + * rd->curr_queue to the dispatch queue + * + */ +static void row_dispatch_insert(struct row_data *rd) +{ + struct request *rq; + + rq = rq_entry_fifo(rd->row_queues[rd->curr_queue].fifo.next); + row_remove_request(rd->dispatch_queue, rq); + elv_dispatch_add_tail(rd->dispatch_queue, rq); + rd->row_queues[rd->curr_queue].nr_dispatched++; + row_clear_rowq_unserved(rd, rd->curr_queue); + row_log_rowq(rd, rd->curr_queue, " Dispatched request nr_disp = %d", + rd->row_queues[rd->curr_queue].nr_dispatched); +} + +/* + * row_choose_queue() - choose the next queue to dispatch from + * @rd: pointer to struct row_data + * + * Updates rd->curr_queue. Returns 1 if there are requests to + * dispatch, 0 if there are no requests in scheduler + * + */ +static int row_choose_queue(struct row_data *rd) +{ + int prev_curr_queue = rd->curr_queue; + + if (!(rd->nr_reqs[0] + rd->nr_reqs[1])) { + row_log(rd->dispatch_queue, "No more requests in scheduler"); + return 0; + } + + row_get_next_queue(rd); + + /* + * Loop over all queues to find the next queue that is not empty. + * Stop when you get back to curr_queue + */ + while (list_empty(&rd->row_queues[rd->curr_queue].fifo) + && rd->curr_queue != prev_curr_queue) { + /* Mark rqueue as unserved */ + row_mark_rowq_unserved(rd, rd->curr_queue); + row_get_next_queue(rd); + } + + return 1; +} + +/* + * row_dispatch_requests() - selects the next request to dispatch + * @q: requests queue + * @force: ignored + * + * Return 0 if no requests were moved to the dispatch queue. + * 1 otherwise + * + */ +static int row_dispatch_requests(struct request_queue *q, int force) +{ + struct row_data *rd = (struct row_data *)q->elevator->elevator_data; + int ret = 0, currq, i; + + currq = rd->curr_queue; + + /* + * Find the first unserved queue (with higher priority then currq) + * that is not empty + */ + for (i = 0; i < currq; i++) { + if (row_rowq_unserved(rd, i) && + !list_empty(&rd->row_queues[i].fifo)) { + row_log_rowq(rd, currq, + " Preemting for unserved rowq%d. (nr_req=%u)", + i, rd->row_queues[currq].nr_req); + rd->curr_queue = i; + row_dispatch_insert(rd); + ret = 1; + goto done; + } + } + + if (rd->row_queues[currq].nr_dispatched >= + rd->row_queues[currq].disp_quantum) { + rd->row_queues[currq].nr_dispatched = 0; + row_log_rowq(rd, currq, "Expiring rqueue"); + ret = row_choose_queue(rd); + if (ret) + row_dispatch_insert(rd); + goto done; + } + + /* Dispatch from curr_queue */ + if (list_empty(&rd->row_queues[currq].fifo)) { + /* check idling */ + if (delayed_work_pending(&rd->read_idle.idle_work)) { + if (force) { + (void)cancel_delayed_work( + &rd->read_idle.idle_work); + row_log_rowq(rd, currq, + "Canceled delayed work - forced dispatch"); + } else { + row_log_rowq(rd, currq, + "Delayed work pending. Exiting"); + goto done; + } + } + + if (!force && row_queues_def[currq].idling_enabled && + rd->row_queues[currq].idle_data.begin_idling) { + if (!queue_delayed_work(rd->read_idle.idle_workqueue, + &rd->read_idle.idle_work, + rd->read_idle.idle_time)) { + row_log_rowq(rd, currq, + "Work already on queue!"); + pr_err("ROW_BUG: Work already on queue!"); + } else + row_log_rowq(rd, currq, + "Scheduled delayed work. exiting"); + goto done; + } else { + row_log_rowq(rd, currq, + "Currq empty. Choose next queue"); + ret = row_choose_queue(rd); + if (!ret) + goto done; + } + } + + ret = 1; + row_dispatch_insert(rd); + +done: + return ret; +} + +/* + * row_init_queue() - Init scheduler data structures + * @q: requests queue + * + * Return pointer to struct row_data to be saved in elevator for + * this dispatch queue + * + */ +static void *row_init_queue(struct request_queue *q) +{ + + struct row_data *rdata; + int i; + + rdata = kmalloc_node(sizeof(*rdata), + GFP_KERNEL | __GFP_ZERO, q->node); + if (!rdata) + return NULL; + + for (i = 0; i < ROWQ_MAX_PRIO; i++) { + INIT_LIST_HEAD(&rdata->row_queues[i].fifo); + rdata->row_queues[i].disp_quantum = row_queues_def[i].quantum; + rdata->row_queues[i].rdata = rdata; + rdata->row_queues[i].prio = i; + rdata->row_queues[i].idle_data.begin_idling = false; + rdata->row_queues[i].idle_data.last_insert_time = + ktime_set(0, 0); + } + + /* + * Currently idling is enabled only for READ queues. If we want to + * enable it for write queues also, note that idling frequency will + * be the same in both cases + */ + rdata->read_idle.idle_time = msecs_to_jiffies(ROW_IDLE_TIME_MSEC); + /* Maybe 0 on some platforms */ + if (!rdata->read_idle.idle_time) + rdata->read_idle.idle_time = 1; + rdata->read_idle.freq = ROW_READ_FREQ_MSEC; + rdata->read_idle.idle_workqueue = alloc_workqueue("row_idle_work", + WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (!rdata->read_idle.idle_workqueue) + panic("Failed to create idle workqueue\n"); + INIT_DELAYED_WORK(&rdata->read_idle.idle_work, kick_queue); + + rdata->curr_queue = ROWQ_PRIO_HIGH_READ; + rdata->dispatch_queue = q; + + rdata->nr_reqs[READ] = rdata->nr_reqs[WRITE] = 0; + + return rdata; +} + +/* + * row_exit_queue() - called on unloading the RAW scheduler + * @e: poiner to struct elevator_queue + * + */ +static void row_exit_queue(struct elevator_queue *e) +{ + struct row_data *rd = (struct row_data *)e->elevator_data; + int i; + + for (i = 0; i < ROWQ_MAX_PRIO; i++) + BUG_ON(!list_empty(&rd->row_queues[i].fifo)); + (void)cancel_delayed_work_sync(&rd->read_idle.idle_work); + BUG_ON(delayed_work_pending(&rd->read_idle.idle_work)); + destroy_workqueue(rd->read_idle.idle_workqueue); + kfree(rd); +} + +/* + * row_merged_requests() - Called when 2 requests are merged + * @q: requests queue + * @rq: request the two requests were merged into + * @next: request that was merged + */ +static void row_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + struct row_queue *rqueue = RQ_ROWQ(next); + + list_del_init(&next->queuelist); + rqueue->nr_req--; + + rqueue->rdata->nr_reqs[rq_data_dir(rq)]--; +} + +/* + * get_queue_type() - Get queue type for a given request + * + * This is a helping function which purpose is to determine what + * ROW queue the given request should be added to (and + * dispatched from leter on) + * + * TODO: Right now only 3 queues are used REG_READ, REG_WRITE + * and REG_SWRITE + */ +static enum row_queue_prio get_queue_type(struct request *rq) +{ + const int data_dir = rq_data_dir(rq); + const bool is_sync = rq_is_sync(rq); + + if (data_dir == READ) + return ROWQ_PRIO_REG_READ; + else if (is_sync) + return ROWQ_PRIO_REG_SWRITE; + else + return ROWQ_PRIO_REG_WRITE; +} + +/* + * row_set_request() - Set ROW data structures associated with this request. + * @q: requests queue + * @rq: pointer to the request + * @gfp_mask: ignored + * + */ +static int +row_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) +{ + struct row_data *rd = (struct row_data *)q->elevator->elevator_data; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + rq->elv.priv[0] = + (void *)(&rd->row_queues[get_queue_type(rq)]); + spin_unlock_irqrestore(q->queue_lock, flags); + + return 0; +} + +/********** Helping sysfs functions/defenitions for ROW attributes ******/ +static ssize_t row_var_show(int var, char *page) +{ + return snprintf(page, 100, "%d\n", var); +} + +static ssize_t row_var_store(int *var, const char *page, size_t count) +{ + int err; + err = kstrtoul(page, 10, (unsigned long *)var); + + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ + struct row_data *rowd = e->elevator_data; \ + int __data = __VAR; \ + if (__CONV) \ + __data = jiffies_to_msecs(__data); \ + return row_var_show(__data, (page)); \ +} +SHOW_FUNCTION(row_hp_read_quantum_show, + rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0); +SHOW_FUNCTION(row_rp_read_quantum_show, + rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0); +SHOW_FUNCTION(row_hp_swrite_quantum_show, + rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0); +SHOW_FUNCTION(row_rp_swrite_quantum_show, + rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0); +SHOW_FUNCTION(row_rp_write_quantum_show, + rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0); +SHOW_FUNCTION(row_lp_read_quantum_show, + rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0); +SHOW_FUNCTION(row_lp_swrite_quantum_show, + rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0); +SHOW_FUNCTION(row_read_idle_show, rowd->read_idle.idle_time, 0); +SHOW_FUNCTION(row_read_idle_freq_show, rowd->read_idle.freq, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, \ + const char *page, size_t count) \ +{ \ + struct row_data *rowd = e->elevator_data; \ + int __data; \ + int ret = row_var_store(&__data, (page), count); \ + if (__CONV) \ + __data = (int)msecs_to_jiffies(__data); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(row_hp_read_quantum_store, +&rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 1, INT_MAX, 0); +STORE_FUNCTION(row_rp_read_quantum_store, + &rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, + 1, INT_MAX, 0); +STORE_FUNCTION(row_hp_swrite_quantum_store, + &rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, + 1, INT_MAX, 0); +STORE_FUNCTION(row_rp_swrite_quantum_store, + &rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, + 1, INT_MAX, 0); +STORE_FUNCTION(row_rp_write_quantum_store, + &rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, + 1, INT_MAX, 0); +STORE_FUNCTION(row_lp_read_quantum_store, + &rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, + 1, INT_MAX, 0); +STORE_FUNCTION(row_lp_swrite_quantum_store, + &rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, + 1, INT_MAX, 1); +STORE_FUNCTION(row_read_idle_store, &rowd->read_idle.idle_time, 1, INT_MAX, 0); +STORE_FUNCTION(row_read_idle_freq_store, &rowd->read_idle.freq, 1, INT_MAX, 0); + +#undef STORE_FUNCTION + +#define ROW_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, row_##name##_show, \ + row_##name##_store) + +static struct elv_fs_entry row_attrs[] = { + ROW_ATTR(hp_read_quantum), + ROW_ATTR(rp_read_quantum), + ROW_ATTR(hp_swrite_quantum), + ROW_ATTR(rp_swrite_quantum), + ROW_ATTR(rp_write_quantum), + ROW_ATTR(lp_read_quantum), + ROW_ATTR(lp_swrite_quantum), + ROW_ATTR(read_idle), + ROW_ATTR(read_idle_freq), + __ATTR_NULL +}; + +static struct elevator_type iosched_row = { + .ops = { + .elevator_merge_req_fn = row_merged_requests, + .elevator_dispatch_fn = row_dispatch_requests, + .elevator_add_req_fn = row_add_request, + .elevator_reinsert_req_fn = row_reinsert_req, + .elevator_is_urgent_fn = row_urgent_pending, + .elevator_former_req_fn = elv_rb_former_request, + .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_set_req_fn = row_set_request, + .elevator_init_fn = row_init_queue, + .elevator_exit_fn = row_exit_queue, + }, + + .elevator_attrs = row_attrs, + .elevator_name = "row", + .elevator_owner = THIS_MODULE, +}; + +static int __init row_init(void) +{ + elv_register(&iosched_row); + return 0; +} + +static void __exit row_exit(void) +{ + elv_unregister(&iosched_row); +} + +module_init(row_init); +module_exit(row_exit); + +MODULE_LICENSE("GPLv2"); +MODULE_DESCRIPTION("Read Over Write IO scheduler"); diff --git a/block/sio-iosched.c b/block/sio-iosched.c new file mode 100755 index 00000000..8861872b --- /dev/null +++ b/block/sio-iosched.c @@ -0,0 +1,399 @@ +/* + * Simple IO scheduler + * Based on Noop, Deadline and V(R) IO schedulers. + * + * Copyright (C) 2012 Miguel Boton + * + * + * This algorithm does not do any kind of sorting, as it is aimed for + * aleatory access devices, but it does some basic merging. We try to + * keep minimum overhead to achieve low latency. + * + * Asynchronous and synchronous requests are not treated separately, but + * we relay on deadlines to ensure fairness. + * + */ +#include +#include +#include +#include +#include +#include + +enum { ASYNC, SYNC }; + +/* Tunables */ +static const int sync_read_expire = HZ / 2; /* max time before a sync read is submitted. */ +static const int sync_write_expire = 2 * HZ; /* max time before a sync write is submitted. */ + +static const int async_read_expire = 4 * HZ; /* ditto for async, these limits are SOFT! */ +static const int async_write_expire = 16 * HZ; /* ditto for async, these limits are SOFT! */ + +static const int writes_starved = 1; /* max times reads can starve a write */ +static const int fifo_batch = 1; /* # of sequential requests treated as one + by the above parameters. For throughput. */ + +/* Elevator data */ +struct sio_data { + /* Request queues */ + struct list_head fifo_list[2][2]; + + /* Attributes */ + unsigned int batched; + unsigned int starved; + + /* Settings */ + int fifo_expire[2][2]; + int fifo_batch; + int writes_starved; +}; + +static void +sio_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + /* + * If next expires before rq, assign its expire time to rq + * and move into next position (next will be deleted) in fifo. + */ + if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) { + if (time_before(rq_fifo_time(next), rq_fifo_time(rq))) { + list_move(&rq->queuelist, &next->queuelist); + rq_set_fifo_time(rq, rq_fifo_time(next)); + } + } + + /* Delete next request */ + rq_fifo_clear(next); +} + +static void +sio_add_request(struct request_queue *q, struct request *rq) +{ + struct sio_data *sd = q->elevator->elevator_data; + const int sync = rq_is_sync(rq); + const int data_dir = rq_data_dir(rq); + + /* + * Add request to the proper fifo list and set its + * expire time. + */ + rq_set_fifo_time(rq, jiffies + sd->fifo_expire[sync][data_dir]); + list_add_tail(&rq->queuelist, &sd->fifo_list[sync][data_dir]); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) +static int +sio_queue_empty(struct request_queue *q) +{ + struct sio_data *sd = q->elevator->elevator_data; + + /* Check if fifo lists are empty */ + return list_empty(&sd->fifo_list[SYNC][READ]) && list_empty(&sd->fifo_list[SYNC][WRITE]) && + list_empty(&sd->fifo_list[ASYNC][READ]) && list_empty(&sd->fifo_list[ASYNC][WRITE]); +} +#endif + +static struct request * +sio_expired_request(struct sio_data *sd, int sync, int data_dir) +{ + struct list_head *list = &sd->fifo_list[sync][data_dir]; + struct request *rq; + + if (list_empty(list)) + return NULL; + + /* Retrieve request */ + rq = rq_entry_fifo(list->next); + + /* Request has expired */ + if (time_after(jiffies, rq_fifo_time(rq))) + return rq; + + return NULL; +} + +static struct request * +sio_choose_expired_request(struct sio_data *sd) +{ + struct request *rq; + + /* + * Check expired requests. + * Asynchronous requests have priority over synchronous. + * Write requests have priority over read. + */ + rq = sio_expired_request(sd, ASYNC, WRITE); + if (rq) + return rq; + rq = sio_expired_request(sd, ASYNC, READ); + if (rq) + return rq; + + rq = sio_expired_request(sd, SYNC, WRITE); + if (rq) + return rq; + rq = sio_expired_request(sd, SYNC, READ); + if (rq) + return rq; + + return NULL; +} + +static struct request * +sio_choose_request(struct sio_data *sd, int data_dir) +{ + struct list_head *sync = sd->fifo_list[SYNC]; + struct list_head *async = sd->fifo_list[ASYNC]; + + /* + * Retrieve request from available fifo list. + * Synchronous requests have priority over asynchronous. + * Read requests have priority over write. + */ + if (!list_empty(&sync[data_dir])) + return rq_entry_fifo(sync[data_dir].next); + if (!list_empty(&async[data_dir])) + return rq_entry_fifo(async[data_dir].next); + + if (!list_empty(&sync[!data_dir])) + return rq_entry_fifo(sync[!data_dir].next); + if (!list_empty(&async[!data_dir])) + return rq_entry_fifo(async[!data_dir].next); + + return NULL; +} + +static inline void +sio_dispatch_request(struct sio_data *sd, struct request *rq) +{ + /* + * Remove the request from the fifo list + * and dispatch it. + */ + rq_fifo_clear(rq); + elv_dispatch_add_tail(rq->q, rq); + + sd->batched++; + + if (rq_data_dir(rq)) + sd->starved = 0; + else + sd->starved++; +} + +static int +sio_dispatch_requests(struct request_queue *q, int force) +{ + struct sio_data *sd = q->elevator->elevator_data; + struct request *rq = NULL; + int data_dir = READ; + + /* + * Retrieve any expired request after a batch of + * sequential requests. + */ + if (sd->batched > sd->fifo_batch) { + sd->batched = 0; + rq = sio_choose_expired_request(sd); + } + + /* Retrieve request */ + if (!rq) { + if (sd->starved > sd->writes_starved) + data_dir = WRITE; + + rq = sio_choose_request(sd, data_dir); + if (!rq) + return 0; + } + + /* Dispatch request */ + sio_dispatch_request(sd, rq); + + return 1; +} + +static struct request * +sio_former_request(struct request_queue *q, struct request *rq) +{ + struct sio_data *sd = q->elevator->elevator_data; + const int sync = rq_is_sync(rq); + const int data_dir = rq_data_dir(rq); + + if (rq->queuelist.prev == &sd->fifo_list[sync][data_dir]) + return NULL; + + /* Return former request */ + return list_entry(rq->queuelist.prev, struct request, queuelist); +} + +static struct request * +sio_latter_request(struct request_queue *q, struct request *rq) +{ + struct sio_data *sd = q->elevator->elevator_data; + const int sync = rq_is_sync(rq); + const int data_dir = rq_data_dir(rq); + + if (rq->queuelist.next == &sd->fifo_list[sync][data_dir]) + return NULL; + + /* Return latter request */ + return list_entry(rq->queuelist.next, struct request, queuelist); +} + +static void * +sio_init_queue(struct request_queue *q) +{ + struct sio_data *sd; + + /* Allocate structure */ + sd = kmalloc_node(sizeof(*sd), GFP_KERNEL, q->node); + if (!sd) + return NULL; + + /* Initialize fifo lists */ + INIT_LIST_HEAD(&sd->fifo_list[SYNC][READ]); + INIT_LIST_HEAD(&sd->fifo_list[SYNC][WRITE]); + INIT_LIST_HEAD(&sd->fifo_list[ASYNC][READ]); + INIT_LIST_HEAD(&sd->fifo_list[ASYNC][WRITE]); + + /* Initialize data */ + sd->batched = 0; + sd->fifo_expire[SYNC][READ] = sync_read_expire; + sd->fifo_expire[SYNC][WRITE] = sync_write_expire; + sd->fifo_expire[ASYNC][READ] = async_read_expire; + sd->fifo_expire[ASYNC][WRITE] = async_write_expire; + sd->fifo_batch = fifo_batch; + + return sd; +} + +static void +sio_exit_queue(struct elevator_queue *e) +{ + struct sio_data *sd = e->elevator_data; + + BUG_ON(!list_empty(&sd->fifo_list[SYNC][READ])); + BUG_ON(!list_empty(&sd->fifo_list[SYNC][WRITE])); + BUG_ON(!list_empty(&sd->fifo_list[ASYNC][READ])); + BUG_ON(!list_empty(&sd->fifo_list[ASYNC][WRITE])); + + /* Free structure */ + kfree(sd); +} + +/* + * sysfs code + */ + +static ssize_t +sio_var_show(int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t +sio_var_store(int *var, const char *page, size_t count) +{ + char *p = (char *) page; + + *var = simple_strtol(p, &p, 10); + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ + struct sio_data *sd = e->elevator_data; \ + int __data = __VAR; \ + if (__CONV) \ + __data = jiffies_to_msecs(__data); \ + return sio_var_show(__data, (page)); \ +} +SHOW_FUNCTION(sio_sync_read_expire_show, sd->fifo_expire[SYNC][READ], 1); +SHOW_FUNCTION(sio_sync_write_expire_show, sd->fifo_expire[SYNC][WRITE], 1); +SHOW_FUNCTION(sio_async_read_expire_show, sd->fifo_expire[ASYNC][READ], 1); +SHOW_FUNCTION(sio_async_write_expire_show, sd->fifo_expire[ASYNC][WRITE], 1); +SHOW_FUNCTION(sio_fifo_batch_show, sd->fifo_batch, 0); +SHOW_FUNCTION(sio_writes_starved_show, sd->writes_starved, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ + struct sio_data *sd = e->elevator_data; \ + int __data; \ + int ret = sio_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + if (__CONV) \ + *(__PTR) = msecs_to_jiffies(__data); \ + else \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(sio_sync_read_expire_store, &sd->fifo_expire[SYNC][READ], 0, INT_MAX, 1); +STORE_FUNCTION(sio_sync_write_expire_store, &sd->fifo_expire[SYNC][WRITE], 0, INT_MAX, 1); +STORE_FUNCTION(sio_async_read_expire_store, &sd->fifo_expire[ASYNC][READ], 0, INT_MAX, 1); +STORE_FUNCTION(sio_async_write_expire_store, &sd->fifo_expire[ASYNC][WRITE], 0, INT_MAX, 1); +STORE_FUNCTION(sio_fifo_batch_store, &sd->fifo_batch, 0, INT_MAX, 0); +STORE_FUNCTION(sio_writes_starved_store, &sd->writes_starved, 0, INT_MAX, 0); +#undef STORE_FUNCTION + +#define DD_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, sio_##name##_show, \ + sio_##name##_store) + +static struct elv_fs_entry sio_attrs[] = { + DD_ATTR(sync_read_expire), + DD_ATTR(sync_write_expire), + DD_ATTR(async_read_expire), + DD_ATTR(async_write_expire), + DD_ATTR(fifo_batch), + DD_ATTR(writes_starved), + __ATTR_NULL +}; + +static struct elevator_type iosched_sio = { + .ops = { + .elevator_merge_req_fn = sio_merged_requests, + .elevator_dispatch_fn = sio_dispatch_requests, + .elevator_add_req_fn = sio_add_request, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) + .elevator_queue_empty_fn = sio_queue_empty, +#endif + .elevator_former_req_fn = sio_former_request, + .elevator_latter_req_fn = sio_latter_request, + .elevator_init_fn = sio_init_queue, + .elevator_exit_fn = sio_exit_queue, + }, + + .elevator_attrs = sio_attrs, + .elevator_name = "sio", + .elevator_owner = THIS_MODULE, +}; + +static int __init sio_init(void) +{ + /* Register elevator */ + elv_register(&iosched_sio); + + return 0; +} + +static void __exit sio_exit(void) +{ + /* Unregister elevator */ + elv_unregister(&iosched_sio); +} + +module_init(sio_init); +module_exit(sio_exit); + +MODULE_AUTHOR("Miguel Boton"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simple IO scheduler"); +MODULE_VERSION("0.2"); diff --git a/block/sioplus-iosched.c b/block/sioplus-iosched.c new file mode 100644 index 00000000..7e54137a --- /dev/null +++ b/block/sioplus-iosched.c @@ -0,0 +1,409 @@ +/* +* Simple IO scheduler plus +* Based on Noop, Deadline and V(R) IO schedulers. +* +* Copyright (C) 2012 Miguel Boton +* (C) 2013 Boy Petersen +* +* +* This algorithm does not do any kind of sorting, as it is aimed for +* aleatory access devices, but it does some basic merging. We try to +* keep minimum overhead to achieve low latency. +* +* Asynchronous and synchronous requests are not treated separately, but +* we relay on deadlines to ensure fairness. +* +* The plus version fixes writes_starved not being initialized on startup +* and also modifies the write starvation counting logic. +* +*/ +#include +#include +#include +#include +#include +#include +#include + +enum { ASYNC, SYNC }; + +/* Tunables */ +static const int sync_read_expire = (HZ / 16) * 5; /* max time before a sync read is submitted. */ +static const int sync_write_expire = (HZ / 2) * 5; /* max time before a sync write is submitted. */ + +static const int async_read_expire = HZ * 4; /* ditto for async, these limits are SOFT! */ +static const int async_write_expire = HZ * 16; /* ditto for async, these limits are SOFT! */ + +static const int writes_starved = 2; /* max times reads can starve a write */ +static const int fifo_batch = 1; /* # of sequential requests treated as one +by the above parameters. For throughput. */ + +/* Elevator data */ +struct sio_data { +/* Request queues */ +struct list_head fifo_list[2][2]; + +/* Attributes */ +unsigned int batched; +unsigned int starved; + +/* Settings */ +int fifo_expire[2][2]; +int fifo_batch; +int writes_starved; +}; + +static void +sio_merged_requests(struct request_queue *q, struct request *rq, +struct request *next) +{ +/* +* If next expires before rq, assign its expire time to rq +* and move into next position (next will be deleted) in fifo. +*/ +if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) { +if (time_before(rq_fifo_time(next), rq_fifo_time(rq))) { +list_move(&rq->queuelist, &next->queuelist); +rq_set_fifo_time(rq, rq_fifo_time(next)); +} +} + +/* Delete next request */ +rq_fifo_clear(next); +} + +static void +sio_add_request(struct request_queue *q, struct request *rq) +{ +struct sio_data *sd = q->elevator->elevator_data; +const int sync = rq_is_sync(rq); +const int data_dir = rq_data_dir(rq); + +/* +* Add request to the proper fifo list and set its +* expire time. +*/ +rq_set_fifo_time(rq, jiffies + sd->fifo_expire[sync][data_dir]); +list_add_tail(&rq->queuelist, &sd->fifo_list[sync][data_dir]); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) +static int +sio_queue_empty(struct request_queue *q) +{ +struct sio_data *sd = q->elevator->elevator_data; + +/* Check if fifo lists are empty */ +return list_empty(&sd->fifo_list[SYNC][READ]) && list_empty(&sd->fifo_list[SYNC][WRITE]) && +list_empty(&sd->fifo_list[ASYNC][READ]) && list_empty(&sd->fifo_list[ASYNC][WRITE]); +} +#endif + +static struct request * +sio_expired_request(struct sio_data *sd, int sync, int data_dir) +{ +struct list_head *list = &sd->fifo_list[sync][data_dir]; +struct request *rq; + +if (list_empty(list)) +return NULL; + +/* Retrieve request */ +rq = rq_entry_fifo(list->next); + +/* Request has expired */ +if (time_after_eq(jiffies, rq_fifo_time(rq))) +return rq; + +return NULL; +} + +static struct request * +sio_choose_expired_request(struct sio_data *sd) +{ +struct request *rq; + +/* +* Check expired requests. +* Asynchronous requests have priority over synchronous. +* Write requests have priority over read. +*/ +rq = sio_expired_request(sd, ASYNC, WRITE); +if (rq) +return rq; +rq = sio_expired_request(sd, ASYNC, READ); +if (rq) +return rq; + +rq = sio_expired_request(sd, SYNC, WRITE); +if (rq) +return rq; +rq = sio_expired_request(sd, SYNC, READ); +if (rq) +return rq; + + +return NULL; +} + +static struct request * +sio_choose_request(struct sio_data *sd, int data_dir) +{ +struct list_head *sync = sd->fifo_list[SYNC]; +struct list_head *async = sd->fifo_list[ASYNC]; + +/* +* Retrieve request from available fifo list. +* Synchronous requests have priority over asynchronous. +* Read requests have priority over write. +*/ +if (!list_empty(&sync[data_dir])) +return rq_entry_fifo(sync[data_dir].next); +if (!list_empty(&async[data_dir])) +return rq_entry_fifo(async[data_dir].next); + +if (!list_empty(&sync[!data_dir])) +return rq_entry_fifo(sync[!data_dir].next); +if (!list_empty(&async[!data_dir])) +return rq_entry_fifo(async[!data_dir].next); + +return NULL; +} + +static inline void +sio_dispatch_request(struct sio_data *sd, struct request *rq) +{ + +/* +* Remove the request from the fifo list +* and dispatch it. +*/ +rq_fifo_clear(rq); +elv_dispatch_add_tail(rq->q, rq); + +sd->batched++; + +if (rq_data_dir(rq)) { +sd->starved = 0; +} else { +if (!list_empty(&sd->fifo_list[SYNC][WRITE]) || +!list_empty(&sd->fifo_list[ASYNC][WRITE])) +sd->starved++; +} +} + +static int +sio_dispatch_requests(struct request_queue *q, int force) +{ +struct sio_data *sd = q->elevator->elevator_data; +struct request *rq = NULL; +int data_dir = READ; + +/* +* Retrieve any expired request after a batch of +* sequential requests. +*/ +if (sd->batched > sd->fifo_batch) { +sd->batched = 0; +rq = sio_choose_expired_request(sd); +} + +/* Retrieve request */ +if (!rq) { +if (sd->starved > sd->writes_starved) +data_dir = WRITE; + +rq = sio_choose_request(sd, data_dir); +if (!rq) +return 0; +} + +/* Dispatch request */ +sio_dispatch_request(sd, rq); + +return 1; +} + +static struct request * +sio_former_request(struct request_queue *q, struct request *rq) +{ +struct sio_data *sd = q->elevator->elevator_data; +const int sync = rq_is_sync(rq); +const int data_dir = rq_data_dir(rq); + +if (rq->queuelist.prev == &sd->fifo_list[sync][data_dir]) +return NULL; + +/* Return former request */ +return list_entry(rq->queuelist.prev, struct request, queuelist); +} + +static struct request * +sio_latter_request(struct request_queue *q, struct request *rq) +{ +struct sio_data *sd = q->elevator->elevator_data; +const int sync = rq_is_sync(rq); +const int data_dir = rq_data_dir(rq); + +if (rq->queuelist.next == &sd->fifo_list[sync][data_dir]) +return NULL; + +/* Return latter request */ +return list_entry(rq->queuelist.next, struct request, queuelist); +} + +static void * +sio_init_queue(struct request_queue *q) +{ +struct sio_data *sd; + +/* Allocate structure */ +sd = kmalloc_node(sizeof(*sd), GFP_KERNEL, q->node); +if (!sd) +return NULL; + +/* Initialize fifo lists */ +INIT_LIST_HEAD(&sd->fifo_list[SYNC][READ]); +INIT_LIST_HEAD(&sd->fifo_list[SYNC][WRITE]); +INIT_LIST_HEAD(&sd->fifo_list[ASYNC][READ]); +INIT_LIST_HEAD(&sd->fifo_list[ASYNC][WRITE]); + +/* Initialize data */ +sd->batched = 0; +sd->fifo_expire[SYNC][READ] = sync_read_expire; +sd->fifo_expire[SYNC][WRITE] = sync_write_expire; +sd->fifo_expire[ASYNC][READ] = async_read_expire; +sd->fifo_expire[ASYNC][WRITE] = async_write_expire; +sd->fifo_batch = fifo_batch; +sd->writes_starved = writes_starved; + +return sd; +} + +static void +sio_exit_queue(struct elevator_queue *e) +{ +struct sio_data *sd = e->elevator_data; + +BUG_ON(!list_empty(&sd->fifo_list[SYNC][READ])); +BUG_ON(!list_empty(&sd->fifo_list[SYNC][WRITE])); +BUG_ON(!list_empty(&sd->fifo_list[ASYNC][READ])); +BUG_ON(!list_empty(&sd->fifo_list[ASYNC][WRITE])); + +/* Free structure */ +kfree(sd); +} + +/* +* sysfs code +*/ + +static ssize_t +sio_var_show(int var, char *page) +{ +return sprintf(page, "%d\n", var); +} + +static ssize_t +sio_var_store(int *var, const char *page, size_t count) +{ +char *p = (char *) page; + +*var = simple_strtol(p, &p, 10); +return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ +struct sio_data *sd = e->elevator_data; \ +int __data = __VAR; \ +if (__CONV) \ +__data = jiffies_to_msecs(__data); \ +return sio_var_show(__data, (page)); \ +} +SHOW_FUNCTION(sio_sync_read_expire_show, sd->fifo_expire[SYNC][READ], 1); +SHOW_FUNCTION(sio_sync_write_expire_show, sd->fifo_expire[SYNC][WRITE], 1); +SHOW_FUNCTION(sio_async_read_expire_show, sd->fifo_expire[ASYNC][READ], 1); +SHOW_FUNCTION(sio_async_write_expire_show, sd->fifo_expire[ASYNC][WRITE], 1); +SHOW_FUNCTION(sio_fifo_batch_show, sd->fifo_batch, 0); +SHOW_FUNCTION(sio_writes_starved_show, sd->writes_starved, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ +struct sio_data *sd = e->elevator_data; \ +int __data; \ +int ret = sio_var_store(&__data, (page), count); \ +if (__data < (MIN)) \ +__data = (MIN); \ +else if (__data > (MAX)) \ +__data = (MAX); \ +if (__CONV) \ +*(__PTR) = msecs_to_jiffies(__data); \ +else \ +*(__PTR) = __data; \ +return ret; \ +} +STORE_FUNCTION(sio_sync_read_expire_store, &sd->fifo_expire[SYNC][READ], 0, INT_MAX, 1); +STORE_FUNCTION(sio_sync_write_expire_store, &sd->fifo_expire[SYNC][WRITE], 0, INT_MAX, 1); +STORE_FUNCTION(sio_async_read_expire_store, &sd->fifo_expire[ASYNC][READ], 0, INT_MAX, 1); +STORE_FUNCTION(sio_async_write_expire_store, &sd->fifo_expire[ASYNC][WRITE], 0, INT_MAX, 1); +STORE_FUNCTION(sio_fifo_batch_store, &sd->fifo_batch, 0, INT_MAX, 0); +STORE_FUNCTION(sio_writes_starved_store, &sd->writes_starved, 0, INT_MAX, 0); +#undef STORE_FUNCTION + +#define DD_ATTR(name) \ +__ATTR(name, S_IRUGO|S_IWUSR, sio_##name##_show, \ +sio_##name##_store) + +static struct elv_fs_entry sio_attrs[] = { +DD_ATTR(sync_read_expire), +DD_ATTR(sync_write_expire), +DD_ATTR(async_read_expire), +DD_ATTR(async_write_expire), +DD_ATTR(fifo_batch), +DD_ATTR(writes_starved), +__ATTR_NULL +}; + +static struct elevator_type iosched_sioplus = { +.ops = { +.elevator_merge_req_fn = sio_merged_requests, +.elevator_dispatch_fn = sio_dispatch_requests, +.elevator_add_req_fn = sio_add_request, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) +.elevator_queue_empty_fn = sio_queue_empty, +#endif +.elevator_former_req_fn = sio_former_request, +.elevator_latter_req_fn = sio_latter_request, +.elevator_init_fn = sio_init_queue, +.elevator_exit_fn = sio_exit_queue, +}, + +.elevator_attrs = sio_attrs, +.elevator_name = "sioplus", +.elevator_owner = THIS_MODULE, +}; + +static int __init sioplus_init(void) +{ +/* Register elevator */ +elv_register(&iosched_sioplus); + +return 0; +} + +static void __exit sioplus_exit(void) +{ +/* Unregister elevator */ +elv_unregister(&iosched_sioplus); +} + +module_init(sioplus_init); +module_exit(sioplus_exit); + +MODULE_AUTHOR("Miguel Boton"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Simple IO scheduler plus"); diff --git a/block/vr-iosched.c b/block/vr-iosched.c new file mode 100644 index 00000000..f94de99c --- /dev/null +++ b/block/vr-iosched.c @@ -0,0 +1,434 @@ +/* + * V(R) I/O Scheduler + * + * Copyright (C) 2007 Aaron Carroll + * + * + * The algorithm: + * + * The next request is decided based on its distance from the last + * request, with a multiplicative penalty of `rev_penalty' applied + * for reversing the head direction. A rev_penalty of 1 means SSTF + * behaviour. As this variable is increased, the algorithm approaches + * pure SCAN. Setting rev_penalty to 0 forces SCAN. + * + * Async and synch requests are not treated seperately. Instead we + * rely on deadlines to ensure fairness. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum vr_data_dir { + ASYNC, + SYNC, +}; + +enum vr_head_dir { + FORWARD, + BACKWARD, +}; + +static const int sync_expire = HZ / 2; /* max time before a sync is submitted. */ +static const int async_expire = 5 * HZ; /* ditto for async, these limits are SOFT! */ +static const int fifo_batch = 1; +static const int rev_penalty = 10; /* penalty for reversing head direction */ + +struct vr_data { + struct rb_root sort_list; + struct list_head fifo_list[2]; + + struct request *next_rq; + struct request *prev_rq; + + unsigned int nbatched; + sector_t last_sector; /* head position */ + int head_dir; + + /* tunables */ + int fifo_expire[2]; + int fifo_batch; + int rev_penalty; +}; + +static void vr_move_request(struct vr_data *, struct request *); + +static inline struct vr_data * +vr_get_data(struct request_queue *q) +{ + return q->elevator->elevator_data; +} + +static void +vr_add_rq_rb(struct vr_data *vd, struct request *rq) +{ + elv_rb_add(&vd->sort_list, rq); + + if (blk_rq_pos(rq) >= vd->last_sector) { + if (!vd->next_rq || blk_rq_pos(vd->next_rq) > blk_rq_pos(rq)) + vd->next_rq = rq; + } + else { + if (!vd->prev_rq || blk_rq_pos(vd->prev_rq) < blk_rq_pos(rq)) + vd->prev_rq = rq; + } + + BUG_ON(vd->next_rq && vd->next_rq == vd->prev_rq); + BUG_ON(vd->next_rq && vd->prev_rq && blk_rq_pos(vd->next_rq) < blk_rq_pos(vd->prev_rq)); +} + +static void +vr_del_rq_rb(struct vr_data *vd, struct request *rq) +{ + /* + * We might be deleting our cached next request. + * If so, find its sucessor. + */ + + if (vd->next_rq == rq) + vd->next_rq = elv_rb_latter_request(NULL, rq); + else if (vd->prev_rq == rq) + vd->prev_rq = elv_rb_former_request(NULL, rq); + + BUG_ON(vd->next_rq && vd->next_rq == vd->prev_rq); + BUG_ON(vd->next_rq && vd->prev_rq && blk_rq_pos(vd->next_rq) < blk_rq_pos(vd->prev_rq)); + + elv_rb_del(&vd->sort_list, rq); +} + +/* + * add rq to rbtree and fifo + */ +static void +vr_add_request(struct request_queue *q, struct request *rq) +{ + struct vr_data *vd = vr_get_data(q); + const int dir = rq_is_sync(rq); + + vr_add_rq_rb(vd, rq); + + if (vd->fifo_expire[dir]) { + rq_set_fifo_time(rq, jiffies + vd->fifo_expire[dir]); + list_add_tail(&rq->queuelist, &vd->fifo_list[dir]); + } +} + +/* + * remove rq from rbtree and fifo. + */ +static void +vr_remove_request(struct request_queue *q, struct request *rq) +{ + struct vr_data *vd = vr_get_data(q); + + rq_fifo_clear(rq); + vr_del_rq_rb(vd, rq); +} + +static int +vr_merge(struct request_queue *q, struct request **rqp, struct bio *bio) +{ + sector_t sector = bio->bi_sector + bio_sectors(bio); + struct vr_data *vd = vr_get_data(q); + struct request *rq = elv_rb_find(&vd->sort_list, sector); + + if (rq && elv_rq_merge_ok(rq, bio)) { + *rqp = rq; + return ELEVATOR_FRONT_MERGE; + } + return ELEVATOR_NO_MERGE; +} + +static void +vr_merged_request(struct request_queue *q, struct request *req, int type) +{ + struct vr_data *vd = vr_get_data(q); + + /* + * if the merge was a front merge, we need to reposition request + */ + if (type == ELEVATOR_FRONT_MERGE) { + vr_del_rq_rb(vd, req); + vr_add_rq_rb(vd, req); + } +} + +static void +vr_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + /* + * if next expires before rq, assign its expire time to rq + * and move into next position (next will be deleted) in fifo + */ + if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) { + if (time_before(rq_fifo_time(next), rq_fifo_time(rq))) { + list_move(&rq->queuelist, &next->queuelist); + rq_set_fifo_time(rq, rq_fifo_time(next)); + } + } + + vr_remove_request(q, next); +} + +/* + * move an entry to dispatch queue + */ +static void +vr_move_request(struct vr_data *vd, struct request *rq) +{ + struct request_queue *q = rq->q; + + if (blk_rq_pos(rq) > vd->last_sector) + vd->head_dir = FORWARD; + else + vd->head_dir = BACKWARD; + + vd->last_sector = blk_rq_pos(rq); + vd->next_rq = elv_rb_latter_request(NULL, rq); + vd->prev_rq = elv_rb_former_request(NULL, rq); + + BUG_ON(vd->next_rq && vd->next_rq == vd->prev_rq); + + vr_remove_request(q, rq); + elv_dispatch_add_tail(q, rq); + vd->nbatched++; +} + +/* + * get the first expired request in direction ddir + */ +static struct request * +vr_expired_request(struct vr_data *vd, int ddir) +{ + struct request *rq; + + if (list_empty(&vd->fifo_list[ddir])) + return NULL; + + rq = rq_entry_fifo(vd->fifo_list[ddir].next); + if (time_after(jiffies, rq_fifo_time(rq))) + return rq; + + return NULL; +} + +/* + * Returns the oldest expired request + */ +static struct request * +vr_check_fifo(struct vr_data *vd) +{ + struct request *rq_sync = vr_expired_request(vd, SYNC); + struct request *rq_async = vr_expired_request(vd, ASYNC); + + if (rq_async && rq_sync) { + if (time_after(rq_fifo_time(rq_async), rq_fifo_time(rq_sync))) + return rq_sync; + } + else if (rq_sync) + return rq_sync; + + return rq_async; +} + +/* + * Return the request with the lowest penalty + */ +static struct request * +vr_choose_request(struct vr_data *vd) +{ + int penalty = (vd->rev_penalty) ? : INT_MAX; + struct request *next = vd->next_rq; + struct request *prev = vd->prev_rq; + sector_t next_pen, prev_pen; + + BUG_ON(prev && prev == next); + + if (!prev) + return next; + else if (!next) + return prev; + + /* At this point both prev and next are defined and distinct */ + + next_pen = blk_rq_pos(next) - vd->last_sector; + prev_pen = vd->last_sector - blk_rq_pos(prev); + + if (vd->head_dir == FORWARD) + next_pen = do_div(next_pen, penalty); + else + prev_pen = do_div(prev_pen, penalty); + + if (next_pen <= prev_pen) + return next; + + return prev; +} + +static int +vr_dispatch_requests(struct request_queue *q, int force) +{ + struct vr_data *vd = vr_get_data(q); + struct request *rq = NULL; + + /* Check for and issue expired requests */ + if (vd->nbatched > vd->fifo_batch) { + vd->nbatched = 0; + rq = vr_check_fifo(vd); + } + + if (!rq) { + rq = vr_choose_request(vd); + if (!rq) + return 0; + } + + vr_move_request(vd, rq); + + return 1; +} + + +static void +vr_exit_queue(struct elevator_queue *e) +{ + struct vr_data *vd = e->elevator_data; + BUG_ON(!RB_EMPTY_ROOT(&vd->sort_list)); + kfree(vd); +} + +/* + * initialize elevator private data (vr_data). + */ +static void *vr_init_queue(struct request_queue *q) +{ + struct vr_data *vd; + + vd = kmalloc_node(sizeof(*vd), GFP_KERNEL | __GFP_ZERO, q->node); + if (!vd) + return NULL; + + INIT_LIST_HEAD(&vd->fifo_list[SYNC]); + INIT_LIST_HEAD(&vd->fifo_list[ASYNC]); + vd->sort_list = RB_ROOT; + vd->fifo_expire[SYNC] = sync_expire; + vd->fifo_expire[ASYNC] = async_expire; + vd->fifo_batch = fifo_batch; + vd->rev_penalty = rev_penalty; + return vd; +} + +/* + * sysfs parts below + */ + +static ssize_t +vr_var_show(int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t +vr_var_store(int *var, const char *page, size_t count) +{ + *var = simple_strtol(page, NULL, 10); + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ + static ssize_t __FUNC(struct elevator_queue *e, char *page) \ + { \ + struct vr_data *vd = e->elevator_data; \ + int __data = __VAR; \ + if (__CONV) \ + __data = jiffies_to_msecs(__data); \ + return vr_var_show(__data, (page)); \ + } +SHOW_FUNCTION(vr_sync_expire_show, vd->fifo_expire[SYNC], 1); +SHOW_FUNCTION(vr_async_expire_show, vd->fifo_expire[ASYNC], 1); +SHOW_FUNCTION(vr_fifo_batch_show, vd->fifo_batch, 0); +SHOW_FUNCTION(vr_rev_penalty_show, vd->rev_penalty, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ + static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ + { \ + struct vr_data *vd = e->elevator_data; \ + int __data; \ + int ret = vr_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + if (__CONV) \ + *(__PTR) = msecs_to_jiffies(__data); \ + else \ + *(__PTR) = __data; \ + return ret; \ + } +STORE_FUNCTION(vr_sync_expire_store, &vd->fifo_expire[SYNC], 0, INT_MAX, 1); +STORE_FUNCTION(vr_async_expire_store, &vd->fifo_expire[ASYNC], 0, INT_MAX, 1); +STORE_FUNCTION(vr_fifo_batch_store, &vd->fifo_batch, 0, INT_MAX, 0); +STORE_FUNCTION(vr_rev_penalty_store, &vd->rev_penalty, 0, INT_MAX, 0); +#undef STORE_FUNCTION + +#define DD_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, vr_##name##_show, \ + vr_##name##_store) + +static struct elv_fs_entry vr_attrs[] = { + DD_ATTR(sync_expire), + DD_ATTR(async_expire), + DD_ATTR(fifo_batch), + DD_ATTR(rev_penalty), + __ATTR_NULL +}; + +static struct elevator_type iosched_vr = { + .ops = { + .elevator_merge_fn = vr_merge, + .elevator_merged_fn = vr_merged_request, + .elevator_merge_req_fn = vr_merged_requests, + .elevator_dispatch_fn = vr_dispatch_requests, + .elevator_add_req_fn = vr_add_request, + .elevator_former_req_fn = elv_rb_former_request, + .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_init_fn = vr_init_queue, + .elevator_exit_fn = vr_exit_queue, + }, + + .elevator_attrs = vr_attrs, + .elevator_name = "vr", + .elevator_owner = THIS_MODULE, +}; + +static int __init vr_init(void) +{ + elv_register(&iosched_vr); + + return 0; +} + +static void __exit vr_exit(void) +{ + elv_unregister(&iosched_vr); +} + +module_init(vr_init); +module_exit(vr_exit); + +MODULE_AUTHOR("Aaron Carroll"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("V(R) IO scheduler"); + diff --git a/block/zen-iosched.c b/block/zen-iosched.c new file mode 100644 index 00000000..77145de8 --- /dev/null +++ b/block/zen-iosched.c @@ -0,0 +1,277 @@ +/* + * Zen IO scheduler + * Primarily based on Noop, deadline, and SIO IO schedulers. + * + * Copyright (C) 2012 Brandon Berhent + * + * FCFS, dispatches are back-inserted, deadlines ensure fairness. + * Should work best with devices where there is no travel delay. + */ +#include +#include +#include +#include +#include +#include + +enum zen_data_dir { ASYNC, SYNC }; + +static const int sync_expire = HZ / 4; /* max time before a sync is submitted. */ +static const int async_expire = 2 * HZ; /* ditto for async, these limits are SOFT! */ +static const int fifo_batch = 1; + +struct zen_data { + /* Runtime Data */ + /* Requests are only present on fifo_list */ + struct list_head fifo_list[2]; + + unsigned int batching; /* number of sequential requests made */ + + /* tunables */ + int fifo_expire[2]; + int fifo_batch; +}; + +static inline struct zen_data * +zen_get_data(struct request_queue *q) { + return q->elevator->elevator_data; +} + +static void zen_dispatch(struct zen_data *, struct request *); + +static void +zen_merged_requests(struct request_queue *q, struct request *rq, + struct request *next) +{ + /* + * if next expires before rq, assign its expire time to arq + * and move into next position (next will be deleted) in fifo + */ + if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) { + if (time_before(rq_fifo_time(next), rq_fifo_time(rq))) { + list_move(&rq->queuelist, &next->queuelist); + rq_set_fifo_time(rq, rq_fifo_time(next)); + } + } + + /* next request is gone */ + rq_fifo_clear(next); +} + +static void zen_add_request(struct request_queue *q, struct request *rq) +{ + struct zen_data *zdata = zen_get_data(q); + const int dir = rq_data_dir(rq); + + if (zdata->fifo_expire[dir]) { + rq_set_fifo_time(rq, jiffies + zdata->fifo_expire[dir]); + list_add_tail(&rq->queuelist, &zdata->fifo_list[dir]); + } +} + +static void zen_dispatch(struct zen_data *zdata, struct request *rq) +{ + /* Remove request from list and dispatch it */ + rq_fifo_clear(rq); + elv_dispatch_add_tail(rq->q, rq); + + /* Increment # of sequential requests */ + zdata->batching++; +} + +/* + * get the first expired request in direction ddir + */ +static struct request * +zen_expired_request(struct zen_data *zdata, int ddir) +{ + struct request *rq; + + if (list_empty(&zdata->fifo_list[ddir])) + return NULL; + + rq = rq_entry_fifo(zdata->fifo_list[ddir].next); + if (time_after(jiffies, rq_fifo_time(rq))) + return rq; + + return NULL; +} + +/* + * zen_check_fifo returns 0 if there are no expired requests on the fifo, + * otherwise it returns the next expired request + */ +static struct request * +zen_check_fifo(struct zen_data *zdata) +{ + struct request *rq_sync = zen_expired_request(zdata, SYNC); + struct request *rq_async = zen_expired_request(zdata, ASYNC); + + if (rq_async && rq_sync) { + if (time_after(rq_fifo_time(rq_async), rq_fifo_time(rq_sync))) + return rq_sync; + } else if (rq_sync) { + return rq_sync; + } else if (rq_async) { + return rq_async; + } + + return 0; +} + +static struct request * +zen_choose_request(struct zen_data *zdata) +{ + /* + * Retrieve request from available fifo list. + * Synchronous requests have priority over asynchronous. + */ + if (!list_empty(&zdata->fifo_list[SYNC])) + return rq_entry_fifo(zdata->fifo_list[SYNC].next); + if (!list_empty(&zdata->fifo_list[ASYNC])) + return rq_entry_fifo(zdata->fifo_list[ASYNC].next); + + return NULL; +} + +static int zen_dispatch_requests(struct request_queue *q, int force) +{ + struct zen_data *zdata = zen_get_data(q); + struct request *rq = NULL; + + /* Check for and issue expired requests */ + if (zdata->batching > zdata->fifo_batch) { + zdata->batching = 0; + rq = zen_check_fifo(zdata); + } + + if (!rq) { + rq = zen_choose_request(zdata); + if (!rq) + return 0; + } + + zen_dispatch(zdata, rq); + + return 1; +} + +static void *zen_init_queue(struct request_queue *q) +{ + struct zen_data *zdata; + + zdata = kmalloc_node(sizeof(*zdata), GFP_KERNEL, q->node); + if (!zdata) + return NULL; + INIT_LIST_HEAD(&zdata->fifo_list[SYNC]); + INIT_LIST_HEAD(&zdata->fifo_list[ASYNC]); + zdata->fifo_expire[SYNC] = sync_expire; + zdata->fifo_expire[ASYNC] = async_expire; + zdata->fifo_batch = fifo_batch; + return zdata; +} + +static void zen_exit_queue(struct elevator_queue *e) +{ + struct zen_data *zdata = e->elevator_data; + + BUG_ON(!list_empty(&zdata->fifo_list[SYNC])); + BUG_ON(!list_empty(&zdata->fifo_list[ASYNC])); + kfree(zdata); +} + +/* Sysfs */ +static ssize_t +zen_var_show(int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t +zen_var_store(int *var, const char *page, size_t count) +{ + *var = simple_strtol(page, NULL, 10); + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, char *page) \ +{ \ + struct zen_data *zdata = e->elevator_data; \ + int __data = __VAR; \ + if (__CONV) \ + __data = jiffies_to_msecs(__data); \ + return zen_var_show(__data, (page)); \ +} +SHOW_FUNCTION(zen_sync_expire_show, zdata->fifo_expire[SYNC], 1); +SHOW_FUNCTION(zen_async_expire_show, zdata->fifo_expire[ASYNC], 1); +SHOW_FUNCTION(zen_fifo_batch_show, zdata->fifo_batch, 0); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ +static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ +{ \ + struct zen_data *zdata = e->elevator_data; \ + int __data; \ + int ret = zen_var_store(&__data, (page), count); \ + if (__data < (MIN)) \ + __data = (MIN); \ + else if (__data > (MAX)) \ + __data = (MAX); \ + if (__CONV) \ + *(__PTR) = msecs_to_jiffies(__data); \ + else \ + *(__PTR) = __data; \ + return ret; \ +} +STORE_FUNCTION(zen_sync_expire_store, &zdata->fifo_expire[SYNC], 0, INT_MAX, 1); +STORE_FUNCTION(zen_async_expire_store, &zdata->fifo_expire[ASYNC], 0, INT_MAX, 1); +STORE_FUNCTION(zen_fifo_batch_store, &zdata->fifo_batch, 0, INT_MAX, 0); +#undef STORE_FUNCTION + +#define DD_ATTR(name) \ + __ATTR(name, S_IRUGO|S_IWUSR, zen_##name##_show, \ + zen_##name##_store) + +static struct elv_fs_entry zen_attrs[] = { + DD_ATTR(sync_expire), + DD_ATTR(async_expire), + DD_ATTR(fifo_batch), + __ATTR_NULL +}; + +static struct elevator_type iosched_zen = { + .ops = { + .elevator_merge_req_fn = zen_merged_requests, + .elevator_dispatch_fn = zen_dispatch_requests, + .elevator_add_req_fn = zen_add_request, + .elevator_former_req_fn = elv_rb_former_request, + .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_init_fn = zen_init_queue, + .elevator_exit_fn = zen_exit_queue, + }, + .elevator_attrs = zen_attrs, + .elevator_name = "zen", + .elevator_owner = THIS_MODULE, +}; + +static int __init zen_init(void) +{ + elv_register(&iosched_zen); + + return 0; +} + +static void __exit zen_exit(void) +{ + elv_unregister(&iosched_zen); +} + +module_init(zen_init); +module_exit(zen_exit); + + +MODULE_AUTHOR("Brandon Berhent"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Zen IO scheduler"); +MODULE_VERSION("1.0"); diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c index 8b7259a1..1d59c745 100644 --- a/drivers/base/genlock.c +++ b/drivers/base/genlock.c @@ -116,7 +116,6 @@ static const struct file_operations genlock_fops = { struct genlock *genlock_create_lock(struct genlock_handle *handle) { struct genlock *lock; - void *ret; if (IS_ERR_OR_NULL(handle)) { GENLOCK_LOG_ERR("Invalid handle\n"); @@ -146,13 +145,8 @@ struct genlock *genlock_create_lock(struct genlock_handle *handle) * other processes */ - ret = anon_inode_getfile("genlock", &genlock_fops, lock, O_RDWR); - if (IS_ERR_OR_NULL(ret)) { - GENLOCK_LOG_ERR("Unable to create lock inode\n"); - kfree(lock); - return ret; - } - lock->file = ret; + lock->file = anon_inode_getfile("genlock", &genlock_fops, + lock, O_RDWR); /* Attach the new lock to the handle */ handle->lock = lock; @@ -666,19 +660,12 @@ static struct genlock_handle *_genlock_get_handle(void) struct genlock_handle *genlock_get_handle(void) { - void *ret; struct genlock_handle *handle = _genlock_get_handle(); if (IS_ERR(handle)) return handle; - ret = anon_inode_getfile("genlock-handle", + handle->file = anon_inode_getfile("genlock-handle", &genlock_handle_fops, handle, O_RDWR); - if (IS_ERR_OR_NULL(ret)) { - GENLOCK_LOG_ERR("Unable to create handle inode\n"); - kfree(handle); - return ret; - } - handle->file = ret; return handle; } @@ -712,6 +699,50 @@ struct genlock_handle *genlock_get_handle_fd(int fd) } EXPORT_SYMBOL(genlock_get_handle_fd); +/* + * Get a file descriptor reference to a lock suitable for sharing with + * other processes + */ + +int genlock_get_fd_handle(struct genlock_handle *handle) +{ + int ret; + struct genlock *lock; + + if (IS_ERR_OR_NULL(handle)) + return -EINVAL; + + lock = handle->lock; + + if (IS_ERR(lock)) + return PTR_ERR(lock); + + if (!lock->file) { + GENLOCK_LOG_ERR("No file attached to the lock\n"); + return -EINVAL; + } + + ret = get_unused_fd_flags(0); + + if (ret < 0) + return ret; + + fd_install(ret, lock->file); + + /* + * Taking a reference for lock file. + * This is required as now we have two file descriptor + * pointing to same file. If one FD is closed, lock file + * will be closed. Taking this reference will make sure + * that file doesn't get close. This refrence will go + * when client will call close on this FD. + */ + fget(ret); + + return ret; +} +EXPORT_SYMBOL(genlock_get_fd_handle); + #ifdef CONFIG_GENLOCK_MISCDEVICE static long genlock_dev_ioctl(struct file *filep, unsigned int cmd, diff --git a/drivers/base/sync.c b/drivers/base/sync.c index 9bc0da50..abcd58b9 100644 --- a/drivers/base/sync.c +++ b/drivers/base/sync.c @@ -28,8 +28,14 @@ #include +#define CREATE_TRACE_POINTS +#include +#include + static void sync_fence_signal_pt(struct sync_pt *pt); static int _sync_pt_has_signaled(struct sync_pt *pt); +static void sync_fence_free(struct kref *kref); +static void sync_dump(struct sync_fence *fence); static LIST_HEAD(sync_timeline_list_head); static DEFINE_SPINLOCK(sync_timeline_list_lock); @@ -50,6 +56,7 @@ struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, if (obj == NULL) return NULL; + kref_init(&obj->kref); obj->ops = ops; strlcpy(obj->name, name, sizeof(obj->name)); @@ -67,34 +74,33 @@ struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, } EXPORT_SYMBOL(sync_timeline_create); -static void sync_timeline_free(struct sync_timeline *obj) +static void sync_timeline_free(struct kref *kref) { + struct sync_timeline *obj = + container_of(kref, struct sync_timeline, kref); unsigned long flags; - if (obj->ops->release_obj) - obj->ops->release_obj(obj); - spin_lock_irqsave(&sync_timeline_list_lock, flags); list_del(&obj->sync_timeline_list); spin_unlock_irqrestore(&sync_timeline_list_lock, flags); + if (obj->ops->release_obj) + obj->ops->release_obj(obj); + kfree(obj); } void sync_timeline_destroy(struct sync_timeline *obj) { - unsigned long flags; - bool needs_freeing; - - spin_lock_irqsave(&obj->child_list_lock, flags); obj->destroyed = true; - needs_freeing = list_empty(&obj->child_list_head); - spin_unlock_irqrestore(&obj->child_list_lock, flags); + smp_wmb(); - if (needs_freeing) - sync_timeline_free(obj); - else - sync_timeline_signal(obj); + /* + * signal any children that their parent is going away. + */ + sync_timeline_signal(obj); + + kref_put(&obj->kref, sync_timeline_free); } EXPORT_SYMBOL(sync_timeline_destroy); @@ -113,7 +119,6 @@ static void sync_timeline_remove_pt(struct sync_pt *pt) { struct sync_timeline *obj = pt->parent; unsigned long flags; - bool needs_freeing; spin_lock_irqsave(&obj->active_list_lock, flags); if (!list_empty(&pt->active_list)) @@ -121,12 +126,10 @@ static void sync_timeline_remove_pt(struct sync_pt *pt) spin_unlock_irqrestore(&obj->active_list_lock, flags); spin_lock_irqsave(&obj->child_list_lock, flags); - list_del(&pt->child_list); - needs_freeing = obj->destroyed && list_empty(&obj->child_list_head); + if (!list_empty(&pt->child_list)) { + list_del_init(&pt->child_list); + } spin_unlock_irqrestore(&obj->child_list_lock, flags); - - if (needs_freeing) - sync_timeline_free(obj); } void sync_timeline_signal(struct sync_timeline *obj) @@ -135,24 +138,30 @@ void sync_timeline_signal(struct sync_timeline *obj) LIST_HEAD(signaled_pts); struct list_head *pos, *n; + trace_sync_timeline(obj); + spin_lock_irqsave(&obj->active_list_lock, flags); list_for_each_safe(pos, n, &obj->active_list_head) { struct sync_pt *pt = container_of(pos, struct sync_pt, active_list); - if (_sync_pt_has_signaled(pt)) - list_move(pos, &signaled_pts); + if (_sync_pt_has_signaled(pt)) { + list_del_init(pos); + list_add(&pt->signaled_list, &signaled_pts); + kref_get(&pt->fence->kref); + } } spin_unlock_irqrestore(&obj->active_list_lock, flags); list_for_each_safe(pos, n, &signaled_pts) { struct sync_pt *pt = - container_of(pos, struct sync_pt, active_list); + container_of(pos, struct sync_pt, signaled_list); list_del_init(pos); sync_fence_signal_pt(pt); + kref_put(&pt->fence->kref, sync_fence_free); } } EXPORT_SYMBOL(sync_timeline_signal); @@ -169,6 +178,7 @@ struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size) return NULL; INIT_LIST_HEAD(&pt->active_list); + kref_get(&parent->kref); sync_timeline_add_pt(parent, pt); return pt; @@ -182,6 +192,8 @@ void sync_pt_free(struct sync_pt *pt) sync_timeline_remove_pt(pt); + kref_put(&pt->parent->kref, sync_timeline_free); + kfree(pt); } EXPORT_SYMBOL(sync_pt_free); @@ -253,12 +265,13 @@ static struct sync_fence *sync_fence_alloc(const char *name) if (fence->file == NULL) goto err; + kref_init(&fence->kref); strlcpy(fence->name, name, sizeof(fence->name)); INIT_LIST_HEAD(&fence->pt_list_head); INIT_LIST_HEAD(&fence->waiter_list_head); spin_lock_init(&fence->waiter_list_lock); - + trace_sync_alloc(fence,current->pid); init_waitqueue_head(&fence->wq); spin_lock_irqsave(&sync_fence_list_lock, flags); @@ -288,6 +301,12 @@ struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt) list_add(&pt->pt_list, &fence->pt_list_head); sync_pt_activate(pt); + /* + * signal the fence in case pt was activated before + * sync_pt_activate(pt) was called + */ + sync_fence_signal_pt(pt); + return fence; } EXPORT_SYMBOL(sync_fence_create); @@ -306,12 +325,68 @@ static int sync_fence_copy_pts(struct sync_fence *dst, struct sync_fence *src) new_pt->fence = dst; list_add(&new_pt->pt_list, &dst->pt_list_head); - sync_pt_activate(new_pt); } return 0; } +static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src) +{ + struct list_head *src_pos, *dst_pos, *n; + + list_for_each(src_pos, &src->pt_list_head) { + struct sync_pt *src_pt = + container_of(src_pos, struct sync_pt, pt_list); + bool collapsed = false; + + list_for_each_safe(dst_pos, n, &dst->pt_list_head) { + struct sync_pt *dst_pt = + container_of(dst_pos, struct sync_pt, pt_list); + /* collapse two sync_pts on the same timeline + * to a single sync_pt that will signal at + * the later of the two + */ + if (dst_pt->parent == src_pt->parent) { + if (dst_pt->parent->ops->compare(dst_pt, src_pt) == -1) { + struct sync_pt *new_pt = + sync_pt_dup(src_pt); + if (new_pt == NULL) + return -ENOMEM; + + new_pt->fence = dst; + list_replace(&dst_pt->pt_list, + &new_pt->pt_list); + sync_pt_free(dst_pt); + } + collapsed = true; + break; + } + } + + if (!collapsed) { + struct sync_pt *new_pt = sync_pt_dup(src_pt); + + if (new_pt == NULL) + return -ENOMEM; + + new_pt->fence = dst; + list_add(&new_pt->pt_list, &dst->pt_list_head); + } + } + + return 0; +} + +static void sync_fence_detach_pts(struct sync_fence *fence) +{ + struct list_head *pos, *n; + + list_for_each_safe(pos, n, &fence->pt_list_head) { + struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list); + sync_timeline_remove_pt(pt); + } +} + static void sync_fence_free_pts(struct sync_fence *fence) { struct list_head *pos, *n; @@ -376,6 +451,7 @@ struct sync_fence *sync_fence_merge(const char *name, struct sync_fence *a, struct sync_fence *b) { struct sync_fence *fence; + struct list_head *pos; int err; fence = sync_fence_alloc(name); @@ -386,11 +462,23 @@ struct sync_fence *sync_fence_merge(const char *name, if (err < 0) goto err; - err = sync_fence_copy_pts(fence, b); + err = sync_fence_merge_pts(fence, b); if (err < 0) goto err; - fence->status = sync_fence_get_status(fence); + list_for_each(pos, &fence->pt_list_head) { + struct sync_pt *pt = + container_of(pos, struct sync_pt, pt_list); + sync_pt_activate(pt); + } + + /* + * signal the fence in case one of it's pts were activated before + * they were activated + */ + sync_fence_signal_pt(list_first_entry(&fence->pt_list_head, + struct sync_pt, + pt_list)); return fence; err: @@ -489,44 +577,91 @@ int sync_fence_cancel_async(struct sync_fence *fence, } EXPORT_SYMBOL(sync_fence_cancel_async); +static bool sync_fence_check(struct sync_fence *fence) +{ + /* + * Make sure that reads to fence->status are ordered with the + * wait queue event triggering + */ + smp_rmb(); + return fence->status != 0; +} + int sync_fence_wait(struct sync_fence *fence, long timeout) { - int err; + int err = 0; + struct sync_pt *pt; + + trace_sync_wait(fence, 1); + list_for_each_entry(pt, &fence->pt_list_head, pt_list) + trace_sync_pt(pt); - if (timeout) { + if (timeout > 0) { timeout = msecs_to_jiffies(timeout); err = wait_event_interruptible_timeout(fence->wq, - fence->status != 0, + sync_fence_check(fence), timeout); - } else { - err = wait_event_interruptible(fence->wq, fence->status != 0); + } else if (timeout < 0) { + err = wait_event_interruptible(fence->wq, + sync_fence_check(fence)); } + trace_sync_wait(fence, 0); if (err < 0) return err; - if (fence->status < 0) + if (fence->status < 0) { + pr_info("fence error %d on [%p]\n", fence->status, fence); + sync_dump(fence); return fence->status; + } - if (fence->status == 0) + if (fence->status == 0) { + if (timeout > 0) { + pr_info("fence timeout on [%p] after %dms\n", fence, + jiffies_to_msecs(timeout)); + sync_dump(fence); + } return -ETIME; + } return 0; } EXPORT_SYMBOL(sync_fence_wait); +static void sync_fence_free(struct kref *kref) +{ + struct sync_fence *fence = container_of(kref, struct sync_fence, kref); + + trace_sync_free(fence, current->pid); + + sync_fence_free_pts(fence); + + kfree(fence); +} + static int sync_fence_release(struct inode *inode, struct file *file) { struct sync_fence *fence = file->private_data; unsigned long flags; - sync_fence_free_pts(fence); - + /* + * We need to remove all ways to access this fence before droping + * our ref. + * + * start with its membership in the global fence list + */ spin_lock_irqsave(&sync_fence_list_lock, flags); list_del(&fence->sync_fence_list); spin_unlock_irqrestore(&sync_fence_list_lock, flags); - kfree(fence); + /* + * remove its pts from their parents so that sync_timeline_signal() + * can't reference the fence. + */ + sync_fence_detach_pts(fence); + + kref_put(&fence->kref, sync_fence_free); return 0; } @@ -537,6 +672,12 @@ static unsigned int sync_fence_poll(struct file *file, poll_table *wait) poll_wait(file, &fence->wq, wait); + /* + * Make sure that reads to fence->status are ordered with the + * wait queue event triggering + */ + smp_rmb(); + if (fence->status == 1) return POLLIN; else if (fence->status < 0) @@ -547,7 +688,7 @@ static unsigned int sync_fence_poll(struct file *file, poll_table *wait) static long sync_fence_ioctl_wait(struct sync_fence *fence, unsigned long arg) { - __u32 value; + __s32 value; if (copy_from_user(&value, (void __user *)arg, sizeof(value))) return -EFAULT; @@ -562,8 +703,13 @@ static long sync_fence_ioctl_merge(struct sync_fence *fence, unsigned long arg) struct sync_fence *fence2, *fence3; struct sync_merge_data data; - if (copy_from_user(&data, (void __user *)arg, sizeof(data))) - return -EFAULT; + if (fd < 0) + return fd; + + if (copy_from_user(&data, (void __user *)arg, sizeof(data))) { + err = -EFAULT; + goto err_put_fd; + } fence2 = sync_fence_fdget(data.fd2); if (fence2 == NULL) { @@ -720,7 +866,17 @@ static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence) seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec); } - if (pt->parent->ops->print_pt) { + if (pt->parent->ops->timeline_value_str && + pt->parent->ops->pt_value_str) { + char value[64]; + pt->parent->ops->pt_value_str(pt, value, sizeof(value)); + seq_printf(s, ": %s", value); + if (fence) { + pt->parent->ops->timeline_value_str(pt->parent, value, + sizeof(value)); + seq_printf(s, " / %s", value); + } + } else if (pt->parent->ops->print_pt) { seq_printf(s, ": "); pt->parent->ops->print_pt(s, pt); } @@ -735,7 +891,11 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) seq_printf(s, "%s %s", obj->name, obj->ops->driver_name); - if (obj->ops->print_obj) { + if (obj->ops->timeline_value_str) { + char value[64]; + obj->ops->timeline_value_str(obj, value, sizeof(value)); + seq_printf(s, ": %s", value); + } else if (obj->ops->print_obj) { seq_printf(s, ": "); obj->ops->print_obj(s, obj); } @@ -756,7 +916,8 @@ static void sync_print_fence(struct seq_file *s, struct sync_fence *fence) struct list_head *pos; unsigned long flags; - seq_printf(s, "%s: %s\n", fence->name, sync_status_str(fence->status)); + seq_printf(s, "[%p] %s: %s\n", fence, fence->name, + sync_status_str(fence->status)); list_for_each(pos, &fence->pt_list_head) { struct sync_pt *pt = @@ -824,7 +985,36 @@ static __init int sync_debugfs_init(void) debugfs_create_file("sync", S_IRUGO, NULL, NULL, &sync_debugfs_fops); return 0; } - late_initcall(sync_debugfs_init); +#define DUMP_CHUNK 256 +static char sync_dump_buf[64 * 1024]; +static void sync_dump(struct sync_fence *fence) +{ + struct seq_file s = { + .buf = sync_dump_buf, + .size = sizeof(sync_dump_buf) - 1, + }; + int i; + + seq_printf(&s, "fence:\n--------------\n"); + sync_print_fence(&s, fence); + seq_printf(&s, "\n"); + + for (i = 0; i < s.count; i += DUMP_CHUNK) { + if ((s.count - i) > DUMP_CHUNK) { + char c = s.buf[i + DUMP_CHUNK]; + s.buf[i + DUMP_CHUNK] = 0; + pr_cont("%s", s.buf + i); + s.buf[i + DUMP_CHUNK] = c; + } else { + s.buf[s.count] = 0; + pr_cont("%s", s.buf + i); + } + } +} +#else +static void sync_dump(struct sync_fence *fence) +{ +} #endif diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index a7964071..e93e2ded 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -118,6 +118,8 @@ source "drivers/block/paride/Kconfig" source "drivers/block/mtip32xx/Kconfig" +source "drivers/block/zram/Kconfig" + config BLK_CPQ_DA tristate "Compaq SMART2 support" depends on PCI && VIRT_TO_BUS diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 5b795059..4fd9bdf5 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -42,4 +42,6 @@ obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ obj-$(CONFIG_BLK_DEV_RBD) += rbd.o obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ +obj-$(CONFIG_ZRAM) += zram/ + swim_mod-y := swim.o swim_asm.o diff --git a/drivers/staging/zram/Kconfig b/drivers/block/zram/Kconfig similarity index 58% rename from drivers/staging/zram/Kconfig rename to drivers/block/zram/Kconfig index 5c12faa3..75f46cb7 100644 --- a/drivers/staging/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -1,7 +1,9 @@ config ZRAM tristate "Compressed RAM block device support" depends on BLOCK && SYSFS && ZSMALLOC - default n + select LZO_COMPRESS + select LZO_DECOMPRESS + default y help Creates virtual block devices called /dev/zramX (X = 0, 1, ...). Pages written to these disks are compressed and stored in memory @@ -12,7 +14,16 @@ config ZRAM disks and maybe many more. See zram.txt for more information. - Project home: + +config ZRAM_LZ4_COMPRESS + bool "Enable LZ4 algorithm support" + depends on ZRAM + select LZ4_COMPRESS + select LZ4_DECOMPRESS + default y + 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" @@ -21,29 +32,3 @@ config ZRAM_DEBUG help This option adds additional debugging code to the compressed RAM block device driver. - -choice ZRAM_COMPRESS - prompt "compression method" - depends on ZRAM - default ZRAM_LZO - help - Select the compression method used by zram. - LZO is the default. Snappy compresses a bit worse (around ~2%) but - much (~2x) faster, at least on x86-64. - -config ZRAM_LZO - bool "LZO compression" - select LZO_COMPRESS - select LZO_DECOMPRESS - -#config ZRAM_LZ4 -# bool "Snappy compression" -# select LZ4_COMPRESS -# select LZ4_DECOMPRESS - -config ZRAM_SNAPPY - bool "Snappy compression" - select SNAPPY_COMPRESS - select SNAPPY_DECOMPRESS - -endchoice diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile new file mode 100644 index 00000000..be0763ff --- /dev/null +++ b/drivers/block/zram/Makefile @@ -0,0 +1,5 @@ +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 index 00000000..f1ff39a3 --- /dev/null +++ b/drivers/block/zram/zcomp.c @@ -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 +#include +#include +#include +#include +#include + +#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 index 00000000..c59d1fca --- /dev/null +++ b/drivers/block/zram/zcomp.h @@ -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 + +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 index 00000000..f2afb7e9 --- /dev/null +++ b/drivers/block/zram/zcomp_lz4.c @@ -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 +#include +#include + +#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 index 00000000..60613fb2 --- /dev/null +++ b/drivers/block/zram/zcomp_lz4.h @@ -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 index 00000000..da1bc47d --- /dev/null +++ b/drivers/block/zram/zcomp_lzo.c @@ -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 +#include +#include + +#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 index 00000000..128c5807 --- /dev/null +++ b/drivers/block/zram/zcomp_lzo.h @@ -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_ */ diff --git a/drivers/staging/zram/zram_drv.c b/drivers/block/zram/zram_drv.c similarity index 66% rename from drivers/staging/zram/zram_drv.c rename to drivers/block/zram/zram_drv.c index 02953802..e67160e3 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -2,6 +2,7 @@ * Compressed RAM block device * * Copyright (C) 2008, 2009, 2010 Nitin Gupta + * 2012, 2013 Minchan Kim * * This code is released using a dual license strategy: BSD/GPL * You can choose the licence that better fits your requirements. @@ -9,7 +10,6 @@ * Released under the terms of 3-clause BSD License * Released under the terms of GNU General Public License Version 2.0 * - * Project home: http://compcache.googlecode.com */ #define KMSG_COMPONENT "zram" @@ -31,57 +31,15 @@ #include #include #include +#include #include #include "zram_drv.h" -#if defined(CONFIG_ZRAM_LZO) -#include -#define WMSIZE LZO1X_MEM_COMPRESS -#define COMPRESS(s, sl, d, dl, wm) \ - lzo1x_1_compress(s, sl, d, dl, wm) -#define DECOMPRESS(s, sl, d, dl) \ - lzo1x_decompress_safe(s, sl, d, dl) -#elif defined(CONFIG_ZRAM_SNAPPY) -#include "../snappy/csnappy.h" /* if built in drivers/staging */ -#define WMSIZE_ORDER ((PAGE_SHIFT > 14) ? (15) : (PAGE_SHIFT+1)) -#define WMSIZE (1 << WMSIZE_ORDER) -static int -snappy_compress_( - const unsigned char *src, - size_t src_len, - unsigned char *dst, - size_t *dst_len, - void *workmem) -{ - const unsigned char *end = csnappy_compress_fragment( - src, (uint32_t)src_len, dst, workmem, WMSIZE_ORDER); - *dst_len = end - dst; - return 0; -} -static int -snappy_decompress_( - const unsigned char *src, - size_t src_len, - unsigned char *dst, - size_t *dst_len) -{ - uint32_t dst_len_ = (uint32_t)*dst_len; - int ret = csnappy_decompress_noheader(src, src_len, dst, &dst_len_); - *dst_len = (size_t)dst_len_; - return ret; -} -#define COMPRESS(s, sl, d, dl, wm) \ - snappy_compress_(s, sl, d, dl, wm) -#define DECOMPRESS(s, sl, d, dl) \ - snappy_decompress_(s, sl, d, dl) -#else -#error either CONFIG_ZRAM_LZO or CONFIG_ZRAM_SNAPPY must be defined -#endif - /* Globals */ static int zram_major; static struct zram *zram_devices; +static const char *default_compressor = "lzo"; /* * We don't need to see memory allocation errors more than once every 1 @@ -92,6 +50,22 @@ static struct zram *zram_devices; /* 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; @@ -102,110 +76,146 @@ 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", 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)(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 */ static int zram_test_flag(struct zram_meta *meta, u32 index, enum zram_pageflags flag) { - return meta->table[index].flags & BIT(flag); + return meta->table[index].value & BIT(flag); } static void zram_set_flag(struct zram_meta *meta, u32 index, enum zram_pageflags flag) { - meta->table[index].flags |= BIT(flag); + meta->table[index].value |= BIT(flag); } static void zram_clear_flag(struct zram_meta *meta, u32 index, enum zram_pageflags flag) { - meta->table[index].flags &= ~BIT(flag); + meta->table[index].value &= ~BIT(flag); +} + +static size_t zram_get_obj_size(struct zram_meta *meta, u32 index) +{ + return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1); +} + +static void zram_set_obj_size(struct zram_meta *meta, + u32 index, size_t size) +{ + unsigned long flags = meta->table[index].value >> ZRAM_FLAG_SHIFT; + + meta->table[index].value = (flags << ZRAM_FLAG_SHIFT) | size; } static inline int is_partial_io(struct bio_vec *bvec) @@ -240,8 +250,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); } @@ -253,22 +261,11 @@ static struct zram_meta *zram_meta_alloc(u64 disksize) if (!meta) goto out; - meta->compress_workmem = kzalloc(WMSIZE, 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 | @@ -282,10 +279,6 @@ static struct zram_meta *zram_meta_alloc(u64 disksize) 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; @@ -330,11 +323,16 @@ static void handle_zero_page(struct bio_vec *bvec) flush_dcache_page(page); } + +/* + * To protect concurrent access to the same index entry, + * caller should hold this table index entry's bit_spinlock to + * indicate this index entry is accessing. + */ 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)) { /* @@ -343,51 +341,50 @@ 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); - zram->stats.pages_zero--; + atomic64_dec(&zram->stats.zero_pages); } return; } - if (unlikely(size > max_zpage_size)) - zram->stats.bad_compress--; - zs_free(meta->mem_pool, handle); - if (size <= PAGE_SIZE / 2) - zram->stats.good_compress--; - - atomic64_sub(meta->table[index].size, &zram->stats.compr_size); - zram->stats.pages_stored--; + atomic64_sub(zram_get_obj_size(meta, index), + &zram->stats.compr_data_size); + atomic64_dec(&zram->stats.pages_stored); meta->table[index].handle = 0; - meta->table[index].size = 0; + zram_set_obj_size(meta, index, 0); } static int zram_decompress_page(struct zram *zram, char *mem, u32 index) { int ret = 0; - size_t clen = PAGE_SIZE; unsigned char *cmem; struct zram_meta *meta = zram->meta; - unsigned long handle = meta->table[index].handle; + unsigned long handle; + size_t size; + + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + handle = meta->table[index].handle; + size = zram_get_obj_size(meta, index); if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) { + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); clear_page(mem); return 0; } cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO); - if (meta->table[index].size == PAGE_SIZE) + if (size == PAGE_SIZE) copy_page(mem, cmem); else - ret = DECOMPRESS(cmem, meta->table[index].size, - mem, &clen); + ret = zcomp_decompress(zram->comp, cmem, size, mem); zs_unmap_object(meta->mem_pool, handle); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); /* Should NEVER happen. Return bio error if it does. */ if (unlikely(ret)) { pr_err("Decompression failed! err=%d, page=%u\n", ret, index); - atomic64_inc(&zram->stats.failed_reads); return ret; } @@ -403,11 +400,14 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, struct zram_meta *meta = zram->meta; page = bvec->bv_page; + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); if (unlikely(!meta->table[index].handle) || zram_test_flag(meta, index, ZRAM_ZERO)) { + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); handle_zero_page(bvec); return 0; } + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); if (is_partial_io(bvec)) /* Use a temporary buffer to decompress the page */ @@ -450,11 +450,11 @@ 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; static unsigned long zram_rs_time; 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 @@ -470,6 +470,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, goto out; } + zstrm = zcomp_strm_find(zram->comp); + locked = true; user_mem = kmap_atomic(page); if (is_partial_io(bvec)) { @@ -484,35 +486,30 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, if (page_zero_filled(uncmem)) { kunmap_atomic(user_mem); /* Free memory associated with this sector now. */ + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); zram_free_page(zram, index); - - zram->stats.pages_zero++; zram_set_flag(meta, index, ZRAM_ZERO); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + + atomic64_inc(&zram->stats.zero_pages); ret = 0; goto out; } - /* - * zram_slot_free_notify could miss free so that let's - * double check. - */ - if (unlikely(meta->table[index].handle || - zram_test_flag(meta, index, ZRAM_ZERO))) - zram_free_page(zram, index); - - COMPRESS(user_mem, 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)) { + pr_err("Compression failed! err=%d\n", ret); + goto out; + } + src = zstrm->buffer; if (unlikely(clen > max_zpage_size)) { - zram->stats.bad_compress++; clen = PAGE_SIZE; - src = NULL; if (is_partial_io(bvec)) src = uncmem; } @@ -536,82 +533,106 @@ 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); /* * Free memory associated with this sector * before overwriting unused sectors. */ + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); zram_free_page(zram, index); meta->table[index].handle = handle; - meta->table[index].size = clen; + zram_set_obj_size(meta, index, clen); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); /* Update stats */ - atomic64_add(clen, &zram->stats.compr_size); - zram->stats.pages_stored++; - if (clen <= PAGE_SIZE / 2) - zram->stats.good_compress++; - + atomic64_add(clen, &zram->stats.compr_data_size); + atomic64_inc(&zram->stats.pages_stored); out: + if (locked) + zcomp_strm_release(zram->comp, zstrm); if (is_partial_io(bvec)) kfree(uncmem); - - if (ret) - atomic64_inc(&zram->stats.failed_writes); return ret; } -static void handle_pending_slot_free(struct zram *zram) -{ - struct zram_slot_free *free_rq; - - spin_lock(&zram->slot_free_lock); - while (zram->slot_free_rq) { - free_rq = zram->slot_free_rq; - zram->slot_free_rq = free_rq->next; - zram_free_page(zram, free_rq->index); - kfree(free_rq); - } - spin_unlock(&zram->slot_free_lock); -} - 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) { - down_read(&zram->lock); - handle_pending_slot_free(zram); + atomic64_inc(&zram->stats.num_reads); ret = zram_bvec_read(zram, bvec, index, offset, bio); - up_read(&zram->lock); } else { - down_write(&zram->lock); - handle_pending_slot_free(zram); + atomic64_inc(&zram->stats.num_writes); ret = zram_bvec_write(zram, bvec, index, offset); - up_write(&zram->lock); + } + + if (unlikely(ret)) { + if (rw == READ) + atomic64_inc(&zram->stats.failed_reads); + else + atomic64_inc(&zram->stats.failed_writes); } 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_size; + struct zram_meta *meta = zram->meta; + + /* + * 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 <= (PAGE_SIZE - offset)) + return; + + n -= (PAGE_SIZE - offset); + index++; + } + + while (n >= PAGE_SIZE) { + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + zram_free_page(zram, index); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + index++; + n -= PAGE_SIZE; + } +} + static void zram_reset_device(struct zram *zram, bool reset_capacity) { size_t index; struct zram_meta *meta; - flush_work(&zram->free_work); - 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; @@ -621,6 +642,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 */ @@ -629,40 +653,26 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity) zram->disksize = 0; if (reset_capacity) set_capacity(zram->disk, 0); - 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; + up_write(&zram->init_lock); - pr_debug("Initialization done!\n"); + /* + * Revalidate disk out of the init_lock to avoid lockdep splat. + * It's okay because disk's capacity is protected by init_lock + * so that revalidate_disk always sees up-to-date capacity. + */ + if (reset_capacity) + revalidate_disk(zram->disk); } 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) @@ -670,20 +680,45 @@ static ssize_t disksize_store(struct device *dev, disksize = PAGE_ALIGN(disksize); 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); + /* + * Revalidate disk out of the init_lock to avoid lockdep splat. + * It's okay because disk's capacity is protected by init_lock + * so that revalidate_disk always sees up-to-date capacity. + */ + revalidate_disk(zram->disk); + 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, @@ -727,24 +762,21 @@ static ssize_t reset_store(struct device *dev, 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 i, offset; u32 index; struct bio_vec *bvec; - switch (rw) { - case READ: - atomic64_inc(&zram->stats.num_reads); - break; - case WRITE: - atomic64_inc(&zram->stats.num_writes); - break; - } - index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; offset = (bio->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, i) { int max_transfer_size = PAGE_SIZE - offset; @@ -759,16 +791,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); @@ -790,7 +821,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)) { @@ -798,7 +829,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; @@ -808,40 +839,19 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio) bio_io_error(bio); } -static void zram_slot_free(struct work_struct *work) -{ - struct zram *zram; - - zram = container_of(work, struct zram, free_work); - down_write(&zram->lock); - handle_pending_slot_free(zram); - up_write(&zram->lock); -} - -static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq) -{ - spin_lock(&zram->slot_free_lock); - free_rq->next = zram->slot_free_rq; - zram->slot_free_rq = free_rq; - spin_unlock(&zram->slot_free_lock); -} - static void zram_slot_free_notify(struct block_device *bdev, unsigned long index) { struct zram *zram; - struct zram_slot_free *free_rq; + struct zram_meta *meta; zram = bdev->bd_disk->private_data; - atomic64_inc(&zram->stats.notify_free); - - free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC); - if (!free_rq) - return; + meta = zram->meta; - free_rq->index = index; - add_slot_free(zram, free_rq); - schedule_work(&zram->free_work); + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + zram_free_page(zram, index); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + atomic64_inc(&zram->stats.notify_free); } static const struct block_device_operations zram_devops = { @@ -853,14 +863,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, @@ -868,12 +885,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, }; @@ -885,13 +906,8 @@ static int create_device(struct zram *zram, int device_id) { int ret = -ENOMEM; - init_rwsem(&zram->lock); init_rwsem(&zram->init_lock); - INIT_WORK(&zram->free_work, zram_slot_free); - spin_lock_init(&zram->slot_free_lock); - zram->slot_free_rq = NULL; - zram->queue = blk_alloc_queue(GFP_KERNEL); if (!zram->queue) { pr_err("Error allocating disk queue for device %d\n", @@ -919,7 +935,8 @@ static int create_device(struct zram *zram, int device_id) /* Actual capacity set using syfs (/sys/block/zram/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. @@ -929,6 +946,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); @@ -938,8 +970,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: @@ -956,13 +989,10 @@ static void destroy_device(struct zram *zram) sysfs_remove_group(&disk_to_dev(zram->disk)->kobj, &zram_disk_attr_group); - if (zram->disk) { - del_gendisk(zram->disk); - put_disk(zram->disk); - } + del_gendisk(zram->disk); + put_disk(zram->disk); - if (zram->queue) - blk_cleanup_queue(zram->queue); + blk_cleanup_queue(zram->queue); } static int __init zram_init(void) diff --git a/drivers/staging/zram/zram_drv.h b/drivers/block/zram/zram_drv.h similarity index 61% rename from drivers/staging/zram/zram_drv.h rename to drivers/block/zram/zram_drv.h index 78464562..b3b68acc 100644 --- a/drivers/staging/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -2,6 +2,7 @@ * Compressed RAM block device * * Copyright (C) 2008, 2009, 2010 Nitin Gupta + * 2012, 2013 Minchan Kim * * This code is released using a dual license strategy: BSD/GPL * You can choose the licence that better fits your requirements. @@ -9,16 +10,15 @@ * Released under the terms of 3-clause BSD License * Released under the terms of GNU General Public License Version 2.0 * - * Project home: http://compcache.googlecode.com */ #ifndef _ZRAM_DRV_H_ #define _ZRAM_DRV_H_ #include -#include +#include -#include "../zsmalloc/zsmalloc.h" +#include "zcomp.h" /* * Some arbitrary value. This is just to catch @@ -43,7 +43,6 @@ static const size_t max_zpage_size = PAGE_SIZE / 10 * 9; /*-- End of configurable params */ #define SECTOR_SHIFT 9 -#define SECTOR_SIZE (1 << SECTOR_SHIFT) #define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) #define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT) #define ZRAM_LOGICAL_BLOCK_SHIFT 12 @@ -51,10 +50,24 @@ static const size_t max_zpage_size = PAGE_SIZE / 10 * 9; #define ZRAM_SECTOR_PER_LOGICAL_BLOCK \ (1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT)) -/* Flags for zram pages (table[page_no].flags) */ + +/* + * The lower ZRAM_FLAG_SHIFT bits of table.value is for + * object size (excluding header), the higher bits is for + * zram_pageflags. + * + * zram is mainly used for memory efficiency so we want to keep memory + * footprint small so we can squeeze size and flags into a field. + * The lower ZRAM_FLAG_SHIFT bits is for object size (excluding header), + * the higher bits is for zram_pageflags. + */ +#define ZRAM_FLAG_SHIFT 24 + +/* Flags for zram pages (table[page_no].value) */ enum zram_pageflags { /* Page consists entirely of zeros */ - ZRAM_ZERO, + ZRAM_ZERO = ZRAM_FLAG_SHIFT + 1, + ZRAM_ACCESS, /* page in now accessed */ __NR_ZRAM_PAGEFLAGS, }; @@ -62,55 +75,34 @@ enum zram_pageflags { /*-- Data structures */ /* Allocated for each disk page */ -struct table { +struct zram_table_entry { unsigned long handle; - u16 size; /* object size (excluding header) */ - u8 count; /* object ref count (not yet used) */ - u8 flags; -} __aligned(4); + unsigned long value; +}; -/* - * All 64bit fields should only be manipulated by 64bit atomic accessors. - * All modifications to 32bit counter should be protected by zram->lock. - */ 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_reads; /* can happen when memory is too low */ 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 */ - u32 pages_zero; /* no. of zero filled pages */ - u32 pages_stored; /* no. of pages currently stored */ - u32 good_compress; /* % of pages with compression ratio<=50% */ - u32 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 { - void *compress_workmem; - void *compress_buffer; - struct table *table; + struct zram_table_entry *table; struct zs_pool *mem_pool; }; -struct zram_slot_free { - unsigned long index; - struct zram_slot_free *next; -}; - struct zram { struct zram_meta *meta; - struct rw_semaphore lock; /* protect compression buffers, table, - * 32bit stat counters against concurrent - * notifications, reads and writes */ - - struct work_struct free_work; /* handle pending free request */ - struct zram_slot_free *slot_free_rq; /* list head of free request */ - 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; /* @@ -118,9 +110,8 @@ struct zram { * we can store in a disk. */ u64 disksize; /* bytes */ - spinlock_t slot_free_lock; - + int max_comp_streams; struct zram_stats stats; + char compressor[10]; }; #endif - diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index ea1c27a3..fcf49012 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -266,4 +266,11 @@ config BT_WILINK Say Y here to compile support for Texas Instrument's WiLink7 driver into the kernel or say M to compile it as module. + +config HUAWEI_BT_WCN2243 + bool "Qualcomm WCN2243 Bluetooth" + default y + help + Select Y to use Qualcomm's BlueZ stack. Used by WCN2243. Not used in Huawei devices. + endmenu diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 497abe16..43447a2a 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -61,57 +61,17 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3000) }, /* Atheros AR3011 with sflash firmware*/ - { USB_DEVICE(0x0489, 0xE027) }, - { USB_DEVICE(0x0489, 0xE03D) }, - { USB_DEVICE(0x04F2, 0xAFF1) }, - { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0CF3, 0x3002) }, - { USB_DEVICE(0x0CF3, 0xE019) }, - { USB_DEVICE(0x13d3, 0x3304) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, /* Atheros AR3012 with sflash firmware*/ - { USB_DEVICE(0x0489, 0xe04d) }, - { USB_DEVICE(0x0489, 0xe04e) }, - { USB_DEVICE(0x0489, 0xe057) }, - { USB_DEVICE(0x0489, 0xe056) }, - { USB_DEVICE(0x0489, 0xe078) }, - { USB_DEVICE(0x04c5, 0x1330) }, - { USB_DEVICE(0x04CA, 0x3004) }, - { USB_DEVICE(0x04CA, 0x3005) }, - { USB_DEVICE(0x04CA, 0x3006) }, - { USB_DEVICE(0x04CA, 0x3008) }, - { USB_DEVICE(0x04CA, 0x3010) }, - { USB_DEVICE(0x0930, 0x0219) }, - { USB_DEVICE(0x0930, 0x0227) }, - { USB_DEVICE(0x0b05, 0x17d0) }, - { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, - { USB_DEVICE(0x0CF3, 0x3008) }, - { USB_DEVICE(0x0CF3, 0x311D) }, - { USB_DEVICE(0x0cf3, 0x3121) }, - { USB_DEVICE(0x0CF3, 0x817a) }, - { USB_DEVICE(0x0cf3, 0xe003) }, - { USB_DEVICE(0x0CF3, 0xE004) }, - { USB_DEVICE(0x0CF3, 0xE005) }, - { USB_DEVICE(0x13d3, 0x3362) }, - { USB_DEVICE(0x13d3, 0x3375) }, - { USB_DEVICE(0x13d3, 0x3393) }, - { USB_DEVICE(0x13d3, 0x3402) }, - { USB_DEVICE(0x13d3, 0x3408) }, - { USB_DEVICE(0x13d3, 0x3423) }, - { USB_DEVICE(0x13d3, 0x3432) }, - { USB_DEVICE(0x13d3, 0x3474) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, - /* Atheros AR5BBU22 with sflash firmware */ - { USB_DEVICE(0x0489, 0xE036) }, - { USB_DEVICE(0x0489, 0xE03C) }, - { } /* Terminating entry */ }; @@ -123,41 +83,7 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); static struct usb_device_id ath3k_blist_tbl[] = { /* Atheros AR3012 with sflash firmware*/ - { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 }, - - /* Atheros AR5BBU22 with sflash firmware */ - { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 }, { } /* Terminating entry */ }; diff --git a/drivers/bluetooth/bluesleep.c b/drivers/bluetooth/bluesleep.c index 6dc98624..a7f14ff5 100644 --- a/drivers/bluetooth/bluesleep.c +++ b/drivers/bluetooth/bluesleep.c @@ -1,3 +1,4 @@ +#if (defined(CONFIG_HUAWEI_BT_BCM43XX) && defined(CONFIG_HUAWEI_KERNEL)) /* This program is free software; you can redistribute it and/or modify @@ -15,7 +16,7 @@ Copyright (C) 2006-2007 - Motorola - Copyright (c) 2008-2010, The Linux Foundation. All rights reserved. + Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. Date Author Comment ----------- -------------- -------------------------------- @@ -44,7 +45,7 @@ #include #include #include -#include +#include #include #include @@ -133,7 +134,837 @@ struct proc_dir_entry *bluetooth_dir, *sleep_dir; static void hsuart_power(int on) { - if (on) { + if(NULL == bsi->uport) + { + BT_ERR("bsi->uport is null"); + return; + } + if (on) { + msm_hs_request_clock_on(bsi->uport); + msm_hs_set_mctrl(bsi->uport, TIOCM_RTS); + } else { + msm_hs_set_mctrl(bsi->uport, 0); + msm_hs_request_clock_off(bsi->uport); + } +} + + +void bluesleep_uart_open(struct uart_port *uport) +{ + BT_DBG("bluesleep_uart_open"); + if(bsi->uport == NULL) { + BT_DBG("bluesleep_uart_open done"); + bsi->uport = uport; + } +} + + +void bluesleep_uart_close(struct uart_port *uport) +{ + BT_DBG("bluesleep_uart_close"); + if(bsi->uport == uport) { + BT_DBG("bluesleep_uart_close done"); + bsi->uport = NULL; + } +} + +/** + * @return 1 if the Host can go to sleep, 0 otherwise. + */ +static inline int bluesleep_can_sleep(void) +{ + /* check if MSM_WAKE_BT_GPIO and BT_WAKE_MSM_GPIO are both deasserted */ + return gpio_get_value(bsi->ext_wake) && + gpio_get_value(bsi->host_wake) && + (bsi->uport != NULL); +} + +void bluesleep_sleep_wakeup(void) +{ + if (test_bit(BT_ASLEEP, &flags)) { + BT_DBG("waking up..."); + /* Start the timer */ + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + gpio_set_value(bsi->ext_wake, 0); + clear_bit(BT_ASLEEP, &flags); + /*Activating UART */ + hsuart_power(1); + } + #ifdef CONFIG_HUAWEI_KERNEL + else + { + /*Tx idle, Rx busy, we must also make host_wake asserted, that is low + * 1 means bt chip can sleep, in bluesleep.c + */ + /* Here we depend on the status of MSM gpio, for stability */ + if(1 == gpio_get_value(bsi->ext_wake)) + { + printk(KERN_ERR "-bluesleep_sleep_wakeup wakeup bt chip\n"); + /*0 means wakup bt chip */ + gpio_set_value(bsi->ext_wake, 0); + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + } + } + #endif +} + +/** + * @brief@ main sleep work handling function which update the flags + * and activate and deactivate UART ,check FIFO. + */ +static void bluesleep_sleep_work(struct work_struct *work) +{ + if (bluesleep_can_sleep()) { + /* already asleep, this is an error case */ + if (test_bit(BT_ASLEEP, &flags)) { + BT_DBG("already asleep"); + return; + } + + if (msm_hs_tx_empty(bsi->uport)) { + BT_DBG("going to sleep..."); + set_bit(BT_ASLEEP, &flags); + /*Deactivating UART */ + hsuart_power(0); + } else { + + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + return; + } + } else if(gpio_get_value(bsi->ext_wake) && !test_bit(BT_ASLEEP, &flags)){ + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + gpio_set_value(bsi->ext_wake, 0); + } else { + bluesleep_sleep_wakeup(); + } +} + +/** + * A tasklet function that runs in tasklet context and reads the value + * of the HOST_WAKE GPIO pin and further defer the work. + * @param data Not used. + */ +static void bluesleep_hostwake_task(unsigned long data) +{ + BT_DBG("hostwake line change"); + + spin_lock(&rw_lock); + + if (gpio_get_value(bsi->host_wake)) + bluesleep_rx_busy(); + else + bluesleep_rx_idle(); + + spin_unlock(&rw_lock); +} + +/** + * Handles proper timer action when outgoing data is delivered to the + * HCI line discipline. Sets BT_TXDATA. + */ +void bluesleep_outgoing_data(void) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&rw_lock, irq_flags); + + /* log data passing by */ + set_bit(BT_TXDATA, &flags); + + /* if the tx side is sleeping... */ + if (gpio_get_value(bsi->ext_wake)) { + + BT_DBG("tx was sleeping"); + bluesleep_sleep_wakeup(); + } + + spin_unlock_irqrestore(&rw_lock, irq_flags); +} + +/** + * Handles HCI device events. + * @param this Not used. + * @param event The event that occurred. + * @param data The HCI device associated with the event. + * @return NOTIFY_DONE. + */ +static int bluesleep_hci_event(struct notifier_block *this, + unsigned long event, void *data) +{ + struct hci_dev *hdev = (struct hci_dev *) data; + struct hci_uart *hu; + struct uart_state *state; + + if (!hdev) + return NOTIFY_DONE; + + switch (event) { + case HCI_DEV_REG: + if (!bluesleep_hdev) { + bluesleep_hdev = hdev; + hu = (struct hci_uart *) hdev->driver_data; + state = (struct uart_state *) hu->tty->driver_data; + bsi->uport = state->uart_port; + } + break; + case HCI_DEV_UNREG: + bluesleep_hdev = NULL; + bsi->uport = NULL; + break; + case HCI_DEV_WRITE: + bluesleep_outgoing_data(); + break; + } + + return NOTIFY_DONE; +} + +/** + * Handles transmission timer expiration. + * @param data Not used. + */ +static void bluesleep_tx_timer_expire(unsigned long data) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&rw_lock, irq_flags); + + BT_DBG("Tx timer expired"); + + /* were we silent during the last timeout? */ + if (!test_bit(BT_TXDATA, &flags)) { + BT_DBG("Tx has been idle"); + gpio_set_value(bsi->ext_wake, 1); + bluesleep_tx_idle(); + } else { + BT_DBG("Tx data during last period"); + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL*HZ)); + } + + /* clear the incoming data flag */ + clear_bit(BT_TXDATA, &flags); + + spin_unlock_irqrestore(&rw_lock, irq_flags); +} + +/** + * Schedules a tasklet to run when receiving an interrupt on the + * HOST_WAKE GPIO pin. + * @param irq Not used. + * @param dev_id Not used. + */ +static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id) +{ + /* schedule a tasklet to handle the change in the host wake line */ + tasklet_schedule(&hostwake_task); + return IRQ_HANDLED; +} + +/** + * Starts the Sleep-Mode Protocol on the Host. + * @return On success, 0. On error, -1, and errno is set + * appropriately. + */ +static int bluesleep_start(void) +{ + int retval; + unsigned long irq_flags; + + spin_lock_irqsave(&rw_lock, irq_flags); + + if (test_bit(BT_PROTO, &flags)) { + spin_unlock_irqrestore(&rw_lock, irq_flags); + return 0; + } + + spin_unlock_irqrestore(&rw_lock, irq_flags); + + if (!atomic_dec_and_test(&open_count)) { + atomic_inc(&open_count); + return -EBUSY; + } + + /* start the timer */ + + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL*HZ)); + + /* assert BT_WAKE */ + gpio_set_value(bsi->ext_wake, 0); +/* add RISING condition to invoke MSM7230 to update the SLEEP FLAG */ +#ifndef CONFIG_HUAWEI_KERNEL + retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "bluetooth hostwake", NULL); +#else + retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr, + IRQF_DISABLED | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "bluetooth hostwake", NULL); +#endif + if (retval < 0) { + BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ"); + goto fail; + } + + retval = enable_irq_wake(bsi->host_wake_irq); + if (retval < 0) { + BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt"); + free_irq(bsi->host_wake_irq, NULL); + goto fail; + } + + set_bit(BT_PROTO, &flags); + return 0; +fail: + del_timer(&tx_timer); + atomic_inc(&open_count); + + return retval; +} + +/** + * Stops the Sleep-Mode Protocol on the Host. + */ +static void bluesleep_stop(void) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&rw_lock, irq_flags); + + if (!test_bit(BT_PROTO, &flags)) { + spin_unlock_irqrestore(&rw_lock, irq_flags); + return; + } + + /* assert BT_WAKE */ + gpio_set_value(bsi->ext_wake, 0); + del_timer(&tx_timer); + clear_bit(BT_PROTO, &flags); + + if (test_bit(BT_ASLEEP, &flags)) { + clear_bit(BT_ASLEEP, &flags); + hsuart_power(1); + } + + atomic_inc(&open_count); + + spin_unlock_irqrestore(&rw_lock, irq_flags); + if (disable_irq_wake(bsi->host_wake_irq)) + BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n"); + free_irq(bsi->host_wake_irq, NULL); +} +/** + * Read the BT_WAKE GPIO pin value via the proc interface. + * When this function returns, page will contain a 1 if the + * pin is high, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluepower_read_proc_btwake(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "btwake:%u\n", gpio_get_value(bsi->ext_wake)); +} + +/** + * Write the BT_WAKE GPIO pin value via the proc interface. + * @param file Not used. + * @param buffer The buffer to read from. + * @param count The number of bytes to be written. + * @param data Not used. + * @return On success, the number of bytes written. On error, -1, and + * errno is set appropriately. + */ +static int bluepower_write_proc_btwake(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char *buf; + + if (count < 1) + return -EINVAL; + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, buffer, count)) { + kfree(buf); + return -EFAULT; + } + + if (buf[0] == '0') { + gpio_set_value(bsi->ext_wake, 0); + } else if (buf[0] == '1') { + gpio_set_value(bsi->ext_wake, 1); + } else { + kfree(buf); + return -EINVAL; + } + + kfree(buf); + return count; +} + +/** + * Read the BT_HOST_WAKE GPIO pin value via the proc interface. + * When this function returns, page will contain a 1 if the pin + * is high, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluepower_read_proc_hostwake(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "hostwake: %u \n", gpio_get_value(bsi->host_wake)); +} + + +/** + * Read the low-power status of the Host via the proc interface. + * When this function returns, page contains a 1 if the Host + * is asleep, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluesleep_read_proc_asleep(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + unsigned int asleep; + + asleep = test_bit(BT_ASLEEP, &flags) ? 1 : 0; + *eof = 1; + return sprintf(page, "asleep: %u\n", asleep); +} + +/** + * Read the low-power protocol being used by the Host via the proc interface. + * When this function returns, page will contain a 1 if the Host + * is using the Sleep Mode Protocol, 0 otherwise. + * @param page Buffer for writing data. + * @param start Not used. + * @param offset Not used. + * @param count Not used. + * @param eof Whether or not there is more data to be read. + * @param data Not used. + * @return The number of bytes written. + */ +static int bluesleep_read_proc_proto(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + unsigned int proto; + + proto = test_bit(BT_PROTO, &flags) ? 1 : 0; + *eof = 1; + return sprintf(page, "proto: %u\n", proto); +} + +/** + * Modify the low-power protocol used by the Host via the proc interface. + * @param file Not used. + * @param buffer The buffer to read from. + * @param count The number of bytes to be written. + * @param data Not used. + * @return On success, the number of bytes written. On error, -1, and + * errno is set appropriately. + */ +static int bluesleep_write_proc_proto(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char proto; + + if (count < 1) + return -EINVAL; + + if (copy_from_user(&proto, buffer, 1)) + return -EFAULT; + + if (proto == '0') + bluesleep_stop(); + else + bluesleep_start(); + + /* claim that we wrote everything */ + return count; +} + +static int __init bluesleep_probe(struct platform_device *pdev) +{ + int ret; + struct resource *res; + + bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL); + if (!bsi) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, + "gpio_host_wake"); + if (!res) { + BT_ERR("couldn't find host_wake gpio\n"); + ret = -ENODEV; + goto free_bsi; + } + bsi->host_wake = res->start; + + ret = gpio_request(bsi->host_wake, "bt_host_wake"); + if (ret) + goto free_bsi; + ret = gpio_direction_input(bsi->host_wake); + if (ret) + goto free_bt_host_wake; + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, + "gpio_ext_wake"); + if (!res) { + BT_ERR("couldn't find ext_wake gpio\n"); + ret = -ENODEV; + goto free_bt_host_wake; + } + bsi->ext_wake = res->start; + + ret = gpio_request(bsi->ext_wake, "bt_ext_wake"); + if (ret) + goto free_bt_host_wake; + /* assert bt wake */ + ret = gpio_direction_output(bsi->ext_wake, 0); + if (ret) + goto free_bt_ext_wake; + + bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake"); + if ((int)bsi->host_wake_irq < 0) { + BT_ERR("couldn't find host_wake irq\n"); + ret = -ENODEV; + goto free_bt_ext_wake; + } + + + return 0; + +free_bt_ext_wake: + gpio_free(bsi->ext_wake); +free_bt_host_wake: + gpio_free(bsi->host_wake); +free_bsi: + kfree(bsi); + return ret; +} + +static int bluesleep_remove(struct platform_device *pdev) +{ + /* assert bt wake */ + gpio_set_value(bsi->ext_wake, 0); + if (test_bit(BT_PROTO, &flags)) { + if (disable_irq_wake(bsi->host_wake_irq)) + BT_ERR("Couldn't disable hostwake IRQ wakeup mode \n"); + free_irq(bsi->host_wake_irq, NULL); + del_timer(&tx_timer); + if (test_bit(BT_ASLEEP, &flags)) + hsuart_power(1); + } + + gpio_free(bsi->host_wake); + gpio_free(bsi->ext_wake); + kfree(bsi); + return 0; +} + +static struct platform_driver bluesleep_driver = { + .remove = bluesleep_remove, + .driver = { + .name = "bluesleep", + .owner = THIS_MODULE, + }, +}; +/** + * Initializes the module. + * @return On success, 0. On error, -1, and errno is set + * appropriately. + */ +static int __init bluesleep_init(void) +{ + int retval; + struct proc_dir_entry *ent; + + BT_INFO("MSM Sleep Mode Driver Ver %s", VERSION); + + retval = platform_driver_probe(&bluesleep_driver, bluesleep_probe); + if (retval) + return retval; + + bluesleep_hdev = NULL; + + bluetooth_dir = proc_mkdir("bluetooth", NULL); + if (bluetooth_dir == NULL) { + BT_ERR("Unable to create /proc/bluetooth directory"); + return -ENOMEM; + } + + sleep_dir = proc_mkdir("sleep", bluetooth_dir); + if (sleep_dir == NULL) { + BT_ERR("Unable to create /proc/%s directory", PROC_DIR); + return -ENOMEM; + } + + /* Creating read/write "btwake" entry */ + ent = create_proc_entry("btwake", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/btwake entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluepower_read_proc_btwake; + ent->write_proc = bluepower_write_proc_btwake; + + /* read only proc entries */ + if (create_proc_read_entry("hostwake", 0, sleep_dir, + bluepower_read_proc_hostwake, NULL) == NULL) { + BT_ERR("Unable to create /proc/%s/hostwake entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + + /* read/write proc entries */ + ent = create_proc_entry("proto", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/proto entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluesleep_read_proc_proto; + ent->write_proc = bluesleep_write_proc_proto; + + /* read only proc entries */ + if (create_proc_read_entry("asleep", 0, + sleep_dir, bluesleep_read_proc_asleep, NULL) == NULL) { + BT_ERR("Unable to create /proc/%s/asleep entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + + flags = 0; /* clear all status bits */ + + /* Initialize spinlock. */ + spin_lock_init(&rw_lock); + + /* Initialize timer */ + init_timer(&tx_timer); + tx_timer.function = bluesleep_tx_timer_expire; + tx_timer.data = 0; + + /* initialize host wake tasklet */ + tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0); + + hci_register_notifier(&hci_event_nblock); + + return 0; + +fail: + remove_proc_entry("asleep", sleep_dir); + remove_proc_entry("proto", sleep_dir); + remove_proc_entry("hostwake", sleep_dir); + remove_proc_entry("btwake", sleep_dir); + remove_proc_entry("sleep", bluetooth_dir); + remove_proc_entry("bluetooth", 0); + return retval; +} + +/** + * Cleans up the module. + */ +static void __exit bluesleep_exit(void) +{ + hci_unregister_notifier(&hci_event_nblock); + platform_driver_unregister(&bluesleep_driver); + + remove_proc_entry("asleep", sleep_dir); + remove_proc_entry("proto", sleep_dir); + remove_proc_entry("hostwake", sleep_dir); + remove_proc_entry("btwake", sleep_dir); + remove_proc_entry("sleep", bluetooth_dir); + remove_proc_entry("bluetooth", 0); +} + +module_init(bluesleep_init); +module_exit(bluesleep_exit); + +MODULE_DESCRIPTION("Bluetooth Sleep Mode Driver ver %s " VERSION); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +#endif +#if (defined(CONFIG_HUAWEI_BT_WCN2243) || (!defined(CONFIG_HUAWEI_KERNEL))) +/* + + 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. + + 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 + + This program is distributed in the hope that it will be useful, but + WITHOUT 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) 2006-2007 - Motorola + Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + + Date Author Comment + ----------- -------------- -------------------------------- + 2006-Apr-28 Motorola The kernel module for running the Bluetooth(R) + Sleep-Mode Protocol from the Host side + 2006-Sep-08 Motorola Added workqueue for handling sleep work. + 2007-Jan-24 Motorola Added mbm_handle_ioi() call to ISR. + +*/ + +#include /* kernel module definitions */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* event notifications */ +#include "hci_uart.h" + +#define BT_SLEEP_DBG +#ifndef BT_SLEEP_DBG +#define BT_DBG(fmt, arg...) +#endif +/* + * Defines + */ + +#define VERSION "1.1" +#define PROC_DIR "bluetooth/sleep" + +#ifdef CONFIG_HUAWEI_KERNEL +#define BT_BLUEDROID_SUPPORT 1 +#else +#define BT_BLUEDROID_SUPPORT 1 +#endif + +struct bluesleep_info { + unsigned host_wake; + unsigned ext_wake; + unsigned host_wake_irq; + struct uart_port *uport; +}; + +/* work function */ +static void bluesleep_sleep_work(struct work_struct *work); + +/* work queue */ +DECLARE_DELAYED_WORK(sleep_workqueue, bluesleep_sleep_work); + +/* Macros for handling sleep work */ +#define bluesleep_rx_busy() schedule_delayed_work(&sleep_workqueue, 0) +#define bluesleep_tx_busy() schedule_delayed_work(&sleep_workqueue, 0) +#define bluesleep_rx_idle() schedule_delayed_work(&sleep_workqueue, 0) +#define bluesleep_tx_idle() schedule_delayed_work(&sleep_workqueue, 0) + +/* 1 second timeout */ +#define TX_TIMER_INTERVAL 1 + +/* state variable names and bit positions */ +#define BT_PROTO 0x01 +#define BT_TXDATA 0x02 +#define BT_ASLEEP 0x04 + +#if BT_BLUEDROID_SUPPORT +static bool has_lpm_enabled = false; +#else +/* global pointer to a single hci device. */ +static struct hci_dev *bluesleep_hdev; +#endif + +static struct platform_device *bluesleep_uart_dev; +static struct bluesleep_info *bsi; + +/* module usage */ +static atomic_t open_count = ATOMIC_INIT(1); + +/* + * Local function prototypes + */ + +#if !BT_BLUEDROID_SUPPORT +static int bluesleep_hci_event(struct notifier_block *this, + unsigned long event, void *data); +#endif + +/* + * Global variables + */ + +/** Global state flags */ +static unsigned long flags; + +/** Tasklet to respond to change in hostwake line */ +static struct tasklet_struct hostwake_task; + +/** Transmission timer */ +static struct timer_list tx_timer; + +/** Lock for state transitions */ +static spinlock_t rw_lock; + +#if !BT_BLUEDROID_SUPPORT +/** Notifier block for HCI events */ +struct notifier_block hci_event_nblock = { + .notifier_call = bluesleep_hci_event, +}; +#endif + +struct proc_dir_entry *bluetooth_dir, *sleep_dir; + +/* + * Local functions + */ + +static void hsuart_power(int on) +{ + if(NULL == bsi->uport) + { + BT_ERR("bsi->uport is null"); + return; + } + if (on) { msm_hs_request_clock_on(bsi->uport); msm_hs_set_mctrl(bsi->uport, TIOCM_RTS); } else { @@ -165,6 +996,22 @@ void bluesleep_sleep_wakeup(void) /*Activating UART */ hsuart_power(1); } + #if defined(CONFIG_HUAWEI_KERNEL) || defined(CONFIG_WERITOS_KERNEL) + else + { + /*Tx idle, Rx busy, we must also make host_wake asserted, that is low + * 1 means bt chip can sleep, in bluesleep.c + */ + /* Here we depend on the status of MSM gpio, for stability */ + if(1 == gpio_get_value(bsi->ext_wake)) + { + printk(KERN_ERR "-bluesleep_sleep_wakeup wakeup bt chip\n"); + /*0 means wakup bt chip */ + gpio_set_value(bsi->ext_wake, 0); + mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ)); + } + } + #endif } /** @@ -237,6 +1084,7 @@ static void bluesleep_outgoing_data(void) spin_unlock_irqrestore(&rw_lock, irq_flags); } +#if !BT_BLUEDROID_SUPPORT /** * Handles HCI device events. * @param this Not used. @@ -274,6 +1122,7 @@ static int bluesleep_hci_event(struct notifier_block *this, return NOTIFY_DONE; } +#endif /** * Handles transmission timer expiration. @@ -346,9 +1195,16 @@ static int bluesleep_start(void) /* assert BT_WAKE */ gpio_set_value(bsi->ext_wake, 0); +/* add RISING condition to invoke MSM7230 to update the SLEEP FLAG */ +#ifndef CONFIG_HUAWEI_KERNEL + retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "bluetooth hostwake", NULL); +#else retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, + IRQF_DISABLED | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "bluetooth hostwake", NULL); +#endif if (retval < 0) { BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ"); goto fail; @@ -401,6 +1257,80 @@ static void bluesleep_stop(void) BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n"); free_irq(bsi->host_wake_irq, NULL); } + +#if BT_BLUEDROID_SUPPORT +static struct uart_port *bluesleep_get_uart_port(void) +{ + struct uart_port *uport = NULL; + if (bluesleep_uart_dev) + uport = (struct uart_port *)platform_get_drvdata(bluesleep_uart_dev); + + return uport; +} + +static int bluesleep_read_proc_lpm(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "unsupported to read\n"); +} + +static int bluesleep_write_proc_lpm(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char b; + + if (count < 1) + return -EINVAL; + + if (copy_from_user(&b, buffer, 1)) + return -EFAULT; + + if (b == '0') { + /* HCI_DEV_UNREG */ + bluesleep_stop(); + has_lpm_enabled = false; + bsi->uport = NULL; + } else { + /* HCI_DEV_REG */ + if (!has_lpm_enabled) { + has_lpm_enabled = true; + bsi->uport = bluesleep_get_uart_port(); + /* if bluetooth started, start bluesleep*/ + bluesleep_start(); + } + } + + return count; +} + +static int bluesleep_read_proc_btwrite(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + *eof = 1; + return sprintf(page, "unsupported to read\n"); +} + +static int bluesleep_write_proc_btwrite(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char b; + + if (count < 1) + return -EINVAL; + + if (copy_from_user(&b, buffer, 1)) + return -EFAULT; + + /* HCI_DEV_WRITE */ + if (b != '0') { + bluesleep_outgoing_data(); + } + + return count; +} +#endif + /** * Read the BT_WAKE GPIO pin value via the proc interface. * When this function returns, page will contain a 1 if the @@ -478,6 +1408,10 @@ static int bluepower_read_proc_hostwake(char *page, char **start, off_t offset, return sprintf(page, "hostwake: %u \n", gpio_get_value(bsi->host_wake)); } +void bluesleep_setup_uart_port(struct platform_device *uart_dev) +{ + bluesleep_uart_dev = uart_dev; +} /** * Read the low-power status of the Host via the proc interface. @@ -655,7 +1589,9 @@ static int __init bluesleep_init(void) if (retval) return retval; - bluesleep_hdev = NULL; +#if !BT_BLUEDROID_SUPPORT + bluesleep_hdev = NULL; +#endif bluetooth_dir = proc_mkdir("bluetooth", NULL); if (bluetooth_dir == NULL) { @@ -705,6 +1641,28 @@ static int __init bluesleep_init(void) goto fail; } +#if BT_BLUEDROID_SUPPORT + /* read/write proc entries */ + ent = create_proc_entry("lpm", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/lpm entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluesleep_read_proc_lpm; + ent->write_proc = bluesleep_write_proc_lpm; + + /* read/write proc entries */ + ent = create_proc_entry("btwrite", 0, sleep_dir); + if (ent == NULL) { + BT_ERR("Unable to create /proc/%s/btwrite entry", PROC_DIR); + retval = -ENOMEM; + goto fail; + } + ent->read_proc = bluesleep_read_proc_btwrite; + ent->write_proc = bluesleep_write_proc_btwrite; +#endif + flags = 0; /* clear all status bits */ /* Initialize spinlock. */ @@ -718,11 +1676,17 @@ static int __init bluesleep_init(void) /* initialize host wake tasklet */ tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0); +#if !BT_BLUEDROID_SUPPORT hci_register_notifier(&hci_event_nblock); +#endif return 0; fail: +#if BT_BLUEDROID_SUPPORT + remove_proc_entry("btwrite", sleep_dir); + remove_proc_entry("lpm", sleep_dir); +#endif remove_proc_entry("asleep", sleep_dir); remove_proc_entry("proto", sleep_dir); remove_proc_entry("hostwake", sleep_dir); @@ -737,9 +1701,15 @@ static int __init bluesleep_init(void) */ static void __exit bluesleep_exit(void) { +#if !BT_BLUEDROID_SUPPORT hci_unregister_notifier(&hci_event_nblock); +#endif platform_driver_unregister(&bluesleep_driver); +#if BT_BLUEDROID_SUPPORT + remove_proc_entry("btwrite", sleep_dir); + remove_proc_entry("lpm", sleep_dir); +#endif remove_proc_entry("asleep", sleep_dir); remove_proc_entry("proto", sleep_dir); remove_proc_entry("hostwake", sleep_dir); @@ -755,3 +1725,4 @@ MODULE_DESCRIPTION("Bluetooth Sleep Mode Driver ver %s " VERSION); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif +#endif diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 718df024..3bf49d1b 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2010, 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 diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 650d7b30..66e5544b 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -55,7 +55,6 @@ static struct usb_driver btusb_driver; #define BTUSB_BROKEN_ISOC 0x20 #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 -#define BTUSB_INTEL_BOOT 0x200 static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -64,9 +63,6 @@ static struct usb_device_id btusb_table[] = { /* Apple-specific (Broadcom) devices */ { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) }, - /* MediaTek MT76x0E */ - { USB_DEVICE(0x0e8d, 0x763f) }, - /* Broadcom SoftSailing reporting vendor specific */ { USB_DEVICE(0x05ac, 0x21e1) }, @@ -107,26 +103,6 @@ static struct usb_device_id btusb_table[] = { /* Canyon CN-BTU1 with HID interfaces */ { USB_DEVICE(0x0c10, 0x0000) }, - /* Broadcom BCM20702A0 */ - { USB_DEVICE(0x0489, 0xe042) }, - { USB_DEVICE(0x04ca, 0x2003) }, - { USB_DEVICE(0x0b05, 0x17b5) }, - { USB_DEVICE(0x0b05, 0x17cb) }, - { USB_DEVICE(0x413c, 0x8197) }, - - /* Foxconn - Hon Hai */ - { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, - - /* Broadcom devices with vendor specific id */ - { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, - - /* ASUSTek Computer - Broadcom based */ - { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01) }, - - /* Intel Bluetooth USB Bootloader (RAM module) */ - { USB_DEVICE(0x8087, 0x0a5a), - .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC }, - { } /* Terminating entry */ }; @@ -140,61 +116,21 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE }, /* Atheros 3011 with sflash firmware */ - { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x04f2, 0xaff1), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, /* Atheros 3012 with sflash firmware */ - { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, - /* Atheros AR5BBU12 with sflash firmware */ - { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, - /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, /* Broadcom BCM2045 */ { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU }, @@ -1075,9 +1011,6 @@ static int btusb_probe(struct usb_interface *intf, hdev->owner = THIS_MODULE; - if (id->driver_info & BTUSB_INTEL_BOOT) - set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); - /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index 65d27aff..e4c1edd2 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -22,8 +22,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#define DEBUG +#include #include +#include #include #include #include @@ -113,7 +114,7 @@ static long st_receive(void *priv_data, struct sk_buff *skb) err = hci_recv_frame(skb); if (err < 0) { BT_ERR("Unable to push skb to HCI core(%d)", err); - return err; + return 0; } lhst->hdev->stat.byte_rx += skb->len; diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index da4cfb00..2fcd8b38 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -2,7 +2,7 @@ * * Bluetooth HCI UART driver * - * Copyright (C) 2000-2001 Qualcomm Technologies, Inc. + * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2004-2005 Marcel Holtmann * diff --git a/drivers/bluetooth/hci_ibs.c b/drivers/bluetooth/hci_ibs.c index 84b253ba..33d210c1 100644 --- a/drivers/bluetooth/hci_ibs.c +++ b/drivers/bluetooth/hci_ibs.c @@ -5,7 +5,7 @@ * protocol extension to H4. * * Copyright (C) 2007 Texas Instruments, Inc. - * Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2010, 2012 Code Aurora Forum. All rights reserved. * * Acknowledgements: * This file is based on hci_ll.c, which was... @@ -745,7 +745,7 @@ static inline int ibs_check_data_len(struct ibs_struct *ibs, int len) static int ibs_recv(struct hci_uart *hu, void *data, int count) { struct ibs_struct *ibs = hu->priv; - register char *ptr; + register unsigned char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index f094df3a..d1bc1e9b 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -4,7 +4,7 @@ * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2004-2005 Marcel Holtmann - * Copyright (c) 2000-2001, 2010-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2000-2001, 2010-2012, Code Aurora Forum. All rights reserved. * * * This program is free software; you can redistribute it and/or modify @@ -121,6 +121,10 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { + struct tty_struct *tty = hu->tty; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; @@ -128,22 +132,6 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) BT_DBG(""); - schedule_work(&hu->write_work); - - return 0; -} - -static void hci_uart_write_work(struct work_struct *work) -{ - struct hci_uart *hu = container_of(work, struct hci_uart, write_work); - struct tty_struct *tty = hu->tty; - struct hci_dev *hdev = hu->hdev; - struct sk_buff *skb; - - /* REVISIT: should we cope with bad skbs or ->write() returning - * and error value ? - */ - restart: clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); @@ -168,6 +156,7 @@ static void hci_uart_write_work(struct work_struct *work) goto restart; clear_bit(HCI_UART_SENDING, &hu->tx_state); + return 0; } /* ------- Interface to HCI layer ------ */ @@ -287,8 +276,6 @@ static int hci_uart_tty_open(struct tty_struct *tty) hu->tty = tty; tty->receive_room = 65536; - INIT_WORK(&hu->write_work, hci_uart_write_work); - spin_lock_init(&hu->rx_lock); tasklet_init(&hu->tty_wakeup_task, hci_uart_tty_wakeup_action, (unsigned long)hu); @@ -327,8 +314,6 @@ static void hci_uart_tty_close(struct tty_struct *tty) tasklet_kill(&hu->tty_wakeup_task); - cancel_work_sync(&hu->write_work); - if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { hu->proto->close(hu); if (hdev) { @@ -604,16 +589,26 @@ static int __init hci_uart_init(void) #ifdef CONFIG_BT_HCIUART_BCSP bcsp_init(); #endif -#ifdef CONFIG_BT_HCIUART_LL +#if defined(CONFIG_BT_HCIUART_LL) && defined(CONFIG_HUAWEI_BT_BCM43XX) ll_init(); #endif + +/*default without Huawei modification*/ +#if defined(CONFIG_BT_HCIUART_LL) && (!defined(CONFIG_HUAWEI_KERNEL)) + ll_init(); +#endif #ifdef CONFIG_BT_HCIUART_ATH3K ath_init(); #endif -#ifdef CONFIG_BT_HCIUART_IBS +#if defined(CONFIG_BT_HCIUART_IBS) && defined(CONFIG_HUAWEI_BT_WCN2243) ibs_init(); #endif +/*default without Huawei modification*/ +#if defined(CONFIG_BT_HCIUART_IBS) && (!defined(CONFIG_HUAWEI_KERNEL)) + ibs_init(); +#endif + return 0; } @@ -627,13 +622,23 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_BCSP bcsp_deinit(); #endif -#ifdef CONFIG_BT_HCIUART_LL +#if defined(CONFIG_BT_HCIUART_LL) && defined(CONFIG_HUAWEI_BT_BCM43XX) + ll_deinit(); +#endif + +/*default without Huawei modification*/ +#if defined(CONFIG_BT_HCIUART_LL) && (!defined(CONFIG_HUAWEI_KERNEL)) ll_deinit(); #endif #ifdef CONFIG_BT_HCIUART_ATH3K ath_deinit(); #endif -#ifdef CONFIG_BT_HCIUART_IBS +#if defined(CONFIG_BT_HCIUART_IBS) && defined(CONFIG_HUAWEI_BT_WCN2243) + ibs_deinit(); +#endif + +/*default without Huawei modification*/ +#if defined(CONFIG_BT_HCIUART_IBS) && (!defined(CONFIG_HUAWEI_KERNEL)) ibs_deinit(); #endif diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c index c0708d7c..60305204 100644 --- a/drivers/bluetooth/hci_smd.c +++ b/drivers/bluetooth/hci_smd.c @@ -2,7 +2,7 @@ * HCI_SMD (HCI Shared Memory Driver) is Qualcomm's Shared memory driver * for the BT HCI protocol. * - * Copyright (c) 2000-2001, 2011-2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2000-2001, 2011-2012 Code Aurora Forum. All rights reserved. * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2004-2006 Marcel Holtmann * diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 09f3497f..123fc24b 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -4,7 +4,7 @@ * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2004-2005 Marcel Holtmann - * Copyright (c) 2000-2001, 2010, 2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2000-2001, 2010, 2012 Code Aurora Forum. All rights reserved. * * * This program is free software; you can redistribute it and/or modify @@ -65,8 +65,6 @@ struct hci_uart { unsigned long flags; unsigned long hdev_flags; - struct work_struct write_work; - struct hci_uart_proto *proto; struct tasklet_struct tty_wakeup_task; void *priv; diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 0dd54ddf..67c180c2 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -2,7 +2,7 @@ * * Bluetooth virtual HCI driver * - * Copyright (C) 2000-2001 Qualcomm Technologies, Inc. + * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2004-2006 Marcel Holtmann * diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 2c4b546c..06dc9189 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -109,9 +109,61 @@ config CPU_FREQ_DEFAULT_GOV_INTERACTIVE loading your cpufreq low-level hardware driver, using the 'interactive' governor for latency-sensitive workloads. -config CPU_FREQ_DEFAULT_GOV_HOTPLUG - bool "hotplug" - select CPU_FREQ_GOV_HOTPLUG +config CPU_FREQ_DEFAULT_GOV_SMARTASS2 + bool "smartass2" + select CPU_FREQ_GOV_SMARTASS2 + help + Use the CPUFreq governor 'smartassV2' as default. + +config CPU_FREQ_DEFAULT_GOV_SMARTASSH3 + bool "SmartassH3" + select CPU_FREQ_GOV_SMARTASSH3 + help + Use the CPUFreq governor 'SmartassH3' as default. + +config CPU_FREQ_DEFAULT_GOV_INTELLIACTIVE + bool "intelliactive" + select CPU_FREQ_GOV_INTELLIACTIVE + help + Use the CPUFreq governor 'intelliactive' as default. This allows + you to get a full dynamic cpu frequency capable system by simply + loading your cpufreq low-level hardware driver, using the + 'interactive' governor for latency-sensitive workloads. + +config CPU_FREQ_DEFAULT_GOV_ADAPTIVE + bool "adaptive" + select CPU_FREQ_GOV_ADAPTIVE + ---help--- + Use the CPUFreq governor 'adaptive' as default. This allows + you to get a full dynamic cpu frequency capable system by simply + loading your cpufreq low-level hardware driver, using the + 'adaptive' governor for latency-sensitive workloads and demanding + performance. + + +config CPU_FREQ_DEFAULT_GOV_INTELLIMM + bool "intelliminmax" + select CPU_FREQ_GOV_INTELLIMM + help + Use the CPUFreq governor 'intelliminmax' as default. This is + governor will use only 3 different frequencies, idle, UI and max + +config CPU_FREQ_DEFAULT_GOV_STOCKDEMAND + bool "stockdemand" + select CPU_FREQ_GOV_STOCKDEMAND + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'stockdemand' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the ondemand + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. + This is default LG ondemand cpu gov. + +config CPU_FREQ_DEFAULT_GOV_YANKDEMAND + bool "yankdemand" + select CPU_FREQ_GOV_YANKDEMAND select CPU_FREQ_GOV_PERFORMANCE help Use the CPUFreq governor 'hotplug' as default. This allows @@ -121,6 +173,57 @@ config CPU_FREQ_DEFAULT_GOV_HOTPLUG governor. If unsure have a look at the help section of the driver. Fallback governor will be the performance governor. +config CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND + bool "intellidemand" + select CPU_FREQ_GOV_INTELLIDEMAND + help + Use the CPUFreq governor 'intellidemand' as default. This is + based on Ondemand with browsing detection based on GPU loading + +config CPU_FREQ_DEFAULT_GOV_LIONHEART + bool "lionheart" + select CPU_FREQ_GOV_LIONHEART + help + Use the CPUFreq governor 'Lionheart' as default. + +config CPU_FREQ_DEFAULT_GOV_HYPER + bool "hyper" + select CPU_FREQ_GOV_HYPER + ---help--- + Use the CPUFreq governor 'hyper' as default. This allows + you to get a full dynamic cpu frequency capable system by simply + loading your cpufreq low-level hardware driver, using the + 'hyper' governor for latency-sensitive workloads. + +config CPU_FREQ_DEFAULT_GOV_ONDEMANDX + bool "ondemandX" + select CPU_FREQ_GOV_ONDEMANDX + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'ondemand' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the ondemand + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. + OndemandX has built in sleep profile, but not working Sysfs + interface. + +config CPU_FREQ_DEFAULT_GOV_INTERACTIVEX + bool "interactiveX" + select CPU_FREQ_GOV_INTERACTIVEX + help + Use the CPUFreq governor 'interactiveX' as default. This allows + you to get a full dynamic cpu frequency capable system by simply + loading your cpufreq low-level hardware driver, using the + 'interactiveX' governor for latency-sensitive workloads. + +config CPU_FREQ_DEFAULT_GOV_ALUCARD + bool "alucard" + select CPU_FREQ_GOV_ALUCARD + help + Use the CPUFreq governor 'alucard' as default. + endchoice config CPU_FREQ_GOV_PERFORMANCE @@ -178,6 +281,23 @@ config CPU_FREQ_GOV_ONDEMAND If in doubt, say N. +config CPU_FREQ_GOV_INTERACTIVE + tristate "'interactive' cpufreq policy governor" + help + 'interactive' - This driver adds a dynamic cpufreq policy governor + designed for latency-sensitive workloads. + + This governor attempts to reduce the latency of clock + increases so that the system is more responsive to + interactive workloads. + + To compile this driver as a module, choose M here: the + module will be called cpufreq_interactive. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + config CPU_FREQ_GOV_CONSERVATIVE tristate "'conservative' cpufreq governor" depends on CPU_FREQ @@ -201,10 +321,26 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. -config CPU_FREQ_GOV_INTERACTIVE - tristate "'interactive' cpufreq policy governor" +config CPU_FREQ_GOV_SMARTASS2 + tristate "'smartassV2' cpufreq governor" + depends on CPU_FREQ help - 'interactive' - This driver adds a dynamic cpufreq policy governor + 'smartassV2' - a "smart" optimized governor! + + If in doubt, say N. + +config CPU_FREQ_GOV_SMARTASSH3 + tristate "'SmartassH3' cpufreq governor" + depends on CPU_FREQ + help + 'SmartassH3' - a "smartassV2 with tweaks by H3ROS" governor! + + If in doubt, say N. + +config CPU_FREQ_GOV_INTELLIACTIVE + tristate "'intelliactive' cpufreq policy governor" + help + 'intelliactive' - This driver adds a dynamic cpufreq policy governor designed for latency-sensitive workloads. This governor attempts to reduce the latency of clock @@ -218,26 +354,115 @@ config CPU_FREQ_GOV_INTERACTIVE If in doubt, say N. -config CPU_FREQ_GOV_HOTPLUG - tristate "'hotplug' cpufreq governor" - depends on CPU_FREQ && NO_HZ && HOTPLUG_CPU +config CPU_FREQ_GOV_ADAPTIVE + tristate "Adaptive" + ---help--- + 'adaptive' - This driver adds a dynamic cpufreq policy governor + designed for latency-sensitive workloads and also for demanding + performance. + + This governor attempts to reduce the latency of clock + increases so that the system is more responsive to + interactive workloads in loweset steady-state but to + to reduce power consumption in middle operation level level up + will be done in step by step to prohibit system from going to + max operation level. + + To compile this driver as a module, choose M here: the + module will be called cpufreq_adaptive. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + + +config CPU_FREQ_GOV_INTELLIMM + tristate "intelliminmax" help - 'hotplug' - this driver mimics the frequency scaling behavior - in 'ondemand', but with several key differences. First is - that frequency transitions use the CPUFreq table directly, - instead of incrementing in a percentage of the maximum - available frequency. Second 'hotplug' will offline auxillary - CPUs when the system is idle, and online those CPUs once the - system becomes busy again. This last feature is needed for - architectures which transition to low power states when only - the "master" CPU is online, or for thermally constrained - devices. - - If you don't have one of these architectures or devices, use - 'ondemand' instead. + To compile this driver as a module, choose M here: the + module will be called cpufreq_interactive. + + If in doubt, say N. + +config CPU_FREQ_GOV_STOCKDEMAND + tristate "'stockdemand' cpufreq policy governor" + select CPU_FREQ_TABLE + help + this is stock LG ondemand GOV. for users that like STOCK. + + +config CPU_FREQ_GOV_YANKDEMAND + tristate "'yankdemand' cpufreq policy governor" + select CPU_FREQ_TABLE + help + 'yankdemand' - This driver adds a dynamic cpufreq policy governor. + The governor is based on ondemand with just different default settings + and can be achieved using ondemand with a script. This is added for + simplification purposes for myself. + +config CPU_FREQ_GOV_INTELLIDEMAND + tristate "'intellidemand' cpufreq policy governor" + select CPU_FREQ_TABLE + help + 'intellidemand' - This driver adds a dynamic cpufreq policy governor. + The governor does a periodic polling and + changes frequency based on the CPU utilization. + The support for this governor depends on CPU capability to + do fast frequency switching (i.e, very low latency frequency + transitions). with browsing detection based on GPU loading + + To compile this driver as a module, choose M here: the + module will be called cpufreq_ondemand. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +config CPU_FREQ_GOV_LIONHEART + tristate "'lionheart' cpufreq governor" + depends on CPU_FREQ + help + 'Lionheart' - A brave and agile conservative-based governor. + +config CPU_FREQ_GOV_HYPER + tristate "'hyper' cpufreq governor" + depends on CPU_FREQ + ---help--- + 'hyper' - A tweaked "ondemand" based smart and smooth optimized governor! + + If in doubt, say N. + +config CPU_FREQ_GOV_ONDEMANDX + tristate "'ondemandx' cpufreq policy governor" + select CPU_FREQ_TABLE + help + 'ondemandx' - This driver adds a dynamic cpufreq policy governor. + The governor does a periodic polling and + changes frequency based on the CPU utilization. + The support for this governor depends on CPU capability to + do fast frequency switching (i.e, very low latency frequency + transitions). + + To compile this driver as a module, choose M here: the + module will be called cpufreq_ondemand. + + For details, take a look at linux/Documentation/cpu-freq. If in doubt, say N. +config CPU_FREQ_GOV_INTERACTIVEX + tristate "'interactiveX' cpufreq policy governor" + help + 'interactiveX' - Modified version of interactive with sleep+wake code. + + If in doubt, say N. + +config CPU_FREQ_GOV_ALUCARD + tristate "'alucard' cpufreq governor" + default y + depends on CPU_FREQ + help + menu "x86 CPU frequency scaling drivers" depends on X86 source "drivers/cpufreq/Kconfig.x86" diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 0dd9c736..4258fecf 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -3,14 +3,28 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o # CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o -# CPUfreq governors +# CPUfreq governors +obj-$(CONFIG_CPU_FREQ_GOV_ALUCARD) += cpufreq_alucard.o obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o +obj-$(CONFIG_CPU_FREQ_GOV_ONDEMANDX) += cpufreq_ondemandx.o +obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o +obj-$(CONFIG_CPU_FREQ_GOV_LIONHEART) += cpufreq_lionheart.o +obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVEX) += cpufreq_interactivex.o +obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o -obj-$(CONFIG_CPU_FREQ_GOV_HOTPLUG) += cpufreq_hotplug.o +obj-$(CONFIG_CPU_FREQ_GOV_SMARTASS2) += cpufreq_smartass2.o +obj-$(CONFIG_CPU_FREQ_GOV_SMARTASSH3) += cpufreq_smartassH3.o +obj-$(CONFIG_CPU_FREQ_GOV_INTELLIACTIVE) += cpufreq_intelliactive.o +obj-$(CONFIG_CPU_FREQ_GOV_ADAPTIVE) += cpufreq_adaptive.o +obj-$(CONFIG_CPU_FREQ_GOV_HYPER) += cpufreq_hyper.o +obj-$(CONFIG_CPU_FREQ_GOV_INTELLIMM) += cpufreq_intellimm.o +obj-$(CONFIG_CPU_FREQ_GOV_STOCKDEMAND) += cpufreq_stockdemand.o +obj-$(CONFIG_CPU_FREQ_GOV_YANKDEMAND) += cpufreq_yankdemand.o +obj-$(CONFIG_CPU_FREQ_GOV_INTELLIDEMAND) += cpufreq_intellidemand.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o diff --git a/drivers/cpufreq/cpufreq_adaptive.c b/drivers/cpufreq/cpufreq_adaptive.c new file mode 100644 index 00000000..c88eed41 --- /dev/null +++ b/drivers/cpufreq/cpufreq_adaptive.c @@ -0,0 +1,947 @@ +/* + * drivers/cpufreq/cpufreq_adaptive.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * dbs is used in this file as a shortform for demandbased switching + * It helps to keep variable names smaller, simpler + */ + +#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) +#define DEF_FREQUENCY_UP_THRESHOLD (80) +#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) +#define MICRO_FREQUENCY_UP_THRESHOLD (95) +#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) +#define MIN_FREQUENCY_UP_THRESHOLD (11) +#define MAX_FREQUENCY_UP_THRESHOLD (100) +#define MIN_ONDEMAND_THRESHOLD (4) +/* + * The polling frequency of this governor depends on the capability of + * the processor. Default polling frequency is 1000 times the transition + * latency of the processor. The governor will work on any processor with + * transition latency <= 10mS, using appropriate sampling + * rate. + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. + * All times here are in uS. + */ +#define MIN_SAMPLING_RATE_RATIO (2) + +static unsigned int min_sampling_rate; + +#define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +static void (*pm_idle_old)(void); +static void do_dbs_timer(struct work_struct *work); +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE +static +#endif +struct cpufreq_governor cpufreq_gov_adaptive = { + .name = "adaptive", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; + +/* Sampling types */ +enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; + +struct cpu_dbs_info_s { + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_iowait; + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + struct cpufreq_frequency_table *freq_table; + unsigned int freq_hi_jiffies; + int cpu; + unsigned int sample_type:1; + bool ondemand; + /* + * percpu mutex that serializes governor limit change with + * do_dbs_timer invocation. We do not want do_dbs_timer to run + * when user is changing the governor or limits. + */ + struct mutex timer_mutex; +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info); + +static unsigned int dbs_enable; /* number of CPUs using this policy */ + +/* + * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on + * different CPUs. It protects dbs_enable in governor start/stop. + */ +static DEFINE_MUTEX(dbs_mutex); +static struct task_struct *up_task; +static struct workqueue_struct *down_wq; +static struct work_struct freq_scale_down_work; +static cpumask_t up_cpumask; +static spinlock_t up_cpumask_lock; +static cpumask_t down_cpumask; +static spinlock_t down_cpumask_lock; + +static DEFINE_PER_CPU(cputime64_t, idle_in_idle); +static DEFINE_PER_CPU(cputime64_t, idle_exit_wall); + +static struct timer_list cpu_timer; +static unsigned int target_freq; +static DEFINE_MUTEX(short_timer_mutex); + +/* Go to max speed when CPU load at or above this value. */ +#define DEFAULT_GO_MAXSPEED_LOAD 70 +static unsigned long go_maxspeed_load; + +#define DEFAULT_KEEP_MINSPEED_LOAD 30 +static unsigned long keep_minspeed_load; + +#define DEFAULT_STEPUP_LOAD 10 +static unsigned long step_up_load; + +static struct dbs_tuners { + unsigned int sampling_rate; + unsigned int up_threshold; + unsigned int down_differential; + unsigned int ignore_nice; + unsigned int io_is_busy; +} dbs_tuners_ins = { + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, + .ignore_nice = 0, +}; + +static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall) +{ + u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); + + if (iowait_time == -1ULL) + return 0; + + return iowait_time; +} + +static void adaptive_init_cpu(int cpu) +{ + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + dbs_info->freq_table = cpufreq_frequency_get_table(cpu); +} + +/************************** sysfs interface ************************/ + +static ssize_t show_sampling_rate_max(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + printk_once(KERN_INFO "CPUFREQ: adaptive sampling_rate_max " + "sysfs file is deprecated - used by: %s\n", current->comm); + return sprintf(buf, "%u\n", -1U); +} + +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", min_sampling_rate); +} + +define_one_global_ro(sampling_rate_max); +define_one_global_ro(sampling_rate_min); + +/* cpufreq_adaptive Governor Tunables */ +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +} +show_one(sampling_rate, sampling_rate); +show_one(io_is_busy, io_is_busy); +show_one(up_threshold, up_threshold); +show_one(ignore_nice_load, ignore_nice); + +/*** delete after deprecation time ***/ + +#define DEPRECATION_MSG(file_name) \ + printk_once(KERN_INFO "CPUFREQ: Per core adaptive sysfs " \ + "interface is deprecated - " #file_name "\n"); + +#define show_one_old(file_name) \ +static ssize_t show_##file_name##_old \ +(struct cpufreq_policy *unused, char *buf) \ +{ \ + printk_once(KERN_INFO "CPUFREQ: Per core adaptive sysfs " \ + "interface is deprecated - " #file_name "\n"); \ + return show_##file_name(NULL, NULL, buf); \ +} + +/*** delete after deprecation time ***/ + +static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + mutex_lock(&dbs_mutex); + dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); + mutex_unlock(&dbs_mutex); + + return count; +} + +static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + mutex_lock(&dbs_mutex); + dbs_tuners_ins.io_is_busy = !!input; + mutex_unlock(&dbs_mutex); + + return count; +} + +static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + + mutex_lock(&dbs_mutex); + dbs_tuners_ins.up_threshold = input; + mutex_unlock(&dbs_mutex); + + return count; +} + +static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (input > 1) + input = 1; + + mutex_lock(&dbs_mutex); + if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */ + mutex_unlock(&dbs_mutex); + return count; + } + dbs_tuners_ins.ignore_nice = input; + + /* we need to re-evaluate prev_cpu_idle */ + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(od_cpu_dbs_info, j); + dbs_info->prev_cpu_idle = get_cpu_idle_time_us(j, + &dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + + } + mutex_unlock(&dbs_mutex); + + return count; +} + +define_one_global_rw(sampling_rate); +define_one_global_rw(io_is_busy); +define_one_global_rw(up_threshold); +define_one_global_rw(ignore_nice_load); + +static struct attribute *dbs_attributes[] = { + &sampling_rate_max.attr, + &sampling_rate_min.attr, + &sampling_rate.attr, + &up_threshold.attr, + &ignore_nice_load.attr, + &io_is_busy.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "adaptive", +}; + +/*** delete after deprecation time ***/ + +#define write_one_old(file_name) \ +static ssize_t store_##file_name##_old \ +(struct cpufreq_policy *unused, const char *buf, size_t count) \ +{ \ + printk_once(KERN_INFO "CPUFREQ: Per core adaptive sysfs " \ + "interface is deprecated - " #file_name "\n"); \ + return store_##file_name(NULL, NULL, buf, count); \ +} + +static void cpufreq_adaptive_timer(unsigned long data) +{ + cputime64_t cur_idle; + cputime64_t cur_wall; + unsigned int delta_idle; + unsigned int delta_time; + int short_load; + unsigned int new_freq; + unsigned long flags; + struct cpu_dbs_info_s *this_dbs_info; + struct cpufreq_policy *policy; + unsigned int j; + unsigned int index; + unsigned int max_load = 0; + + this_dbs_info = &per_cpu(od_cpu_dbs_info, 0); + + policy = this_dbs_info->cur_policy; + + for_each_online_cpu(j) { + cur_idle = get_cpu_idle_time_us(j, &cur_wall); + + delta_idle = (unsigned int) (cur_idle - per_cpu(idle_in_idle, j)); + delta_time = (unsigned int) (cur_wall - per_cpu(idle_exit_wall, j)); + + /* + * If timer ran less than 1ms after short-term sample started, retry. + */ + if (delta_time < 1000) + goto do_nothing; + + if (delta_idle > delta_time) + short_load = 0; + else + short_load = 100 * (delta_time - delta_idle) / delta_time; + + if (short_load > max_load) + max_load = short_load; + } + + if (this_dbs_info->ondemand) + goto do_nothing; + + if (max_load >= go_maxspeed_load) + new_freq = policy->max; + else + new_freq = policy->max * max_load / 100; + + if ((max_load <= keep_minspeed_load) && + (policy->cur == policy->min)) + new_freq = policy->cur; + + if (cpufreq_frequency_table_target(policy, this_dbs_info->freq_table, + new_freq, CPUFREQ_RELATION_L, + &index)) { + goto do_nothing; + } + + new_freq = this_dbs_info->freq_table[index].frequency; + + target_freq = new_freq; + + if (new_freq < this_dbs_info->cur_policy->cur) { + spin_lock_irqsave(&down_cpumask_lock, flags); + cpumask_set_cpu(0, &down_cpumask); + spin_unlock_irqrestore(&down_cpumask_lock, flags); + queue_work(down_wq, &freq_scale_down_work); + } else { + spin_lock_irqsave(&up_cpumask_lock, flags); + cpumask_set_cpu(0, &up_cpumask); + spin_unlock_irqrestore(&up_cpumask_lock, flags); + wake_up_process(up_task); + } + + return; + +do_nothing: + for_each_online_cpu(j) { + per_cpu(idle_in_idle, j) = + get_cpu_idle_time_us(j, + &per_cpu(idle_exit_wall, j)); + } + mod_timer(&cpu_timer, jiffies + 2); + schedule_delayed_work_on(0, &this_dbs_info->work, 10); + + if (mutex_is_locked(&short_timer_mutex)) + mutex_unlock(&short_timer_mutex); + return; +} + +/*** delete after deprecation time ***/ + +/************************** sysfs end ************************/ + +static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) +{ +#ifndef CONFIG_ARCH_EXYNOS4 + if (p->cur == p->max) + return; +#endif + __cpufreq_driver_target(p, freq, CPUFREQ_RELATION_H); +} + +static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) +{ + unsigned int max_load_freq; + + struct cpufreq_policy *policy; + unsigned int j; + + unsigned int index, new_freq; + unsigned int longterm_load = 0; + + policy = this_dbs_info->cur_policy; + + /* + * Every sampling_rate, we check, if current idle time is less + * than 20% (default), then we try to increase frequency + * Every sampling_rate, we look for a the lowest + * frequency which can sustain the load while keeping idle time over + * 30%. If such a frequency exist, we try to decrease to this frequency. + * + * Any frequency increase takes it to the maximum frequency. + * Frequency reduction happens at minimum steps of + * 5% (default) of current frequency + */ + + /* Get Absolute Load - in terms of freq */ + max_load_freq = 0; + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + unsigned int idle_time, wall_time, iowait_time; + unsigned int load, load_freq; + int freq_avg; + + j_dbs_info = &per_cpu(od_cpu_dbs_info, j); + + cur_idle_time = get_cpu_idle_time_us(j, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_dbs_info->prev_cpu_idle); + j_dbs_info->prev_cpu_idle = cur_idle_time; + + iowait_time = (unsigned int) + (cur_iowait_time - j_dbs_info->prev_cpu_iowait); + j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + if (dbs_tuners_ins.ignore_nice) { + u64 cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + j_dbs_info->prev_cpu_nice; + /* + * Assumption: nice time between sampling periods will + * be less than 2^32 jiffies for 32 bit sys + */ + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + /* + * For the purpose of adaptive, waiting for disk IO is an + * indication that you're performance critical, and not that + * the system is actually idle. So subtract the iowait time + * from the cpu idle time. + */ + + if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time) + idle_time -= iowait_time; + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + load = 100 * (wall_time - idle_time) / wall_time; + + if (load > longterm_load) + longterm_load = load; + + freq_avg = __cpufreq_driver_getavg(policy, j); + if (freq_avg <= 0) + freq_avg = policy->cur; + + load_freq = load * freq_avg; + + if (load_freq > max_load_freq) + max_load_freq = load_freq; + } + + if (longterm_load >= MIN_ONDEMAND_THRESHOLD) + this_dbs_info->ondemand = true; + else + this_dbs_info->ondemand = false; + + /* Check for frequency increase */ + if (max_load_freq > (dbs_tuners_ins.up_threshold * policy->cur)) { + cpufreq_frequency_table_target(policy, + this_dbs_info->freq_table, + (policy->cur + step_up_load), + CPUFREQ_RELATION_L, &index); + + new_freq = this_dbs_info->freq_table[index].frequency; + dbs_freq_increase(policy, new_freq); + return; + } + + /* Check for frequency decrease */ + /* if we cannot reduce the frequency anymore, break out early */ +#ifndef CONFIG_ARCH_EXYNOS4 + if (policy->cur == policy->min) + return; +#endif + /* + * The optimal frequency is the frequency that is the lowest that + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ + if (max_load_freq < + (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * + policy->cur) { + unsigned int freq_next; + freq_next = max_load_freq / + (dbs_tuners_ins.up_threshold - + dbs_tuners_ins.down_differential); + + if (freq_next < policy->min) + freq_next = policy->min; + + __cpufreq_driver_target(policy, freq_next, + CPUFREQ_RELATION_L); + } +} + +static void do_dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + + int delay; + + mutex_lock(&dbs_info->timer_mutex); + + /* Common NORMAL_SAMPLE setup */ + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + dbs_check_cpu(dbs_info); + + /* We want all CPUs to do sampling nearly on + * same jiffy + */ + delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + schedule_delayed_work_on(cpu, &dbs_info->work, delay); + + mutex_unlock(&dbs_info->timer_mutex); +} + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) +{ + /* We want all CPUs to do sampling nearly on same jiffy */ + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); + schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +{ + cancel_delayed_work_sync(&dbs_info->work); +} + +/* + * Not all CPUs want IO time to be accounted as busy; this dependson how + * efficient idling at a higher frequency/voltage is. + * Pavel Machek says this is not so for various generations of AMD and old + * Intel systems. + * Mike Chan (androidlcom) calis this is also not true for ARM. + * Because of this, whitelist specific known (series) of CPUs by default, and + * leave all others up to the user. + */ +static int should_io_be_busy(void) +{ +#if defined(CONFIG_X86) + /* + * For Intel, Core 2 (model 15) andl later have an efficient idle. + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 15) + return 1; +#endif + return 0; +} + +static void cpufreq_adaptive_idle(void) +{ + int i; + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, 0); + struct cpufreq_policy *policy; + + policy = dbs_info->cur_policy; + + pm_idle_old(); + + if ((policy->cur == policy->min) || + (policy->cur == policy->max)) { + + if (timer_pending(&cpu_timer)) + return; + + if (mutex_trylock(&short_timer_mutex)) { + for_each_online_cpu(i) { + per_cpu(idle_in_idle, i) = + get_cpu_idle_time_us(i, + &per_cpu(idle_exit_wall, i)); + } + + mod_timer(&cpu_timer, jiffies + 2); + cancel_delayed_work(&dbs_info->work); + } + } else { + if (timer_pending(&cpu_timer)) + del_timer(&cpu_timer); + + } +} + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; + int rc; + + this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_mutex); + + rc = sysfs_create_group(&policy->kobj, &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + + dbs_enable++; + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(od_cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle = get_cpu_idle_time_us(j, + &j_dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + j_dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + this_dbs_info->cpu = cpu; + adaptive_init_cpu(cpu); + + /* + * Start the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 1) { + unsigned int latency; + + rc = sysfs_create_group(cpufreq_global_kobject, + &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + + /* policy latency is in nS. Convert it to uS first */ + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + /* Bring kernel and HW constraints together */ + min_sampling_rate = max(min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + dbs_tuners_ins.sampling_rate = + max(min_sampling_rate, + latency * LATENCY_MULTIPLIER); + dbs_tuners_ins.io_is_busy = should_io_be_busy(); + } + mutex_unlock(&dbs_mutex); + + mutex_init(&this_dbs_info->timer_mutex); + dbs_timer_init(this_dbs_info); + + pm_idle_old = pm_idle; + pm_idle = cpufreq_adaptive_idle; + break; + + case CPUFREQ_GOV_STOP: + dbs_timer_exit(this_dbs_info); + + mutex_lock(&dbs_mutex); + sysfs_remove_group(&policy->kobj, &dbs_attr_group); + mutex_destroy(&this_dbs_info->timer_mutex); + dbs_enable--; + mutex_unlock(&dbs_mutex); + if (!dbs_enable) + sysfs_remove_group(cpufreq_global_kobject, + &dbs_attr_group); + + pm_idle = pm_idle_old; + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&this_dbs_info->timer_mutex); + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->min, CPUFREQ_RELATION_L); + mutex_unlock(&this_dbs_info->timer_mutex); + break; + } + return 0; +} + +static inline void cpufreq_adaptive_update_time(void) +{ + struct cpu_dbs_info_s *this_dbs_info; + struct cpufreq_policy *policy; + int j; + + this_dbs_info = &per_cpu(od_cpu_dbs_info, 0); + policy = this_dbs_info->cur_policy; + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + + j_dbs_info = &per_cpu(od_cpu_dbs_info, j); + + cur_idle_time = get_cpu_idle_time_us(j, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); + + j_dbs_info->prev_cpu_wall = cur_wall_time; + + j_dbs_info->prev_cpu_idle = cur_idle_time; + + j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + if (dbs_tuners_ins.ignore_nice) + j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + + } + +} + +static int cpufreq_adaptive_up_task(void *data) +{ + unsigned long flags; + struct cpu_dbs_info_s *this_dbs_info; + struct cpufreq_policy *policy; + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + this_dbs_info = &per_cpu(od_cpu_dbs_info, 0); + policy = this_dbs_info->cur_policy; + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&up_cpumask_lock, flags); + + if (cpumask_empty(&up_cpumask)) { + spin_unlock_irqrestore(&up_cpumask_lock, flags); + schedule(); + + if (kthread_should_stop()) + break; + + spin_lock_irqsave(&up_cpumask_lock, flags); + } + + set_current_state(TASK_RUNNING); + + cpumask_clear(&up_cpumask); + spin_unlock_irqrestore(&up_cpumask_lock, flags); + + __cpufreq_driver_target(this_dbs_info->cur_policy, + target_freq, + CPUFREQ_RELATION_H); + if (policy->cur != policy->max) { + mutex_lock(&this_dbs_info->timer_mutex); + + schedule_delayed_work_on(0, &this_dbs_info->work, delay); + mutex_unlock(&this_dbs_info->timer_mutex); + cpufreq_adaptive_update_time(); + } + if (mutex_is_locked(&short_timer_mutex)) + mutex_unlock(&short_timer_mutex); + } + + return 0; +} + +static void cpufreq_adaptive_freq_down(struct work_struct *work) +{ + unsigned long flags; + struct cpu_dbs_info_s *this_dbs_info; + struct cpufreq_policy *policy; + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + spin_lock_irqsave(&down_cpumask_lock, flags); + cpumask_clear(&down_cpumask); + spin_unlock_irqrestore(&down_cpumask_lock, flags); + + this_dbs_info = &per_cpu(od_cpu_dbs_info, 0); + policy = this_dbs_info->cur_policy; + + __cpufreq_driver_target(this_dbs_info->cur_policy, + target_freq, + CPUFREQ_RELATION_H); + + if (policy->cur != policy->min) { + mutex_lock(&this_dbs_info->timer_mutex); + + schedule_delayed_work_on(0, &this_dbs_info->work, delay); + mutex_unlock(&this_dbs_info->timer_mutex); + cpufreq_adaptive_update_time(); + } + + if (mutex_is_locked(&short_timer_mutex)) + mutex_unlock(&short_timer_mutex); +} + +static int __init cpufreq_gov_dbs_init(void) +{ + cputime64_t wall; + u64 idle_time; + int cpu = get_cpu(); + + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + go_maxspeed_load = DEFAULT_GO_MAXSPEED_LOAD; + keep_minspeed_load = DEFAULT_KEEP_MINSPEED_LOAD; + step_up_load = DEFAULT_STEPUP_LOAD; + + idle_time = get_cpu_idle_time_us(cpu, &wall); + put_cpu(); + if (idle_time != -1ULL) { + /* Idle micro accounting is supported. Use finer thresholds */ + dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; + dbs_tuners_ins.down_differential = + MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + /* + * In no_hz/micro accounting case we set the minimum frequency + * not depending on HZ, but fixed (very low). The deferred + * timer might skip some samples if idle/sleeping as needed. + */ + min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + } else { + /* For correct statistics, we need 10 ticks for each measure */ + min_sampling_rate = + MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + } + + init_timer(&cpu_timer); + cpu_timer.function = cpufreq_adaptive_timer; + + up_task = kthread_create(cpufreq_adaptive_up_task, NULL, + "kadaptiveup"); + + if (IS_ERR(up_task)) + return PTR_ERR(up_task); + + sched_setscheduler_nocheck(up_task, SCHED_FIFO, ¶m); + get_task_struct(up_task); + + /* No rescuer thread, bind to CPU queuing the work for possibly + warm cache (probably doesn't matter much). */ + down_wq = alloc_workqueue("kadaptive_down", 0, 1); + + if (!down_wq) + goto err_freeuptask; + + INIT_WORK(&freq_scale_down_work, cpufreq_adaptive_freq_down); + + + return cpufreq_register_governor(&cpufreq_gov_adaptive); +err_freeuptask: + put_task_struct(up_task); + return -ENOMEM; +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_adaptive); +} + + +MODULE_AUTHOR("Venkatesh Pallipadi "); +MODULE_AUTHOR("Alexey Starikovskiy "); +MODULE_DESCRIPTION("'cpufreq_adaptive' - A dynamic cpufreq governor for " + "Low Latency Frequency Transition capable processors"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE +fs_initcall(cpufreq_gov_dbs_init); +#else +module_init(cpufreq_gov_dbs_init); +#endif +module_exit(cpufreq_gov_dbs_exit); diff --git a/drivers/cpufreq/cpufreq_alucard.c b/drivers/cpufreq/cpufreq_alucard.c new file mode 100644 index 00000000..180e2050 --- /dev/null +++ b/drivers/cpufreq/cpufreq_alucard.c @@ -0,0 +1,599 @@ +/* + * drivers/cpufreq/cpufreq_alucard.c + * + * Copyright (C) 2011 Samsung Electronics co. ltd + * ByungChang Cha + * + * Based on ondemand governor + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * + * 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. + * + * Created by Alucard_24@xda + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * dbs is used in this file as a shortform for demandbased switching + * It helps to keep variable names smaller, simpler + */ + +static void do_alucard_timer(struct work_struct *work); +static int cpufreq_governor_alucard(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD +static +#endif +struct cpufreq_governor cpufreq_gov_alucard = { + .name = "alucard", + .governor = cpufreq_governor_alucard, + .owner = THIS_MODULE, +}; + +struct cpufreq_alucard_cpuinfo { + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_idle; + struct cpufreq_frequency_table *freq_table; + struct delayed_work work; + struct cpufreq_policy *cur_policy; + int cpu; + unsigned int enable:1; + /* + * mutex that serializes governor limit change with + * do_alucard_timer invocation. We do not want do_alucard_timer to run + * when user is changing the governor or limits. + */ + struct mutex timer_mutex; +}; + +static DEFINE_PER_CPU(struct cpufreq_alucard_cpuinfo, od_alucard_cpuinfo); + +static unsigned int alucard_enable; /* number of CPUs using this policy */ +/* + * alucard_mutex protects alucard_enable in governor start/stop. + */ +static DEFINE_MUTEX(alucard_mutex); + +/* alucard tuners */ +static struct alucard_tuners { + atomic_t sampling_rate; + atomic_t inc_cpu_load_at_min_freq; + atomic_t inc_cpu_load; + atomic_t dec_cpu_load_at_min_freq; + atomic_t dec_cpu_load; + atomic_t freq_responsiveness; + atomic_t pump_inc_step; + atomic_t pump_dec_step; +} alucard_tuners_ins = { + .sampling_rate = ATOMIC_INIT(60000), + .inc_cpu_load_at_min_freq = ATOMIC_INIT(70), + .inc_cpu_load = ATOMIC_INIT(70), + .dec_cpu_load_at_min_freq = ATOMIC_INIT(70), + .dec_cpu_load = ATOMIC_INIT(70), +#ifdef CONFIG_CPU_EXYNOS4210 + .freq_responsiveness = ATOMIC_INIT(600000), +#else + .freq_responsiveness = ATOMIC_INIT(600000), +#endif + .pump_inc_step = ATOMIC_INIT(1), + .pump_dec_step = ATOMIC_INIT(1), +}; + +/************************** sysfs interface ************************/ + +/* cpufreq_alucard Governor Tunables */ +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%d\n", atomic_read(&alucard_tuners_ins.object)); \ +} +show_one(sampling_rate, sampling_rate); +show_one(inc_cpu_load_at_min_freq, inc_cpu_load_at_min_freq); +show_one(inc_cpu_load, inc_cpu_load); +show_one(dec_cpu_load_at_min_freq, dec_cpu_load_at_min_freq); +show_one(dec_cpu_load, dec_cpu_load); +show_one(freq_responsiveness, freq_responsiveness); +show_one(pump_inc_step, pump_inc_step); +show_one(pump_dec_step, pump_dec_step); + +/** + * update_sampling_rate - update sampling rate effective immediately if needed. + * @new_rate: new sampling rate + * + * If new rate is smaller than the old, simply updaing + * alucard_tuners_ins.sampling_rate might not be appropriate. For example, + * if the original sampling_rate was 1 second and the requested new sampling + * rate is 10 ms because the user needs immediate reaction from ondemand + * governor, but not sure if higher frequency will be required or not, + * then, the governor may change the sampling rate too late; up to 1 second + * later. Thus, if we are reducing the sampling rate, we need to make the + * new value effective immediately. + */ +static void update_sampling_rate(unsigned int new_rate) +{ + int cpu; + + atomic_set(&alucard_tuners_ins.sampling_rate,new_rate); + + get_online_cpus(); + for_each_online_cpu(cpu) { + struct cpufreq_policy *policy; + struct cpufreq_alucard_cpuinfo *alucard_cpuinfo; + unsigned long next_sampling, appointed_at; + + policy = cpufreq_cpu_get(cpu); + if (!policy) + continue; + alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, policy->cpu); + cpufreq_cpu_put(policy); + + mutex_lock(&alucard_cpuinfo->timer_mutex); + + if (!delayed_work_pending(&alucard_cpuinfo->work)) { + mutex_unlock(&alucard_cpuinfo->timer_mutex); + continue; + } + + next_sampling = jiffies + usecs_to_jiffies(new_rate); + appointed_at = alucard_cpuinfo->work.timer.expires; + + + if (time_before(next_sampling, appointed_at)) { + + mutex_unlock(&alucard_cpuinfo->timer_mutex); + cancel_delayed_work_sync(&alucard_cpuinfo->work); + mutex_lock(&alucard_cpuinfo->timer_mutex); + + #ifdef CONFIG_CPU_EXYNOS4210 + mod_delayed_work_on(alucard_cpuinfo->cpu, system_wq, &alucard_cpuinfo->work, usecs_to_jiffies(new_rate)); + #else + queue_delayed_work_on(alucard_cpuinfo->cpu, system_wq, &alucard_cpuinfo->work, usecs_to_jiffies(new_rate)); + #endif + } + mutex_unlock(&alucard_cpuinfo->timer_mutex); + } + put_online_cpus(); +} + +/* sampling_rate */ +static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) + return -EINVAL; + + input = max(input,10000); + + if (input == atomic_read(&alucard_tuners_ins.sampling_rate)) + return count; + + update_sampling_rate(input); + + return count; +} + +/* inc_cpu_load_at_min_freq */ +static ssize_t store_inc_cpu_load_at_min_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) { + return -EINVAL; + } + + input = min(input,atomic_read(&alucard_tuners_ins.inc_cpu_load)); + + if (input == atomic_read(&alucard_tuners_ins.inc_cpu_load_at_min_freq)) + return count; + + atomic_set(&alucard_tuners_ins.inc_cpu_load_at_min_freq,input); + + return count; +} + +/* inc_cpu_load */ +static ssize_t store_inc_cpu_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) + return -EINVAL; + + input = max(min(input,100),0); + + if (input == atomic_read(&alucard_tuners_ins.inc_cpu_load)) + return count; + + atomic_set(&alucard_tuners_ins.inc_cpu_load,input); + + return count; +} + +/* dec_cpu_load_at_min_freq */ +static ssize_t store_dec_cpu_load_at_min_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) { + return -EINVAL; + } + + input = min(input,atomic_read(&alucard_tuners_ins.dec_cpu_load)); + + if (input == atomic_read(&alucard_tuners_ins.dec_cpu_load_at_min_freq)) + return count; + + atomic_set(&alucard_tuners_ins.dec_cpu_load_at_min_freq,input); + + return count; +} + +/* dec_cpu_load */ +static ssize_t store_dec_cpu_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) + return -EINVAL; + + input = max(min(input,95),5); + + if (input == atomic_read(&alucard_tuners_ins.dec_cpu_load)) + return count; + + atomic_set(&alucard_tuners_ins.dec_cpu_load,input); + + return count; +} + +/* freq_responsiveness */ +static ssize_t store_freq_responsiveness(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) + return -EINVAL; + + if (input == atomic_read(&alucard_tuners_ins.freq_responsiveness)) + return count; + + atomic_set(&alucard_tuners_ins.freq_responsiveness,input); + + return count; +} + +/* pump_inc_step */ +static ssize_t store_pump_inc_step(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) + return -EINVAL; + + input = max(min(input,3),1); + + if (input == atomic_read(&alucard_tuners_ins.pump_inc_step)) + return count; + + atomic_set(&alucard_tuners_ins.pump_inc_step,input); + + return count; +} + +/* pump_dec_step */ +static ssize_t store_pump_dec_step(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input; + int ret; + + ret = sscanf(buf, "%d", &input); + if (ret != 1) + return -EINVAL; + + input = max(min(input,3),1); + + if (input == atomic_read(&alucard_tuners_ins.pump_dec_step)) + return count; + + atomic_set(&alucard_tuners_ins.pump_dec_step,input); + + return count; +} + +define_one_global_rw(sampling_rate); +define_one_global_rw(inc_cpu_load_at_min_freq); +define_one_global_rw(inc_cpu_load); +define_one_global_rw(dec_cpu_load_at_min_freq); +define_one_global_rw(dec_cpu_load); +define_one_global_rw(freq_responsiveness); +define_one_global_rw(pump_inc_step); +define_one_global_rw(pump_dec_step); + +static struct attribute *alucard_attributes[] = { + &sampling_rate.attr, + &inc_cpu_load_at_min_freq.attr, + &inc_cpu_load.attr, + &dec_cpu_load_at_min_freq.attr, + &dec_cpu_load.attr, + &freq_responsiveness.attr, + &pump_inc_step.attr, + &pump_dec_step.attr, + NULL +}; + +static struct attribute_group alucard_attr_group = { + .attrs = alucard_attributes, + .name = "alucard", +}; + +/************************** sysfs end ************************/ + +static void alucard_check_cpu(struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo) +{ + struct cpufreq_policy *cpu_policy; + unsigned int min_freq; + unsigned int max_freq; + unsigned int freq_responsiveness; + int dec_cpu_load; + int inc_cpu_load; + int pump_inc_step; + int pump_dec_step; + cputime64_t cur_wall_time, cur_idle_time; + unsigned int wall_time, idle_time; +#ifndef CONFIG_CPU_EXYNOS4210 + unsigned int index = 0; + unsigned int tmp_freq = 0; +#endif + unsigned int next_freq = 0; + int cur_load = -1; + unsigned int cpu; + + cpu = this_alucard_cpuinfo->cpu; + cpu_policy = this_alucard_cpuinfo->cur_policy; + + cur_idle_time = get_cpu_idle_time_us(cpu, NULL); + cur_idle_time += get_cpu_iowait_time_us(cpu, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - this_alucard_cpuinfo->prev_cpu_wall); + this_alucard_cpuinfo->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - this_alucard_cpuinfo->prev_cpu_idle); + this_alucard_cpuinfo->prev_cpu_idle = cur_idle_time; + + if (!cpu_policy) + return; + + /*printk(KERN_ERR "TIMER CPU[%u], wall[%u], idle[%u]\n",cpu, wall_time, idle_time);*/ + if (wall_time >= idle_time) { /*if wall_time < idle_time, evaluate cpu load next time*/ + cur_load = wall_time > idle_time ? (100 * (wall_time - idle_time)) / wall_time : 1;/*if wall_time is equal to idle_time cpu_load is equal to 1*/ + tmp_freq = cpu_policy->cur; + /* Checking Frequency Limit */ + min_freq = cpu_policy->min; + max_freq = cpu_policy->max; + + freq_responsiveness = atomic_read(&alucard_tuners_ins.freq_responsiveness); + + pump_inc_step = atomic_read(&alucard_tuners_ins.pump_inc_step); + pump_dec_step = atomic_read(&alucard_tuners_ins.pump_dec_step); + + /* CPUs Online Scale Frequency*/ + if (cpu_policy->cur < freq_responsiveness) { + inc_cpu_load = atomic_read(&alucard_tuners_ins.inc_cpu_load_at_min_freq); + dec_cpu_load = atomic_read(&alucard_tuners_ins.dec_cpu_load_at_min_freq); + } else { + inc_cpu_load = atomic_read(&alucard_tuners_ins.inc_cpu_load); + dec_cpu_load = atomic_read(&alucard_tuners_ins.dec_cpu_load); + } + /* Check for frequency increase or for frequency decrease */ +#ifdef CONFIG_CPU_EXYNOS4210 + if (cur_load >= inc_cpu_load && cpu_policy->cur < max_freq) { + next_freq = min(cpu_policy->cur + (pump_inc_step * 100000), max_freq); + } else if (cur_load < dec_cpu_load && cpu_policy->cur > min_freq) { + next_freq = max(cpu_policy->cur - (pump_dec_step * 100000), min_freq); + } else { + next_freq = cpu_policy->cur; + } +#else + if (cur_load >= inc_cpu_load && cpu_policy->cur < max_freq) { + tmp_freq = min(cpu_policy->cur + (pump_inc_step * 108000), max_freq); + } else if (cur_load < dec_cpu_load && cpu_policy->cur > min_freq) { + tmp_freq = max(cpu_policy->cur - (pump_dec_step * 108000), min_freq); + } else { + tmp_freq = cpu_policy->cur; + } + cpufreq_frequency_table_target(cpu_policy, this_alucard_cpuinfo->freq_table, tmp_freq, + CPUFREQ_RELATION_H, &index); + if (this_alucard_cpuinfo->freq_table[index].frequency != cpu_policy->cur) { + cpufreq_frequency_table_target(cpu_policy, this_alucard_cpuinfo->freq_table, tmp_freq, + CPUFREQ_RELATION_L, &index); + } + next_freq = this_alucard_cpuinfo->freq_table[index].frequency; +#endif + /*printk(KERN_ERR "FREQ CALC.: CPU[%u], load[%d], target freq[%u], cur freq[%u], min freq[%u], max_freq[%u]\n",cpu, cur_load, next_freq, cpu_policy->cur, cpu_policy->min, max_freq);*/ + if (next_freq != cpu_policy->cur && cpu_online(cpu)) { + __cpufreq_driver_target(cpu_policy, next_freq, CPUFREQ_RELATION_L); + } + } + +} + +static void do_alucard_timer(struct work_struct *work) +{ + struct cpufreq_alucard_cpuinfo *alucard_cpuinfo; + int delay; + unsigned int cpu; + + alucard_cpuinfo = container_of(work, struct cpufreq_alucard_cpuinfo, work.work); + cpu = alucard_cpuinfo->cpu; + + mutex_lock(&alucard_cpuinfo->timer_mutex); + alucard_check_cpu(alucard_cpuinfo); + /* We want all CPUs to do sampling nearly on + * same jiffy + */ + delay = usecs_to_jiffies(atomic_read(&alucard_tuners_ins.sampling_rate)); + if (num_online_cpus() > 1) { + delay -= jiffies % delay; + } + +#ifdef CONFIG_CPU_EXYNOS4210 + mod_delayed_work_on(cpu, system_wq, &alucard_cpuinfo->work, delay); +#else + queue_delayed_work_on(cpu, system_wq, &alucard_cpuinfo->work, delay); +#endif + mutex_unlock(&alucard_cpuinfo->timer_mutex); +} + +static int cpufreq_governor_alucard(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu; + struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo; + int rc, delay; + + cpu = policy->cpu; + this_alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&alucard_mutex); + + this_alucard_cpuinfo->cur_policy = policy; + + this_alucard_cpuinfo->prev_cpu_idle = get_cpu_idle_time_us(cpu, NULL); + this_alucard_cpuinfo->prev_cpu_idle += get_cpu_iowait_time_us(cpu, &this_alucard_cpuinfo->prev_cpu_wall); + + this_alucard_cpuinfo->freq_table = cpufreq_frequency_get_table(cpu); + this_alucard_cpuinfo->cpu = cpu; + + mutex_init(&this_alucard_cpuinfo->timer_mutex); + + alucard_enable++; + /* + * Start the timerschedule work, when this governor + * is used for first time + */ + if (alucard_enable == 1) { + rc = sysfs_create_group(cpufreq_global_kobject, + &alucard_attr_group); + if (rc) { + mutex_unlock(&alucard_mutex); + return rc; + } + } + + mutex_unlock(&alucard_mutex); + + delay=usecs_to_jiffies(atomic_read(&alucard_tuners_ins.sampling_rate)); + if (num_online_cpus() > 1) { + delay -= jiffies % delay; + } + + this_alucard_cpuinfo->enable = 1; +#ifdef CONFIG_CPU_EXYNOS4210 + INIT_DEFERRABLE_WORK(&this_alucard_cpuinfo->work, do_alucard_timer); + mod_delayed_work_on(this_alucard_cpuinfo->cpu, system_wq, &this_alucard_cpuinfo->work, delay); +#else + INIT_DELAYED_WORK_DEFERRABLE(&this_alucard_cpuinfo->work, do_alucard_timer); + queue_delayed_work_on(this_alucard_cpuinfo->cpu, system_wq, &this_alucard_cpuinfo->work, delay); +#endif + + break; + + case CPUFREQ_GOV_STOP: + this_alucard_cpuinfo->enable = 0; + cancel_delayed_work_sync(&this_alucard_cpuinfo->work); + + mutex_lock(&alucard_mutex); + alucard_enable--; + mutex_destroy(&this_alucard_cpuinfo->timer_mutex); + + if (!alucard_enable) { + sysfs_remove_group(cpufreq_global_kobject, + &alucard_attr_group); + } + mutex_unlock(&alucard_mutex); + + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&this_alucard_cpuinfo->timer_mutex); + if (policy->max < this_alucard_cpuinfo->cur_policy->cur) + __cpufreq_driver_target(this_alucard_cpuinfo->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_alucard_cpuinfo->cur_policy->cur) + __cpufreq_driver_target(this_alucard_cpuinfo->cur_policy, + policy->min, CPUFREQ_RELATION_L); + mutex_unlock(&this_alucard_cpuinfo->timer_mutex); + + break; + } + return 0; +} + +static int __init cpufreq_gov_alucard_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_alucard); +} + +static void __exit cpufreq_gov_alucard_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_alucard); +} + +MODULE_AUTHOR("Alucard24@XDA"); +MODULE_DESCRIPTION("'cpufreq_alucard' - A dynamic cpufreq governor v1.0 (SnapDragon)"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD +fs_initcall(cpufreq_gov_alucard_init); +#else +module_init(cpufreq_gov_alucard_init); +#endif +module_exit(cpufreq_gov_alucard_exit); diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c index 8f086aaa..84446d3c 100644 --- a/drivers/cpufreq/cpufreq_gov_msm.c +++ b/drivers/cpufreq/cpufreq_gov_msm.c @@ -18,114 +18,20 @@ #include #include #include -#include -#include -#include -#include #include -struct cpu_idle_info { - int enabled; - int dcvs_core_id; - struct pm_qos_request pm_qos_req; -}; - -static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info); -static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu); -static uint32_t latency; - -static int msm_dcvs_idle_notifier(int core_num, - enum msm_core_control_event event) -{ - struct cpu_idle_info *info = &per_cpu(cpu_idle_info, core_num); - - switch (event) { - case MSM_DCVS_ENABLE_IDLE_PULSE: - info->enabled = true; - break; - - case MSM_DCVS_DISABLE_IDLE_PULSE: - info->enabled = false; - break; - - case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES: - pm_qos_update_request(&info->pm_qos_req, PM_QOS_DEFAULT_VALUE); - break; - - case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES: - pm_qos_update_request(&info->pm_qos_req, latency); - break; - } - - return 0; -} - -static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd, - void *v) -{ - struct cpu_idle_info *info = - &per_cpu(cpu_idle_info, smp_processor_id()); - u64 io_wait_us = 0; - u64 prev_io_wait_us = 0; - u64 last_update_time = 0; - u64 val = 0; - uint32_t iowaited = 0; - - if (!info->enabled) - return NOTIFY_OK; - - switch (cmd) { - case CPU_PM_ENTER: - val = get_cpu_iowait_time_us(smp_processor_id(), - &last_update_time); - /* val could be -1 when NOHZ is not enabled */ - if (val == (u64)-1) - val = 0; - per_cpu(iowait_on_cpu, smp_processor_id()) = val; - msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0); - break; - - case CPU_PM_EXIT: - prev_io_wait_us = per_cpu(iowait_on_cpu, smp_processor_id()); - val = get_cpu_iowait_time_us(smp_processor_id(), - &last_update_time); - if (val == (u64)-1) - val = 0; - io_wait_us = val; - iowaited = (io_wait_us - prev_io_wait_us); - msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_EXIT, iowaited); - break; - } - - return NOTIFY_OK; -} - -static struct notifier_block idle_nb = { - .notifier_call = msm_cpuidle_notifier, -}; - -static void msm_gov_idle_source_init(int cpu, int dcvs_core_id) -{ - struct cpu_idle_info *info = NULL; - - info = &per_cpu(cpu_idle_info, cpu); - info->dcvs_core_id = dcvs_core_id; - - pm_qos_add_request(&info->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, - PM_QOS_DEFAULT_VALUE); -} - struct msm_gov { - int cpu; - unsigned int cur_freq; - unsigned int min_freq; - unsigned int max_freq; - struct cpufreq_policy *policy; - int dcvs_core_id; + int cpu; + unsigned int cur_freq; + unsigned int min_freq; + unsigned int max_freq; + struct msm_dcvs_freq gov_notifier; + struct cpufreq_policy *policy; }; static DEFINE_PER_CPU_SHARED_ALIGNED(struct mutex, gov_mutex); static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_gov, msm_gov_info); +static char core_name[NR_CPUS][10]; static void msm_gov_check_limits(struct cpufreq_policy *policy) { @@ -134,7 +40,7 @@ static void msm_gov_check_limits(struct cpufreq_policy *policy) if (policy->max < gov->cur_freq) __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > gov->cur_freq) + else if (policy->min > gov->min_freq) __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); else @@ -144,14 +50,14 @@ static void msm_gov_check_limits(struct cpufreq_policy *policy) gov->cur_freq = policy->cur; gov->min_freq = policy->min; gov->max_freq = policy->max; - msm_dcvs_update_limits(gov->dcvs_core_id); } -static int msm_dcvs_freq_set(int core_num, +static int msm_dcvs_freq_set(struct msm_dcvs_freq *self, unsigned int freq) { int ret = -EINVAL; - struct msm_gov *gov = &per_cpu(msm_gov_info, core_num); + struct msm_gov *gov = + container_of(self, struct msm_gov, gov_notifier); mutex_lock(&per_cpu(gov_mutex, gov->cpu)); @@ -160,30 +66,23 @@ static int msm_dcvs_freq_set(int core_num, if (freq > gov->max_freq) freq = gov->max_freq; - mutex_unlock(&per_cpu(gov_mutex, gov->cpu)); + ret = __cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L); + gov->cur_freq = gov->policy->cur; - ret = cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L); + mutex_unlock(&per_cpu(gov_mutex, gov->cpu)); - if (!ret) { - gov->cur_freq = cpufreq_quick_get(gov->cpu); - if (freq != gov->cur_freq) - pr_err("cpu %d freq %u gov->cur_freq %u didn't match", - gov->cpu, freq, gov->cur_freq); - } - ret = gov->cur_freq; + if (!ret) + return gov->cur_freq; return ret; } -static unsigned int msm_dcvs_freq_get(int core_num) +static unsigned int msm_dcvs_freq_get(struct msm_dcvs_freq *self) { - struct msm_gov *gov = &per_cpu(msm_gov_info, core_num); - /* - * the rw_sem in cpufreq is always held when this is called. - * The policy->cur won't be updated in this case - so it is safe to - * access policy->cur - */ - return gov->policy->cur; + struct msm_gov *gov = + container_of(self, struct msm_gov, gov_notifier); + + return gov->cur_freq; } static int cpufreq_governor_msm(struct cpufreq_policy *policy, @@ -193,6 +92,8 @@ static int cpufreq_governor_msm(struct cpufreq_policy *policy, int ret = 0; int handle = 0; struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu); + struct msm_dcvs_freq *dcvs_notifier = + &(per_cpu(msm_gov_info, cpu).gov_notifier); switch (event) { case CPUFREQ_GOV_START: @@ -202,14 +103,19 @@ static int cpufreq_governor_msm(struct cpufreq_policy *policy, mutex_lock(&per_cpu(gov_mutex, cpu)); per_cpu(msm_gov_info, cpu).cpu = cpu; gov->policy = policy; - handle = msm_dcvs_freq_sink_start(gov->dcvs_core_id); + dcvs_notifier->core_name = core_name[cpu]; + dcvs_notifier->set_frequency = msm_dcvs_freq_set; + dcvs_notifier->get_frequency = msm_dcvs_freq_get; + handle = msm_dcvs_freq_sink_register(dcvs_notifier); BUG_ON(handle < 0); msm_gov_check_limits(policy); mutex_unlock(&per_cpu(gov_mutex, cpu)); break; case CPUFREQ_GOV_STOP: - msm_dcvs_freq_sink_stop(gov->dcvs_core_id); + mutex_lock(&per_cpu(gov_mutex, cpu)); + msm_dcvs_freq_sink_unregister(dcvs_notifier); + mutex_unlock(&per_cpu(gov_mutex, cpu)); break; case CPUFREQ_GOV_LIMITS: @@ -230,41 +136,21 @@ struct cpufreq_governor cpufreq_gov_msm = { static int __devinit msm_gov_probe(struct platform_device *pdev) { + int ret = 0; int cpu; + uint32_t group_id = 0x43505530; /* CPU0 */ struct msm_dcvs_core_info *core = NULL; - struct msm_dcvs_core_info *core_info = NULL; - struct msm_gov_platform_data *pdata = pdev->dev.platform_data; - int sensor = 0; core = pdev->dev.platform_data; - core_info = pdata->info; - latency = pdata->latency; for_each_possible_cpu(cpu) { - struct msm_gov *gov = &per_cpu(msm_gov_info, cpu); - mutex_init(&per_cpu(gov_mutex, cpu)); - if (cpu < core->num_cores) - sensor = core_info->sensors[cpu]; - gov->dcvs_core_id = msm_dcvs_register_core( - MSM_DCVS_CORE_TYPE_CPU, - cpu, - core_info, - msm_dcvs_freq_set, - msm_dcvs_freq_get, - msm_dcvs_idle_notifier, - NULL, - sensor); - if (gov->dcvs_core_id < 0) { + snprintf(core_name[cpu], 10, "cpu%d", cpu); + ret = msm_dcvs_register_core(core_name[cpu], group_id, core); + if (ret) pr_err("Unable to register core for %d\n", cpu); - return -EINVAL; - } - - msm_gov_idle_source_init(cpu, gov->dcvs_core_id); } - cpu_pm_register_notifier(&idle_nb); - return cpufreq_register_governor(&cpufreq_gov_msm); } diff --git a/drivers/cpufreq/cpufreq_hyper.c b/drivers/cpufreq/cpufreq_hyper.c new file mode 100644 index 00000000..76326db1 --- /dev/null +++ b/drivers/cpufreq/cpufreq_hyper.c @@ -0,0 +1,898 @@ +/* + * drivers/cpufreq/cpufreq_hyper.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * + * 2012 Minor Edits by Sar Castillo + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * dbs is used in this file as a shortform for demandbased switching + * It helps to keep variable names smaller, simpler + */ + +#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) +#define DEF_FREQUENCY_UP_THRESHOLD (65) +#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) +#define MICRO_FREQUENCY_UP_THRESHOLD (85) +#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) +#define MIN_FREQUENCY_UP_THRESHOLD (11) +#define MAX_FREQUENCY_UP_THRESHOLD (100) +#define DEF_SUSPEND_FREQ (500000) + +/* + * The polling frequency of this governor depends on the capability of + * the processor. Default polling frequency is 1000 times the transition + * latency of the processor. The governor will work on any processor with + * transition latency <= 10mS, using appropriate sampling + * rate. + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. + * All times here are in uS. + */ +#define MIN_SAMPLING_RATE_RATIO (2) + +static unsigned int min_sampling_rate; + +static DEFINE_PER_CPU(unsigned int, idle_start); +static DEFINE_PER_CPU(unsigned int, idle_end); + +static int idle_event_handler(struct notifier_block *n, + unsigned long cmd, void *p) +{ + switch (cmd) { + case IDLE_START: + percpu_write(idle_start, jiffies); + break; + case IDLE_END: + percpu_write(idle_end, jiffies); + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block idle_notifier_block = { + .notifier_call = idle_event_handler, +}; + +#define LATENCY_MULTIPLIER (350) +#define MIN_LATENCY_MULTIPLIER (100) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +static void do_dbs_timer(struct work_struct *work); +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER +static +#endif +struct cpufreq_governor cpufreq_gov_hyper = { + .name = "hyper", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; + +/* Sampling types */ +enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; + +struct cpu_dbs_info_s { + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_iowait; + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + struct cpufreq_frequency_table *freq_table; + unsigned int freq_lo; + unsigned int freq_lo_jiffies; + unsigned int freq_hi_jiffies; + int cpu; + unsigned int sample_type:1; + /* + * percpu mutex that serializes governor limit change with + * do_dbs_timer invocation. We do not want do_dbs_timer to run + * when user is changing the governor or limits. + */ + struct mutex timer_mutex; +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info); + +static unsigned int dbs_enable; /* number of CPUs using this policy */ + +/* + * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on + * different CPUs. It protects dbs_enable in governor start/stop. + */ +static DEFINE_MUTEX(dbs_mutex); + +static struct workqueue_struct *khyper_wq; + +static struct dbs_tuners { + unsigned int sampling_rate; + unsigned int up_threshold; + unsigned int down_differential; + unsigned int ignore_nice; + unsigned int powersave_bias; + unsigned int io_is_busy; + unsigned int fast_start; + unsigned int deep_sleep; + unsigned int suspend_freq; +} dbs_tuners_ins = { + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, + .ignore_nice = 0, + .powersave_bias = 0, + .deep_sleep = 1, + .fast_start = 1, + .suspend_freq = DEF_SUSPEND_FREQ, +}; + +static unsigned int dbs_enable=0; /* number of CPUs using this policy */ + +// hyper suspend mods (Thanks to Imoseyon) +static unsigned int suspended = 0; +static void hyper_suspend(int suspend) +{ + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, smp_processor_id()); + if (dbs_enable==0) return; + if (!suspend) { // resume at max speed: + suspended = 0; + __cpufreq_driver_target(dbs_info->cur_policy, dbs_info->cur_policy->max, + CPUFREQ_RELATION_L); + pr_info("[hyper] hyper awake at %d\n", dbs_info->cur_policy->cur); + } else { + suspended = 1; + // let's give it a little breathing room + __cpufreq_driver_target(dbs_info->cur_policy, dbs_tuners_ins.suspend_freq, CPUFREQ_RELATION_H); + pr_info("[hyper] hyper suspended at %d\n", dbs_info->cur_policy->cur); + } +} + +static void hyper_early_suspend(struct early_suspend *handler) { + hyper_suspend(1); +} + +static void hyper_late_resume(struct early_suspend *handler) { + hyper_suspend(0); +} + +static struct early_suspend hyper_power_suspend = { + .suspend = hyper_early_suspend, + .resume = hyper_late_resume, + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, +}; + +static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu, + cputime64_t *wall) +{ + cputime64_t idle_time; + cputime64_t cur_wall_time; + cputime64_t busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = (cputime64_t)jiffies_to_usecs(cur_wall_time); + + return (cputime64_t)jiffies_to_usecs(idle_time); +} + +static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, wall); + + if (idle_time == -1ULL) + return get_cpu_idle_time_jiffy(cpu, wall); + + return idle_time; +} + +static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall) +{ + u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); + + if (iowait_time == -1ULL) + return 0; + + return iowait_time; +} + +/* + * Find right freq to be set now with powersave_bias on. + * Returns the freq_hi to be used right now and will set freq_hi_jiffies, + * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs. + */ +static unsigned int powersave_bias_target(struct cpufreq_policy *policy, + unsigned int freq_next, + unsigned int relation) +{ + unsigned int freq_req, freq_reduc, freq_avg; + unsigned int freq_hi, freq_lo; + unsigned int index = 0; + unsigned int jiffies_total, jiffies_hi, jiffies_lo; + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, + policy->cpu); + + if (!dbs_info->freq_table) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_next; + } + + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, + relation, &index); + freq_req = dbs_info->freq_table[index].frequency; + freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000; + freq_avg = freq_req - freq_reduc; + + /* Find freq bounds for freq_avg in freq_table */ + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_H, &index); + freq_lo = dbs_info->freq_table[index].frequency; + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_L, &index); + freq_hi = dbs_info->freq_table[index].frequency; + + /* Find out how long we have to be in hi and lo freqs */ + if (freq_hi == freq_lo) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_lo; + } + jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + jiffies_hi = (freq_avg - freq_lo) * jiffies_total; + jiffies_hi += ((freq_hi - freq_lo) / 2); + jiffies_hi /= (freq_hi - freq_lo); + jiffies_lo = jiffies_total - jiffies_hi; + dbs_info->freq_lo = freq_lo; + dbs_info->freq_lo_jiffies = jiffies_lo; + dbs_info->freq_hi_jiffies = jiffies_hi; + return freq_hi; +} + +static void hyper_powersave_bias_init_cpu(int cpu) +{ + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + dbs_info->freq_table = cpufreq_frequency_get_table(cpu); + dbs_info->freq_lo = 0; +} + +static void hyper_powersave_bias_init(void) +{ + int i; + for_each_online_cpu(i) { + hyper_powersave_bias_init_cpu(i); + } +} + +/************************** sysfs interface ************************/ + +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", min_sampling_rate); +} + +define_one_global_ro(sampling_rate_min); + +/* cpufreq_hyper Governor Tunables */ +#define show_one(file_name, object) \ + static ssize_t show_##file_name \ + (struct kobject *kobj, struct attribute *attr, char *buf) \ + { \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ + } + +show_one(sampling_rate, sampling_rate); +show_one(io_is_busy, io_is_busy); +show_one(fast_start, fast_start); +show_one(deep_sleep, deep_sleep); +show_one(up_threshold, up_threshold); +show_one(ignore_nice_load, ignore_nice); +show_one(powersave_bias, powersave_bias); +show_one(suspend_freq, suspend_freq); + +static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); + return count; +} + +static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.io_is_busy = !!input; + return count; +} + +static ssize_t store_fast_start(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + dbs_tuners_ins.fast_start = !!input; + + return count; +} + +static ssize_t store_deep_sleep(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + dbs_tuners_ins.deep_sleep = !!input; + + return count; +} + +static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + + dbs_tuners_ins.up_threshold = input; + + return count; +} + +static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (input > 1) + input = 1; + + if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */ + return count; + } + dbs_tuners_ins.ignore_nice = input; + + /* we need to re-evaluate prev_cpu_idle */ + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(od_cpu_dbs_info, j); + dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + + } + + return count; +} + +static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + if (input > 1000) + input = 1000; + + dbs_tuners_ins.powersave_bias = input; + hyper_powersave_bias_init(); + + return count; +} + +static ssize_t store_suspend_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + if (input > 1200000) + input = 1200000; + + if (input < 100000) + input = 100000; + + dbs_tuners_ins.suspend_freq = input; + + return count; +} + +define_one_global_rw(sampling_rate); +define_one_global_rw(io_is_busy); +define_one_global_rw(deep_sleep); +define_one_global_rw(fast_start); +define_one_global_rw(up_threshold); +define_one_global_rw(ignore_nice_load); +define_one_global_rw(powersave_bias); +define_one_global_rw(suspend_freq); + +static struct attribute *dbs_attributes[] = { + &sampling_rate_min.attr, + &sampling_rate.attr, + &up_threshold.attr, + &ignore_nice_load.attr, + &powersave_bias.attr, + &io_is_busy.attr, + &deep_sleep.attr, + &fast_start.attr, + &suspend_freq.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "hyper", +}; + +/************************** sysfs end ************************/ + +static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) +{ + unsigned int max_load_freq; + + struct cpufreq_policy *policy; + unsigned int j; + + this_dbs_info->freq_lo = 0; + policy = this_dbs_info->cur_policy; + + /* + * Every sampling_rate, we check, if current idle time is less + * than 20% (default), then we try to increase frequency + * Every sampling_rate, we look for a the lowest + * frequency which can sustain the load while keeping idle time over + * 30%. If such a frequency exist, we try to decrease to this frequency. + * + * Any frequency increase takes it to the maximum frequency. + * Frequency reduction happens at minimum steps of + * 5% (default) of current frequency + */ + + /* Get Absolute Load - in terms of freq */ + max_load_freq = 0; + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + unsigned int idle_time, wall_time, iowait_time; + unsigned int load, load_freq; + int freq_avg; + unsigned long start, end, delta, sampling_delta; + + j_dbs_info = &per_cpu(od_cpu_dbs_info, j); + + start = per_cpu(idle_start, j); + end = per_cpu(idle_end, j); + if (time_after(end, start)) + delta = (long)end - (long)start; + else + delta = 0; + sampling_delta = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + /* + * Deep sleep detection. + * + * If the previous low-power idle interval was 4x the sampling + * rate or more, we're probably exiting or entering from a deep + * sleep state. + * + * In both cases ignore the cpu activity, because probably + * there's a big chance to get back to the deep sleep again. + */ + if (dbs_tuners_ins.deep_sleep) { + if (delta > 4 * sampling_delta) + continue; + } + + /* + * Fast start detection. + * + * If in the last 4 samples the cpu did not enter in low-power + * idle state, probably the cpu is busy; try to jump to the + * maximum speed. + */ + if (dbs_tuners_ins.fast_start) { + if (delta && time_is_before_jiffies(end + + 4 * sampling_delta)) { + max_load_freq = UINT_MAX; + break; + } + } + + cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_dbs_info->prev_cpu_idle); + j_dbs_info->prev_cpu_idle = cur_idle_time; + + iowait_time = (unsigned int) + (cur_iowait_time - j_dbs_info->prev_cpu_iowait); + j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + if (dbs_tuners_ins.ignore_nice) { + u64 cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + j_dbs_info->prev_cpu_nice; + /* + * Assumption: nice time between sampling periods will + * be less than 2^32 jiffies for 32 bit sys + */ + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + /* + * For the purpose of hyper, waiting for disk IO is an + * indication that you're performance critical, and not that + * the system is actually idle. So subtract the iowait time + * from the cpu idle time. + */ + + if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time) + idle_time -= iowait_time; + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + load = 100 * (wall_time - idle_time) / wall_time; + + freq_avg = __cpufreq_driver_getavg(policy, j); + if (freq_avg <= 0) + freq_avg = policy->cur; + + load_freq = load * freq_avg; + if (load_freq > max_load_freq) + max_load_freq = load_freq; + } + + /* Check for frequency increase */ + if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) { + /* if we are already at full speed then break out early */ + if (!dbs_tuners_ins.powersave_bias) { + //if (policy->cur == policy->max) + // return; + + __cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_H); + } else { + int freq = powersave_bias_target(policy, policy->max, + CPUFREQ_RELATION_H); + __cpufreq_driver_target(policy, freq, + CPUFREQ_RELATION_L); + } + return; + } + + /* Check for frequency decrease */ + /* if we cannot reduce the frequency anymore, break out early */ + if (policy->cur == policy->min) { + __cpufreq_driver_target(policy, policy->min, + CPUFREQ_RELATION_L); + return; + } + + /* + * The optimal frequency is the frequency that is the lowest that + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ + if (max_load_freq < + (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * + policy->cur) { + unsigned int freq_next; + freq_next = max_load_freq / + (dbs_tuners_ins.up_threshold - + dbs_tuners_ins.down_differential); + + if (freq_next < policy->min) + freq_next = policy->min; + + if (!dbs_tuners_ins.powersave_bias) { + __cpufreq_driver_target(policy, freq_next, + CPUFREQ_RELATION_L); + } else { + int freq = powersave_bias_target(policy, freq_next, + CPUFREQ_RELATION_L); + __cpufreq_driver_target(policy, freq, + CPUFREQ_RELATION_L); + } + } +} + +static void do_dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + int sample_type = dbs_info->sample_type; + + /* We want all CPUs to do sampling nearly on same jiffy */ + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + mutex_lock(&dbs_info->timer_mutex); + + /* Common NORMAL_SAMPLE setup */ + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + if (!dbs_tuners_ins.powersave_bias || + sample_type == DBS_NORMAL_SAMPLE) { + dbs_check_cpu(dbs_info); + if (dbs_info->freq_lo) { + /* Setup timer for SUB_SAMPLE */ + dbs_info->sample_type = DBS_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; + } + } else { + if (!suspended) + __cpufreq_driver_target(dbs_info->cur_policy, + dbs_info->freq_lo, CPUFREQ_RELATION_H); + delay = dbs_info->freq_lo_jiffies; + } + queue_delayed_work_on(cpu, khyper_wq, &dbs_info->work, delay); + mutex_unlock(&dbs_info->timer_mutex); +} + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) +{ + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); + queue_delayed_work_on(dbs_info->cpu, khyper_wq, &dbs_info->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +{ + cancel_delayed_work_sync(&dbs_info->work); +} + +/* + * Not all CPUs want IO time to be accounted as busy; this dependson how + * efficient idling at a higher frequency/voltage is. + * Pavel Machek says this is not so for various generations of AMD and old + * Intel systems. + * Mike Chan (androidlcom) calis this is also not true for ARM. + * Because of this, whitelist specific known (series) of CPUs by default, and + * leave all others up to the user. + */ +static int should_io_be_busy(void) +{ + return 0; +} + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; + int rc; + + this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_mutex); + + dbs_enable++; + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(od_cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &j_dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + j_dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + this_dbs_info->cpu = cpu; + hyper_powersave_bias_init_cpu(cpu); + /* + * Start the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 1) { + unsigned int latency; + + rc = sysfs_create_group(cpufreq_global_kobject, + &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + + /* policy latency is in nS. Convert it to uS first */ + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + /* Bring kernel and HW constraints together */ + min_sampling_rate = max(min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + dbs_tuners_ins.sampling_rate = + max(min_sampling_rate, + latency * LATENCY_MULTIPLIER); + dbs_tuners_ins.io_is_busy = should_io_be_busy(); + } + mutex_unlock(&dbs_mutex); + + mutex_init(&this_dbs_info->timer_mutex); + dbs_timer_init(this_dbs_info); + register_early_suspend(&hyper_power_suspend); + pr_info("[hyper] hyper active\n"); + break; + + case CPUFREQ_GOV_STOP: + dbs_timer_exit(this_dbs_info); + + mutex_lock(&dbs_mutex); + mutex_destroy(&this_dbs_info->timer_mutex); + dbs_enable--; + mutex_unlock(&dbs_mutex); + if (!dbs_enable) + sysfs_remove_group(cpufreq_global_kobject, + &dbs_attr_group); + unregister_early_suspend(&hyper_power_suspend); + pr_info("[hyper] hyper inactive\n"); + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&this_dbs_info->timer_mutex); + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->min, CPUFREQ_RELATION_L); + mutex_unlock(&this_dbs_info->timer_mutex); + break; + } + return 0; +} + +static int __init cpufreq_gov_dbs_init(void) +{ + cputime64_t wall; + u64 idle_time; + int cpu = get_cpu(); + int err = 0; + + idle_time = get_cpu_idle_time_us(cpu, &wall); + put_cpu(); + if (idle_time != -1ULL) { + /* Idle micro accounting is supported. Use finer thresholds */ + dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; + dbs_tuners_ins.down_differential = + MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + /* + * In no_hz/micro accounting case we set the minimum frequency + * not depending on HZ, but fixed (very low). The deferred + * timer might skip some samples if idle/sleeping as needed. + */ + min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + } else { + /* For correct statistics, we need 10 ticks for each measure */ + min_sampling_rate = + MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + } + + khyper_wq = create_workqueue("khyper"); + if (!khyper_wq) { + printk(KERN_ERR "Creation of khyper failed\n"); + return -EFAULT; + } + + idle_notifier_register(&idle_notifier_block); + + err = cpufreq_register_governor(&cpufreq_gov_hyper); + if (err) + destroy_workqueue(khyper_wq); + + return err; +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + idle_notifier_unregister(&idle_notifier_block); + cpufreq_unregister_governor(&cpufreq_gov_hyper); + destroy_workqueue(khyper_wq); +} + +MODULE_AUTHOR("Venkatesh Pallipadi "); +MODULE_AUTHOR("Alexey Starikovskiy "); +MODULE_DESCRIPTION("'cpufreq_hyper' - A dynamic cpufreq governor with a sleep profile based on ondemand for " + "Low Latency Frequency Transition capable processors"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER +fs_initcall(cpufreq_gov_dbs_init); +#else +module_init(cpufreq_gov_dbs_init); +#endif +module_exit(cpufreq_gov_dbs_exit); diff --git a/drivers/cpufreq/cpufreq_intelliactive.c b/drivers/cpufreq/cpufreq_intelliactive.c new file mode 100644 index 00000000..9af81527 --- /dev/null +++ b/drivers/cpufreq/cpufreq_intelliactive.c @@ -0,0 +1,1544 @@ +/* + * drivers/cpufreq/cpufreq_intelliactive.c + * + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2014 Paul Reioux + * + * 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. + * + * Author: Mike Chan (mike@android.com) + * Author: Paul Reioux (reioux@gmail.com) Modified for intelliactive + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CORES (2) + +static int active_count; + +struct cpufreq_interactive_cpuinfo { + struct timer_list cpu_timer; + struct timer_list cpu_slack_timer; + spinlock_t load_lock; /* protects the next 4 fields */ + u64 time_in_idle; + u64 time_in_idle_timestamp; + u64 cputime_speedadj; + u64 cputime_speedadj_timestamp; + struct cpufreq_policy *policy; + struct cpufreq_frequency_table *freq_table; + unsigned int target_freq; + unsigned int floor_freq; + u64 floor_validate_time; + u64 hispeed_validate_time; + struct rw_semaphore enable_sem; + int governor_enabled; + int prev_load; + unsigned int two_phase_freq; +}; + +static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo); + +/* realtime thread handles frequency scaling */ +static struct task_struct *speedchange_task; +static cpumask_t speedchange_cpumask; +static spinlock_t speedchange_cpumask_lock; +static struct mutex gov_lock; + +/* Hi speed to bump to from lo speed when load burst (default max) */ +static unsigned int hispeed_freq; + +/* Go to hi speed when CPU load at or above this value. */ +#define DEFAULT_GO_HISPEED_LOAD 99 +static unsigned long go_hispeed_load = DEFAULT_GO_HISPEED_LOAD; + +/* Sampling down factor to be applied to min_sample_time at max freq */ +static unsigned int sampling_down_factor; + +/* Target load. Lower values result in higher CPU speeds. */ +#define DEFAULT_TARGET_LOAD 90 +static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD}; +static spinlock_t target_loads_lock; +static unsigned int *target_loads = default_target_loads; +static int ntarget_loads = ARRAY_SIZE(default_target_loads); + +/* + * The minimum amount of time to spend at a frequency before we can ramp down. + */ +#define DEFAULT_MIN_SAMPLE_TIME (80 * USEC_PER_MSEC) +static unsigned long min_sample_time = DEFAULT_MIN_SAMPLE_TIME; + +/* + * The sample rate of the timer used to increase frequency + */ +#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC) +static unsigned long timer_rate = DEFAULT_TIMER_RATE; + +/* Busy SDF parameters*/ +#define MIN_BUSY_TIME (100 * USEC_PER_MSEC) + +/* + * Wait this long before raising speed above hispeed, by default a single + * timer interval. + */ +#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE +static unsigned int default_above_hispeed_delay[] = { + DEFAULT_ABOVE_HISPEED_DELAY }; +static spinlock_t above_hispeed_delay_lock; +static unsigned int *above_hispeed_delay = default_above_hispeed_delay; +static int nabove_hispeed_delay = ARRAY_SIZE(default_above_hispeed_delay); + +/* Non-zero means indefinite speed boost active */ +static int boost_val; +/* Duration of a boot pulse in usecs */ +static int boostpulse_duration_val = DEFAULT_MIN_SAMPLE_TIME; +/* End time of boost pulse in ktime converted to usecs */ +static u64 boostpulse_endtime; + +/* + * Max additional time to wait in idle, beyond timer_rate, at speeds above + * minimum before wakeup to reduce speed, or -1 if unnecessary. + */ +#define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE) +static int timer_slack_val = DEFAULT_TIMER_SLACK; + +static bool io_is_busy = 1; + +/* + * If the max load among other CPUs is higher than up_threshold_any_cpu_load + * and if the highest frequency among the other CPUs is higher than + * up_threshold_any_cpu_freq then do not let the frequency to drop below + * sync_freq + */ +static unsigned int up_threshold_any_cpu_load = 95; +static unsigned int sync_freq = 245000; +static unsigned int up_threshold_any_cpu_freq = 320000; + +static int two_phase_freq_array[MAX_CORES] = {[0 ... MAX_CORES-1] = 700000} ; + +static int cpufreq_governor_intelliactive(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIACTIVE +static +#endif +struct cpufreq_governor cpufreq_gov_intelliactive = { + .name = "intelliactive", + .governor = cpufreq_governor_intelliactive, + .max_transition_latency = 10000000, + .owner = THIS_MODULE, +}; + +static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu, + cputime64_t *wall) +{ + u64 idle_time; + u64 cur_wall_time; + u64 busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = jiffies_to_usecs(cur_wall_time); + + return jiffies_to_usecs(idle_time); +} + +static inline cputime64_t get_cpu_idle_time(unsigned int cpu, + cputime64_t *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, wall); + + if (idle_time == -1ULL) + idle_time = get_cpu_idle_time_jiffy(cpu, wall); + else if (!io_is_busy) + idle_time += get_cpu_iowait_time_us(cpu, wall); + + return idle_time; +} + +static void cpufreq_interactive_timer_resched( + struct cpufreq_interactive_cpuinfo *pcpu) +{ + unsigned long expires; + unsigned long flags; + + spin_lock_irqsave(&pcpu->load_lock, flags); + pcpu->time_in_idle = + get_cpu_idle_time(smp_processor_id(), + &pcpu->time_in_idle_timestamp); + pcpu->cputime_speedadj = 0; + pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp; + expires = jiffies + usecs_to_jiffies(timer_rate); + mod_timer_pinned(&pcpu->cpu_timer, expires); + + if (timer_slack_val >= 0 && pcpu->target_freq > pcpu->policy->min) { + expires += usecs_to_jiffies(timer_slack_val); + mod_timer_pinned(&pcpu->cpu_slack_timer, expires); + } + + spin_unlock_irqrestore(&pcpu->load_lock, flags); +} + +/* The caller shall take enable_sem write semaphore to avoid any timer race. + * The cpu_timer and cpu_slack_timer must be deactivated when calling this + * function. + */ +static void cpufreq_interactive_timer_start(int cpu) +{ + struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu); + unsigned long expires = jiffies + usecs_to_jiffies(timer_rate); + unsigned long flags; + + pcpu->cpu_timer.expires = expires; + if (cpu_online(cpu)) { + add_timer_on(&pcpu->cpu_timer, cpu); + if (timer_slack_val >= 0 && pcpu->target_freq > + pcpu->policy->min) { + expires += usecs_to_jiffies(timer_slack_val); + pcpu->cpu_slack_timer.expires = expires; + add_timer_on(&pcpu->cpu_slack_timer, cpu); + } + } + + spin_lock_irqsave(&pcpu->load_lock, flags); + pcpu->time_in_idle = + get_cpu_idle_time(cpu, &pcpu->time_in_idle_timestamp); + pcpu->cputime_speedadj = 0; + pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp; + spin_unlock_irqrestore(&pcpu->load_lock, flags); +} + +static unsigned int freq_to_above_hispeed_delay(unsigned int freq) +{ + int i; + unsigned int ret; + unsigned long flags; + + spin_lock_irqsave(&above_hispeed_delay_lock, flags); + + for (i = 0; i < nabove_hispeed_delay - 1 && + freq >= above_hispeed_delay[i+1]; i += 2) + ; + + ret = above_hispeed_delay[i]; + ret = (ret > (1 * USEC_PER_MSEC)) ? (ret - (1 * USEC_PER_MSEC)) : ret; + + spin_unlock_irqrestore(&above_hispeed_delay_lock, flags); + return ret; +} + +static unsigned int freq_to_targetload(unsigned int freq) +{ + int i; + unsigned int ret; + unsigned long flags; + + spin_lock_irqsave(&target_loads_lock, flags); + + for (i = 0; i < ntarget_loads - 1 && freq >= target_loads[i+1]; i += 2) + ; + + ret = target_loads[i]; + spin_unlock_irqrestore(&target_loads_lock, flags); + return ret; +} + +/* + * If increasing frequencies never map to a lower target load then + * choose_freq() will find the minimum frequency that does not exceed its + * target load given the current load. + */ + +static unsigned int choose_freq( + struct cpufreq_interactive_cpuinfo *pcpu, unsigned int loadadjfreq) +{ + unsigned int freq = pcpu->policy->cur; + unsigned int prevfreq, freqmin, freqmax; + unsigned int tl; + int index; + + freqmin = 0; + freqmax = UINT_MAX; + + do { + prevfreq = freq; + tl = freq_to_targetload(freq); + + /* + * Find the lowest frequency where the computed load is less + * than or equal to the target load. + */ + + if (cpufreq_frequency_table_target( + pcpu->policy, pcpu->freq_table, loadadjfreq / tl, + CPUFREQ_RELATION_L, &index)) + break; + freq = pcpu->freq_table[index].frequency; + + if (freq > prevfreq) { + /* The previous frequency is too low. */ + freqmin = prevfreq; + + if (freq >= freqmax) { + /* + * Find the highest frequency that is less + * than freqmax. + */ + if (cpufreq_frequency_table_target( + pcpu->policy, pcpu->freq_table, + freqmax - 1, CPUFREQ_RELATION_H, + &index)) + break; + freq = pcpu->freq_table[index].frequency; + + if (freq == freqmin) { + /* + * The first frequency below freqmax + * has already been found to be too + * low. freqmax is the lowest speed + * we found that is fast enough. + */ + freq = freqmax; + break; + } + } + } else if (freq < prevfreq) { + /* The previous frequency is high enough. */ + freqmax = prevfreq; + + if (freq <= freqmin) { + /* + * Find the lowest frequency that is higher + * than freqmin. + */ + if (cpufreq_frequency_table_target( + pcpu->policy, pcpu->freq_table, + freqmin + 1, CPUFREQ_RELATION_L, + &index)) + break; + freq = pcpu->freq_table[index].frequency; + + /* + * If freqmax is the first frequency above + * freqmin then we have already found that + * this speed is fast enough. + */ + if (freq == freqmax) + break; + } + } + + /* If same frequency chosen as previous then done. */ + } while (freq != prevfreq); + + return freq; +} + +static u64 update_load(int cpu) +{ + struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu); + u64 now; + u64 now_idle; + unsigned int delta_idle; + unsigned int delta_time; + u64 active_time; + + now_idle = get_cpu_idle_time(cpu, &now); + delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle); + delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp); + + if (delta_time <= delta_idle) + active_time = 0; + else + active_time = delta_time - delta_idle; + + pcpu->cputime_speedadj += active_time * pcpu->policy->cur; + + pcpu->time_in_idle = now_idle; + pcpu->time_in_idle_timestamp = now; + return now; +} + +static void cpufreq_interactive_timer(unsigned long data) +{ + u64 now; + unsigned int delta_time; + u64 cputime_speedadj; + int cpu_load; + struct cpufreq_interactive_cpuinfo *pcpu = + &per_cpu(cpuinfo, data); + unsigned int new_freq; + unsigned int loadadjfreq; + unsigned int index; + unsigned long flags; + bool boosted; + unsigned long mod_min_sample_time; + int i, max_load; + unsigned int max_freq; + struct cpufreq_interactive_cpuinfo *picpu; + static unsigned int phase = 0; + static unsigned int counter = 0; + unsigned int nr_cpus; + + if (!down_read_trylock(&pcpu->enable_sem)) + return; + if (!pcpu->governor_enabled) + goto exit; + + if (cpu_is_offline(data)) + goto exit; + + spin_lock_irqsave(&pcpu->load_lock, flags); + now = update_load(data); + delta_time = (unsigned int)(now - pcpu->cputime_speedadj_timestamp); + cputime_speedadj = pcpu->cputime_speedadj; + spin_unlock_irqrestore(&pcpu->load_lock, flags); + + if (WARN_ON_ONCE(!delta_time)) + goto rearm; + + do_div(cputime_speedadj, delta_time); + loadadjfreq = (unsigned int)cputime_speedadj * 100; + cpu_load = loadadjfreq / pcpu->target_freq; + pcpu->prev_load = cpu_load; + boosted = boost_val || now < boostpulse_endtime; + + // HACK HACK HACK BEGIN + if (counter < 5) { + counter++; + if (counter > 2) { + phase = 1; + } + } + + if (cpu_load >= go_hispeed_load || boosted) { + if (pcpu->target_freq < hispeed_freq) { + nr_cpus = num_online_cpus(); + + pcpu->two_phase_freq = two_phase_freq_array[nr_cpus-1]; + if (pcpu->two_phase_freq < pcpu->policy->cur) + phase = 1; + if (pcpu->two_phase_freq != 0 && phase == 0) { + new_freq = pcpu->two_phase_freq; + } else + new_freq = hispeed_freq; + } else { + new_freq = choose_freq(pcpu, loadadjfreq); + + if (new_freq < hispeed_freq) + new_freq = hispeed_freq; + } + } else { + new_freq = choose_freq(pcpu, loadadjfreq); + + if (sync_freq && new_freq < sync_freq) { + + max_load = 0; + max_freq = 0; + + for_each_online_cpu(i) { + picpu = &per_cpu(cpuinfo, i); + + if (i == data || picpu->prev_load < + up_threshold_any_cpu_load) + continue; + + max_load = max(max_load, picpu->prev_load); + max_freq = max(max_freq, picpu->target_freq); + } + + if (max_freq > up_threshold_any_cpu_freq && + max_load >= up_threshold_any_cpu_load) + new_freq = sync_freq; + } + } + + if (counter > 0) { + counter--; + if (counter == 0) { + phase = 0; + } + } + + if (pcpu->target_freq >= hispeed_freq && + new_freq > pcpu->target_freq && + now - pcpu->hispeed_validate_time < + freq_to_above_hispeed_delay(pcpu->target_freq)) { + goto rearm; + } + + pcpu->hispeed_validate_time = now; + + if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table, + new_freq, CPUFREQ_RELATION_L, + &index)) + goto rearm; + + new_freq = pcpu->freq_table[index].frequency; + + /* + * Do not scale below floor_freq unless we have been at or above the + * floor frequency for the minimum sample time since last validated. + */ + if (sampling_down_factor && pcpu->policy->cur == pcpu->policy->max) + mod_min_sample_time = sampling_down_factor; + else + mod_min_sample_time = min_sample_time; + + if (new_freq < pcpu->floor_freq) { + if (now - pcpu->floor_validate_time < mod_min_sample_time) { + goto rearm; + } + } + + /* + * Update the timestamp for checking whether speed has been held at + * or above the selected frequency for a minimum of min_sample_time, + * if not boosted to hispeed_freq. If boosted to hispeed_freq then we + * allow the speed to drop as soon as the boostpulse duration expires + * (or the indefinite boost is turned off). + */ + + if (!boosted || new_freq > hispeed_freq) { + pcpu->floor_freq = new_freq; + pcpu->floor_validate_time = now; + } + + if (pcpu->target_freq == new_freq) { + goto rearm_if_notmax; + } + + pcpu->target_freq = new_freq; + spin_lock_irqsave(&speedchange_cpumask_lock, flags); + cpumask_set_cpu(data, &speedchange_cpumask); + spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); + wake_up_process(speedchange_task); + +rearm_if_notmax: + /* + * Already set max speed and don't see a need to change that, + * wait until next idle to re-evaluate, don't need timer. + */ + if (pcpu->target_freq == pcpu->policy->max) + goto exit; + +rearm: + if (!timer_pending(&pcpu->cpu_timer)) + cpufreq_interactive_timer_resched(pcpu); + +exit: + up_read(&pcpu->enable_sem); + return; +} + +static void cpufreq_interactive_idle_start(void) +{ + int cpu = smp_processor_id(); + struct cpufreq_interactive_cpuinfo *pcpu = + &per_cpu(cpuinfo, smp_processor_id()); + int pending; + u64 now; + + if (!down_read_trylock(&pcpu->enable_sem)) + return; + if (!pcpu->governor_enabled) + goto exit; + + /* Cancel the timer if cpu is offline */ + if (cpu_is_offline(cpu)) { + del_timer(&pcpu->cpu_timer); + del_timer(&pcpu->cpu_slack_timer); + goto exit; + } + + pending = timer_pending(&pcpu->cpu_timer); + + if (pcpu->target_freq != pcpu->policy->min) { + /* + * Entering idle while not at lowest speed. On some + * platforms this can hold the other CPU(s) at that speed + * even though the CPU is idle. Set a timer to re-evaluate + * speed so this idle CPU doesn't hold the other CPUs above + * min indefinitely. This should probably be a quirk of + * the CPUFreq driver. + */ + if (!pending) { + cpufreq_interactive_timer_resched(pcpu); + + now = ktime_to_us(ktime_get()); + if ((pcpu->policy->cur == pcpu->policy->max) && + (now - pcpu->hispeed_validate_time) > + MIN_BUSY_TIME) { + pcpu->floor_validate_time = now; + } + + } + } +exit: + up_read(&pcpu->enable_sem); +} + +static void cpufreq_interactive_idle_end(void) +{ + struct cpufreq_interactive_cpuinfo *pcpu = + &per_cpu(cpuinfo, smp_processor_id()); + + if (!down_read_trylock(&pcpu->enable_sem)) + return; + if (!pcpu->governor_enabled) { + up_read(&pcpu->enable_sem); + return; + } + + /* Arm the timer for 1-2 ticks later if not already. */ + if (!timer_pending(&pcpu->cpu_timer)) { + cpufreq_interactive_timer_resched(pcpu); + } else if (time_after_eq(jiffies, pcpu->cpu_timer.expires)) { + del_timer(&pcpu->cpu_timer); + del_timer(&pcpu->cpu_slack_timer); + cpufreq_interactive_timer(smp_processor_id()); + } + + up_read(&pcpu->enable_sem); +} + +static int cpufreq_interactive_speedchange_task(void *data) +{ + unsigned int cpu; + cpumask_t tmp_mask; + unsigned long flags; + struct cpufreq_interactive_cpuinfo *pcpu; + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&speedchange_cpumask_lock, flags); + + if (cpumask_empty(&speedchange_cpumask)) { + spin_unlock_irqrestore(&speedchange_cpumask_lock, + flags); + schedule(); + + if (kthread_should_stop()) + break; + + spin_lock_irqsave(&speedchange_cpumask_lock, flags); + } + + set_current_state(TASK_RUNNING); + tmp_mask = speedchange_cpumask; + cpumask_clear(&speedchange_cpumask); + spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); + + for_each_cpu(cpu, &tmp_mask) { + unsigned int j; + unsigned int max_freq = 0; + + pcpu = &per_cpu(cpuinfo, cpu); + if (!down_read_trylock(&pcpu->enable_sem)) + continue; + if (!pcpu->governor_enabled) { + up_read(&pcpu->enable_sem); + continue; + } + + for_each_cpu(j, pcpu->policy->cpus) { + struct cpufreq_interactive_cpuinfo *pjcpu = + &per_cpu(cpuinfo, j); + + if (pjcpu->target_freq > max_freq) + max_freq = pjcpu->target_freq; + } + + if (max_freq != pcpu->policy->cur) + __cpufreq_driver_target(pcpu->policy, + max_freq, + CPUFREQ_RELATION_H); + + up_read(&pcpu->enable_sem); + } + } + + return 0; +} + +static void cpufreq_interactive_boost(void) +{ + int i; + int anyboost = 0; + unsigned long flags; + struct cpufreq_interactive_cpuinfo *pcpu; + + spin_lock_irqsave(&speedchange_cpumask_lock, flags); + + for_each_online_cpu(i) { + pcpu = &per_cpu(cpuinfo, i); + + if (pcpu->target_freq < hispeed_freq) { + pcpu->target_freq = hispeed_freq; + cpumask_set_cpu(i, &speedchange_cpumask); + pcpu->hispeed_validate_time = + ktime_to_us(ktime_get()); + anyboost = 1; + } + + /* + * Set floor freq and (re)start timer for when last + * validated. + */ + + pcpu->floor_freq = hispeed_freq; + pcpu->floor_validate_time = ktime_to_us(ktime_get()); + } + + spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); + + if (anyboost) + wake_up_process(speedchange_task); +} + +static int cpufreq_interactive_notifier( + struct notifier_block *nb, unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = data; + struct cpufreq_interactive_cpuinfo *pcpu; + int cpu; + unsigned long flags; + + if (val == CPUFREQ_POSTCHANGE) { + pcpu = &per_cpu(cpuinfo, freq->cpu); + if (!down_read_trylock(&pcpu->enable_sem)) + return 0; + if (!pcpu->governor_enabled) { + up_read(&pcpu->enable_sem); + return 0; + } + + for_each_cpu(cpu, pcpu->policy->cpus) { + struct cpufreq_interactive_cpuinfo *pjcpu = + &per_cpu(cpuinfo, cpu); + if (cpu != freq->cpu) { + if (!down_read_trylock(&pjcpu->enable_sem)) + continue; + if (!pjcpu->governor_enabled) { + up_read(&pjcpu->enable_sem); + continue; + } + } + spin_lock_irqsave(&pjcpu->load_lock, flags); + update_load(cpu); + spin_unlock_irqrestore(&pjcpu->load_lock, flags); + if (cpu != freq->cpu) + up_read(&pjcpu->enable_sem); + } + + up_read(&pcpu->enable_sem); + } + return 0; +} + +static struct notifier_block cpufreq_notifier_block = { + .notifier_call = cpufreq_interactive_notifier, +}; + +static unsigned int *get_tokenized_data(const char *buf, int *num_tokens) +{ + const char *cp; + int i; + int ntokens = 1; + unsigned int *tokenized_data; + int err = -EINVAL; + + cp = buf; + while ((cp = strpbrk(cp + 1, " :"))) + ntokens++; + + if (!(ntokens & 0x1)) + goto err; + + tokenized_data = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL); + if (!tokenized_data) { + err = -ENOMEM; + goto err; + } + + cp = buf; + i = 0; + while (i < ntokens) { + if (sscanf(cp, "%u", &tokenized_data[i++]) != 1) + goto err_kfree; + + cp = strpbrk(cp, " :"); + if (!cp) + break; + cp++; + } + + if (i != ntokens) + goto err_kfree; + + *num_tokens = ntokens; + return tokenized_data; + +err_kfree: + kfree(tokenized_data); +err: + return ERR_PTR(err); +} + +static ssize_t show_two_phase_freq +(struct kobject *kobj, struct attribute *attr, char *buf) +{ + int i = 0 ; + int shift = 0 ; + char *buf_pos = buf; + for ( i = 0 ; i < MAX_CORES; i++) { + shift = sprintf(buf_pos,"%d,",two_phase_freq_array[i]); + buf_pos += shift; + } + *(buf_pos-1) = '\0'; + return strlen(buf); +} + +static ssize_t store_two_phase_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + + int ret = 0; + ret = sscanf(buf,"%u,%u",&two_phase_freq_array[0], + &two_phase_freq_array[1]); + if (ret < MAX_CORES) + return -EINVAL; + + return count; +} + +static struct global_attr two_phase_freq_attr = + __ATTR(two_phase_freq, S_IRUGO | S_IWUSR, + show_two_phase_freq, store_two_phase_freq); + +static ssize_t show_target_loads( + struct kobject *kobj, struct attribute *attr, char *buf) +{ + int i; + ssize_t ret = 0; + unsigned long flags; + + spin_lock_irqsave(&target_loads_lock, flags); + + for (i = 0; i < ntarget_loads; i++) + ret += sprintf(buf + ret, "%u%s", target_loads[i], + i & 0x1 ? ":" : " "); + + --ret; + ret += sprintf(buf + ret, "\n"); + spin_unlock_irqrestore(&target_loads_lock, flags); + return ret; +} + +static ssize_t store_target_loads( + struct kobject *kobj, struct attribute *attr, const char *buf, + size_t count) +{ + int ntokens; + unsigned int *new_target_loads = NULL; + unsigned long flags; + + new_target_loads = get_tokenized_data(buf, &ntokens); + if (IS_ERR(new_target_loads)) + return PTR_RET(new_target_loads); + + spin_lock_irqsave(&target_loads_lock, flags); + if (target_loads != default_target_loads) + kfree(target_loads); + target_loads = new_target_loads; + ntarget_loads = ntokens; + spin_unlock_irqrestore(&target_loads_lock, flags); + return count; +} + +static struct global_attr target_loads_attr = + __ATTR(target_loads, S_IRUGO | S_IWUSR, + show_target_loads, store_target_loads); + +static ssize_t show_above_hispeed_delay( + struct kobject *kobj, struct attribute *attr, char *buf) +{ + int i; + ssize_t ret = 0; + unsigned long flags; + + spin_lock_irqsave(&above_hispeed_delay_lock, flags); + + for (i = 0; i < nabove_hispeed_delay; i++) + ret += sprintf(buf + ret, "%u%s", above_hispeed_delay[i], + i & 0x1 ? ":" : " "); + + --ret; + ret += sprintf(buf + ret, "\n"); + spin_unlock_irqrestore(&above_hispeed_delay_lock, flags); + return ret; +} + +static ssize_t store_above_hispeed_delay( + struct kobject *kobj, struct attribute *attr, const char *buf, + size_t count) +{ + int ntokens; + unsigned int *new_above_hispeed_delay = NULL; + unsigned long flags; + + new_above_hispeed_delay = get_tokenized_data(buf, &ntokens); + if (IS_ERR(new_above_hispeed_delay)) + return PTR_RET(new_above_hispeed_delay); + + spin_lock_irqsave(&above_hispeed_delay_lock, flags); + if (above_hispeed_delay != default_above_hispeed_delay) + kfree(above_hispeed_delay); + above_hispeed_delay = new_above_hispeed_delay; + nabove_hispeed_delay = ntokens; + spin_unlock_irqrestore(&above_hispeed_delay_lock, flags); + return count; + +} + +static struct global_attr above_hispeed_delay_attr = + __ATTR(above_hispeed_delay, S_IRUGO | S_IWUSR, + show_above_hispeed_delay, store_above_hispeed_delay); + +static ssize_t show_hispeed_freq(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", hispeed_freq); +} + +static ssize_t store_hispeed_freq(struct kobject *kobj, + struct attribute *attr, const char *buf, + size_t count) +{ + int ret; + long unsigned int val; + + ret = strict_strtoul(buf, 0, &val); + if (ret < 0) + return ret; + hispeed_freq = val; + return count; +} + +static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644, + show_hispeed_freq, store_hispeed_freq); + +static ssize_t show_sampling_down_factor(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", sampling_down_factor); +} + +static ssize_t store_sampling_down_factor(struct kobject *kobj, + struct attribute *attr, const char *buf, + size_t count) +{ + int ret; + long unsigned int val; + + ret = strict_strtoul(buf, 0, &val); + if (ret < 0) + return ret; + sampling_down_factor = val; + return count; +} + +static struct global_attr sampling_down_factor_attr = + __ATTR(sampling_down_factor, 0644, + show_sampling_down_factor, store_sampling_down_factor); + +static ssize_t show_go_hispeed_load(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", go_hispeed_load); +} + +static ssize_t store_go_hispeed_load(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = strict_strtoul(buf, 0, &val); + if (ret < 0) + return ret; + go_hispeed_load = val; + return count; +} + +static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load, 0644, + show_go_hispeed_load, store_go_hispeed_load); + +static ssize_t show_min_sample_time(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", min_sample_time); +} + +static ssize_t store_min_sample_time(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = strict_strtoul(buf, 0, &val); + if (ret < 0) + return ret; + min_sample_time = val; + return count; +} + +static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644, + show_min_sample_time, store_min_sample_time); + +static ssize_t show_timer_rate(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", timer_rate); +} + +static ssize_t store_timer_rate(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = strict_strtoul(buf, 0, &val); + if (ret < 0) + return ret; + timer_rate = val; + return count; +} + +static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644, + show_timer_rate, store_timer_rate); + +static ssize_t show_timer_slack( + struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", timer_slack_val); +} + +static ssize_t store_timer_slack( + struct kobject *kobj, struct attribute *attr, const char *buf, + size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + timer_slack_val = val; + return count; +} + +define_one_global_rw(timer_slack); + +static ssize_t show_boost(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", boost_val); +} + +static ssize_t store_boost(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + + boost_val = val; + + if (boost_val) { + cpufreq_interactive_boost(); + } + + return count; +} + +define_one_global_rw(boost); + +static ssize_t store_boostpulse(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + + boostpulse_endtime = ktime_to_us(ktime_get()) + boostpulse_duration_val; + cpufreq_interactive_boost(); + return count; +} + +static struct global_attr boostpulse = + __ATTR(boostpulse, 0200, NULL, store_boostpulse); + +static ssize_t show_boostpulse_duration( + struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", boostpulse_duration_val); +} + +static ssize_t store_boostpulse_duration( + struct kobject *kobj, struct attribute *attr, const char *buf, + size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + + boostpulse_duration_val = val; + return count; +} + +define_one_global_rw(boostpulse_duration); + +static ssize_t show_io_is_busy(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", io_is_busy); +} + +static ssize_t store_io_is_busy(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + io_is_busy = val; + return count; +} + +static struct global_attr io_is_busy_attr = __ATTR(io_is_busy, 0644, + show_io_is_busy, store_io_is_busy); + +static ssize_t show_sync_freq(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", sync_freq); +} + +static ssize_t store_sync_freq(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + sync_freq = val; + return count; +} + +static struct global_attr sync_freq_attr = __ATTR(sync_freq, 0644, + show_sync_freq, store_sync_freq); + +static ssize_t show_up_threshold_any_cpu_load(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", up_threshold_any_cpu_load); +} + +static ssize_t store_up_threshold_any_cpu_load(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + up_threshold_any_cpu_load = val; + return count; +} + +static struct global_attr up_threshold_any_cpu_load_attr = + __ATTR(up_threshold_any_cpu_load, 0644, + show_up_threshold_any_cpu_load, + store_up_threshold_any_cpu_load); + +static ssize_t show_up_threshold_any_cpu_freq(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", up_threshold_any_cpu_freq); +} + +static ssize_t store_up_threshold_any_cpu_freq(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + up_threshold_any_cpu_freq = val; + return count; +} + +static struct global_attr up_threshold_any_cpu_freq_attr = + __ATTR(up_threshold_any_cpu_freq, 0644, + show_up_threshold_any_cpu_freq, + store_up_threshold_any_cpu_freq); + +static struct attribute *interactive_attributes[] = { + &target_loads_attr.attr, + &above_hispeed_delay_attr.attr, + &hispeed_freq_attr.attr, + &go_hispeed_load_attr.attr, + &min_sample_time_attr.attr, + &timer_rate_attr.attr, + &timer_slack.attr, + &boost.attr, + &boostpulse.attr, + &boostpulse_duration.attr, + &io_is_busy_attr.attr, + &sampling_down_factor_attr.attr, + &sync_freq_attr.attr, + &up_threshold_any_cpu_load_attr.attr, + &up_threshold_any_cpu_freq_attr.attr, + &two_phase_freq_attr.attr, + NULL, +}; + +static void interactive_input_event(struct input_handle *handle, + unsigned int type, + unsigned int code, int value) +{ + if (type == EV_SYN && code == SYN_REPORT) { + boostpulse_endtime = ktime_to_us(ktime_get()) + + boostpulse_duration_val; + cpufreq_interactive_boost(); + } +} + +static int interactive_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "cpufreq"; + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void interactive_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id interactive_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, /* multi-touch touchscreen */ + { + .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, + .absbit = { [BIT_WORD(ABS_X)] = + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, /* touchpad */ +}; + +static struct input_handler interactive_input_handler = { + .event = interactive_input_event, + .connect = interactive_input_connect, + .disconnect = interactive_input_disconnect, + .name = "intelliactive", + .id_table = interactive_ids, +}; + +static struct attribute_group interactive_attr_group = { + .attrs = interactive_attributes, + .name = "intelliactive", +}; + +static int cpufreq_interactive_idle_notifier(struct notifier_block *nb, + unsigned long val, + void *data) +{ + switch (val) { + case IDLE_START: + cpufreq_interactive_idle_start(); + break; + case IDLE_END: + cpufreq_interactive_idle_end(); + break; + } + + return 0; +} + +static struct notifier_block cpufreq_interactive_idle_nb = { + .notifier_call = cpufreq_interactive_idle_notifier, +}; + +static int cpufreq_governor_intelliactive(struct cpufreq_policy *policy, + unsigned int event) +{ + int rc; + unsigned int j; + struct cpufreq_interactive_cpuinfo *pcpu; + struct cpufreq_frequency_table *freq_table; + + switch (event) { + case CPUFREQ_GOV_START: + if (!cpu_online(policy->cpu)) + return -EINVAL; + + mutex_lock(&gov_lock); + + freq_table = + cpufreq_frequency_get_table(policy->cpu); + if (!hispeed_freq) + hispeed_freq = policy->max; + + for_each_cpu(j, policy->cpus) { + pcpu = &per_cpu(cpuinfo, j); + pcpu->policy = policy; + pcpu->target_freq = policy->cur; + pcpu->freq_table = freq_table; + pcpu->floor_freq = pcpu->target_freq; + pcpu->floor_validate_time = + ktime_to_us(ktime_get()); + pcpu->hispeed_validate_time = + pcpu->floor_validate_time; + down_write(&pcpu->enable_sem); + del_timer_sync(&pcpu->cpu_timer); + del_timer_sync(&pcpu->cpu_slack_timer); + cpufreq_interactive_timer_start(j); + pcpu->governor_enabled = 1; + up_write(&pcpu->enable_sem); + } + + /* + * Do not register the idle hook and create sysfs + * entries if we have already done so. + */ + if (++active_count > 1) { + mutex_unlock(&gov_lock); + return 0; + } + + if (!policy->cpu) + rc = input_register_handler + (&interactive_input_handler); + + rc = sysfs_create_group(cpufreq_global_kobject, + &interactive_attr_group); + if (rc) { + mutex_unlock(&gov_lock); + return rc; + } + + idle_notifier_register(&cpufreq_interactive_idle_nb); + cpufreq_register_notifier( + &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + mutex_unlock(&gov_lock); + break; + + case CPUFREQ_GOV_STOP: + mutex_lock(&gov_lock); + for_each_cpu(j, policy->cpus) { + pcpu = &per_cpu(cpuinfo, j); + down_write(&pcpu->enable_sem); + pcpu->governor_enabled = 0; + pcpu->target_freq = 0; + del_timer_sync(&pcpu->cpu_timer); + del_timer_sync(&pcpu->cpu_slack_timer); + up_write(&pcpu->enable_sem); + } + + if (--active_count > 0) { + if (!policy->cpu) + input_unregister_handler(&interactive_input_handler); + mutex_unlock(&gov_lock); + return 0; + } + + cpufreq_unregister_notifier( + &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + idle_notifier_unregister(&cpufreq_interactive_idle_nb); + sysfs_remove_group(cpufreq_global_kobject, + &interactive_attr_group); + mutex_unlock(&gov_lock); + + break; + + case CPUFREQ_GOV_LIMITS: + if (policy->max < policy->cur) + __cpufreq_driver_target(policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > policy->cur) + __cpufreq_driver_target(policy, + policy->min, CPUFREQ_RELATION_L); + for_each_cpu(j, policy->cpus) { + pcpu = &per_cpu(cpuinfo, j); + + /* hold write semaphore to avoid race */ + down_write(&pcpu->enable_sem); + if (pcpu->governor_enabled == 0) { + up_write(&pcpu->enable_sem); + continue; + } + + /* update target_freq firstly */ + if (policy->max < pcpu->target_freq) + pcpu->target_freq = policy->max; + else if (policy->min > pcpu->target_freq) + pcpu->target_freq = policy->min; + + /* Reschedule timer. + * Delete the timers, else the timer callback may + * return without re-arm the timer when failed + * acquire the semaphore. This race may cause timer + * stopped unexpectedly. + */ + del_timer_sync(&pcpu->cpu_timer); + del_timer_sync(&pcpu->cpu_slack_timer); + cpufreq_interactive_timer_start(j); + up_write(&pcpu->enable_sem); + } + break; + } + return 0; +} + +static void cpufreq_interactive_nop_timer(unsigned long data) +{ +} + +static int __init cpufreq_intelliactive_init(void) +{ + unsigned int i; + struct cpufreq_interactive_cpuinfo *pcpu; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + + /* Initalize per-cpu timers */ + for_each_possible_cpu(i) { + pcpu = &per_cpu(cpuinfo, i); + init_timer_deferrable(&pcpu->cpu_timer); + pcpu->cpu_timer.function = cpufreq_interactive_timer; + pcpu->cpu_timer.data = i; + init_timer(&pcpu->cpu_slack_timer); + pcpu->cpu_slack_timer.function = cpufreq_interactive_nop_timer; + spin_lock_init(&pcpu->load_lock); + init_rwsem(&pcpu->enable_sem); + } + + spin_lock_init(&target_loads_lock); + spin_lock_init(&speedchange_cpumask_lock); + spin_lock_init(&above_hispeed_delay_lock); + mutex_init(&gov_lock); + speedchange_task = + kthread_create(cpufreq_interactive_speedchange_task, NULL, + "cfintelliactive"); + if (IS_ERR(speedchange_task)) + return PTR_ERR(speedchange_task); + + sched_setscheduler_nocheck(speedchange_task, SCHED_FIFO, ¶m); + get_task_struct(speedchange_task); + + /* NB: wake up so the thread does not look hung to the freezer */ + wake_up_process(speedchange_task); + + return cpufreq_register_governor(&cpufreq_gov_intelliactive); +} + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIACTIVE +fs_initcall(cpufreq_intelliactive_init); +#else +module_init(cpufreq_intelliactive_init); +#endif + +static void __exit cpufreq_interactive_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_intelliactive); + kthread_stop(speedchange_task); + put_task_struct(speedchange_task); +} + +module_exit(cpufreq_interactive_exit); + +MODULE_AUTHOR("Mike Chan "); +MODULE_AUTHOR("Paul Reioux "); +MODULE_DESCRIPTION("'cpufreq_intelliactive' - A cpufreq governor for " + "Latency sensitive workloads based on Google's Interactive"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/cpufreq_intellidemand.c b/drivers/cpufreq/cpufreq_intellidemand.c new file mode 100644 index 00000000..4653db28 --- /dev/null +++ b/drivers/cpufreq/cpufreq_intellidemand.c @@ -0,0 +1,2469 @@ +/* + * drivers/cpufreq/cpufreq_intellidemand.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * (C) 2013 The Linux Foundation. All rights reserved. + * (C) 2013 Paul Reioux + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#include +#endif + +#define INTELLIDEMAND_MAJOR_VERSION 5 +#define INTELLIDEMAND_MINOR_VERSION 5 + +/* + * dbs is used in this file as a shortform for demandbased switching + * It helps to keep variable names smaller, simpler + */ + +#define DEF_SAMPLING_RATE (120000) +#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) +#define DEF_FREQUENCY_UP_THRESHOLD (80) +#define DEF_SAMPLING_DOWN_FACTOR (1) +#define MAX_SAMPLING_DOWN_FACTOR (100000) +#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) +#define MICRO_FREQUENCY_UP_THRESHOLD (95) +#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) +#define MIN_FREQUENCY_UP_THRESHOLD (11) +#define MAX_FREQUENCY_UP_THRESHOLD (100) +#define MIN_FREQUENCY_DOWN_DIFFERENTIAL (1) +#define DBS_INPUT_EVENT_MIN_FREQ (700000) +#define DEF_UI_DYNAMIC_SAMPLING_RATE (30000) +#define DBS_UI_SAMPLING_MIN_TIMEOUT (30) +#define DBS_UI_SAMPLING_MAX_TIMEOUT (1000) +#define DBS_UI_SAMPLING_TIMEOUT (80) + +#define DEF_FREQ_STEP (10) +#define DEF_STEP_UP_EARLY_HISPEED (700000) +#define DEF_STEP_UP_INTERIM_HISPEED (1008000) +#define DEF_SAMPLING_EARLY_HISPEED_FACTOR (2) +#define DEF_SAMPLING_INTERIM_HISPEED_FACTOR (3) + +/* PATCH : SMART_UP */ +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) + +#define SMART_UP_PLUS (0) +#define SMART_UP_SLOW_UP_AT_HIGH_FREQ (1) +#define SUP_MAX_STEP (3) +#define SUP_CORE_NUM (4) +#define SUP_SLOW_UP_DUR (5) +#define SUP_SLOW_UP_DUR_DEFAULT (2) + +#define SUP_HIGH_SLOW_UP_DUR (5) +#define SUP_FREQ_LEVEL (14) + +#if 0 +static unsigned long stored_sampling_rate; +#endif + +#if defined(SMART_UP_PLUS) +static unsigned int SUP_THRESHOLD_STEPS[SUP_MAX_STEP] = {85, 90, 95}; +static unsigned int SUP_FREQ_STEPS[SUP_MAX_STEP] = {4, 3, 2}; +//static unsigned int min_range = 108000; +typedef struct{ + unsigned int freq_idx; + unsigned int freq_value; +} freq_table_idx; +static freq_table_idx pre_freq_idx[SUP_CORE_NUM] = {}; + +#endif + + +#if defined(SMART_UP_SLOW_UP_AT_HIGH_FREQ) + +#define SUP_SLOW_UP_FREQUENCY (700000) +#define SUP_HIGH_SLOW_UP_FREQUENCY (1008000) +#define SUP_SLOW_UP_LOAD (95) + +typedef struct { + unsigned int hist_max_load[SUP_SLOW_UP_DUR]; + unsigned int hist_load_cnt; +} history_load; +static void reset_hist(history_load *hist_load); +static history_load hist_load[SUP_CORE_NUM] = {}; + +typedef struct { + unsigned int hist_max_load[SUP_HIGH_SLOW_UP_DUR]; + unsigned int hist_load_cnt; +} history_load_high; +static void reset_hist_high(history_load_high *hist_load); +static history_load_high hist_load_high[SUP_CORE_NUM] = {}; + +#endif + + +/* + * The polling frequency of this governor depends on the capability of + * the processor. Default polling frequency is 1000 times the transition + * latency of the processor. The governor will work on any processor with + * transition latency <= 10mS, using appropriate sampling + * rate. + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. + * All times here are in uS. + */ +#define MIN_SAMPLING_RATE_RATIO (2) + +static unsigned int min_sampling_rate; +static unsigned int skip_intellidemand = 0; + +#define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (20) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +#define POWERSAVE_BIAS_MAXLEVEL (1000) +#define POWERSAVE_BIAS_MINLEVEL (-1000) + +static void do_dbs_timer(struct work_struct *work); +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND +static +#endif +struct cpufreq_governor cpufreq_gov_intellidemand = { + .name = "intellidemand", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; + +/* Sampling types */ +enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; + +struct cpu_dbs_info_s { + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_iowait; + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + struct cpufreq_frequency_table *freq_table; + unsigned int freq_lo; + unsigned int freq_lo_jiffies; + unsigned int freq_hi_jiffies; + unsigned int rate_mult; + unsigned int prev_load; + unsigned int max_load; + int cpu; + unsigned int sample_type:1; + unsigned int freq_stay_count; + /* + * percpu mutex that serializes governor limit change with + * do_dbs_timer invocation. We do not want do_dbs_timer to run + * when user is changing the governor or limits. + */ + struct mutex timer_mutex; + + struct task_struct *sync_thread; + wait_queue_head_t sync_wq; + atomic_t src_sync_cpu; + atomic_t sync_enabled; +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, id_cpu_dbs_info); + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info); +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info); + +static unsigned int dbs_enable; /* number of CPUs using this policy */ + +static DEFINE_PER_CPU(struct task_struct *, up_task); +static spinlock_t input_boost_lock; +static bool input_event_boost = false; +static unsigned long ui_sampling_expired = 0; + +/* + * dbs_mutex protects dbs_enable and dbs_info during start/stop. + */ +static DEFINE_MUTEX(dbs_mutex); + +static struct workqueue_struct *dbs_wq; + +struct dbs_work_struct { + struct work_struct work; + unsigned int cpu; +}; + +static DEFINE_PER_CPU(struct dbs_work_struct, dbs_refresh_work); + +static struct dbs_tuners { + unsigned int sampling_rate; + unsigned int up_threshold; + unsigned int up_threshold_multi_core; + unsigned int down_differential; + unsigned int down_differential_multi_core; + unsigned int optimal_freq; + unsigned int up_threshold_any_cpu_load; + unsigned int sync_freq; + unsigned int ignore_nice; + unsigned int sampling_down_factor; + int powersave_bias; + unsigned int io_is_busy; + //20130711 smart_up + unsigned int smart_up; + unsigned int smart_slow_up_load; + unsigned int smart_slow_up_freq; + unsigned int smart_slow_up_dur; + unsigned int smart_high_slow_up_freq; + unsigned int smart_high_slow_up_dur; + unsigned int smart_each_off; + // end smart_up + unsigned int freq_step; + unsigned int step_up_early_hispeed; + unsigned int step_up_interim_hispeed; + unsigned int sampling_early_factor; + unsigned int sampling_interim_factor; + unsigned int two_phase_freq; + unsigned int origin_sampling_rate; + unsigned int ui_sampling_rate; + unsigned int ui_timeout; + unsigned int enable_boost_cpu; + +} dbs_tuners_ins = { + .up_threshold_multi_core = DEF_FREQUENCY_UP_THRESHOLD, + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, + .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, + .down_differential_multi_core = MICRO_FREQUENCY_DOWN_DIFFERENTIAL, + .up_threshold_any_cpu_load = DEF_FREQUENCY_UP_THRESHOLD, + .ignore_nice = 0, + .powersave_bias = 0, + .sync_freq = 0, + .optimal_freq = 0, + //20130711 smart_up + .smart_up = SMART_UP_PLUS, + .smart_slow_up_load = SUP_SLOW_UP_LOAD, + .smart_slow_up_freq = SUP_SLOW_UP_FREQUENCY, + .smart_slow_up_dur = SUP_SLOW_UP_DUR_DEFAULT, + .smart_high_slow_up_freq = SUP_HIGH_SLOW_UP_FREQUENCY, + .smart_high_slow_up_dur = SUP_HIGH_SLOW_UP_DUR, + .smart_each_off = 0, + // end smart_up + .freq_step = DEF_FREQ_STEP, + .step_up_early_hispeed = DEF_STEP_UP_EARLY_HISPEED, + .step_up_interim_hispeed = DEF_STEP_UP_INTERIM_HISPEED, + .sampling_early_factor = DEF_SAMPLING_EARLY_HISPEED_FACTOR, + .sampling_interim_factor = DEF_SAMPLING_INTERIM_HISPEED_FACTOR, + .two_phase_freq = 0, + .ui_sampling_rate = DEF_UI_DYNAMIC_SAMPLING_RATE, + .ui_timeout = DBS_UI_SAMPLING_TIMEOUT, + .enable_boost_cpu = 1, + +}; + +static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) +{ + u64 idle_time; + u64 cur_wall_time; + u64 busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = jiffies_to_usecs(cur_wall_time); + + return jiffies_to_usecs(idle_time); +} + +static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, NULL); + + if (idle_time == -1ULL) + return get_cpu_idle_time_jiffy(cpu, wall); + else + idle_time += get_cpu_iowait_time_us(cpu, wall); + + return idle_time; +} + +static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall) +{ + u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); + + if (iowait_time == -1ULL) + return 0; + + return iowait_time; +} + +/* + * Find right freq to be set now with powersave_bias on. + * Returns the freq_hi to be used right now and will set freq_hi_jiffies, + * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs. + */ +static unsigned int powersave_bias_target(struct cpufreq_policy *policy, + unsigned int freq_next, + unsigned int relation) +{ + unsigned int freq_req, freq_avg; + unsigned int freq_hi, freq_lo; + unsigned int index = 0; + unsigned int jiffies_total, jiffies_hi, jiffies_lo; + int freq_reduc; + struct cpu_dbs_info_s *dbs_info = &per_cpu(id_cpu_dbs_info, + policy->cpu); + + if (!dbs_info->freq_table) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_next; + } + + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, + relation, &index); + freq_req = dbs_info->freq_table[index].frequency; + freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000; + freq_avg = freq_req - freq_reduc; + + /* Find freq bounds for freq_avg in freq_table */ + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_H, &index); + freq_lo = dbs_info->freq_table[index].frequency; + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_L, &index); + freq_hi = dbs_info->freq_table[index].frequency; + + /* Find out how long we have to be in hi and lo freqs */ + if (freq_hi == freq_lo) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_lo; + } + jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + jiffies_hi = (freq_avg - freq_lo) * jiffies_total; + jiffies_hi += ((freq_hi - freq_lo) / 2); + jiffies_hi /= (freq_hi - freq_lo); + jiffies_lo = jiffies_total - jiffies_hi; + dbs_info->freq_lo = freq_lo; + dbs_info->freq_lo_jiffies = jiffies_lo; + dbs_info->freq_hi_jiffies = jiffies_hi; + return freq_hi; +} + +static int intellidemand_powersave_bias_setspeed(struct cpufreq_policy *policy, + struct cpufreq_policy *altpolicy, + int level) +{ + if (level == POWERSAVE_BIAS_MAXLEVEL) { + /* maximum powersave; set to lowest frequency */ + __cpufreq_driver_target(policy, + (altpolicy) ? altpolicy->min : policy->min, + CPUFREQ_RELATION_L); + return 1; + } else if (level == POWERSAVE_BIAS_MINLEVEL) { + /* minimum powersave; set to highest frequency */ + __cpufreq_driver_target(policy, + (altpolicy) ? altpolicy->max : policy->max, + CPUFREQ_RELATION_H); + return 1; + } + return 0; +} + +static void intellidemand_powersave_bias_init_cpu(int cpu) +{ + struct cpu_dbs_info_s *dbs_info = &per_cpu(id_cpu_dbs_info, cpu); + dbs_info->freq_table = cpufreq_frequency_get_table(cpu); + dbs_info->freq_lo = 0; +} + +static void intellidemand_powersave_bias_init(void) +{ + int i; + for_each_online_cpu(i) { + intellidemand_powersave_bias_init_cpu(i); + } +} + +void intellidemand_boost_cpu(int boost) +{ + int cpu; + + if (!dbs_tuners_ins.enable_boost_cpu) + return; + + for_each_online_cpu(cpu) { + struct cpufreq_policy *policy; + struct cpu_dbs_info_s *dbs_info; + + policy = cpufreq_cpu_get(cpu); + if (!policy) + continue; + dbs_info = &per_cpu(id_cpu_dbs_info, policy->cpu); + cpufreq_cpu_put(policy); + + mutex_lock(&dbs_info->timer_mutex); + if (boost) { + skip_intellidemand = 1; + __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); + } else { + skip_intellidemand = 0; + } + mutex_unlock(&dbs_info->timer_mutex); + } +} +EXPORT_SYMBOL(intellidemand_boost_cpu); + +/************************** sysfs interface ************************/ + +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", min_sampling_rate); +} + +define_one_global_ro(sampling_rate_min); + +/* cpufreq_intellidemand Governor Tunables */ +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +} +show_one(sampling_rate, sampling_rate); +show_one(io_is_busy, io_is_busy); +show_one(up_threshold, up_threshold); +show_one(up_threshold_multi_core, up_threshold_multi_core); +show_one(down_differential, down_differential); +show_one(sampling_down_factor, sampling_down_factor); +show_one(ignore_nice_load, ignore_nice); +show_one(optimal_freq, optimal_freq); +show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load); +show_one(sync_freq, sync_freq); +//20130711 smart_up +show_one(smart_up, smart_up); +show_one(smart_slow_up_load, smart_slow_up_load); +show_one(smart_slow_up_freq, smart_slow_up_freq); +show_one(smart_slow_up_dur, smart_slow_up_dur); +show_one(smart_high_slow_up_freq, smart_high_slow_up_freq); +show_one(smart_high_slow_up_dur, smart_high_slow_up_dur); +show_one(smart_each_off, smart_each_off); +// end smart_up +show_one(freq_step, freq_step); +show_one(step_up_early_hispeed, step_up_early_hispeed); +show_one(step_up_interim_hispeed, step_up_interim_hispeed); +show_one(sampling_early_factor, sampling_early_factor); +show_one(sampling_interim_factor, sampling_interim_factor); +show_one(enable_boost_cpu, enable_boost_cpu) + +static ssize_t show_powersave_bias +(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dbs_tuners_ins.powersave_bias); +} + +/** + * update_sampling_rate - update sampling rate effective immediately if needed. + * @new_rate: new sampling rate + * + * If new rate is smaller than the old, simply updaing + * dbs_tuners_int.sampling_rate might not be appropriate. For example, + * if the original sampling_rate was 1 second and the requested new sampling + * rate is 10 ms because the user needs immediate reaction from intellidemand + * governor, but not sure if higher frequency will be required or not, + * then, the governor may change the sampling rate too late; up to 1 second + * later. Thus, if we are reducing the sampling rate, we need to make the + * new value effective immediately. + */ +static void update_sampling_rate(unsigned int new_rate) +{ + int cpu; + + dbs_tuners_ins.sampling_rate = new_rate + = max(new_rate, min_sampling_rate); + + get_online_cpus(); + for_each_online_cpu(cpu) { + struct cpufreq_policy *policy; + struct cpu_dbs_info_s *dbs_info; + unsigned long next_sampling, appointed_at; + + policy = cpufreq_cpu_get(cpu); + if (!policy) + continue; + dbs_info = &per_cpu(id_cpu_dbs_info, policy->cpu); + cpufreq_cpu_put(policy); + + mutex_lock(&dbs_info->timer_mutex); + + if (!delayed_work_pending(&dbs_info->work)) { + mutex_unlock(&dbs_info->timer_mutex); + continue; + } + + next_sampling = jiffies + usecs_to_jiffies(new_rate); + appointed_at = dbs_info->work.timer.expires; + + + if (time_before(next_sampling, appointed_at)) { + + mutex_unlock(&dbs_info->timer_mutex); + cancel_delayed_work_sync(&dbs_info->work); + mutex_lock(&dbs_info->timer_mutex); + + queue_delayed_work_on(dbs_info->cpu, dbs_wq, + &dbs_info->work, usecs_to_jiffies(new_rate)); + + } + mutex_unlock(&dbs_info->timer_mutex); + } + put_online_cpus(); +} + +show_one(ui_timeout, ui_timeout); + +static ssize_t store_ui_timeout(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + input = max(input, (unsigned int)DBS_UI_SAMPLING_MIN_TIMEOUT); + dbs_tuners_ins.ui_timeout = min(input, (unsigned int)DBS_UI_SAMPLING_MAX_TIMEOUT); + + return count; +} + +static int two_phase_freq_array[NR_CPUS] = {[0 ... NR_CPUS-1] = 700000} ; + +static ssize_t show_two_phase_freq +(struct kobject *kobj, struct attribute *attr, char *buf) +{ + int i = 0 ; + int shift = 0 ; + char *buf_pos = buf; + for ( i = 0 ; i < NR_CPUS; i++) { + shift = sprintf(buf_pos,"%d,",two_phase_freq_array[i]); + buf_pos += shift; + } + *(buf_pos-1) = '\0'; + return strlen(buf); +} + +static ssize_t store_two_phase_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + + int ret = 0; + if (NR_CPUS == 1) + ret = sscanf(buf,"%u",&two_phase_freq_array[0]); + else if (NR_CPUS == 2) + ret = sscanf(buf,"%u,%u",&two_phase_freq_array[0], + &two_phase_freq_array[1]); + else if (NR_CPUS == 4) + ret = sscanf(buf, "%u,%u,%u,%u", &two_phase_freq_array[0], + &two_phase_freq_array[1], + &two_phase_freq_array[2], + &two_phase_freq_array[3]); + if (ret < NR_CPUS) + return -EINVAL; + + return count; +} + +static int input_event_min_freq_array[NR_CPUS] = {[0 ... NR_CPUS-1] = DBS_INPUT_EVENT_MIN_FREQ} ; + +static ssize_t show_input_event_min_freq +(struct kobject *kobj, struct attribute *attr, char *buf) +{ + int i = 0 ; + int shift = 0 ; + char *buf_pos = buf; + for ( i = 0 ; i < NR_CPUS; i++) { + shift = sprintf(buf_pos,"%d,",input_event_min_freq_array[i]); + buf_pos += shift; + } + *(buf_pos-1) = '\0'; + return strlen(buf); +} + +static ssize_t store_input_event_min_freq(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + + int ret = 0; + if (NR_CPUS == 1) + ret = sscanf(buf,"%u",&input_event_min_freq_array[0]); + else if (NR_CPUS == 2) + ret = sscanf(buf,"%u,%u",&input_event_min_freq_array[0], + &input_event_min_freq_array[1]); + else if (NR_CPUS == 4) + ret = sscanf(buf, "%u,%u,%u,%u", &input_event_min_freq_array[0], + &input_event_min_freq_array[1], + &input_event_min_freq_array[2], + &input_event_min_freq_array[3]); + if (ret < NR_CPUS) + return -EINVAL; + + return count; +} + +show_one(ui_sampling_rate, ui_sampling_rate); + +static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input == dbs_tuners_ins.origin_sampling_rate) + return count; + update_sampling_rate(input); + dbs_tuners_ins.origin_sampling_rate = dbs_tuners_ins.sampling_rate; + return count; +} + +static ssize_t store_ui_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + dbs_tuners_ins.ui_sampling_rate = max(input, min_sampling_rate); + + return count; +} + +static ssize_t store_sync_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.sync_freq = input; + return count; +} + +static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.io_is_busy = !!input; + return count; +} + +static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.optimal_freq = input; + return count; +} + +static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + dbs_tuners_ins.up_threshold = input; + return count; +} + +static ssize_t store_up_threshold_multi_core(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + dbs_tuners_ins.up_threshold_multi_core = input; + return count; +} + +static ssize_t store_up_threshold_any_cpu_load(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + dbs_tuners_ins.up_threshold_any_cpu_load = input; + return count; +} + +static ssize_t store_down_differential(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input >= dbs_tuners_ins.up_threshold || + input < MIN_FREQUENCY_DOWN_DIFFERENTIAL) { + return -EINVAL; + } + + dbs_tuners_ins.down_differential = input; + + return count; +} + +static ssize_t store_sampling_down_factor(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input, j; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) + return -EINVAL; + dbs_tuners_ins.sampling_down_factor = input; + + /* Reset down sampling multiplier in case it was active */ + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(id_cpu_dbs_info, j); + dbs_info->rate_mult = 1; + } + return count; +} + +static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (input > 1) + input = 1; + + if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */ + return count; + } + dbs_tuners_ins.ignore_nice = input; + + /* we need to re-evaluate prev_cpu_idle */ + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(id_cpu_dbs_info, j); + dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + + } + return count; +} + +static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input = 0; + int bypass = 0; + int ret, cpu, reenable_timer, j; + struct cpu_dbs_info_s *dbs_info; + + struct cpumask cpus_timer_done; + cpumask_clear(&cpus_timer_done); + + ret = sscanf(buf, "%d", &input); + + if (ret != 1) + return -EINVAL; + + if (input >= POWERSAVE_BIAS_MAXLEVEL) { + input = POWERSAVE_BIAS_MAXLEVEL; + bypass = 1; + } else if (input <= POWERSAVE_BIAS_MINLEVEL) { + input = POWERSAVE_BIAS_MINLEVEL; + bypass = 1; + } + + if (input == dbs_tuners_ins.powersave_bias) { + /* no change */ + return count; + } + + reenable_timer = ((dbs_tuners_ins.powersave_bias == + POWERSAVE_BIAS_MAXLEVEL) || + (dbs_tuners_ins.powersave_bias == + POWERSAVE_BIAS_MINLEVEL)); + + dbs_tuners_ins.powersave_bias = input; + + get_online_cpus(); + mutex_lock(&dbs_mutex); + + if (!bypass) { + if (reenable_timer) { + /* reinstate dbs timer */ + for_each_online_cpu(cpu) { + if (lock_policy_rwsem_write(cpu) < 0) + continue; + + dbs_info = &per_cpu(id_cpu_dbs_info, cpu); + + for_each_cpu(j, &cpus_timer_done) { + if (!dbs_info->cur_policy) { + pr_err("Dbs policy is NULL\n"); + goto skip_this_cpu; + } + if (cpumask_test_cpu(j, dbs_info-> + cur_policy->cpus)) + goto skip_this_cpu; + } + + cpumask_set_cpu(cpu, &cpus_timer_done); + if (dbs_info->cur_policy) { + /* restart dbs timer */ + dbs_timer_init(dbs_info); + /* Enable frequency synchronization + * of CPUs */ + atomic_set(&dbs_info->sync_enabled, 1); + } +skip_this_cpu: + unlock_policy_rwsem_write(cpu); + } + } + intellidemand_powersave_bias_init(); + } else { + /* running at maximum or minimum frequencies; cancel + dbs timer as periodic load sampling is not necessary */ + for_each_online_cpu(cpu) { + if (lock_policy_rwsem_write(cpu) < 0) + continue; + + dbs_info = &per_cpu(id_cpu_dbs_info, cpu); + + for_each_cpu(j, &cpus_timer_done) { + if (!dbs_info->cur_policy) { + pr_err("Dbs policy is NULL\n"); + goto skip_this_cpu_bypass; + } + if (cpumask_test_cpu(j, dbs_info-> + cur_policy->cpus)) + goto skip_this_cpu_bypass; + } + + cpumask_set_cpu(cpu, &cpus_timer_done); + + if (dbs_info->cur_policy) { + /* cpu using intellidemand, cancel dbs timer */ + dbs_timer_exit(dbs_info); + /* Disable frequency synchronization of + * CPUs to avoid re-queueing of work from + * sync_thread */ + atomic_set(&dbs_info->sync_enabled, 0); + + mutex_lock(&dbs_info->timer_mutex); + intellidemand_powersave_bias_setspeed( + dbs_info->cur_policy, + NULL, + input); + mutex_unlock(&dbs_info->timer_mutex); + + } +skip_this_cpu_bypass: + unlock_policy_rwsem_write(cpu); + } + } + + mutex_unlock(&dbs_mutex); + put_online_cpus(); + + return count; +} + +static ssize_t store_enable_boost_cpu(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if(ret != 1) + return -EINVAL; + + dbs_tuners_ins.enable_boost_cpu = (input > 0 ? input : 0); + return count; +} + +/* PATCH : SMART_UP */ +#if defined(SMART_UP_SLOW_UP_AT_HIGH_FREQ) +static void reset_hist(history_load *hist_load) +{ int i; + + for (i = 0; i < SUP_SLOW_UP_DUR ; i++) + hist_load->hist_max_load[i] = 0; + + hist_load->hist_load_cnt = 0; +} + + +static void reset_hist_high(history_load_high *hist_load) +{ int i; + + for (i = 0; i < SUP_HIGH_SLOW_UP_DUR ; i++) + hist_load->hist_max_load[i] = 0; + + hist_load->hist_load_cnt = 0; +} + +#endif + +//20130711 smart_up +static ssize_t store_smart_up(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + unsigned int i; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input > 1 ){ + input = 1; + }else if (input < 0 ){ + input = 0; + } + + // buffer reset + for_each_online_cpu(i){ + reset_hist(&hist_load[i]); + reset_hist_high(&hist_load_high[i]); + } + dbs_tuners_ins.smart_up = input; + return count; +} + +static ssize_t store_smart_slow_up_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + unsigned int i; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input > 100 ){ + input = 100; + }else if (input < 0){ + input = 0; + } + // buffer reset + for_each_online_cpu(i){ + reset_hist(&hist_load[i]); + reset_hist_high(&hist_load_high[i]); + } + dbs_tuners_ins.smart_slow_up_load = input; + return count; +} +static ssize_t store_smart_slow_up_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + unsigned int i; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input < 0) + input = 0; + // buffer reset + for_each_online_cpu(i){ + reset_hist(&hist_load[i]); + reset_hist_high(&hist_load_high[i]); + } + dbs_tuners_ins.smart_slow_up_freq = input; + return count; +} +static ssize_t store_smart_slow_up_dur(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + unsigned int i; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input > SUP_SLOW_UP_DUR ){ + input = SUP_SLOW_UP_DUR; + }else if (input < 1 ){ + input = 1; + } + // buffer reset + for_each_online_cpu(i){ + reset_hist(&hist_load[i]); + reset_hist_high(&hist_load_high[i]); + } + dbs_tuners_ins.smart_slow_up_dur = input; + return count; +} +static ssize_t store_smart_high_slow_up_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + unsigned int i; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input < 0) + input = 0; + // buffer reset + for_each_online_cpu(i){ + reset_hist(&hist_load[i]); + reset_hist_high(&hist_load_high[i]); + } + dbs_tuners_ins.smart_high_slow_up_freq = input; + return count; +} +static ssize_t store_smart_high_slow_up_dur(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + unsigned int i; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input > SUP_HIGH_SLOW_UP_DUR ){ + input = SUP_HIGH_SLOW_UP_DUR; + }else if (input < 1 ){ + input = 1; + } + // buffer reset + for_each_online_cpu(i){ + reset_hist(&hist_load[i]); + reset_hist_high(&hist_load_high[i]); + } + dbs_tuners_ins.smart_high_slow_up_dur = input; + return count; +} +static ssize_t store_smart_each_off(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + unsigned int i; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input > SUP_CORE_NUM){ + input = SUP_CORE_NUM; + }else if ( input < 0){ + input = 0; + } + // buffer reset + for_each_online_cpu(i){ + reset_hist(&hist_load[i]); + reset_hist_high(&hist_load_high[i]); + } + dbs_tuners_ins.smart_each_off = input; + + return count; +} +//end smart_up + +static ssize_t store_freq_step(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 100 || + input < 0) { + return -EINVAL; + } + dbs_tuners_ins.freq_step = input; + return count; +} + +static ssize_t store_step_up_early_hispeed(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 2265600 || + input < 0) { + return -EINVAL; + } + dbs_tuners_ins.step_up_early_hispeed = input; + return count; +} + +static ssize_t store_step_up_interim_hispeed(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > DEF_STEP_UP_INTERIM_HISPEED || + input < 0) { + return -EINVAL; + } + dbs_tuners_ins.step_up_interim_hispeed = input; + return count; +} + +static ssize_t store_sampling_early_factor(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input < 1) + return -EINVAL; + dbs_tuners_ins.sampling_early_factor = input; + return count; +} + +static ssize_t store_sampling_interim_factor(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input < 1) + return -EINVAL; + dbs_tuners_ins.sampling_interim_factor = input; + return count; +} + +define_one_global_rw(sampling_rate); +define_one_global_rw(io_is_busy); +define_one_global_rw(up_threshold); +define_one_global_rw(down_differential); +define_one_global_rw(sampling_down_factor); +define_one_global_rw(ignore_nice_load); +define_one_global_rw(powersave_bias); +define_one_global_rw(up_threshold_multi_core); +define_one_global_rw(optimal_freq); +define_one_global_rw(up_threshold_any_cpu_load); +define_one_global_rw(sync_freq); +//20130711 smart_up +define_one_global_rw(smart_up); +define_one_global_rw(smart_slow_up_load); +define_one_global_rw(smart_slow_up_freq); +define_one_global_rw(smart_slow_up_dur); +define_one_global_rw(smart_high_slow_up_freq); +define_one_global_rw(smart_high_slow_up_dur); +define_one_global_rw(smart_each_off); +// end smart_up +define_one_global_rw(freq_step); +define_one_global_rw(step_up_early_hispeed); +define_one_global_rw(step_up_interim_hispeed); +define_one_global_rw(sampling_early_factor); +define_one_global_rw(sampling_interim_factor); +define_one_global_rw(two_phase_freq); +define_one_global_rw(input_event_min_freq); +define_one_global_rw(ui_sampling_rate); +define_one_global_rw(ui_timeout); +define_one_global_rw(enable_boost_cpu); + +static struct attribute *dbs_attributes[] = { + &sampling_rate_min.attr, + &sampling_rate.attr, + &up_threshold.attr, + &down_differential.attr, + &sampling_down_factor.attr, + &ignore_nice_load.attr, + &powersave_bias.attr, + &io_is_busy.attr, + &up_threshold_multi_core.attr, + &optimal_freq.attr, + &up_threshold_any_cpu_load.attr, + &sync_freq.attr, + //20130711 smart_up + &smart_up.attr, + &smart_slow_up_load.attr, + &smart_slow_up_freq.attr, + &smart_slow_up_dur.attr, + &smart_high_slow_up_freq.attr, + &smart_high_slow_up_dur.attr, + &smart_each_off.attr, + // end smart_up + &freq_step.attr, + &step_up_early_hispeed.attr, + &step_up_interim_hispeed.attr, + &sampling_early_factor.attr, + &sampling_interim_factor.attr, + &two_phase_freq.attr, + &input_event_min_freq.attr, + &ui_sampling_rate.attr, + &ui_timeout.attr, + &enable_boost_cpu.attr, + + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "intellidemand", +}; + +/************************** sysfs end ************************/ + +static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) +{ + if (dbs_tuners_ins.powersave_bias) + freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H); + else if (p->cur == p->max) + return; + + __cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ? + CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); +} + +int set_two_phase_freq(int cpufreq) +{ + int i = 0; + for ( i = 0 ; i < NR_CPUS; i++) + two_phase_freq_array[i] = cpufreq; + return 0; +} + +void set_two_phase_freq_by_cpu ( int cpu_nr, int cpufreq){ + two_phase_freq_array[cpu_nr-1] = cpufreq; +} + +static int input_event_boosted(void) +{ + unsigned long flags; + + + spin_lock_irqsave(&input_boost_lock, flags); + if (input_event_boost) { + if (time_before(jiffies, ui_sampling_expired)) { + spin_unlock_irqrestore(&input_boost_lock, flags); + return 1; + } + input_event_boost = false; + dbs_tuners_ins.sampling_rate = dbs_tuners_ins.origin_sampling_rate; + } + spin_unlock_irqrestore(&input_boost_lock, flags); + + return 0; +} + +static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) +{ + +#if defined(SMART_UP_PLUS) + unsigned int max_load = 0; + unsigned int core_j = 0; +#endif + + /* Extrapolated load of this CPU */ + unsigned int load_at_max_freq = 0; + unsigned int max_load_freq; + /* Current load across this CPU */ + unsigned int cur_load = 0; + unsigned int max_load_other_cpu = 0; + struct cpufreq_policy *policy; + unsigned int j; + static unsigned int phase = 0; + static unsigned int counter = 0; + unsigned int nr_cpus; + + this_dbs_info->freq_lo = 0; + policy = this_dbs_info->cur_policy; + + /* + * Every sampling_rate, we check, if current idle time is less + * than 20% (default), then we try to increase frequency + * Every sampling_rate, we look for a the lowest + * frequency which can sustain the load while keeping idle time over + * 30%. If such a frequency exist, we try to decrease to this frequency. + * + * Any frequency increase takes it to the maximum frequency. + * Frequency reduction happens at minimum steps of + * 5% (default) of current frequency + */ + + /* Get Absolute Load - in terms of freq */ + max_load_freq = 0; + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + unsigned int idle_time, wall_time, iowait_time; + unsigned int load_freq; + int freq_avg; + + j_dbs_info = &per_cpu(id_cpu_dbs_info, j); + + cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_dbs_info->prev_cpu_idle); + j_dbs_info->prev_cpu_idle = cur_idle_time; + + iowait_time = (unsigned int) + (cur_iowait_time - j_dbs_info->prev_cpu_iowait); + j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + if (dbs_tuners_ins.ignore_nice) { + u64 cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + j_dbs_info->prev_cpu_nice; + /* + * Assumption: nice time between sampling periods will + * be less than 2^32 jiffies for 32 bit sys + */ + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + /* + * For the purpose of intellidemand, waiting for disk IO is an + * indication that you're performance critical, and not that + * the system is actually idle. So subtract the iowait time + * from the cpu idle time. + */ + + if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time) + idle_time -= iowait_time; + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + /* + * If the CPU had gone completely idle, and a task just woke up + * on this CPU now, it would be unfair to calculate 'load' the + * usual way for this elapsed time-window, because it will show + * near-zero load, irrespective of how CPU intensive the new + * task is. This is undesirable for latency-sensitive bursty + * workloads. + * + * To avoid this, we reuse the 'load' from the previous + * time-window and give this task a chance to start with a + * reasonably high CPU frequency. + * + * Detecting this situation is easy: the governor's deferrable + * timer would not have fired during CPU-idle periods. Hence + * an unusually large 'wall_time' indicates this scenario. + */ + if (unlikely(wall_time > (2 * dbs_tuners_ins.sampling_rate))) { + cur_load = j_dbs_info->prev_load; + } else { + cur_load = 100 * (wall_time - idle_time) / wall_time; + } + j_dbs_info->max_load = max(cur_load, j_dbs_info->prev_load); + j_dbs_info->prev_load = cur_load; + freq_avg = __cpufreq_driver_getavg(policy, j); + if (freq_avg <= 0) + freq_avg = policy->cur; + + load_freq = cur_load * freq_avg; + if (load_freq > max_load_freq) + max_load_freq = load_freq; + +#if defined(SMART_UP_PLUS) + max_load = cur_load; + core_j = j; +#endif + + } + + for_each_online_cpu(j) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(id_cpu_dbs_info, j); + + if (j == policy->cpu) + continue; + + if (max_load_other_cpu < j_dbs_info->max_load) + max_load_other_cpu = j_dbs_info->max_load; + /* + * The other cpu could be running at higher frequency + * but may not have completed it's sampling_down_factor. + * For that case consider other cpu is loaded so that + * frequency imbalance does not occur. + */ + + if ((j_dbs_info->cur_policy != NULL) + && (j_dbs_info->cur_policy->cur == + j_dbs_info->cur_policy->max)) { + + if (policy->cur >= dbs_tuners_ins.optimal_freq) + max_load_other_cpu = + dbs_tuners_ins.up_threshold_any_cpu_load; + } + } + + /* calculate the scaled load across CPU */ + load_at_max_freq = (cur_load * policy->cur)/policy->cpuinfo.max_freq; + + cpufreq_notify_utilization(policy, load_at_max_freq); + +/* PATCH : SMART_UP */ + if (dbs_tuners_ins.smart_up && ( core_j + 1 ) > dbs_tuners_ins.smart_each_off ){ + + if (max_load_freq > SUP_THRESHOLD_STEPS[0] * policy->cur) { + int smart_up_inc = + (policy->max - policy->cur) / SUP_FREQ_STEPS[0]; + int freq_next = 0; + int i = 0; + + //20130429 UPDATE + int check_idx = 0; + int check_freq = 0; + int temp_up_inc =0; + + if (counter < 5) { + counter++; + if (counter > 2) { + phase = 1; + } + } + + nr_cpus = num_online_cpus(); + dbs_tuners_ins.two_phase_freq = two_phase_freq_array[nr_cpus-1]; + if (dbs_tuners_ins.two_phase_freq < policy->cur) + phase = 1; + if (dbs_tuners_ins.two_phase_freq != 0 && phase == 0) { + dbs_freq_increase(policy, dbs_tuners_ins.two_phase_freq); + } else { + if (policy->cur < policy->max) + this_dbs_info->rate_mult = + dbs_tuners_ins.sampling_down_factor; + dbs_freq_increase(policy, policy->max); + } + + for (i = (SUP_MAX_STEP - 1); i > 0; i--) { + if (max_load_freq > SUP_THRESHOLD_STEPS[i] + * policy->cur) { + smart_up_inc = (policy->max - policy->cur) + / SUP_FREQ_STEPS[i]; + + break; + } + } + + //20130429 UPDATE + check_idx = pre_freq_idx[core_j].freq_idx; + check_freq = pre_freq_idx[core_j].freq_value; + if ( ( check_idx == 0) + || (this_dbs_info->freq_table[check_idx].frequency + != policy->cur) ) + { + int i = 0; + for( i =0; i < SUP_FREQ_LEVEL; i ++) + { + if (this_dbs_info->freq_table[i].frequency == policy->cur) + { + + pre_freq_idx[core_j].freq_idx = i; + pre_freq_idx[core_j].freq_value = policy->cur; + check_idx = i; + check_freq = policy->cur; + break; + } + } + + } + if( check_idx < SUP_FREQ_LEVEL-1 ){ + temp_up_inc = + this_dbs_info->freq_table[check_idx + 1].frequency + - check_freq; + } + + if (smart_up_inc < temp_up_inc ) + smart_up_inc = temp_up_inc; + + freq_next = MIN((policy->cur + smart_up_inc), policy->max); + + + if (policy->cur >= dbs_tuners_ins.smart_high_slow_up_freq){ + int idx = hist_load_high[core_j].hist_load_cnt; + int avg_hist_load = 0; + + if (idx >= dbs_tuners_ins.smart_high_slow_up_dur) + idx = 0; + + hist_load_high[core_j].hist_max_load[idx] = max_load; + hist_load_high[core_j].hist_load_cnt = idx + 1; + + /* note : check history_load and get_sum_hist_load */ + if (hist_load_high[core_j]. + hist_max_load[dbs_tuners_ins.smart_high_slow_up_dur - 1] > 0) { + int sum_hist_load_freq = 0; + int i = 0; + for (i = 0; i < dbs_tuners_ins.smart_high_slow_up_dur; i++) + sum_hist_load_freq += + hist_load_high[core_j].hist_max_load[i]; + + avg_hist_load = sum_hist_load_freq + /dbs_tuners_ins.smart_high_slow_up_dur; + + if (avg_hist_load > dbs_tuners_ins.smart_slow_up_load){ + reset_hist_high(&hist_load_high[core_j]); + freq_next = MIN((policy->cur + temp_up_inc), policy->max); + } else + freq_next = policy->cur; + } else { + freq_next = policy->cur; + } + + } else if (policy->cur >= dbs_tuners_ins.smart_slow_up_freq ) { + int idx = hist_load[core_j].hist_load_cnt; + int avg_hist_load = 0; + + if (idx >= dbs_tuners_ins.smart_slow_up_dur) + idx = 0; + + hist_load[core_j].hist_max_load[idx] = max_load; + hist_load[core_j].hist_load_cnt = idx + 1; + + /* note : check history_load and get_sum_hist_load */ + if (hist_load[core_j]. + hist_max_load[dbs_tuners_ins.smart_slow_up_dur - 1] > 0) { + int sum_hist_load_freq = 0; + int i = 0; + for (i = 0; i < dbs_tuners_ins.smart_slow_up_dur; i++) + sum_hist_load_freq += + hist_load[core_j].hist_max_load[i]; + + avg_hist_load = sum_hist_load_freq + / dbs_tuners_ins.smart_slow_up_dur ; + + if (avg_hist_load > dbs_tuners_ins.smart_slow_up_load){ + reset_hist(&hist_load[core_j]); + freq_next = MIN((policy->cur + temp_up_inc), policy->max); + } else + freq_next = policy->cur; + } else { + freq_next = policy->cur; + } + } else { + reset_hist(&hist_load[core_j]); + } + if (freq_next == policy->max) + this_dbs_info->rate_mult = + dbs_tuners_ins.sampling_down_factor; + + dbs_freq_increase(policy, freq_next); + + return; + } + }else{ + /* Check for frequency increase */ + if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) { + int target; + int inc; + + if (policy->cur < dbs_tuners_ins.step_up_early_hispeed) { + target = dbs_tuners_ins.step_up_early_hispeed; + }else if (policy->cur < dbs_tuners_ins.step_up_interim_hispeed) { + if(policy->cur == dbs_tuners_ins.step_up_early_hispeed) { + if(this_dbs_info->freq_stay_count < + dbs_tuners_ins.sampling_early_factor) { + this_dbs_info->freq_stay_count++; + return; + } + } + this_dbs_info->freq_stay_count = 1; + inc = (policy->max * dbs_tuners_ins.freq_step) / 100; + target = min(dbs_tuners_ins.step_up_interim_hispeed, + policy->cur + inc); + }else { + if(policy->cur == dbs_tuners_ins.step_up_interim_hispeed) { + if(this_dbs_info->freq_stay_count < + dbs_tuners_ins.sampling_interim_factor) { + this_dbs_info->freq_stay_count++; + return; + } + } + this_dbs_info->freq_stay_count = 1; + target = policy->max; + + //int inc = (policy->max * dbs_tuners_ins.freq_step) / 100; + //target = min(policy->max, policy->cur + inc); + } + + pr_debug("%s: cpu=%d, cur=%d, target=%d\n", + __func__, policy->cpu, policy->cur, target); + + /* If switching to max speed, apply sampling_down_factor */ + if (target == policy->max) + this_dbs_info->rate_mult = + dbs_tuners_ins.sampling_down_factor; + + dbs_freq_increase(policy, target); + return; + } + } + if (counter > 0) { + counter--; + if (counter == 0) { + phase = 0; + } + } + + if (num_online_cpus() > 1) { + + if (max_load_other_cpu > + dbs_tuners_ins.up_threshold_any_cpu_load) { + if (policy->cur < dbs_tuners_ins.sync_freq) + dbs_freq_increase(policy, + dbs_tuners_ins.sync_freq); + return; + } + + if (max_load_freq > dbs_tuners_ins.up_threshold_multi_core * + policy->cur) { + if (policy->cur < dbs_tuners_ins.optimal_freq) + dbs_freq_increase(policy, + dbs_tuners_ins.optimal_freq); + return; + } + } + + if (input_event_boosted()) { + return; + } + + /* Check for frequency decrease */ + /* if we cannot reduce the frequency anymore, break out early */ + if (policy->cur == policy->min) + return; + + /* + * The optimal frequency is the frequency that is the lowest that + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ + if (max_load_freq < + (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * + policy->cur) { + unsigned int freq_next; + freq_next = max_load_freq / + (dbs_tuners_ins.up_threshold - + dbs_tuners_ins.down_differential); + + pr_debug("%s: cpu=%d, cur=%d, target=%d (down)\n", + __func__, policy->cpu, policy->cur, freq_next); + +/* PATCH : SMART_UP */ + if (dbs_tuners_ins.smart_up && ( core_j + 1 ) > dbs_tuners_ins.smart_each_off ){ + + if (freq_next >= dbs_tuners_ins.smart_high_slow_up_freq){ + int idx = hist_load_high[core_j].hist_load_cnt; + + if (idx >= dbs_tuners_ins.smart_high_slow_up_dur ) + idx = 0; + + hist_load_high[core_j].hist_max_load[idx] = max_load; + hist_load_high[core_j].hist_load_cnt = idx + 1; + + + }else if (freq_next >= dbs_tuners_ins.smart_slow_up_freq) { + int idx = hist_load[core_j].hist_load_cnt; + + if (idx >= dbs_tuners_ins.smart_slow_up_dur) + idx = 0; + + hist_load[core_j].hist_max_load[idx] = max_load; + hist_load[core_j].hist_load_cnt = idx + 1; + + reset_hist_high(&hist_load_high[core_j]); + + + } else if (policy->cur >= dbs_tuners_ins.smart_slow_up_freq) { + reset_hist(&hist_load[core_j]); + reset_hist_high(&hist_load_high[core_j]); + + + } + } +//#endif + + /* No longer fully busy, reset rate_mult */ + this_dbs_info->rate_mult = 1; + this_dbs_info->freq_stay_count = 1; + + + if (freq_next < policy->min) + freq_next = policy->min; + + if (num_online_cpus() > 1) { + if (max_load_other_cpu > + (dbs_tuners_ins.up_threshold_multi_core - + dbs_tuners_ins.down_differential) && + freq_next < dbs_tuners_ins.sync_freq) + freq_next = dbs_tuners_ins.sync_freq; + + if (max_load_freq > + ((dbs_tuners_ins.up_threshold_multi_core - + dbs_tuners_ins.down_differential_multi_core) * + policy->cur) && + freq_next < dbs_tuners_ins.optimal_freq) + freq_next = dbs_tuners_ins.optimal_freq; + + } + if (!dbs_tuners_ins.powersave_bias) { + __cpufreq_driver_target(policy, freq_next, + CPUFREQ_RELATION_L); + } else { + int freq = powersave_bias_target(policy, freq_next, + CPUFREQ_RELATION_L); + __cpufreq_driver_target(policy, freq, + CPUFREQ_RELATION_L); + } + } +} + +static void do_dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + int sample_type = dbs_info->sample_type; + int delay = msecs_to_jiffies(50); + + if (skip_intellidemand) + goto sched_wait; + + mutex_lock(&dbs_info->timer_mutex); + + /* Common NORMAL_SAMPLE setup */ + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + if (!dbs_tuners_ins.powersave_bias || + sample_type == DBS_NORMAL_SAMPLE) { + dbs_check_cpu(dbs_info); + if (dbs_info->freq_lo) { + /* Setup timer for SUB_SAMPLE */ + dbs_info->sample_type = DBS_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; + } else { + /* We want all CPUs to do sampling nearly on + * same jiffy + */ + delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate + * dbs_info->rate_mult); + + if (num_online_cpus() > 1) + delay -= jiffies % delay; + } + } else { + if (input_event_boosted()) + goto sched_wait; + + __cpufreq_driver_target(dbs_info->cur_policy, + dbs_info->freq_lo, CPUFREQ_RELATION_H); + delay = dbs_info->freq_lo_jiffies; + } +sched_wait: + queue_delayed_work_on(cpu, dbs_wq, &dbs_info->work, delay); + mutex_unlock(&dbs_info->timer_mutex); +} + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) +{ + /* We want all CPUs to do sampling nearly on same jiffy */ + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + if (num_online_cpus() > 1) + delay -= jiffies % delay; + + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); + queue_delayed_work_on(dbs_info->cpu, dbs_wq, &dbs_info->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +{ + cancel_delayed_work_sync(&dbs_info->work); +} + +/* + * Not all CPUs want IO time to be accounted as busy; this dependson how + * efficient idling at a higher frequency/voltage is. + * Pavel Machek says this is not so for various generations of AMD and old + * Intel systems. + * Mike Chan (androidlcom) calis this is also not true for ARM. + * Because of this, whitelist specific known (series) of CPUs by default, and + * leave all others up to the user. + */ +static int should_io_be_busy(void) +{ +#if defined(CONFIG_X86) + /* + * For Intel, Core 2 (model 15) andl later have an efficient idle. + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 15) + return 1; +#endif + return 0; +} + +static void dbs_refresh_callback(struct work_struct *work) +{ + struct cpufreq_policy *policy; + struct cpu_dbs_info_s *this_dbs_info; + struct dbs_work_struct *dbs_work; + unsigned int cpu; + + dbs_work = container_of(work, struct dbs_work_struct, work); + cpu = dbs_work->cpu; + + get_online_cpus(); + + if (lock_policy_rwsem_write(cpu) < 0) + goto bail_acq_sema_failed; + + this_dbs_info = &per_cpu(id_cpu_dbs_info, cpu); + policy = this_dbs_info->cur_policy; + if (!policy) { + /* CPU not using intellidemand governor */ + goto bail_incorrect_governor; + } + + if (policy->cur < policy->max) { + /* + * Arch specific cpufreq driver may fail. + * Don't update governor frequency upon failure. + */ + if (__cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_L) >= 0) + policy->cur = policy->max; + + this_dbs_info->prev_cpu_idle = get_cpu_idle_time(cpu, + &this_dbs_info->prev_cpu_wall); + } + +bail_incorrect_governor: + unlock_policy_rwsem_write(cpu); + +bail_acq_sema_failed: + put_online_cpus(); + return; +} + +static int dbs_migration_notify(struct notifier_block *nb, + unsigned long target_cpu, void *arg) +{ + struct cpu_dbs_info_s *target_dbs_info = + &per_cpu(id_cpu_dbs_info, target_cpu); + + atomic_set(&target_dbs_info->src_sync_cpu, (int)arg); + wake_up(&target_dbs_info->sync_wq); + + return NOTIFY_OK; +} + +static struct notifier_block dbs_migration_nb = { + .notifier_call = dbs_migration_notify, +}; + +static int sync_pending(struct cpu_dbs_info_s *this_dbs_info) +{ + return atomic_read(&this_dbs_info->src_sync_cpu) >= 0; +} + +static int dbs_sync_thread(void *data) +{ + int src_cpu, cpu = (int)data; + unsigned int src_freq, src_max_load; + struct cpu_dbs_info_s *this_dbs_info, *src_dbs_info; + struct cpufreq_policy *policy; + int delay; + + this_dbs_info = &per_cpu(id_cpu_dbs_info, cpu); + + while (1) { + wait_event(this_dbs_info->sync_wq, + sync_pending(this_dbs_info) || + kthread_should_stop()); + + if (kthread_should_stop()) + break; + + get_online_cpus(); + + src_cpu = atomic_read(&this_dbs_info->src_sync_cpu); + src_dbs_info = &per_cpu(id_cpu_dbs_info, src_cpu); + if (src_dbs_info != NULL && + src_dbs_info->cur_policy != NULL) { + src_freq = src_dbs_info->cur_policy->cur; + src_max_load = src_dbs_info->max_load; + } else { + src_freq = dbs_tuners_ins.sync_freq; + src_max_load = 0; + } + + if (lock_policy_rwsem_write(cpu) < 0) + goto bail_acq_sema_failed; + + if (!atomic_read(&this_dbs_info->sync_enabled)) { + atomic_set(&this_dbs_info->src_sync_cpu, -1); + put_online_cpus(); + unlock_policy_rwsem_write(cpu); + continue; + } + + policy = this_dbs_info->cur_policy; + if (!policy) { + /* CPU not using intellidemand governor */ + goto bail_incorrect_governor; + } + delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + + if (policy->cur < src_freq) { + /* cancel the next intellidemand sample */ + cancel_delayed_work_sync(&this_dbs_info->work); + + /* + * Arch specific cpufreq driver may fail. + * Don't update governor frequency upon failure. + */ + if (__cpufreq_driver_target(policy, src_freq, + CPUFREQ_RELATION_L) >= 0) { + policy->cur = src_freq; + if (src_max_load > this_dbs_info->max_load) { + this_dbs_info->max_load = src_max_load; + this_dbs_info->prev_load = src_max_load; + } + } + + /* reschedule the next intellidemand sample */ + mutex_lock(&this_dbs_info->timer_mutex); + queue_delayed_work_on(cpu, dbs_wq, + &this_dbs_info->work, delay); + mutex_unlock(&this_dbs_info->timer_mutex); + } + +bail_incorrect_governor: + unlock_policy_rwsem_write(cpu); +bail_acq_sema_failed: + put_online_cpus(); + atomic_set(&this_dbs_info->src_sync_cpu, -1); + } + + return 0; +} + +static void dbs_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + int i; + struct cpu_dbs_info_s *dbs_info; + unsigned long flags; + int input_event_min_freq; + + if ((dbs_tuners_ins.powersave_bias == POWERSAVE_BIAS_MAXLEVEL) || + (dbs_tuners_ins.powersave_bias == POWERSAVE_BIAS_MINLEVEL)) { + /* nothing to do */ + return; + } + + if (type == EV_SYN && code == SYN_REPORT) { + spin_lock_irqsave(&input_boost_lock, flags); + input_event_boost = true; + ui_sampling_expired = jiffies + msecs_to_jiffies(dbs_tuners_ins.ui_timeout); + spin_unlock_irqrestore(&input_boost_lock, flags); + + input_event_min_freq = input_event_min_freq_array[num_online_cpus() - 1]; + for_each_online_cpu(i) { + dbs_info = &per_cpu(id_cpu_dbs_info, i); + if (dbs_info->cur_policy && + dbs_info->cur_policy->cur < input_event_min_freq) { + wake_up_process(per_cpu(up_task, i)); + } + } + } +} + +static int input_dev_filter(const char *input_dev_name) +{ + if (strstr(input_dev_name, "touchscreen") || + strstr(input_dev_name, "synaptics_dsx_i2c") || + strstr(input_dev_name, "elan-touchscreen") || + strstr(input_dev_name, "touch_dev") || + strstr(input_dev_name, "sec-touchscreen") || + strstr(input_dev_name, "keypad")) { + return 0; + } else { + return 1; + } +} + + +static int dbs_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + if (input_dev_filter(dev->name)) + return -ENODEV; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "cpufreq"; + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void dbs_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id dbs_ids[] = { + { .driver_info = 1 }, + { }, +}; + +static struct input_handler dbs_input_handler = { + .event = dbs_input_event, + .connect = dbs_input_connect, + .disconnect = dbs_input_disconnect, + .name = "cpufreq_id", + .id_table = dbs_ids, +}; + +int set_input_event_min_freq(int cpufreq) +{ + int i = 0; + for ( i = 0 ; i < NR_CPUS; i++) + input_event_min_freq_array[i] = cpufreq; + return 0; +} + +void set_input_event_min_freq_by_cpu ( int cpu_nr, int cpufreq){ + input_event_min_freq_array[cpu_nr-1] = cpufreq; +} + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; + int rc; + + this_dbs_info = &per_cpu(id_cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_mutex); + + dbs_enable++; + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + cputime64_t tmp; + j_dbs_info = &per_cpu(id_cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &j_dbs_info->prev_cpu_wall); + tmp = j_dbs_info->prev_cpu_wall - + j_dbs_info->prev_cpu_idle; + do_div(tmp, j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_load = 100 * tmp; + if (dbs_tuners_ins.ignore_nice) + j_dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + set_cpus_allowed(j_dbs_info->sync_thread, + *cpumask_of(j)); + if (!dbs_tuners_ins.powersave_bias) + atomic_set(&j_dbs_info->sync_enabled, 1); + } + this_dbs_info->cpu = cpu; + this_dbs_info->rate_mult = 1; + this_dbs_info->freq_stay_count = 1; + intellidemand_powersave_bias_init_cpu(cpu); + /* + * Start the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 1) { + unsigned int latency; + + rc = sysfs_create_group(cpufreq_global_kobject, + &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + + /* policy latency is in nS. Convert it to uS first */ + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + /* Bring kernel and HW constraints together */ + min_sampling_rate = max(min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + dbs_tuners_ins.sampling_rate = + max(min_sampling_rate, + latency * LATENCY_MULTIPLIER); + if (dbs_tuners_ins.sampling_rate < DEF_SAMPLING_RATE) + dbs_tuners_ins.sampling_rate = DEF_SAMPLING_RATE; + dbs_tuners_ins.origin_sampling_rate = dbs_tuners_ins.sampling_rate; + dbs_tuners_ins.io_is_busy = should_io_be_busy(); + + if (dbs_tuners_ins.optimal_freq == 0) + dbs_tuners_ins.optimal_freq = policy->min; + + if (dbs_tuners_ins.sync_freq == 0) + dbs_tuners_ins.sync_freq = policy->min; + + atomic_notifier_chain_register(&migration_notifier_head, + &dbs_migration_nb); + } + if (!cpu) + rc = input_register_handler(&dbs_input_handler); + mutex_unlock(&dbs_mutex); + + + if (!intellidemand_powersave_bias_setspeed( + this_dbs_info->cur_policy, + NULL, + dbs_tuners_ins.powersave_bias)) + dbs_timer_init(this_dbs_info); + break; + + case CPUFREQ_GOV_STOP: + dbs_timer_exit(this_dbs_info); + + mutex_lock(&dbs_mutex); + dbs_enable--; + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(id_cpu_dbs_info, j); + atomic_set(&j_dbs_info->sync_enabled, 0); + } + + /* If device is being removed, policy is no longer + * valid. */ + this_dbs_info->cur_policy = NULL; + if (!cpu) + input_unregister_handler(&dbs_input_handler); + if (!dbs_enable) { + sysfs_remove_group(cpufreq_global_kobject, + &dbs_attr_group); + atomic_notifier_chain_unregister( + &migration_notifier_head, + &dbs_migration_nb); + } + + mutex_unlock(&dbs_mutex); + + break; + + case CPUFREQ_GOV_LIMITS: + if (this_dbs_info->cur_policy == NULL) { + pr_debug("Unable to limit cpu freq due to cur_policy == NULL\n"); + return -EPERM; + } + mutex_lock(&this_dbs_info->timer_mutex); + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->min, CPUFREQ_RELATION_L); + else if (dbs_tuners_ins.powersave_bias != 0) + intellidemand_powersave_bias_setspeed( + this_dbs_info->cur_policy, + policy, + dbs_tuners_ins.powersave_bias); + mutex_unlock(&this_dbs_info->timer_mutex); + break; + } + return 0; +} + +static int cpufreq_gov_dbs_up_task(void *data) +{ + struct cpufreq_policy *policy; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int cpu = smp_processor_id(); + int input_event_min_freq; + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + if (kthread_should_stop()) + break; + + set_current_state(TASK_RUNNING); + + get_online_cpus(); + + if (lock_policy_rwsem_write(cpu) < 0) + goto bail_acq_sema_failed; + + this_dbs_info = &per_cpu(id_cpu_dbs_info, cpu); + policy = this_dbs_info->cur_policy; + if (!policy) { + + goto bail_incorrect_governor; + } + + mutex_lock(&this_dbs_info->timer_mutex); + + input_event_min_freq = input_event_min_freq_array[num_online_cpus() - 1]; + if (policy->cur < input_event_min_freq) { + + dbs_tuners_ins.powersave_bias = 0; + dbs_freq_increase(policy, input_event_min_freq); + this_dbs_info->prev_cpu_idle = get_cpu_idle_time(cpu, &this_dbs_info->prev_cpu_wall); + } + + mutex_unlock(&this_dbs_info->timer_mutex); + +bail_incorrect_governor: + unlock_policy_rwsem_write(cpu); + +bail_acq_sema_failed: + put_online_cpus(); + + dbs_tuners_ins.sampling_rate = dbs_tuners_ins.ui_sampling_rate; + } + + return 0; +} + +#if 0 +static void cpufreq_intellidemand_power_suspend(struct power_suspend *h) +{ + mutex_lock(&dbs_mutex); + stored_sampling_rate = dbs_tuners_ins.sampling_rate; + dbs_tuners_ins.sampling_rate = DEF_SAMPLING_RATE * 6; + update_sampling_rate(dbs_tuners_ins.sampling_rate); + mutex_unlock(&dbs_mutex); +} + +static void cpufreq_intellidemand_power_resume(struct power_suspend *h) +{ + mutex_lock(&dbs_mutex); + dbs_tuners_ins.sampling_rate = stored_sampling_rate; + update_sampling_rate(dbs_tuners_ins.sampling_rate); + mutex_unlock(&dbs_mutex); +} + +static struct power_suspend cpufreq_intellidemand_power_suspend_info = { + .suspend = cpufreq_intellidemand_power_suspend, + .resume = cpufreq_intellidemand_power_resume, +}; +#endif + +static int __init cpufreq_gov_dbs_init(void) +{ + u64 idle_time; + unsigned int i; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + struct task_struct *pthread; + int cpu = get_cpu(); + + idle_time = get_cpu_idle_time_us(cpu, NULL); + put_cpu(); + if (idle_time != -1ULL) { + /* Idle micro accounting is supported. Use finer thresholds */ + dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; + dbs_tuners_ins.down_differential = + MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + /* + * In nohz/micro accounting case we set the minimum frequency + * not depending on HZ, but fixed (very low). The deferred + * timer might skip some samples if idle/sleeping as needed. + */ + min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + } else { + /* For correct statistics, we need 10 ticks for each measure */ + min_sampling_rate = + MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + } + + dbs_wq = alloc_workqueue("intellidemand_dbs_wq", WQ_HIGHPRI, 0); + if (!dbs_wq) { + printk(KERN_ERR "Failed to create intellidemand_dbs_wq workqueue\n"); + return -EFAULT; + } + for_each_possible_cpu(i) { + struct cpu_dbs_info_s *this_dbs_info = + &per_cpu(id_cpu_dbs_info, i); + struct dbs_work_struct *dbs_work = + &per_cpu(dbs_refresh_work, i); + + pthread = kthread_create_on_node(cpufreq_gov_dbs_up_task, + NULL, cpu_to_node(i), + "kdbs_up/%d", i); + if (likely(!IS_ERR(pthread))) { + kthread_bind(pthread, i); + sched_setscheduler_nocheck(pthread, SCHED_FIFO, ¶m); + get_task_struct(pthread); + per_cpu(up_task, i) = pthread; + } + + mutex_init(&this_dbs_info->timer_mutex); + INIT_WORK(&dbs_work->work, dbs_refresh_callback); + dbs_work->cpu = i; + + atomic_set(&this_dbs_info->src_sync_cpu, -1); + init_waitqueue_head(&this_dbs_info->sync_wq); + + this_dbs_info->sync_thread = kthread_run(dbs_sync_thread, + (void *)i, + "dbs_sync/%d", i); + } + +#if 0 + register_power_suspend(&cpufreq_intellidemand_power_suspend_info); +#endif + return cpufreq_register_governor(&cpufreq_gov_intellidemand); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + unsigned int i; + + cpufreq_unregister_governor(&cpufreq_gov_intellidemand); + for_each_possible_cpu(i) { + struct cpu_dbs_info_s *this_dbs_info = + &per_cpu(id_cpu_dbs_info, i); + mutex_destroy(&this_dbs_info->timer_mutex); + kthread_stop(this_dbs_info->sync_thread); + if (per_cpu(up_task, i)) { + kthread_stop(per_cpu(up_task, i)); + put_task_struct(per_cpu(up_task, i)); + } + } + destroy_workqueue(dbs_wq); +} + +MODULE_AUTHOR("Venkatesh Pallipadi "); +MODULE_AUTHOR("Alexey Starikovskiy "); +MODULE_AUTHOR("Paul Reioux "); +MODULE_DESCRIPTION("'cpufreq_intellidemand' - A dynamic cpufreq governor for " + "Low Latency Frequency Transition capable processors"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND +fs_initcall(cpufreq_gov_dbs_init); +#else +module_init(cpufreq_gov_dbs_init); +#endif +module_exit(cpufreq_gov_dbs_exit); + diff --git a/drivers/cpufreq/cpufreq_intellimm.c b/drivers/cpufreq/cpufreq_intellimm.c new file mode 100644 index 00000000..ce33e319 --- /dev/null +++ b/drivers/cpufreq/cpufreq_intellimm.c @@ -0,0 +1,1664 @@ +/* + * drivers/cpufreq/cpufreq_inteiiimm.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * (c) 2013 The Linux Foundation. All rights reserved. + * (c) 2014 Paul Reioux (aka Faux123) + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEF_SAMPLING_RATE (120000) +#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) +#define DEF_FREQUENCY_UP_THRESHOLD (80) +#define DEF_SAMPLING_DOWN_FACTOR (1) +#define MAX_SAMPLING_DOWN_FACTOR (100000) +#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) +#define MICRO_FREQUENCY_UP_THRESHOLD (95) +#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) +#define MIN_FREQUENCY_UP_THRESHOLD (11) +#define MAX_FREQUENCY_UP_THRESHOLD (100) +#define MIN_FREQUENCY_DOWN_DIFFERENTIAL (1) + +#define DEF_POWER_SAVE_FREQUENCY (700000) +#define DEF_TWO_PHASE_FREQUENCY (1008000) +#define DBS_INPUT_EVENT_MIN_FREQ (700000) +#define DEF_FREQUENCY_OPTIMAL (245000) +#define DEF_FREQ_DOWN_STEP (320000) +#define DEF_FREQ_DOWN_STEP_BARRIER (700000) + +#define DEF_INPUT_BOOST_DURATION (6) +#define CPU0 (0) + +#define MIN_SAMPLING_RATE_RATIO (2) + +static unsigned int min_sampling_rate; + +#define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +#define POWERSAVE_BIAS_MAXLEVEL (1000) +#define POWERSAVE_BIAS_MINLEVEL (-1000) + +static void do_dbs_timer(struct work_struct *work); +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIMM +static +#endif +struct cpufreq_governor cpufreq_gov_intellimm = { + .name = "intellimm", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; + +enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; + +struct cpu_dbs_info_s { + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_iowait; + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + struct cpufreq_frequency_table *freq_table; + unsigned int freq_lo; + unsigned int freq_lo_jiffies; + unsigned int freq_hi_jiffies; + unsigned int rate_mult; + unsigned int prev_load; + unsigned int cur_load; + unsigned int max_load; + int input_event_freq; + int cpu; + unsigned int sample_type:1; + struct mutex timer_mutex; + +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, imm_cpu_dbs_info); + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info); +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info); + +static unsigned int dbs_enable; + +static DEFINE_PER_CPU(struct task_struct *, up_task); +static spinlock_t input_boost_lock; +static bool input_event_boost = false; +static unsigned long input_event_boost_expired = 0; + +#define TABLE_SIZE 1 + +#define MAX(x,y) (x > y ? x : y) +#define MIN(x,y) (x < y ? x : y) +#define FREQ_NEED_BURST(x) (x < 600000 ? 1 : 0) + +static struct cpufreq_frequency_table *tbl = NULL; +static unsigned int *tblmap[TABLE_SIZE] __read_mostly; +static unsigned int tbl_select[4] = {0}; +static int input_event_counter = 0; + +static unsigned int up_threshold_level[2] __read_mostly = {90, 80}; +static void reset_freq_map_table(struct cpufreq_policy *); + +static DEFINE_MUTEX(dbs_mutex); + +static struct workqueue_struct *dbs_wq; + +static struct dbs_tuners { + unsigned int sampling_rate; + unsigned int up_threshold; + unsigned int up_threshold_multi_core; + unsigned int down_differential; + unsigned int down_differential_multi_core; + unsigned int optimal_freq; + unsigned int up_threshold_any_cpu_load; + unsigned int ignore_nice; + unsigned int sampling_down_factor; + int powersave_bias; + unsigned int io_is_busy; + unsigned int shortcut; + unsigned int power_save_freq; + unsigned int two_phase_freq; + unsigned int freq_down_step; + unsigned int freq_down_step_barrier; +} dbs_tuners_ins = { + .up_threshold_multi_core = DEF_FREQUENCY_UP_THRESHOLD, + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, + .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, + .down_differential_multi_core = MICRO_FREQUENCY_DOWN_DIFFERENTIAL, + .up_threshold_any_cpu_load = DEF_FREQUENCY_UP_THRESHOLD, + .ignore_nice = 0, + .powersave_bias = 0, + .optimal_freq = 0, + .shortcut = 0, + .power_save_freq = DEF_POWER_SAVE_FREQUENCY, + .two_phase_freq = DEF_TWO_PHASE_FREQUENCY, + .freq_down_step = DEF_FREQ_DOWN_STEP, + .freq_down_step_barrier = DEF_FREQ_DOWN_STEP_BARRIER, +}; + +static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) +{ + u64 idle_time; + u64 cur_wall_time; + u64 busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = jiffies_to_usecs(cur_wall_time); + + return jiffies_to_usecs(idle_time); +} + +static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, NULL); + + if (idle_time == -1ULL) + return get_cpu_idle_time_jiffy(cpu, wall); + else + idle_time += get_cpu_iowait_time_us(cpu, wall); + + return idle_time; +} + +static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, + cputime64_t *wall) +{ + u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); + + if (iowait_time == -1ULL) + return 0; + + return iowait_time; +} + +static unsigned int powersave_bias_target(struct cpufreq_policy *policy, + unsigned int freq_next, + unsigned int relation) +{ + unsigned int freq_req, freq_avg; + unsigned int freq_hi, freq_lo; + unsigned int index = 0; + unsigned int jiffies_total, jiffies_hi, jiffies_lo; + int freq_reduc; + struct cpu_dbs_info_s *dbs_info = &per_cpu(imm_cpu_dbs_info, + policy->cpu); + + if (!dbs_info->freq_table) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_next; + } + + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, + relation, &index); + freq_req = dbs_info->freq_table[index].frequency; + freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000; + freq_avg = freq_req - freq_reduc; + + + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_H, &index); + freq_lo = dbs_info->freq_table[index].frequency; + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_L, &index); + freq_hi = dbs_info->freq_table[index].frequency; + + + if (freq_hi == freq_lo) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_lo; + } + jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + jiffies_hi = (freq_avg - freq_lo) * jiffies_total; + jiffies_hi += ((freq_hi - freq_lo) / 2); + jiffies_hi /= (freq_hi - freq_lo); + jiffies_lo = jiffies_total - jiffies_hi; + dbs_info->freq_lo = freq_lo; + dbs_info->freq_lo_jiffies = jiffies_lo; + dbs_info->freq_hi_jiffies = jiffies_hi; + return freq_hi; +} + +static int intellimm_powersave_bias_setspeed(struct cpufreq_policy *policy, + struct cpufreq_policy *altpolicy, + int level) +{ + if (level == POWERSAVE_BIAS_MAXLEVEL) { + + __cpufreq_driver_target(policy, + (altpolicy) ? altpolicy->min : policy->min, + CPUFREQ_RELATION_L); + return 1; + } else if (level == POWERSAVE_BIAS_MINLEVEL) { + + __cpufreq_driver_target(policy, + (altpolicy) ? altpolicy->max : policy->max, + CPUFREQ_RELATION_H); + return 1; + } + return 0; +} + +static void intellimm_powersave_bias_init_cpu(int cpu) +{ + struct cpu_dbs_info_s *dbs_info = &per_cpu(imm_cpu_dbs_info, cpu); + dbs_info->freq_table = cpufreq_frequency_get_table(cpu); + dbs_info->freq_lo = 0; +} + +static void intellimm_powersave_bias_init(void) +{ + int i; + for_each_online_cpu(i) { + intellimm_powersave_bias_init_cpu(i); + } +} + + +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", min_sampling_rate); +} + +define_one_global_ro(sampling_rate_min); + +#define show_one(file_name, object) \ +static ssize_t show_##file_name (struct kobject *kobj, \ + struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +} + +show_one(sampling_rate, sampling_rate); +show_one(io_is_busy, io_is_busy); +show_one(shortcut, shortcut); +show_one(up_threshold, up_threshold); +show_one(up_threshold_multi_core, up_threshold_multi_core); +show_one(down_differential, down_differential); +show_one(sampling_down_factor, sampling_down_factor); +show_one(ignore_nice_load, ignore_nice); +show_one(down_differential_multi_core, down_differential_multi_core); +show_one(optimal_freq, optimal_freq); +show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load); +show_one(freq_down_step, freq_down_step); +show_one(freq_down_step_barrier, freq_down_step_barrier); + +static ssize_t show_powersave_bias(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dbs_tuners_ins.powersave_bias); +} + +static void update_sampling_rate(unsigned int new_rate) +{ + int cpu; + + dbs_tuners_ins.sampling_rate = new_rate + = max(new_rate, min_sampling_rate); + + get_online_cpus(); + for_each_online_cpu(cpu) { + struct cpufreq_policy *policy; + struct cpu_dbs_info_s *dbs_info; + unsigned long next_sampling, appointed_at; + + policy = cpufreq_cpu_get(cpu); + if (!policy) + continue; + dbs_info = &per_cpu(imm_cpu_dbs_info, policy->cpu); + cpufreq_cpu_put(policy); + + mutex_lock(&dbs_info->timer_mutex); + + if (!delayed_work_pending(&dbs_info->work)) { + mutex_unlock(&dbs_info->timer_mutex); + continue; + } + + next_sampling = jiffies + usecs_to_jiffies(new_rate); + appointed_at = dbs_info->work.timer.expires; + + if (time_before(next_sampling, appointed_at)) { + + mutex_unlock(&dbs_info->timer_mutex); + cancel_delayed_work_sync(&dbs_info->work); + mutex_lock(&dbs_info->timer_mutex); + + queue_delayed_work_on(dbs_info->cpu, dbs_wq, + &dbs_info->work, usecs_to_jiffies(new_rate)); + + } + mutex_unlock(&dbs_info->timer_mutex); + } + put_online_cpus(); +} + +static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + update_sampling_rate(input); + return count; +} + +static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.io_is_busy = !!input; + return count; +} + +static ssize_t store_shortcut(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (dbs_tuners_ins.shortcut != input) { + dbs_tuners_ins.shortcut = input; + } + + return count; +} + +static ssize_t store_down_differential_multi_core(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.down_differential_multi_core = input; + return count; +} + + +static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.optimal_freq = input; + return count; +} + +static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + dbs_tuners_ins.up_threshold = input; + return count; +} + +static ssize_t store_up_threshold_multi_core(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + dbs_tuners_ins.up_threshold_multi_core = input; + return count; +} + +static ssize_t store_up_threshold_any_cpu_load(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + dbs_tuners_ins.up_threshold_any_cpu_load = input; + return count; +} + +static ssize_t store_down_differential(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input >= dbs_tuners_ins.up_threshold || + input < MIN_FREQUENCY_DOWN_DIFFERENTIAL) { + return -EINVAL; + } + + dbs_tuners_ins.down_differential = input; + + return count; +} + +static ssize_t store_sampling_down_factor(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input, j; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) + return -EINVAL; + dbs_tuners_ins.sampling_down_factor = input; + + + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(imm_cpu_dbs_info, j); + dbs_info->rate_mult = 1; + } + return count; +} + +static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (input > 1) + input = 1; + + if (input == dbs_tuners_ins.ignore_nice) { + return count; + } + dbs_tuners_ins.ignore_nice = input; + + + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(imm_cpu_dbs_info, j); + dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + + } + return count; +} + +static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + int input = 0; + int bypass = 0; + int ret, cpu, reenable_timer, j; + struct cpu_dbs_info_s *dbs_info; + + struct cpumask cpus_timer_done; + cpumask_clear(&cpus_timer_done); + + ret = sscanf(buf, "%d", &input); + + if (ret != 1) + return -EINVAL; + + if (input >= POWERSAVE_BIAS_MAXLEVEL) { + input = POWERSAVE_BIAS_MAXLEVEL; + bypass = 1; + } else if (input <= POWERSAVE_BIAS_MINLEVEL) { + input = POWERSAVE_BIAS_MINLEVEL; + bypass = 1; + } + + if (input == dbs_tuners_ins.powersave_bias) { + + return count; + } + + reenable_timer = ((dbs_tuners_ins.powersave_bias == + POWERSAVE_BIAS_MAXLEVEL) || + (dbs_tuners_ins.powersave_bias == + POWERSAVE_BIAS_MINLEVEL)); + + dbs_tuners_ins.powersave_bias = input; + + get_online_cpus(); + mutex_lock(&dbs_mutex); + + if (!bypass) { + if (reenable_timer) { + + for_each_online_cpu(cpu) { + if (lock_policy_rwsem_write(cpu) < 0) + continue; + + dbs_info = &per_cpu(imm_cpu_dbs_info, cpu); + + if (!dbs_info->cur_policy) { + pr_err("Dbs policy is NULL\n"); + goto skip_this_cpu; + } + + for_each_cpu(j, &cpus_timer_done) { + if (cpumask_test_cpu(j, dbs_info-> + cur_policy->cpus)) + goto skip_this_cpu; + } + + cpumask_set_cpu(cpu, &cpus_timer_done); + if (dbs_info->cur_policy) { + dbs_timer_exit(dbs_info); + + mutex_lock(&dbs_info->timer_mutex); + dbs_timer_init(dbs_info); + } +skip_this_cpu: + unlock_policy_rwsem_write(cpu); + } + } + intellimm_powersave_bias_init(); + } else { + for_each_online_cpu(cpu) { + if (lock_policy_rwsem_write(cpu) < 0) + continue; + + dbs_info = &per_cpu(imm_cpu_dbs_info, cpu); + + if (!dbs_info->cur_policy) { + pr_err("Dbs policy is NULL\n"); + goto skip_this_cpu_bypass; + } + + for_each_cpu(j, &cpus_timer_done) { + if (cpumask_test_cpu(j, dbs_info-> + cur_policy->cpus)) + goto skip_this_cpu_bypass; + } + + cpumask_set_cpu(cpu, &cpus_timer_done); + + if (dbs_info->cur_policy) { + + dbs_timer_exit(dbs_info); + + mutex_lock(&dbs_info->timer_mutex); + intellimm_powersave_bias_setspeed( + dbs_info->cur_policy, + NULL, + input); + mutex_unlock(&dbs_info->timer_mutex); + + } +skip_this_cpu_bypass: + unlock_policy_rwsem_write(cpu); + } + } + + mutex_unlock(&dbs_mutex); + put_online_cpus(); + + return count; +} + +static int input_event_min_freq_array[NR_CPUS] = + {[0 ... NR_CPUS-1] = + DBS_INPUT_EVENT_MIN_FREQ} ; + +static ssize_t show_input_event_min_freq(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + int i = 0; + int shift = 0; + char *buf_pos = buf; + for ( i = 0 ; i < NR_CPUS; i++) { + shift = sprintf(buf_pos,"%d,",input_event_min_freq_array[i]); + buf_pos += shift; + } + *(buf_pos-1) = '\n'; + *buf_pos = '\0'; + buf_pos++; + return strlen(buf); +} + +static ssize_t store_input_event_min_freq(struct kobject *a, + struct attribute *b, + const char *buf, size_t count) +{ + int ret = 0; + if (NR_CPUS == 1) + ret = sscanf(buf,"%u",&input_event_min_freq_array[0]); + else if (NR_CPUS == 2) + ret = sscanf(buf,"%u,%u",&input_event_min_freq_array[0], + &input_event_min_freq_array[1]); + else if (NR_CPUS == 4) + ret = sscanf(buf, "%u,%u,%u,%u", &input_event_min_freq_array[0], + &input_event_min_freq_array[1], + &input_event_min_freq_array[2], + &input_event_min_freq_array[3]); + if (ret < NR_CPUS) + return -EINVAL; + + return count; +} + +static int freq_cnt = 0; +static int low_index = 0; +static int nom_index = 0; + +static ssize_t show_multi_phase_freq_tbl(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + int i = 0,j = 0; + int shift = 0; + char *buf_pos = buf; + + for (i = 0; i < TABLE_SIZE; i++) { + shift = snprintf(buf_pos,PAGE_SIZE-(buf_pos - buf), + "%s %d %s","Table",i+1,"shows:\n"); + buf_pos += shift; + for (j = 0; j < freq_cnt; j++) { + shift = snprintf(buf_pos,PAGE_SIZE-(buf_pos - buf), + "%02d: %8u\n",j,tblmap[i][j]); + buf_pos += shift; + } + } + + *(buf_pos) = '\0'; + + return strlen(buf); +} + +static ssize_t store_multi_phase_freq_tbl(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + return 0; +} + +show_one(two_phase_freq, two_phase_freq); + +static ssize_t store_two_phase_freq(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + struct cpu_dbs_info_s *dbs_info; + struct cpufreq_policy *policy; + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + dbs_info = &per_cpu(imm_cpu_dbs_info, 0); + policy = dbs_info->cur_policy; + if (policy) { + if (input < policy->cpuinfo.min_freq || + input > policy->cpuinfo.max_freq) + return -EINVAL; + if (dbs_tuners_ins.two_phase_freq != input) { + dbs_tuners_ins.two_phase_freq = input; + reset_freq_map_table(policy); + } + } + + return count; +} + +static ssize_t store_freq_down_step(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + dbs_tuners_ins.freq_down_step = input; + return count; +} + +static ssize_t store_freq_down_step_barrier(struct kobject *a, + struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.freq_down_step_barrier = input; + return count; +} + +define_one_global_rw(sampling_rate); +define_one_global_rw(io_is_busy); +define_one_global_rw(shortcut); +define_one_global_rw(up_threshold); +define_one_global_rw(down_differential); +define_one_global_rw(sampling_down_factor); +define_one_global_rw(ignore_nice_load); +define_one_global_rw(powersave_bias); +define_one_global_rw(up_threshold_multi_core); +define_one_global_rw(down_differential_multi_core); +define_one_global_rw(optimal_freq); +define_one_global_rw(up_threshold_any_cpu_load); +define_one_global_rw(input_event_min_freq); +define_one_global_rw(multi_phase_freq_tbl); +define_one_global_rw(two_phase_freq); +define_one_global_rw(freq_down_step); +define_one_global_rw(freq_down_step_barrier); + +static struct attribute *dbs_attributes[] = { + &sampling_rate_min.attr, + &sampling_rate.attr, + &up_threshold.attr, + &down_differential.attr, + &sampling_down_factor.attr, + &ignore_nice_load.attr, + &powersave_bias.attr, + &io_is_busy.attr, + &shortcut.attr, + &up_threshold_multi_core.attr, + &down_differential_multi_core.attr, + &optimal_freq.attr, + &up_threshold_any_cpu_load.attr, + &input_event_min_freq.attr, + &multi_phase_freq_tbl.attr, + &two_phase_freq.attr, + &freq_down_step.attr, + &freq_down_step_barrier.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "intellimm", +}; + +static int adjust_freq_map_table(int freq, int cnt, + struct cpufreq_policy *policy) +{ + int i, upper, lower; + + if (policy && tbl) { + upper = policy->cpuinfo.max_freq; + lower = policy->cpuinfo.min_freq; + } + else + return freq; + + for(i = 0; i < cnt; i++) + { + if(freq >= tbl[i].frequency) + { + lower = tbl[i].frequency; + } + else + { + upper = tbl[i].frequency; + break; + } + } + + return (freq - lower < upper - freq)?lower:upper; +} + +static void reset_freq_map_table(struct cpufreq_policy *policy) +{ + unsigned int real_freq, low_freq; + int index; + + if (!tbl) + return; + + for (index = 0; index < freq_cnt; index++) + tblmap[0][index] = tbl[index].frequency; + + low_freq = adjust_freq_map_table(dbs_tuners_ins.power_save_freq, + freq_cnt, policy); + + for (index = 0; index < 5; index++) { + tblmap[0][index] = low_freq; + low_index = index; + } + + real_freq = adjust_freq_map_table(dbs_tuners_ins.two_phase_freq, + freq_cnt, policy); + + for (index = 5; index < freq_cnt; index++) { + if (tbl[index].frequency <= real_freq) { + tblmap[0][index] = real_freq; + nom_index = index; + } + } +} + +static void dbs_init_freq_map_table(struct cpufreq_policy *policy) +{ + tbl = cpufreq_frequency_get_table(0); + + for (freq_cnt = 0; + (tbl[freq_cnt].frequency != CPUFREQ_TABLE_END); + freq_cnt++) + ; + + tblmap[0] = kmalloc(sizeof(unsigned int) * freq_cnt, GFP_KERNEL); + BUG_ON(!tblmap[0]); + + reset_freq_map_table(policy); +} + +static void dbs_deinit_freq_map_table(void) +{ + int i; + + if (!tbl) + return; + + tbl = NULL; + + for (i = 0; i < TABLE_SIZE; i++) + kfree(tblmap[i]); +} + +static inline int get_cpu_freq_next(unsigned int freq) +{ + static int saved_index = 0; + int index; + + if (!tbl) { + pr_warn("tbl is NULL, use previous value %d\n", saved_index); + return saved_index; + } + + for (index = 0; (tbl[index].frequency != CPUFREQ_TABLE_END); index++) { + if (tbl[index].frequency > freq) { + if (index >= freq_cnt) + index = freq_cnt - 1; + saved_index = index; + break; + } + } + return index; +} + +static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) +{ + if (dbs_tuners_ins.powersave_bias) + freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H); + else if (p->cur == p->max){ + return; + } + + __cpufreq_driver_target(p, freq, (dbs_tuners_ins.powersave_bias || + freq < p->max) ? + CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); +} + +int input_event_boosted(void) +{ + unsigned long flags; + + + spin_lock_irqsave(&input_boost_lock, flags); + if (input_event_boost) { + if (time_before(jiffies, input_event_boost_expired)) { + spin_unlock_irqrestore(&input_boost_lock, flags); + return 1; + } + input_event_boost = false; + } + spin_unlock_irqrestore(&input_boost_lock, flags); + + return 0; +} + +static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) +{ + struct cpufreq_policy *policy; + unsigned int j, prev_load = 0; + struct cpu_dbs_info_s *j_dbs_info; + + unsigned int up_threshold; + unsigned max_load = 0, avg_load = 0; + unsigned avg_load_freq = 0; + unsigned num_of_cpus = 0; + + this_dbs_info->freq_lo = 0; + policy = this_dbs_info->cur_policy; + +#ifdef CONFIG_ARCH_MSM_CORTEXMP + for (j = 1; j < NR_CPUS; j++) { + j_dbs_info = &per_cpu(imm_cpu_dbs_info, j); + if (j_dbs_info->prev_load && !cpu_online(j)) + j_dbs_info->prev_load = 0; + } +#endif + + /* per cpu load calculation */ + for_each_cpu(j, policy->cpus) { + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + unsigned int idle_time, wall_time, iowait_time; + unsigned int cur_load; + + j_dbs_info = &per_cpu(imm_cpu_dbs_info, j); + + cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_dbs_info->prev_cpu_idle); + j_dbs_info->prev_cpu_idle = cur_idle_time; + + iowait_time = (unsigned int) + (cur_iowait_time - j_dbs_info->prev_cpu_iowait); + j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + if (dbs_tuners_ins.ignore_nice) { + u64 cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + j_dbs_info->prev_cpu_nice; + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + j_dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + + if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time) + idle_time -= iowait_time; + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + if (prev_load < j_dbs_info->prev_load) + prev_load = j_dbs_info->prev_load; + + cur_load = 100 * (wall_time - idle_time) / wall_time; + j_dbs_info->cur_load = cur_load; + j_dbs_info->max_load = max(cur_load, j_dbs_info->prev_load); + j_dbs_info->prev_load = cur_load; + } + + num_of_cpus = num_online_cpus(); + for_each_online_cpu(j) { + j_dbs_info = &per_cpu(imm_cpu_dbs_info, j); + avg_load += j_dbs_info->cur_load; + max_load += j_dbs_info->max_load; + } + + avg_load = avg_load / num_of_cpus; + max_load = max_load / num_of_cpus; + + if (max_load > avg_load) + avg_load_freq = (avg_load + max_load) / 2 * policy->cur; + else + avg_load_freq = avg_load * policy->cur; + + // normal path up + if (dbs_tuners_ins.shortcut) + up_threshold = dbs_tuners_ins.up_threshold; + else + up_threshold = up_threshold_level[1]; + + if (avg_load_freq > up_threshold * policy->cur) { + unsigned int freq_next; + int index; + + index = get_cpu_freq_next(policy->cur); + + if (dbs_tuners_ins.shortcut) { + freq_next = policy->max; + goto set_freq; + } + + if (FREQ_NEED_BURST(policy->cur) && + avg_load > up_threshold_level[0]) + freq_next = tblmap[tbl_select[0]][nom_index]; + else if (avg_load > up_threshold_level[1] && + avg_load < up_threshold_level[0]) + freq_next = + tblmap[tbl_select[0]][max(index, nom_index-1)]; + else if (avg_load >= up_threshold_level[0]) + freq_next = + tblmap[tbl_select[0]][index]; + else + freq_next = tblmap[tbl_select[0]] + [max(index, low_index-1)]; + +set_freq: + dbs_freq_increase(policy, freq_next); + + if (policy->cur == policy->max) + this_dbs_info->rate_mult = + dbs_tuners_ins.sampling_down_factor; + return; + } + + // shortcuts + if (input_event_boosted()) { + return; + } + + if (num_of_cpus > 1) { + if (avg_load_freq > dbs_tuners_ins.up_threshold_multi_core * + policy->cur) { + if (policy->cur < dbs_tuners_ins.optimal_freq) + dbs_freq_increase(policy, + dbs_tuners_ins.optimal_freq); + return; + } + } + + if (policy->cur == policy->min){ + return; + } + + // normal path down + if (avg_load_freq < + (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * + policy->cur) { + unsigned int freq_next; + freq_next = avg_load_freq / + (dbs_tuners_ins.up_threshold - + dbs_tuners_ins.down_differential); + + this_dbs_info->rate_mult = 1; + + if (freq_next < policy->min) + freq_next = policy->min; + + if (num_of_cpus > 1) { + if (dbs_tuners_ins.optimal_freq > + policy->min && avg_load_freq > + ((dbs_tuners_ins.up_threshold_multi_core - + dbs_tuners_ins.down_differential_multi_core) * + policy->cur) && + freq_next < dbs_tuners_ins.optimal_freq) + freq_next = dbs_tuners_ins.optimal_freq; + } + + if (dbs_tuners_ins.powersave_bias) { + freq_next = powersave_bias_target(policy, freq_next, + CPUFREQ_RELATION_L); + } + + if (dbs_tuners_ins.freq_down_step) { + unsigned int new_freq_next = freq_next; + if ((policy->cur - freq_next) > + dbs_tuners_ins.freq_down_step) { + new_freq_next = + policy->cur - + dbs_tuners_ins.freq_down_step; + } + + if (dbs_tuners_ins.freq_down_step_barrier) { + if (dbs_tuners_ins.freq_down_step_barrier < + new_freq_next) { + new_freq_next = + dbs_tuners_ins.freq_down_step_barrier; + } + + if (policy->cur <= + dbs_tuners_ins.freq_down_step_barrier) { + new_freq_next = freq_next; + } + } + + freq_next = new_freq_next; + } + + __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); + } +} + +static void do_dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + int sample_type = dbs_info->sample_type; + + int delay; + + if (unlikely(!cpu_online(cpu) || !dbs_info->cur_policy)) + return; + + mutex_lock(&dbs_info->timer_mutex); + + + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + if (!dbs_tuners_ins.powersave_bias || + sample_type == DBS_NORMAL_SAMPLE) { + dbs_check_cpu(dbs_info); + if (dbs_info->freq_lo) { + + dbs_info->sample_type = DBS_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; + } else { + delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate + * dbs_info->rate_mult); + + if (num_online_cpus() > 1) + delay -= jiffies % delay; + } + } else { + delay = dbs_info->freq_lo_jiffies; + if (input_event_boosted()) + goto sched_wait; + + __cpufreq_driver_target(dbs_info->cur_policy, + dbs_info->freq_lo, CPUFREQ_RELATION_H); + } + +sched_wait: + queue_delayed_work_on(cpu, dbs_wq, &dbs_info->work, delay); + mutex_unlock(&dbs_info->timer_mutex); +} + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) +{ + + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + if (num_online_cpus() > 1) + delay -= jiffies % delay; + + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); + queue_delayed_work_on(dbs_info->cpu, dbs_wq, &dbs_info->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +{ + cancel_delayed_work_sync(&dbs_info->work); +} + +static int should_io_be_busy(void) +{ +#if defined(CONFIG_X86) + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 15) + return 1; +#endif + return 0; +} + +static void dbs_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + int i; + struct cpu_dbs_info_s *dbs_info; + unsigned long flags; + int input_event_min_freq = 0; + + if ((dbs_tuners_ins.powersave_bias == POWERSAVE_BIAS_MAXLEVEL) || + (dbs_tuners_ins.powersave_bias == POWERSAVE_BIAS_MINLEVEL)) { + + return; + } + + if (type == EV_SYN && code == SYN_REPORT) { + dbs_tuners_ins.powersave_bias = 0; + } + else if (type == EV_ABS && code == ABS_MT_TRACKING_ID) { + + if (value != -1) { + input_event_counter++; + input_event_min_freq = + input_event_min_freq_array[num_online_cpus() - 1]; + + } + else { + if (likely(input_event_counter > 0)) + input_event_counter--; + else + pr_warning("dbs_input_event: Touch isn't paired!\n"); + input_event_min_freq = 0; + } + } + else if (type == EV_KEY && value == 1 && + (code == KEY_POWER || code == KEY_VOLUMEUP || + code == KEY_VOLUMEDOWN)) + { + input_event_min_freq = + input_event_min_freq_array[num_online_cpus() - 1]; + } + + if (input_event_min_freq > 0) { + spin_lock_irqsave(&input_boost_lock, flags); + input_event_boost = true; + input_event_boost_expired = jiffies + + usecs_to_jiffies(dbs_tuners_ins.sampling_rate * + DEF_INPUT_BOOST_DURATION); + spin_unlock_irqrestore(&input_boost_lock, flags); + + for_each_online_cpu(i) + { +#ifdef CONFIG_ARCH_MSM_CORTEXMP + if (i != CPU0) + break; +#endif + dbs_info = &per_cpu(imm_cpu_dbs_info, i); + if (dbs_info->cur_policy && + dbs_info->cur_policy->cur < + input_event_min_freq) { + dbs_info->input_event_freq = + input_event_min_freq; + wake_up_process(per_cpu(up_task, i)); + } + } + } +} + +static int dbs_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "cpufreq"; + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void dbs_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id dbs_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, + + { + .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, + .absbit = { [BIT_WORD(ABS_X)] = + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, + + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { }, +}; + +static struct input_handler dbs_input_handler = { + .event = dbs_input_event, + .connect = dbs_input_connect, + .disconnect = dbs_input_disconnect, + .name = "cpufreq_imm", + .id_table = dbs_ids, +}; + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; + int rc; + + this_dbs_info = &per_cpu(imm_cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_mutex); + + dbs_enable++; + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(imm_cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &j_dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + j_dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + this_dbs_info->cpu = cpu; + this_dbs_info->rate_mult = 1; + intellimm_powersave_bias_init_cpu(cpu); + if (dbs_enable == 1) { + unsigned int latency; + + rc = sysfs_create_group(cpufreq_global_kobject, + &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + + + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + + min_sampling_rate = max(min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + dbs_tuners_ins.sampling_rate = + max(min_sampling_rate, + latency * LATENCY_MULTIPLIER); + + if (dbs_tuners_ins.sampling_rate < DEF_SAMPLING_RATE) + dbs_tuners_ins.sampling_rate = + DEF_SAMPLING_RATE; + + dbs_tuners_ins.io_is_busy = should_io_be_busy(); + + if (dbs_tuners_ins.optimal_freq == 0) + dbs_tuners_ins.optimal_freq = policy->min; + + dbs_init_freq_map_table(policy); + + } + if (!cpu) + rc = input_register_handler(&dbs_input_handler); + mutex_unlock(&dbs_mutex); + + if (!intellimm_powersave_bias_setspeed( + this_dbs_info->cur_policy, + NULL, + dbs_tuners_ins.powersave_bias)) + dbs_timer_init(this_dbs_info); + break; + + case CPUFREQ_GOV_STOP: + dbs_timer_exit(this_dbs_info); + this_dbs_info->prev_load = 0; + + mutex_lock(&dbs_mutex); + dbs_enable--; + + this_dbs_info->cur_policy = NULL; + if (!cpu) + input_unregister_handler(&dbs_input_handler); + if (!dbs_enable) { + dbs_deinit_freq_map_table(); + + sysfs_remove_group(cpufreq_global_kobject, + &dbs_attr_group); + + } + + mutex_unlock(&dbs_mutex); + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&this_dbs_info->timer_mutex); + if(this_dbs_info->cur_policy) { + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info-> + cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info-> + cur_policy, + policy->min, CPUFREQ_RELATION_L); + else if (dbs_tuners_ins.powersave_bias != 0) + intellimm_powersave_bias_setspeed( + this_dbs_info->cur_policy, + policy, + dbs_tuners_ins.powersave_bias); + } + mutex_unlock(&this_dbs_info->timer_mutex); + break; + } + return 0; +} + +static int cpufreq_gov_dbs_up_task(void *data) +{ + struct cpufreq_policy *policy; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int cpu = smp_processor_id(); + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + if (kthread_should_stop()) + break; + + set_current_state(TASK_RUNNING); + + get_online_cpus(); + + if (lock_policy_rwsem_write(cpu) < 0) + goto bail_acq_sema_failed; + + this_dbs_info = &per_cpu(imm_cpu_dbs_info, cpu); + policy = this_dbs_info->cur_policy; + if (!policy) { + + goto bail_incorrect_governor; + } + + mutex_lock(&this_dbs_info->timer_mutex); + + + dbs_tuners_ins.powersave_bias = 0; + dbs_freq_increase(policy, this_dbs_info->input_event_freq); + this_dbs_info->prev_cpu_idle = get_cpu_idle_time(cpu, + &this_dbs_info->prev_cpu_wall); + + mutex_unlock(&this_dbs_info->timer_mutex); + +bail_incorrect_governor: + unlock_policy_rwsem_write(cpu); + +bail_acq_sema_failed: + put_online_cpus(); + } + + return 0; +} + +static int __init cpufreq_gov_dbs_init(void) +{ + u64 idle_time; + unsigned int i; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + struct task_struct *pthread; + int cpu = get_cpu(); + + idle_time = get_cpu_idle_time_us(cpu, NULL); + put_cpu(); + if (idle_time != -1ULL) { + + dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; + dbs_tuners_ins.down_differential = + MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + } else { + + min_sampling_rate = + MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + } + + dbs_wq = alloc_workqueue("intellimm_dbs_wq", WQ_HIGHPRI, 0); + if (!dbs_wq) { + printk(KERN_ERR "Failed to create intellimm_dbs_wq workqueue\n"); + return -EFAULT; + } + + spin_lock_init(&input_boost_lock); + + for_each_possible_cpu(i) { + struct cpu_dbs_info_s *this_dbs_info = + &per_cpu(imm_cpu_dbs_info, i); + +#ifdef CONFIG_ARCH_MSM_CORTEXMP + if (i == CPU0) +#endif + { + pthread = kthread_create_on_node( + cpufreq_gov_dbs_up_task, NULL, + cpu_to_node(i), "kimm_up/%d", i); + if (likely(!IS_ERR(pthread))) { + kthread_bind(pthread, i); + sched_setscheduler_nocheck(pthread, + SCHED_FIFO, ¶m); + get_task_struct(pthread); + per_cpu(up_task, i) = pthread; + } + } + + mutex_init(&this_dbs_info->timer_mutex); + } + + return cpufreq_register_governor(&cpufreq_gov_intellimm); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + unsigned int i; + + cpufreq_unregister_governor(&cpufreq_gov_intellimm); + for_each_possible_cpu(i) { + struct cpu_dbs_info_s *this_dbs_info = + &per_cpu(imm_cpu_dbs_info, i); +#ifdef CONFIG_ARCH_MSM_CORTEXMP + if (i == CPU0) +#endif + if (per_cpu(up_task, i)) { + kthread_stop(per_cpu(up_task, i)); + put_task_struct(per_cpu(up_task, i)); + } + + mutex_destroy(&this_dbs_info->timer_mutex); + } + destroy_workqueue(dbs_wq); +} + +MODULE_AUTHOR("Venkatesh Pallipadi "); +MODULE_AUTHOR("Alexey Starikovskiy "); +MODULE_AUTHOR("Paul Reioux "); +MODULE_DESCRIPTION("'cpufreq_intellimm' - A simple min/max cpufreq governor" + "for Low Latency Frequency Transition capable processors"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIMM +fs_initcall(cpufreq_gov_dbs_init); +#else +module_init(cpufreq_gov_dbs_init); +#endif +module_exit(cpufreq_gov_dbs_exit); diff --git a/drivers/cpufreq/cpufreq_interactivex.c b/drivers/cpufreq/cpufreq_interactivex.c new file mode 100644 index 00000000..3b9f6a4d --- /dev/null +++ b/drivers/cpufreq/cpufreq_interactivex.c @@ -0,0 +1,405 @@ +/* + * drivers/cpufreq/cpufreq_interactivex.c + * + * Copyright (C) 2010 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. + * + * Author: Mike Chan (mike@android.com) - modified for suspend/wake by imoseyon + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static void (*pm_idle_old)(void); +static atomic_t active_count = ATOMIC_INIT(0); + +static DEFINE_PER_CPU(struct timer_list, cpu_timer); + +static DEFINE_PER_CPU(u64, time_in_idle); +static DEFINE_PER_CPU(u64, idle_exit_time); + +static struct cpufreq_policy *policy; +static unsigned int target_freq; + +/* Workqueues handle frequency scaling */ +static struct workqueue_struct *up_wq; +static struct workqueue_struct *down_wq; +static struct work_struct freq_scale_work; + +static u64 freq_change_time; +static u64 freq_change_time_in_idle; + +static cpumask_t work_cpumask; + +static unsigned int suspended = 0; +static unsigned int enabled = 0; + +/* + * The minimum ammount of time to spend at a frequency before we can ramp down, + * default is 50ms. + */ +#define DEFAULT_MIN_SAMPLE_TIME 20000; +static unsigned long min_sample_time; + +#define FREQ_THRESHOLD 1209600; +static unsigned int freq_threshld; + +#define RESUME_SPEED 1209600; +static unsigned int resum_speed; + +static int cpufreq_governor_interactivex(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVEX +static +#endif +struct cpufreq_governor cpufreq_gov_interactivex = { + .name = "interactiveX", + .governor = cpufreq_governor_interactivex, +#if defined(CONFIG_ARCH_MSM_SCORPION) + .max_transition_latency = 8000000, +#else + .max_transition_latency = 10000000, +#endif + .owner = THIS_MODULE, +}; + +static void cpufreq_interactivex_timer(unsigned long data) +{ + u64 delta_idle; + u64 update_time; + u64 *cpu_time_in_idle; + u64 *cpu_idle_exit_time; + struct timer_list *t; + + u64 now_idle = get_cpu_idle_time_us(data, + &update_time); + + + cpu_time_in_idle = &per_cpu(time_in_idle, data); + cpu_idle_exit_time = &per_cpu(idle_exit_time, data); + + if (update_time == *cpu_idle_exit_time) + return; + + delta_idle = now_idle - *cpu_time_in_idle; + + /* Scale up if there were no idle cycles since coming out of idle */ + if (delta_idle == 0) { + if (policy->cur == policy->max) + return; + + if (nr_running() < 1) + return; + + target_freq = policy->max; + + cpumask_set_cpu(data, &work_cpumask); + queue_work(up_wq, &freq_scale_work); + return; + } + + /* + * There is a window where if the cpu utlization can go from low to high + * between the timer expiring, delta_idle will be > 0 and the cpu will + * be 100% busy, preventing idle from running, and this timer from + * firing. So setup another timer to fire to check cpu utlization. + * Do not setup the timer if there is no scheduled work. + */ + t = &per_cpu(cpu_timer, data); + if (!timer_pending(t) && nr_running() > 0) { + *cpu_time_in_idle = get_cpu_idle_time_us( + data, cpu_idle_exit_time); + mod_timer(t, jiffies + 2); + } + + if (policy->cur == policy->min) + return; + + /* + * Do not scale down unless we have been at this frequency for the + * minimum sample time. + */ + if ((update_time - freq_change_time) < min_sample_time) + return; + + target_freq = policy->min; + cpumask_set_cpu(data, &work_cpumask); + queue_work(down_wq, &freq_scale_work); +} + +static void cpufreq_idle(void) +{ + struct timer_list *t; + u64 *cpu_time_in_idle; + u64 *cpu_idle_exit_time; + + pm_idle_old(); + + if (!cpumask_test_cpu(smp_processor_id(), policy->cpus)) + return; + + /* Timer to fire in 1-2 ticks, jiffie aligned. */ + t = &per_cpu(cpu_timer, smp_processor_id()); + cpu_idle_exit_time = &per_cpu(idle_exit_time, smp_processor_id()); + cpu_time_in_idle = &per_cpu(time_in_idle, smp_processor_id()); + + if (timer_pending(t) == 0) { + *cpu_time_in_idle = get_cpu_idle_time_us( + smp_processor_id(), cpu_idle_exit_time); + mod_timer(t, jiffies + 2); + } +} + +/* + * Choose the cpu frequency based off the load. For now choose the minimum + * frequency that will satisfy the load, which is not always the lower power. + */ +static unsigned int cpufreq_interactivex_calc_freq(unsigned int cpu) +{ + unsigned int delta_time; + unsigned int idle_time; + unsigned int cpu_load; + unsigned int newfreq; + u64 current_wall_time; + u64 current_idle_time;; + + current_idle_time = get_cpu_idle_time_us(cpu, ¤t_wall_time); + + idle_time = (unsigned int) current_idle_time - freq_change_time_in_idle; + delta_time = (unsigned int) current_wall_time - freq_change_time; + + cpu_load = 100 * (delta_time - idle_time) / delta_time; + + if (cpu_load > 95) newfreq = policy->max; + else newfreq = policy->cur * cpu_load / 100; + + return newfreq; +} + + +/* We use the same work function to sale up and down */ +static void cpufreq_interactivex_freq_change_time_work(struct work_struct *work) +{ + unsigned int cpu; + unsigned int newtarget; + cpumask_t tmp_mask = work_cpumask; + newtarget = freq_threshld; + + for_each_cpu(cpu, &tmp_mask) { + if (!suspended) { + if (target_freq == policy->max) { + if (nr_running() == 1) { + cpumask_clear_cpu(cpu, &work_cpumask); + return; + } +// __cpufreq_driver_target(policy, target_freq, CPUFREQ_RELATION_H); + __cpufreq_driver_target(policy, newtarget, CPUFREQ_RELATION_H); + } else { + target_freq = cpufreq_interactivex_calc_freq(cpu); + __cpufreq_driver_target(policy, target_freq, + CPUFREQ_RELATION_L); + } + } + freq_change_time_in_idle = get_cpu_idle_time_us(cpu, &freq_change_time); + cpumask_clear_cpu(cpu, &work_cpumask); + } + + +} + +static ssize_t show_min_sample_time(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", min_sample_time); +} + +static ssize_t store_min_sample_time(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + return strict_strtoul(buf, 0, &min_sample_time); +} + +static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644, + show_min_sample_time, store_min_sample_time); + +static struct attribute *interactivex_attributes[] = { + &min_sample_time_attr.attr, + NULL, +}; + +static struct attribute_group interactivex_attr_group = { + .attrs = interactivex_attributes, + .name = "interactiveX", +}; + +static void interactivex_suspend(int suspend) +{ + unsigned int max_speed; + + max_speed = resum_speed; + + if (!enabled) return; + if (!suspend) { // resume at max speed: + suspended = 0; + __cpufreq_driver_target(policy, max_speed, CPUFREQ_RELATION_L); + pr_info("[imoseyon] interactiveX awake at %d\n", policy->cur); + } else { + suspended = 1; + __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); + pr_info("[imoseyon] interactiveX suspended at %d\n", policy->cur); + } +} + +static void interactivex_early_suspend(struct early_suspend *handler) { + interactivex_suspend(1); +} + +static void interactivex_late_resume(struct early_suspend *handler) { + interactivex_suspend(0); +} + +static struct early_suspend interactivex_power_suspend = { + .suspend = interactivex_early_suspend, + .resume = interactivex_late_resume, + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, +}; + +static int cpufreq_governor_interactivex(struct cpufreq_policy *new_policy, + unsigned int event) +{ + int rc; + unsigned int min_freq = ~0; + unsigned int max_freq = 0; + unsigned int i; + struct cpufreq_frequency_table *freq_table; + + switch (event) { + case CPUFREQ_GOV_START: + if (!cpu_online(new_policy->cpu)) + return -EINVAL; + + /* + * Do not register the idle hook and create sysfs + * entries if we have already done so. + */ + if (atomic_inc_return(&active_count) > 1) + return 0; + + rc = sysfs_create_group(cpufreq_global_kobject, + &interactivex_attr_group); + if (rc) + return rc; + + pm_idle_old = pm_idle; + pm_idle = cpufreq_idle; + policy = new_policy; + enabled = 1; + register_early_suspend(&interactivex_power_suspend); + pr_info("[imoseyon] interactiveX active\n"); + freq_table = cpufreq_frequency_get_table(new_policy->cpu); + for (i = 0; (freq_table[i].frequency != CPUFREQ_TABLE_END); i++) { + unsigned int freq = freq_table[i].frequency; + if (freq == CPUFREQ_ENTRY_INVALID) { + continue; + } + if (freq < min_freq) + min_freq = freq; + if (freq > max_freq) + max_freq = freq; + } + resum_speed = freq_table[(i-1)/2].frequency > min_freq ? freq_table[(i-1)/2].frequency : max_freq; //Value in midrange of available CPU frequencies if sufficient number of freq bins available + freq_threshld = max_freq; + break; + + case CPUFREQ_GOV_STOP: + if (atomic_dec_return(&active_count) > 1) + return 0; + + sysfs_remove_group(cpufreq_global_kobject, + &interactivex_attr_group); + + pm_idle = pm_idle_old; + del_timer(&per_cpu(cpu_timer, new_policy->cpu)); + enabled = 0; + unregister_early_suspend(&interactivex_power_suspend); + pr_info("[imoseyon] interactiveX inactive\n"); + break; + + case CPUFREQ_GOV_LIMITS: + if (new_policy->max < new_policy->cur) + __cpufreq_driver_target(new_policy, + new_policy->max, CPUFREQ_RELATION_H); + else if (new_policy->min > new_policy->cur) + __cpufreq_driver_target(new_policy, + new_policy->min, CPUFREQ_RELATION_L); + break; + } + return 0; +} + +static int __init cpufreq_interactivex_init(void) +{ + unsigned int i; + struct timer_list *t; + min_sample_time = DEFAULT_MIN_SAMPLE_TIME; + resum_speed = RESUME_SPEED; + freq_threshld = FREQ_THRESHOLD; + + /* Initalize per-cpu timers */ + for_each_possible_cpu(i) { + t = &per_cpu(cpu_timer, i); + init_timer_deferrable(t); + t->function = cpufreq_interactivex_timer; + t->data = i; + } + + /* Scale up is high priority */ + up_wq = create_workqueue("kinteractive_up"); + down_wq = create_workqueue("knteractive_down"); + + INIT_WORK(&freq_scale_work, cpufreq_interactivex_freq_change_time_work); + + pr_info("[imoseyon] interactiveX enter\n"); + return cpufreq_register_governor(&cpufreq_gov_interactivex); +} + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVEX +fs_initcall(cpufreq_interactivex_init); +#else +module_init(cpufreq_interactivex_init); +#endif + +static void __exit cpufreq_interactivex_exit(void) +{ + pr_info("[imoseyon] interactiveX exit\n"); + cpufreq_unregister_governor(&cpufreq_gov_interactivex); + destroy_workqueue(up_wq); + destroy_workqueue(down_wq); +} + +module_exit(cpufreq_interactivex_exit); + +MODULE_AUTHOR("Mike Chan "); +MODULE_DESCRIPTION("'cpufreq_interactiveX' - A cpufreq governor for " + "Latency sensitive workloads"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/cpufreq_lionheart.c b/drivers/cpufreq/cpufreq_lionheart.c new file mode 100755 index 00000000..9e549007 --- /dev/null +++ b/drivers/cpufreq/cpufreq_lionheart.c @@ -0,0 +1,545 @@ +/* + * drivers/cpufreq/cpufreq_lionheart.c + * + * Patched & tweaked: knzo + * + * Based on the Conservative governor by: + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * (C) 2009 Alexander Clouter + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEF_FREQUENCY_UP_THRESHOLD (70) +#define DEF_FREQUENCY_DOWN_THRESHOLD (30) +#define MIN_SAMPLING_RATE_RATIO (2) + +static unsigned int min_sampling_rate; + +#define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) +#define DEF_SAMPLING_DOWN_FACTOR (1) +#define MAX_SAMPLING_DOWN_FACTOR (10) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +static void do_dbs_timer(struct work_struct *work); + +struct cpu_dbs_info_s { + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + unsigned int down_skip; + unsigned int requested_freq; + int cpu; + unsigned int enable:1; + + struct mutex timer_mutex; +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, cs_cpu_dbs_info); + +static unsigned int dbs_enable; + +static DEFINE_MUTEX(dbs_mutex); + +static struct dbs_tuners { + unsigned int sampling_rate; + unsigned int sampling_down_factor; + unsigned int up_threshold; + unsigned int down_threshold; + unsigned int ignore_nice; + unsigned int freq_step; +} dbs_tuners_ins = { + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, + .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, + .ignore_nice = 0, + .freq_step = 5, +}; + +static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu, + cputime64_t *wall) +{ + cputime64_t idle_time; + cputime64_t cur_wall_time; + cputime64_t busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = (cputime64_t)jiffies_to_usecs(cur_wall_time); + + return (cputime64_t)jiffies_to_usecs(idle_time); +} + +static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, wall); + + if (idle_time == -1ULL) + return get_cpu_idle_time_jiffy(cpu, wall); + + return idle_time; +} + +static int +dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freq = data; + struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cs_cpu_dbs_info, + freq->cpu); + + struct cpufreq_policy *policy; + + if (!this_dbs_info->enable) + return 0; + + policy = this_dbs_info->cur_policy; + + if (this_dbs_info->requested_freq > policy->max + || this_dbs_info->requested_freq < policy->min) + this_dbs_info->requested_freq = freq->new; + + return 0; +} + +static struct notifier_block dbs_cpufreq_notifier_block = { + .notifier_call = dbs_cpufreq_notifier +}; + +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", min_sampling_rate); +} + +define_one_global_ro(sampling_rate_min); + +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +} + +show_one(sampling_rate, sampling_rate); +show_one(sampling_down_factor, sampling_down_factor); +show_one(up_threshold, up_threshold); +show_one(down_threshold, down_threshold); +show_one(ignore_nice_load, ignore_nice); +show_one(freq_step, freq_step); + +static ssize_t store_sampling_down_factor(struct kobject *a, + struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) + return -EINVAL; + + dbs_tuners_ins.sampling_down_factor = input; + return count; +} + +static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); + return count; +} + +static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > 100 || + input <= dbs_tuners_ins.down_threshold) + return -EINVAL; + + dbs_tuners_ins.up_threshold = input; + return count; +} + +static ssize_t store_down_threshold(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input < 11 || input > 100 || + input >= dbs_tuners_ins.up_threshold) + return -EINVAL; + + dbs_tuners_ins.down_threshold = input; + return count; +} + +static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (input > 1) + input = 1; + + if (input == dbs_tuners_ins.ignore_nice) + return count; + + dbs_tuners_ins.ignore_nice = input; + + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(cs_cpu_dbs_info, j); + dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + return count; +} + +static ssize_t store_freq_step(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + if (input > 100) + input = 100; + + dbs_tuners_ins.freq_step = input; + return count; +} + +define_one_global_rw(sampling_rate); +define_one_global_rw(sampling_down_factor); +define_one_global_rw(up_threshold); +define_one_global_rw(down_threshold); +define_one_global_rw(ignore_nice_load); +define_one_global_rw(freq_step); + +static struct attribute *dbs_attributes[] = { + &sampling_rate_min.attr, + &sampling_rate.attr, + &sampling_down_factor.attr, + &up_threshold.attr, + &down_threshold.attr, + &ignore_nice_load.attr, + &freq_step.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "lionheart", +}; + +static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) +{ + unsigned int load = 0; + unsigned int max_load = 0; + unsigned int freq_target; + + struct cpufreq_policy *policy; + unsigned int j; + + policy = this_dbs_info->cur_policy; + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + cputime64_t cur_wall_time, cur_idle_time; + unsigned int idle_time, wall_time; + + j_dbs_info = &per_cpu(cs_cpu_dbs_info, j); + + cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_dbs_info->prev_cpu_idle); + j_dbs_info->prev_cpu_idle = cur_idle_time; + + if (dbs_tuners_ins.ignore_nice) { + cputime64_t cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + j_dbs_info->prev_cpu_nice; + /* + * Assumption: nice time between sampling periods will + * be less than 2^32 jiffies for 32 bit sys + */ + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + load = 100 * (wall_time - idle_time) / wall_time; + + if (load > max_load) + max_load = load; + } + + if (dbs_tuners_ins.freq_step == 0) + return; + + if (max_load > dbs_tuners_ins.up_threshold) { + this_dbs_info->down_skip = 0; + + if (this_dbs_info->requested_freq == policy->max) + return; + + freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100; + + if (unlikely(freq_target == 0)) + freq_target = 5; + + this_dbs_info->requested_freq += freq_target; + if (this_dbs_info->requested_freq > policy->max) + this_dbs_info->requested_freq = policy->max; + + __cpufreq_driver_target(policy, this_dbs_info->requested_freq, + CPUFREQ_RELATION_H); + return; + } + + if (max_load < (dbs_tuners_ins.down_threshold - 10)) { + freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100; + + this_dbs_info->requested_freq -= freq_target; + if (this_dbs_info->requested_freq < policy->min) + this_dbs_info->requested_freq = policy->min; + + if (policy->cur == policy->min) + return; + + __cpufreq_driver_target(policy, this_dbs_info->requested_freq, + CPUFREQ_RELATION_H); + return; + } +} + +static void do_dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + // delay -= jiffies % delay; + + mutex_lock(&dbs_info->timer_mutex); + + dbs_check_cpu(dbs_info); + + schedule_delayed_work_on(cpu, &dbs_info->work, delay); + mutex_unlock(&dbs_info->timer_mutex); +} + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) +{ + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + // delay -= jiffies % delay; + + dbs_info->enable = 1; + INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); + schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +{ + dbs_info->enable = 0; + cancel_delayed_work_sync(&dbs_info->work); +} + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; + int rc; + + this_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_mutex); + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(cs_cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &j_dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + j_dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + this_dbs_info->down_skip = 0; + this_dbs_info->requested_freq = policy->cur; + + mutex_init(&this_dbs_info->timer_mutex); + dbs_enable++; + + if (dbs_enable == 1) { + unsigned int latency; + + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + + rc = sysfs_create_group(cpufreq_global_kobject, + &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + + min_sampling_rate = 10000; + dbs_tuners_ins.sampling_rate = 10000; + + cpufreq_register_notifier( + &dbs_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + mutex_unlock(&dbs_mutex); + + dbs_timer_init(this_dbs_info); + + break; + + case CPUFREQ_GOV_STOP: + dbs_timer_exit(this_dbs_info); + + mutex_lock(&dbs_mutex); + dbs_enable--; + mutex_destroy(&this_dbs_info->timer_mutex); + + if (dbs_enable == 0) + cpufreq_unregister_notifier( + &dbs_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + + mutex_unlock(&dbs_mutex); + if (!dbs_enable) + sysfs_remove_group(cpufreq_global_kobject, + &dbs_attr_group); + + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&this_dbs_info->timer_mutex); + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target( + this_dbs_info->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target( + this_dbs_info->cur_policy, + policy->min, CPUFREQ_RELATION_L); + mutex_unlock(&this_dbs_info->timer_mutex); + + break; + } + return 0; +} + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_LIONHEART +static +#endif +struct cpufreq_governor cpufreq_gov_lionheart = { + .name = "lionheart", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; + +static int __init cpufreq_gov_dbs_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_lionheart); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_lionheart); +} + +MODULE_AUTHOR("knzo"); +MODULE_DESCRIPTION("'cpufreq_lionheart' - A brave and agile conservative-based governor."); +MODULE_LICENSE("GPL"); + +fs_initcall(cpufreq_gov_dbs_init); +module_exit(cpufreq_gov_dbs_exit); diff --git a/drivers/cpufreq/cpufreq_ondemandx.c b/drivers/cpufreq/cpufreq_ondemandx.c new file mode 100644 index 00000000..779d3962 --- /dev/null +++ b/drivers/cpufreq/cpufreq_ondemandx.c @@ -0,0 +1,830 @@ +/* + * drivers/cpufreq/cpufreq_ondemandX.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * dbs is used in this file as a shortform for demandbased switching + * It helps to keep variable names smaller, simpler + */ + +#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) +#define DEF_FREQUENCY_UP_THRESHOLD (80) +#define DEF_SAMPLING_DOWN_FACTOR (170) +#define MAX_SAMPLING_DOWN_FACTOR (100000) +#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) +#define MICRO_FREQUENCY_UP_THRESHOLD (95) +#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) +#define MIN_FREQUENCY_UP_THRESHOLD (11) +#define MAX_FREQUENCY_UP_THRESHOLD (100) + +/* + * The polling frequency of this governor depends on the capability of + * the processor. Default polling frequency is 1000 times the transition + * latency of the processor. The governor will work on any processor with + * transition latency <= 10mS, using appropriate sampling + * rate. + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. + * All times here are in uS. + */ +#define MIN_SAMPLING_RATE_RATIO (2) + +static unsigned int min_sampling_rate; + +static unsigned int suspendfreq = 384000; + +#define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +static void do_dbs_timer(struct work_struct *work); +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMANDX +static +#endif +struct cpufreq_governor cpufreq_gov_ondemandX = { + .name = "ondemandX", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; + +/* Sampling types */ +enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; + +struct cpu_dbs_info_s { + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_iowait; + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + struct cpufreq_frequency_table *freq_table; + unsigned int freq_lo; + unsigned int freq_lo_jiffies; + unsigned int freq_hi_jiffies; + unsigned int rate_mult; + int cpu; + unsigned int sample_type:1; + /* + * percpu mutex that serializes governor limit change with + * do_dbs_timer invocation. We do not want do_dbs_timer to run + * when user is changing the governor or limits. + */ + struct mutex timer_mutex; +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info); + +static unsigned int dbs_enable=0; /* number of CPUs using this policy */ + +// used for imoseyon's mods +static unsigned int suspended = 0; +static void ondemandX_suspend(int suspend) +{ + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, smp_processor_id()); + if (dbs_enable==0) return; + if (!suspend) { // resume at max speed: + suspended = 0; + __cpufreq_driver_target(dbs_info->cur_policy, dbs_info->cur_policy->max, + CPUFREQ_RELATION_L); + pr_info("[imoseyon] ondemandX awake at %d\n", dbs_info->cur_policy->cur); + } else { + suspended = 1; + // let's give it a little breathing room + __cpufreq_driver_target(dbs_info->cur_policy, suspendfreq, CPUFREQ_RELATION_H); + pr_info("[imoseyon] ondemandX suspended at %d\n", dbs_info->cur_policy->cur); + } +} + +static void ondemandX_early_suspend(struct early_suspend *handler) { + ondemandX_suspend(1); +} + +static void ondemandX_late_resume(struct early_suspend *handler) { + ondemandX_suspend(0); +} + +static struct early_suspend ondemandX_power_suspend = { + .suspend = ondemandX_early_suspend, + .resume = ondemandX_late_resume, + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, +}; + +/* + * dbs_mutex protects dbs_enable in governor start/stop. + */ +static DEFINE_MUTEX(dbs_mutex); + +static struct dbs_tuners { + unsigned int sampling_rate; + unsigned int up_threshold; + unsigned int down_differential; + unsigned int ignore_nice; + unsigned int sampling_down_factor; + unsigned int powersave_bias; + unsigned int io_is_busy; +} dbs_tuners_ins = { + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, + .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, + .ignore_nice = 0, + .powersave_bias = 100, +}; + +static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu, + cputime64_t *wall) +{ + cputime64_t idle_time; + cputime64_t cur_wall_time; + cputime64_t busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = (cputime64_t)jiffies_to_usecs(cur_wall_time); + + return (cputime64_t)jiffies_to_usecs(idle_time); +} + +static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, wall); + + if (idle_time == -1ULL) + return get_cpu_idle_time_jiffy(cpu, wall); + + return idle_time; +} + +static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall) +{ + u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); + + if (iowait_time == -1ULL) + return 0; + + return iowait_time; +} + +/* + * Find right freq to be set now with powersave_bias on. + * Returns the freq_hi to be used right now and will set freq_hi_jiffies, + * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs. + */ +static unsigned int powersave_bias_target(struct cpufreq_policy *policy, + unsigned int freq_next, + unsigned int relation) +{ + unsigned int freq_req, freq_reduc, freq_avg; + unsigned int freq_hi, freq_lo; + unsigned int index = 0; + unsigned int jiffies_total, jiffies_hi, jiffies_lo; + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, + policy->cpu); + + if (!dbs_info->freq_table) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_next; + } + + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, + relation, &index); + freq_req = dbs_info->freq_table[index].frequency; + freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000; + freq_avg = freq_req - freq_reduc; + + /* Find freq bounds for freq_avg in freq_table */ + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_H, &index); + freq_lo = dbs_info->freq_table[index].frequency; + index = 0; + cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, + CPUFREQ_RELATION_L, &index); + freq_hi = dbs_info->freq_table[index].frequency; + + /* Find out how long we have to be in hi and lo freqs */ + if (freq_hi == freq_lo) { + dbs_info->freq_lo = 0; + dbs_info->freq_lo_jiffies = 0; + return freq_lo; + } + jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + jiffies_hi = (freq_avg - freq_lo) * jiffies_total; + jiffies_hi += ((freq_hi - freq_lo) / 2); + jiffies_hi /= (freq_hi - freq_lo); + jiffies_lo = jiffies_total - jiffies_hi; + dbs_info->freq_lo = freq_lo; + dbs_info->freq_lo_jiffies = jiffies_lo; + dbs_info->freq_hi_jiffies = jiffies_hi; + return freq_hi; +} + +static void ondemandX_powersave_bias_init_cpu(int cpu) +{ + struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + dbs_info->freq_table = cpufreq_frequency_get_table(cpu); + dbs_info->freq_lo = 0; +} + +static void ondemandX_powersave_bias_init(void) +{ + int i; + for_each_online_cpu(i) { + ondemandX_powersave_bias_init_cpu(i); + } +} + +/************************** sysfs interface ************************/ + +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", min_sampling_rate); +} + +define_one_global_ro(sampling_rate_min); + +/* cpufreq_ondemandX Governor Tunables */ +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +} +show_one(sampling_rate, sampling_rate); +show_one(io_is_busy, io_is_busy); +show_one(up_threshold, up_threshold); +show_one(down_differential, down_differential); +show_one(sampling_down_factor, sampling_down_factor); +show_one(ignore_nice_load, ignore_nice); +show_one(powersave_bias, powersave_bias); + +static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); + return count; +} + +static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + dbs_tuners_ins.io_is_busy = !!input; + return count; +} + +static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD) { + return -EINVAL; + } + dbs_tuners_ins.up_threshold = input; + return count; +} + +static ssize_t store_sampling_down_factor(struct kobject *a, + struct attribute *b, const char *buf, size_t count) +{ + unsigned int input, j; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) + return -EINVAL; + dbs_tuners_ins.sampling_down_factor = input; + + /* Reset down sampling multiplier in case it was active */ + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(od_cpu_dbs_info, j); + dbs_info->rate_mult = 1; + } + return count; +} + +static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + + if (input > 1) + input = 1; + + if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */ + return count; + } + dbs_tuners_ins.ignore_nice = input; + + /* we need to re-evaluate prev_cpu_idle */ + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(od_cpu_dbs_info, j); + dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + + } + return count; +} + +static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + if (input > 1000) + input = 1000; + + dbs_tuners_ins.powersave_bias = input; + ondemandX_powersave_bias_init(); + return count; +} + +static ssize_t store_down_differential(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + + if (ret != 1) + return -EINVAL; + + if (input > 30) + input = 30; + + if (input < 0) + input = 0; + + mutex_lock(&dbs_mutex); + dbs_tuners_ins.down_differential = input; + mutex_unlock(&dbs_mutex); + + return count; +} + +define_one_global_rw(sampling_rate); +define_one_global_rw(io_is_busy); +define_one_global_rw(up_threshold); +define_one_global_rw(down_differential); +define_one_global_rw(sampling_down_factor); +define_one_global_rw(ignore_nice_load); +define_one_global_rw(powersave_bias); + +static struct attribute *dbs_attributes[] = { + &sampling_rate_min.attr, + &sampling_rate.attr, + &up_threshold.attr, + &down_differential.attr, + &sampling_down_factor.attr, + &ignore_nice_load.attr, + &powersave_bias.attr, + &io_is_busy.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "ondemandX", +}; + +/************************** sysfs end ************************/ + +static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) +{ + if (dbs_tuners_ins.powersave_bias) + freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H); + else if (p->cur == p->max) + return; + if (suspended && freq > suspendfreq) { + freq = suspendfreq; + __cpufreq_driver_target(p, freq, CPUFREQ_RELATION_H); + } else + __cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ? + CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); +} + +static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) +{ + unsigned int max_load_freq; + + struct cpufreq_policy *policy; + unsigned int j; + + this_dbs_info->freq_lo = 0; + policy = this_dbs_info->cur_policy; + + /* + * Every sampling_rate, we check, if current idle time is less + * than 20% (default), then we try to increase frequency + * Every sampling_rate, we look for a the lowest + * frequency which can sustain the load while keeping idle time over + * 30%. If such a frequency exist, we try to decrease to this frequency. + * + * Any frequency increase takes it to the maximum frequency. + * Frequency reduction happens at minimum steps of + * 5% (default) of current frequency + */ + + /* Get Absolute Load - in terms of freq */ + max_load_freq = 0; + + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + unsigned int idle_time, wall_time, iowait_time; + unsigned int load, load_freq; + int freq_avg; + + j_dbs_info = &per_cpu(od_cpu_dbs_info, j); + + cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); + cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_dbs_info->prev_cpu_idle); + j_dbs_info->prev_cpu_idle = cur_idle_time; + + iowait_time = (unsigned int) + (cur_iowait_time - j_dbs_info->prev_cpu_iowait); + j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + if (dbs_tuners_ins.ignore_nice) { + u64 cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + j_dbs_info->prev_cpu_nice; + /* + * Assumption: nice time between sampling periods will + * be less than 2^32 jiffies for 32 bit sys + */ + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + /* + * For the purpose of ondemandX, waiting for disk IO is an + * indication that you're performance critical, and not that + * the system is actually idle. So subtract the iowait time + * from the cpu idle time. + */ + + if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time) + idle_time -= iowait_time; + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + load = 100 * (wall_time - idle_time) / wall_time; + + freq_avg = __cpufreq_driver_getavg(policy, j); + if (freq_avg <= 0) + freq_avg = policy->cur; + + load_freq = load * freq_avg; + if (load_freq > max_load_freq) + max_load_freq = load_freq; + } + + /* Check for frequency increase */ + if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) { + /* If switching to max speed, apply sampling_down_factor */ + if (policy->cur < policy->max) + this_dbs_info->rate_mult = + dbs_tuners_ins.sampling_down_factor; + dbs_freq_increase(policy, policy->max); + return; + } + + /* Check for frequency decrease */ + /* if we cannot reduce the frequency anymore, break out early */ + if (policy->cur == policy->min) + return; + + /* + * The optimal frequency is the frequency that is the lowest that + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ + if (max_load_freq < + (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * + policy->cur) { + unsigned int freq_next; + freq_next = max_load_freq / + (dbs_tuners_ins.up_threshold - + dbs_tuners_ins.down_differential); + + /* No longer fully busy, reset rate_mult */ + this_dbs_info->rate_mult = 1; + + if (freq_next < policy->min) + freq_next = policy->min; + + if (!dbs_tuners_ins.powersave_bias) { + __cpufreq_driver_target(policy, freq_next, + CPUFREQ_RELATION_L); + } else { + int freq = powersave_bias_target(policy, freq_next, + CPUFREQ_RELATION_L); + __cpufreq_driver_target(policy, freq, + CPUFREQ_RELATION_L); + } + } +} + +static void do_dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + int sample_type = dbs_info->sample_type; + + int delay; + + mutex_lock(&dbs_info->timer_mutex); + + /* Common NORMAL_SAMPLE setup */ + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + if (!dbs_tuners_ins.powersave_bias || + sample_type == DBS_NORMAL_SAMPLE) { + dbs_check_cpu(dbs_info); + if (dbs_info->freq_lo) { + /* Setup timer for SUB_SAMPLE */ + dbs_info->sample_type = DBS_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; + } else { + /* We want all CPUs to do sampling nearly on + * same jiffy + */ + delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate + * dbs_info->rate_mult); + + if (num_online_cpus() > 1) + delay -= jiffies % delay; + } + } else { + if (!suspended) + __cpufreq_driver_target(dbs_info->cur_policy, + dbs_info->freq_lo, CPUFREQ_RELATION_H); + delay = dbs_info->freq_lo_jiffies; + } + schedule_delayed_work_on(cpu, &dbs_info->work, delay); + mutex_unlock(&dbs_info->timer_mutex); +} + +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) +{ + /* We want all CPUs to do sampling nearly on same jiffy */ + int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + if (num_online_cpus() > 1) + delay -= jiffies % delay; + + dbs_info->sample_type = DBS_NORMAL_SAMPLE; + INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); + schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +{ + cancel_delayed_work_sync(&dbs_info->work); +} + +/* + * Not all CPUs want IO time to be accounted as busy; this dependson how + * efficient idling at a higher frequency/voltage is. + * Pavel Machek says this is not so for various generations of AMD and old + * Intel systems. + * Mike Chan (androidlcom) calis this is also not true for ARM. + * Because of this, whitelist specific known (series) of CPUs by default, and + * leave all others up to the user. + */ +static int should_io_be_busy(void) +{ +#if defined(CONFIG_X86) + /* + * For Intel, Core 2 (model 15) andl later have an efficient idle. + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 15) + return 1; +#endif + return 0; +} + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; + int rc; + + this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_mutex); + + dbs_enable++; + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(od_cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, + &j_dbs_info->prev_cpu_wall); + if (dbs_tuners_ins.ignore_nice) + j_dbs_info->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + this_dbs_info->cpu = cpu; + this_dbs_info->rate_mult = 1; + ondemandX_powersave_bias_init_cpu(cpu); + /* + * Start the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 1) { + unsigned int latency; + + rc = sysfs_create_group(cpufreq_global_kobject, + &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + + /* policy latency is in nS. Convert it to uS first */ + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + /* Bring kernel and HW constraints together */ + min_sampling_rate = max(min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + dbs_tuners_ins.sampling_rate = + max(min_sampling_rate, + latency * LATENCY_MULTIPLIER); + dbs_tuners_ins.io_is_busy = should_io_be_busy(); + } + mutex_unlock(&dbs_mutex); + + mutex_init(&this_dbs_info->timer_mutex); + dbs_timer_init(this_dbs_info); + register_early_suspend(&ondemandX_power_suspend); + pr_info("[imoseyon] ondemandX active\n"); + break; + + case CPUFREQ_GOV_STOP: + dbs_timer_exit(this_dbs_info); + + mutex_lock(&dbs_mutex); + mutex_destroy(&this_dbs_info->timer_mutex); + dbs_enable--; + mutex_unlock(&dbs_mutex); + if (!dbs_enable) + sysfs_remove_group(cpufreq_global_kobject, + &dbs_attr_group); + unregister_early_suspend(&ondemandX_power_suspend); + pr_info("[imoseyon] ondemandX inactive\n"); + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&this_dbs_info->timer_mutex); + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target(this_dbs_info->cur_policy, + policy->min, CPUFREQ_RELATION_L); + mutex_unlock(&this_dbs_info->timer_mutex); + break; + } + return 0; +} + +static int __init cpufreq_gov_dbs_init(void) +{ + cputime64_t wall; + u64 idle_time; + int cpu = get_cpu(); + + idle_time = get_cpu_idle_time_us(cpu, &wall); + put_cpu(); + if (idle_time != -1ULL) { + /* Idle micro accounting is supported. Use finer thresholds */ + dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; + dbs_tuners_ins.down_differential = + MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + /* + * In no_hz/micro accounting case we set the minimum frequency + * not depending on HZ, but fixed (very low). The deferred + * timer might skip some samples if idle/sleeping as needed. + */ + min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + } else { + /* For correct statistics, we need 10 ticks for each measure */ + min_sampling_rate = + MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + } + + pr_info("[imoseyon] ondemandX enter\n"); + return cpufreq_register_governor(&cpufreq_gov_ondemandX); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + pr_info("[imoseyon] ondemandX exit\n"); + cpufreq_unregister_governor(&cpufreq_gov_ondemandX); +} + + +MODULE_AUTHOR("Venkatesh Pallipadi "); +MODULE_AUTHOR("Alexey Starikovskiy "); +MODULE_DESCRIPTION("'cpufreq_ondemandX' - A dynamic cpufreq governor for " + "Low Latency Frequency Transition capable processors"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMANDX +fs_initcall(cpufreq_gov_dbs_init); +#else +module_init(cpufreq_gov_dbs_init); +#endif +module_exit(cpufreq_gov_dbs_exit); + diff --git a/drivers/cpufreq/cpufreq_smartass2.c b/drivers/cpufreq/cpufreq_smartass2.c new file mode 100644 index 00000000..065bc124 --- /dev/null +++ b/drivers/cpufreq/cpufreq_smartass2.c @@ -0,0 +1,868 @@ +/* + * drivers/cpufreq/cpufreq_smartass2.c + * + * Copyright (C) 2010 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. + * + * Author: Erasmux + * + * Based on the interactive governor By Mike Chan (mike@android.com) + * which was adaptated to 2.6.29 kernel by Nadlabak (pavel@doshaska.net) + * + * SMP support based on mod by faux123 + * + * For a general overview of smartassV2 see the relavent part in + * Documentation/cpu-freq/governors.txt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define cputime64_sub(__a, __b) ((__a) - (__b)) + +/******************** Tunable parameters: ********************/ + +/* + * The "ideal" frequency to use when awake. The governor will ramp up faster + * towards the ideal frequency and slower after it has passed it. Similarly, + * lowering the frequency towards the ideal frequency is faster than below it. + */ +#define DEFAULT_AWAKE_IDEAL_FREQ 700000 +static unsigned int awake_ideal_freq; + +/* + * The "ideal" frequency to use when suspended. + * When set to 0, the governor will not track the suspended state (meaning + * that practically when sleep_ideal_freq==0 the awake_ideal_freq is used + * also when suspended). + */ +#define DEFAULT_SLEEP_IDEAL_FREQ 320000 +static unsigned int sleep_ideal_freq; + +/* + * Freqeuncy delta when ramping up above the ideal freqeuncy. + * Zero disables and causes to always jump straight to max frequency. + * When below the ideal freqeuncy we always ramp up to the ideal freq. + */ +#define DEFAULT_RAMP_UP_STEP 224000 +static unsigned int ramp_up_step; + +/* + * Freqeuncy delta when ramping down below the ideal freqeuncy. + * Zero disables and will calculate ramp down according to load heuristic. + * When above the ideal freqeuncy we always ramp down to the ideal freq. + */ +#define DEFAULT_RAMP_DOWN_STEP 192000 +static unsigned int ramp_down_step; + +/* + * CPU freq will be increased if measured load > max_cpu_load; + */ +#define DEFAULT_MAX_CPU_LOAD 60 +static unsigned long max_cpu_load; + +/* + * CPU freq will be decreased if measured load < min_cpu_load; + */ +#define DEFAULT_MIN_CPU_LOAD 30 +static unsigned long min_cpu_load; + +/* + * The minimum amount of time to spend at a frequency before we can ramp up. + * Notice we ignore this when we are below the ideal frequency. + */ +#define DEFAULT_UP_RATE_US 35000; +static unsigned long up_rate_us; + +/* + * The minimum amount of time to spend at a frequency before we can ramp down. + * Notice we ignore this when we are above the ideal frequency. + */ +#define DEFAULT_DOWN_RATE_US 75000; +static unsigned long down_rate_us; + +/* + * The frequency to set when waking up from sleep. + * When sleep_ideal_freq=0 this will have no effect. + */ +#define DEFAULT_SLEEP_WAKEUP_FREQ 99999999 +static unsigned int sleep_wakeup_freq; + +/* + * Sampling rate, I highly recommend to leave it at 2. + */ +#define DEFAULT_SAMPLE_RATE_JIFFIES 2 +static unsigned int sample_rate_jiffies; + + +/*************** End of tunables ***************/ + + +static void (*pm_idle_old)(void); +static atomic_t active_count = ATOMIC_INIT(0); + +struct smartass_info_s { + struct cpufreq_policy *cur_policy; + struct cpufreq_frequency_table *freq_table; + struct timer_list timer; + u64 time_in_idle; + u64 idle_exit_time; + u64 freq_change_time; + u64 freq_change_time_in_idle; + int cur_cpu_load; + int old_freq; + int ramp_dir; + unsigned int enable; + int ideal_speed; +}; +static DEFINE_PER_CPU(struct smartass_info_s, smartass_info); + +/* Workqueues handle frequency scaling */ +static struct workqueue_struct *up_wq; +static struct workqueue_struct *down_wq; +static struct work_struct freq_scale_work; + +static cpumask_t work_cpumask; +static spinlock_t cpumask_lock; + +static unsigned int suspended; + +#define dprintk(flag,msg...) do { \ + if (debug_mask & flag) printk(KERN_DEBUG msg); \ + } while (0) + +enum { + SMARTASS_DEBUG_JUMPS=1, + SMARTASS_DEBUG_LOAD=2, + SMARTASS_DEBUG_ALG=4 +}; + +/* + * Combination of the above debug flags. + */ +static unsigned long debug_mask; + +static int cpufreq_governor_smartass(struct cpufreq_policy *policy, + unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2 +static +#endif +struct cpufreq_governor cpufreq_gov_smartass2 = { + .name = "smartassV2", + .governor = cpufreq_governor_smartass, + .max_transition_latency = 9000000, + .owner = THIS_MODULE, +}; + +inline static void smartass_update_min_max(struct smartass_info_s *this_smartass, struct cpufreq_policy *policy, int suspend) { + if (suspend) { + this_smartass->ideal_speed = // sleep_ideal_freq; but make sure it obeys the policy min/max + policy->max > sleep_ideal_freq ? + (sleep_ideal_freq > policy->min ? sleep_ideal_freq : policy->min) : policy->max; + } else { + this_smartass->ideal_speed = // awake_ideal_freq; but make sure it obeys the policy min/max + policy->min < awake_ideal_freq ? + (awake_ideal_freq < policy->max ? awake_ideal_freq : policy->max) : policy->min; + } +} + +inline static void smartass_update_min_max_allcpus(void) { + unsigned int i; + for_each_online_cpu(i) { + struct smartass_info_s *this_smartass = &per_cpu(smartass_info, i); + if (this_smartass->enable) + smartass_update_min_max(this_smartass,this_smartass->cur_policy,suspended); + } +} + +inline static unsigned int validate_freq(struct cpufreq_policy *policy, int freq) { + if (freq > (int)policy->max) + return policy->max; + if (freq < (int)policy->min) + return policy->min; + return freq; +} + +inline static void reset_timer(unsigned long cpu, struct smartass_info_s *this_smartass) { + this_smartass->time_in_idle = get_cpu_idle_time_us(cpu, &this_smartass->idle_exit_time); + mod_timer(&this_smartass->timer, jiffies + sample_rate_jiffies); +} + +inline static void work_cpumask_set(unsigned long cpu) { + unsigned long flags; + spin_lock_irqsave(&cpumask_lock, flags); + cpumask_set_cpu(cpu, &work_cpumask); + spin_unlock_irqrestore(&cpumask_lock, flags); +} + +inline static int work_cpumask_test_and_clear(unsigned long cpu) { + unsigned long flags; + int res = 0; + spin_lock_irqsave(&cpumask_lock, flags); + res = cpumask_test_and_clear_cpu(cpu, &work_cpumask); + spin_unlock_irqrestore(&cpumask_lock, flags); + return res; +} + +inline static int target_freq(struct cpufreq_policy *policy, struct smartass_info_s *this_smartass, + int new_freq, int old_freq, int prefered_relation) { + int index, target; + struct cpufreq_frequency_table *table = this_smartass->freq_table; + + if (new_freq == old_freq) + return 0; + new_freq = validate_freq(policy,new_freq); + if (new_freq == old_freq) + return 0; + + if (table && + !cpufreq_frequency_table_target(policy,table,new_freq,prefered_relation,&index)) + { + target = table[index].frequency; + if (target == old_freq) { + // if for example we are ramping up to *at most* current + ramp_up_step + // but there is no such frequency higher than the current, try also + // to ramp up to *at least* current + ramp_up_step. + if (new_freq > old_freq && prefered_relation==CPUFREQ_RELATION_H + && !cpufreq_frequency_table_target(policy,table,new_freq, CPUFREQ_RELATION_L,&index)) + target = table[index].frequency; + // simlarly for ramping down: + else if (new_freq < old_freq && prefered_relation==CPUFREQ_RELATION_L + && !cpufreq_frequency_table_target(policy,table,new_freq, CPUFREQ_RELATION_H,&index)) + target = table[index].frequency; + } + + if (target == old_freq) { + // We should not get here: + // If we got here we tried to change to a validated new_freq which is different + // from old_freq, so there is no reason for us to remain at same frequency. + printk(KERN_WARNING "Smartass: frequency change failed: %d to %d => %d\n", + old_freq,new_freq,target); + return 0; + } + } + else target = new_freq; + + __cpufreq_driver_target(policy, target, prefered_relation); + + dprintk(SMARTASS_DEBUG_JUMPS,"SmartassQ: jumping from %d to %d => %d (%d)\n", + old_freq,new_freq,target,policy->cur); + + return target; +} + +static void cpufreq_smartass_timer(unsigned long cpu) +{ + u64 delta_idle; + u64 delta_time; + int cpu_load; + int old_freq; + u64 update_time; + u64 now_idle; + int queued_work = 0; + struct smartass_info_s *this_smartass = &per_cpu(smartass_info, cpu); + struct cpufreq_policy *policy = this_smartass->cur_policy; + + now_idle = get_cpu_idle_time_us(cpu, &update_time); + old_freq = policy->cur; + + if (this_smartass->idle_exit_time == 0 || update_time == this_smartass->idle_exit_time) + return; + + delta_idle = now_idle - this_smartass->time_in_idle; + delta_time = update_time - this_smartass->idle_exit_time; + + // If timer ran less than 1ms after short-term sample started, retry. + if (delta_time < 1000) { + if (!timer_pending(&this_smartass->timer)) + reset_timer(cpu,this_smartass); + return; + } + + if (delta_idle > delta_time) + cpu_load = 0; + else + cpu_load = 100 * (unsigned int)(delta_time - delta_idle) / (unsigned int)delta_time; + + dprintk(SMARTASS_DEBUG_LOAD,"smartassT @ %d: load %d (delta_time %llu)\n", + old_freq,cpu_load,delta_time); + + this_smartass->cur_cpu_load = cpu_load; + this_smartass->old_freq = old_freq; + + // Scale up if load is above max or if there where no idle cycles since coming out of idle, + // additionally, if we are at or above the ideal_speed, verify we have been at this frequency + // for at least up_rate_us: + if (cpu_load > max_cpu_load || delta_idle == 0) + { + if (old_freq < policy->max && + (old_freq < this_smartass->ideal_speed || delta_idle == 0 || + (update_time - this_smartass->freq_change_time) >= up_rate_us)) + { + dprintk(SMARTASS_DEBUG_ALG,"smartassT @ %d ramp up: load %d (delta_idle %llu)\n", + old_freq,cpu_load,delta_idle); + this_smartass->ramp_dir = 1; + work_cpumask_set(cpu); + queue_work(up_wq, &freq_scale_work); + queued_work = 1; + } + else this_smartass->ramp_dir = 0; + } + // Similarly for scale down: load should be below min and if we are at or below ideal + // frequency we require that we have been at this frequency for at least down_rate_us: + else if (cpu_load < min_cpu_load && old_freq > policy->min && + (old_freq > this_smartass->ideal_speed || + (update_time - this_smartass->freq_change_time) >= down_rate_us)) + { + dprintk(SMARTASS_DEBUG_ALG,"smartassT @ %d ramp down: load %d (delta_idle %llu)\n", + old_freq,cpu_load,delta_idle); + this_smartass->ramp_dir = -1; + work_cpumask_set(cpu); + queue_work(down_wq, &freq_scale_work); + queued_work = 1; + } + else this_smartass->ramp_dir = 0; + + // To avoid unnecessary load when the CPU is already at high load, we don't + // reset ourselves if we are at max speed. If and when there are idle cycles, + // the idle loop will activate the timer. + // Additionally, if we queued some work, the work task will reset the timer + // after it has done its adjustments. + if (!queued_work && old_freq < policy->max) + reset_timer(cpu,this_smartass); +} + +static void cpufreq_idle(void) +{ + struct smartass_info_s *this_smartass = &per_cpu(smartass_info, smp_processor_id()); + struct cpufreq_policy *policy = this_smartass->cur_policy; + + if (!this_smartass->enable) { + pm_idle_old(); + return; + } + + if (policy->cur == policy->min && timer_pending(&this_smartass->timer)) + del_timer(&this_smartass->timer); + + pm_idle_old(); + + if (!timer_pending(&this_smartass->timer)) + reset_timer(smp_processor_id(), this_smartass); +} + +/* We use the same work function to sale up and down */ +static void cpufreq_smartass_freq_change_time_work(struct work_struct *work) +{ + unsigned int cpu; + int new_freq; + int old_freq; + int ramp_dir; + struct smartass_info_s *this_smartass; + struct cpufreq_policy *policy; + unsigned int relation = CPUFREQ_RELATION_L; + for_each_possible_cpu(cpu) { + this_smartass = &per_cpu(smartass_info, cpu); + if (!work_cpumask_test_and_clear(cpu)) + continue; + + ramp_dir = this_smartass->ramp_dir; + this_smartass->ramp_dir = 0; + + old_freq = this_smartass->old_freq; + policy = this_smartass->cur_policy; + + if (old_freq != policy->cur) { + // frequency was changed by someone else? + printk(KERN_WARNING "Smartass: frequency changed by 3rd party: %d to %d\n", + old_freq,policy->cur); + new_freq = old_freq; + } + else if (ramp_dir > 0 && nr_running() > 1) { + // ramp up logic: + if (old_freq < this_smartass->ideal_speed) + new_freq = this_smartass->ideal_speed; + else if (ramp_up_step) { + new_freq = old_freq + ramp_up_step; + relation = CPUFREQ_RELATION_H; + } + else { + new_freq = policy->max; + relation = CPUFREQ_RELATION_H; + } + dprintk(SMARTASS_DEBUG_ALG,"smartassQ @ %d ramp up: ramp_dir=%d ideal=%d\n", + old_freq,ramp_dir,this_smartass->ideal_speed); + } + else if (ramp_dir < 0) { + // ramp down logic: + if (old_freq > this_smartass->ideal_speed) { + new_freq = this_smartass->ideal_speed; + relation = CPUFREQ_RELATION_H; + } + else if (ramp_down_step) + new_freq = old_freq - ramp_down_step; + else { + // Load heuristics: Adjust new_freq such that, assuming a linear + // scaling of load vs. frequency, the load in the new frequency + // will be max_cpu_load: + new_freq = old_freq * this_smartass->cur_cpu_load / max_cpu_load; + if (new_freq > old_freq) // min_cpu_load > max_cpu_load ?! + new_freq = old_freq -1; + } + dprintk(SMARTASS_DEBUG_ALG,"smartassQ @ %d ramp down: ramp_dir=%d ideal=%d\n", + old_freq,ramp_dir,this_smartass->ideal_speed); + } + else { // ramp_dir==0 ?! Could the timer change its mind about a queued ramp up/down + // before the work task gets to run? + // This may also happen if we refused to ramp up because the nr_running()==1 + new_freq = old_freq; + dprintk(SMARTASS_DEBUG_ALG,"smartassQ @ %d nothing: ramp_dir=%d nr_running=%lu\n", + old_freq,ramp_dir,nr_running()); + } + + // do actual ramp up (returns 0, if frequency change failed): + new_freq = target_freq(policy,this_smartass,new_freq,old_freq,relation); + if (new_freq) + this_smartass->freq_change_time_in_idle = + get_cpu_idle_time_us(cpu,&this_smartass->freq_change_time); + + // reset timer: + if (new_freq < policy->max) + reset_timer(cpu,this_smartass); + // if we are maxed out, it is pointless to use the timer + // (idle cycles wake up the timer when the timer comes) + else if (timer_pending(&this_smartass->timer)) + del_timer(&this_smartass->timer); + } +} + +static ssize_t show_debug_mask(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", debug_mask); +} + +static ssize_t store_debug_mask(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0) + debug_mask = input; + return res; +} + +static ssize_t show_up_rate_us(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", up_rate_us); +} + +static ssize_t store_up_rate_us(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input >= 0 && input <= 100000000) + up_rate_us = input; + return res; +} + +static ssize_t show_down_rate_us(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", down_rate_us); +} + +static ssize_t store_down_rate_us(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input >= 0 && input <= 100000000) + down_rate_us = input; + return res; +} + +static ssize_t show_sleep_ideal_freq(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", sleep_ideal_freq); +} + +static ssize_t store_sleep_ideal_freq(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input >= 0) { + sleep_ideal_freq = input; + if (suspended) + smartass_update_min_max_allcpus(); + } + return res; +} + +static ssize_t show_sleep_wakeup_freq(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", sleep_wakeup_freq); +} + +static ssize_t store_sleep_wakeup_freq(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input >= 0) + sleep_wakeup_freq = input; + return res; +} + +static ssize_t show_awake_ideal_freq(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", awake_ideal_freq); +} + +static ssize_t store_awake_ideal_freq(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input >= 0) { + awake_ideal_freq = input; + if (!suspended) + smartass_update_min_max_allcpus(); + } + return res; +} + +static ssize_t show_sample_rate_jiffies(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", sample_rate_jiffies); +} + +static ssize_t store_sample_rate_jiffies(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input > 0 && input <= 1000) + sample_rate_jiffies = input; + return res; +} + +static ssize_t show_ramp_up_step(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", ramp_up_step); +} + +static ssize_t store_ramp_up_step(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input >= 0) + ramp_up_step = input; + return res; +} + +static ssize_t show_ramp_down_step(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", ramp_down_step); +} + +static ssize_t store_ramp_down_step(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input >= 0) + ramp_down_step = input; + return res; +} + +static ssize_t show_max_cpu_load(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", max_cpu_load); +} + +static ssize_t store_max_cpu_load(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input > 0 && input <= 100) + max_cpu_load = input; + return res; +} + +static ssize_t show_min_cpu_load(struct kobject *kobj, struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", min_cpu_load); +} + +static ssize_t store_min_cpu_load(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ + ssize_t res; + unsigned long input; + res = strict_strtoul(buf, 0, &input); + if (res >= 0 && input > 0 && input < 100) + min_cpu_load = input; + return res; +} + +#define define_global_rw_attr(_name) \ +static struct global_attr _name##_attr = \ + __ATTR(_name, 0644, show_##_name, store_##_name) + +define_global_rw_attr(debug_mask); +define_global_rw_attr(up_rate_us); +define_global_rw_attr(down_rate_us); +define_global_rw_attr(sleep_ideal_freq); +define_global_rw_attr(sleep_wakeup_freq); +define_global_rw_attr(awake_ideal_freq); +define_global_rw_attr(sample_rate_jiffies); +define_global_rw_attr(ramp_up_step); +define_global_rw_attr(ramp_down_step); +define_global_rw_attr(max_cpu_load); +define_global_rw_attr(min_cpu_load); + +static struct attribute * smartass_attributes[] = { + &debug_mask_attr.attr, + &up_rate_us_attr.attr, + &down_rate_us_attr.attr, + &sleep_ideal_freq_attr.attr, + &sleep_wakeup_freq_attr.attr, + &awake_ideal_freq_attr.attr, + &sample_rate_jiffies_attr.attr, + &ramp_up_step_attr.attr, + &ramp_down_step_attr.attr, + &max_cpu_load_attr.attr, + &min_cpu_load_attr.attr, + NULL, +}; + +static struct attribute_group smartass_attr_group = { + .attrs = smartass_attributes, + .name = "smartassV2", +}; + +static int cpufreq_governor_smartass(struct cpufreq_policy *new_policy, + unsigned int event) +{ + unsigned int cpu = new_policy->cpu; + int rc; + struct smartass_info_s *this_smartass = &per_cpu(smartass_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!new_policy->cur)) + return -EINVAL; + + this_smartass->cur_policy = new_policy; + + this_smartass->enable = 1; + + smartass_update_min_max(this_smartass,new_policy,suspended); + + this_smartass->freq_table = cpufreq_frequency_get_table(cpu); + if (!this_smartass->freq_table) + printk(KERN_WARNING "Smartass: no frequency table for cpu %d?!\n",cpu); + + smp_wmb(); + + // Do not register the idle hook and create sysfs + // entries if we have already done so. + if (atomic_inc_return(&active_count) <= 1) { + rc = sysfs_create_group(cpufreq_global_kobject, + &smartass_attr_group); + if (rc) + return rc; + + pm_idle_old = pm_idle; + pm_idle = cpufreq_idle; + } + + if (this_smartass->cur_policy->cur < new_policy->max && !timer_pending(&this_smartass->timer)) + reset_timer(cpu,this_smartass); + + break; + + case CPUFREQ_GOV_LIMITS: + smartass_update_min_max(this_smartass,new_policy,suspended); + + if (this_smartass->cur_policy->cur > new_policy->max) { + dprintk(SMARTASS_DEBUG_JUMPS,"SmartassI: jumping to new max freq: %d\n",new_policy->max); + __cpufreq_driver_target(this_smartass->cur_policy, + new_policy->max, CPUFREQ_RELATION_H); + } + else if (this_smartass->cur_policy->cur < new_policy->min) { + dprintk(SMARTASS_DEBUG_JUMPS,"SmartassI: jumping to new min freq: %d\n",new_policy->min); + __cpufreq_driver_target(this_smartass->cur_policy, + new_policy->min, CPUFREQ_RELATION_L); + } + + if (this_smartass->cur_policy->cur < new_policy->max && !timer_pending(&this_smartass->timer)) + reset_timer(cpu,this_smartass); + + break; + + case CPUFREQ_GOV_STOP: + this_smartass->enable = 0; + smp_wmb(); + del_timer(&this_smartass->timer); + flush_work(&freq_scale_work); + this_smartass->idle_exit_time = 0; + + if (atomic_dec_return(&active_count) <= 1) { + sysfs_remove_group(cpufreq_global_kobject, + &smartass_attr_group); + pm_idle = pm_idle_old; + } + break; + } + + return 0; +} + +static void smartass_suspend(int cpu, int suspend) +{ + struct smartass_info_s *this_smartass = &per_cpu(smartass_info, smp_processor_id()); + struct cpufreq_policy *policy = this_smartass->cur_policy; + unsigned int new_freq; + + if (!this_smartass->enable) + return; + + smartass_update_min_max(this_smartass,policy,suspend); + if (!suspend) { // resume at max speed: + new_freq = validate_freq(policy,sleep_wakeup_freq); + + dprintk(SMARTASS_DEBUG_JUMPS,"SmartassS: awaking at %d\n",new_freq); + + __cpufreq_driver_target(policy, new_freq, + CPUFREQ_RELATION_L); + } else { + // to avoid wakeup issues with quick sleep/wakeup don't change actual frequency when entering sleep + // to allow some time to settle down. Instead we just reset our statistics (and reset the timer). + // Eventually, the timer will adjust the frequency if necessary. + + this_smartass->freq_change_time_in_idle = + get_cpu_idle_time_us(cpu,&this_smartass->freq_change_time); + + dprintk(SMARTASS_DEBUG_JUMPS,"SmartassS: suspending at %d\n",policy->cur); + } + + reset_timer(smp_processor_id(),this_smartass); +} + +static void smartass_early_suspend(struct early_suspend *handler) { + int i; + if (suspended || sleep_ideal_freq==0) // disable behavior for sleep_ideal_freq==0 + return; + suspended = 1; + for_each_online_cpu(i) + smartass_suspend(i,1); +} + +static void smartass_late_resume(struct early_suspend *handler) { + int i; + if (!suspended) // already not suspended so nothing to do + return; + suspended = 0; + for_each_online_cpu(i) + smartass_suspend(i,0); +} + +static struct early_suspend smartass_power_suspend = { + .suspend = smartass_early_suspend, + .resume = smartass_late_resume, +#ifdef CONFIG_MACH_HERO + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, +#endif +}; + +static int __init cpufreq_smartass_init(void) +{ + unsigned int i; + struct smartass_info_s *this_smartass; + debug_mask = 0; + up_rate_us = DEFAULT_UP_RATE_US; + down_rate_us = DEFAULT_DOWN_RATE_US; + sleep_ideal_freq = DEFAULT_SLEEP_IDEAL_FREQ; + sleep_wakeup_freq = DEFAULT_SLEEP_WAKEUP_FREQ; + awake_ideal_freq = DEFAULT_AWAKE_IDEAL_FREQ; + sample_rate_jiffies = DEFAULT_SAMPLE_RATE_JIFFIES; + ramp_up_step = DEFAULT_RAMP_UP_STEP; + ramp_down_step = DEFAULT_RAMP_DOWN_STEP; + max_cpu_load = DEFAULT_MAX_CPU_LOAD; + min_cpu_load = DEFAULT_MIN_CPU_LOAD; + + spin_lock_init(&cpumask_lock); + + suspended = 0; + + /* Initalize per-cpu data: */ + for_each_possible_cpu(i) { + this_smartass = &per_cpu(smartass_info, i); + this_smartass->enable = 0; + this_smartass->cur_policy = 0; + this_smartass->ramp_dir = 0; + this_smartass->time_in_idle = 0; + this_smartass->idle_exit_time = 0; + this_smartass->freq_change_time = 0; + this_smartass->freq_change_time_in_idle = 0; + this_smartass->cur_cpu_load = 0; + // intialize timer: + init_timer_deferrable(&this_smartass->timer); + this_smartass->timer.function = cpufreq_smartass_timer; + this_smartass->timer.data = i; + work_cpumask_test_and_clear(i); + } + + // Scale up is high priority + up_wq = alloc_workqueue("ksmartass_up", WQ_HIGHPRI, 1); + down_wq = alloc_workqueue("ksmartass_down", 0, 1); + if (!up_wq || !down_wq) + return -ENOMEM; + + INIT_WORK(&freq_scale_work, cpufreq_smartass_freq_change_time_work); + + register_early_suspend(&smartass_power_suspend); + + return cpufreq_register_governor(&cpufreq_gov_smartass2); +} + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2 +fs_initcall(cpufreq_smartass_init); +#else +module_init(cpufreq_smartass_init); +#endif + +static void __exit cpufreq_smartass_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_smartass2); + destroy_workqueue(up_wq); + destroy_workqueue(down_wq); +} + +module_exit(cpufreq_smartass_exit); + +MODULE_AUTHOR ("Erasmux"); +MODULE_DESCRIPTION ("'cpufreq_smartass2' - A smart cpufreq governor"); +MODULE_LICENSE ("GPL"); diff --git a/drivers/cpufreq/cpufreq_smartassH3.c b/drivers/cpufreq/cpufreq_smartassH3.c new file mode 100644 index 00000000..3f02d597 --- /dev/null +++ b/drivers/cpufreq/cpufreq_smartassH3.c @@ -0,0 +1,981 @@ +/* +* drivers/cpufreq/cpufreq_smartassH3.c +* +* Copyright (C) 2010 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. +* +* Author: Erasmux +* +* Based on the interactive governor By Mike Chan (mike@android.com) +* which was adaptated to 2.6.29 kernel by Nadlabak (pavel@doshaska.net) +* +* SMP support based on mod by faux123 +* +* ZTE Skate specific tweaks by H3ROS @ MoDaCo, integrated by C3C0 @ MoDaCo +* +* For a general overview of smartassV2 see the relavent part in +* Documentation/cpu-freq/governors.txt +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define cputime64_sub(__a, __b) ((__a) - (__b)) + +/******************** Tunable parameters: ********************/ + +/* +* The "ideal" frequency to use when awake. The governor will ramp up faster +* towards the ideal frequency and slower after it has passed it. Similarly, +* lowering the frequency towards the ideal frequency is faster than below it. +*/ +#define DEFAULT_AWAKE_IDEAL_FREQ 700000 +static unsigned int awake_ideal_freq; + +/* +* The "ideal" frequency to use when suspended. +* When set to 0, the governor will not track the suspended state (meaning +* that practically when sleep_ideal_freq==0 the awake_ideal_freq is used +* also when suspended). +*/ +#define DEFAULT_SLEEP_IDEAL_FREQ 122880 +static unsigned int sleep_ideal_freq; + +/* +* Freqeuncy delta when ramping up above the ideal freqeuncy. +* Zero disables and causes to always jump straight to max frequency. +* When below the ideal freqeuncy we always ramp up to the ideal freq. +*/ +#define DEFAULT_RAMP_UP_STEP 128000 +static unsigned int ramp_up_step; + +/* +* Freqeuncy delta when ramping down below the ideal freqeuncy. +* Zero disables and will calculate ramp down according to load heuristic. +* When above the ideal freqeuncy we always ramp down to the ideal freq. +*/ +#define DEFAULT_RAMP_DOWN_STEP 128000 +static unsigned int ramp_down_step; + +/* +* CPU freq will be increased if measured load > max_cpu_load; +*/ +#define DEFAULT_MAX_CPU_LOAD 50 +static unsigned long max_cpu_load; + +/* +* CPU freq will be decreased if measured load < min_cpu_load; +*/ +#define DEFAULT_MIN_CPU_LOAD 25 +static unsigned long min_cpu_load; + +/* +* The minimum amount of time to spend at a frequency before we can ramp up. +* Notice we ignore this when we are below the ideal frequency. +*/ +#define DEFAULT_UP_RATE_US 48000; +static unsigned long up_rate_us; + +/* +* The minimum amount of time to spend at a frequency before we can ramp down. +* Notice we ignore this when we are above the ideal frequency. +*/ +#define DEFAULT_DOWN_RATE_US 48000; +static unsigned long down_rate_us; + +/* +* The frequency to set when waking up from sleep. +* When sleep_ideal_freq=0 this will have no effect. +*/ +#define DEFAULT_SLEEP_WAKEUP_FREQ 700000 +static unsigned int sleep_wakeup_freq; + +/* +* Sampling rate, I highly recommend to leave it at 2. +*/ +#define DEFAULT_SAMPLE_RATE_JIFFIES 2 +static unsigned int sample_rate_jiffies; + +/* +* Boost enabled +*/ +#define DEFAULT_BOOST_ENABLED 0 +static unsigned int boost_enabled; + +/* +* Boost pulse +*/ +#define DEFAULT_BOOST_PULSE 500000 +#define MAX_BOOST_PULSE 5000000 +static unsigned long boost_pulse; +static u64 boost_pulse_time; + + +/*************** End of tunables ***************/ + + +static void (*pm_idle_old)(void); +static atomic_t active_count = ATOMIC_INIT(0); + +struct smartass_info_s { +struct cpufreq_policy *cur_policy; +struct cpufreq_frequency_table *freq_table; +struct timer_list timer; +u64 time_in_idle; +u64 idle_exit_time; +u64 freq_change_time; +u64 freq_change_time_in_idle; +int cur_cpu_load; +int old_freq; +int ramp_dir; +unsigned int enable; +int ideal_speed; +}; +static DEFINE_PER_CPU(struct smartass_info_s, smartass_info); + +/* Workqueues handle frequency scaling */ +static struct workqueue_struct *up_wq; +static struct workqueue_struct *down_wq; +static struct work_struct freq_scale_work; + +static cpumask_t work_cpumask; +static spinlock_t cpumask_lock; + +static unsigned int suspended; + +#define dprintk(flag,msg...) do { \ +if (debug_mask & flag) printk(KERN_DEBUG msg); \ +} while (0) + +enum { +SMARTASS_DEBUG_JUMPS=1, +SMARTASS_DEBUG_LOAD=2, +SMARTASS_DEBUG_ALG=4 +}; + +/* +* Combination of the above debug flags. +*/ +static unsigned long debug_mask; + +static int cpufreq_governor_smartass_h3(struct cpufreq_policy *policy, +unsigned int event); + +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASSH3 +static +#endif +struct cpufreq_governor cpufreq_gov_smartass_h3 = { +.name = "SmartassH3", +.governor = cpufreq_governor_smartass_h3, +.max_transition_latency = 9000000, +.owner = THIS_MODULE, +}; + +inline static void smartass_update_min_max(struct smartass_info_s *this_smartass, struct cpufreq_policy *policy, int suspend) { +if (suspend) { +this_smartass->ideal_speed = // sleep_ideal_freq; but make sure it obeys the policy min/max +policy->max > sleep_ideal_freq ? +(sleep_ideal_freq > policy->min ? sleep_ideal_freq : policy->min) : policy->max; +} else { +this_smartass->ideal_speed = // awake_ideal_freq; but make sure it obeys the policy min/max +policy->min < awake_ideal_freq ? +(awake_ideal_freq < policy->max ? awake_ideal_freq : policy->max) : policy->min; +} +} + +inline static void smartass_update_min_max_allcpus(void) { +unsigned int i; +for_each_online_cpu(i) { +struct smartass_info_s *this_smartass = &per_cpu(smartass_info, i); +if (this_smartass->enable) +smartass_update_min_max(this_smartass,this_smartass->cur_policy,suspended); +} +} + +inline static unsigned int validate_freq(struct cpufreq_policy *policy, int freq) { +if (freq > (int)policy->max) +return policy->max; +if (freq < (int)policy->min) +return policy->min; +return freq; +} + +inline static void reset_timer(unsigned long cpu, struct smartass_info_s *this_smartass) { +this_smartass->time_in_idle = get_cpu_idle_time_us(cpu, &this_smartass->idle_exit_time); +mod_timer(&this_smartass->timer, jiffies + sample_rate_jiffies); +} + +inline static void work_cpumask_set(unsigned long cpu) { +unsigned long flags; +spin_lock_irqsave(&cpumask_lock, flags); +cpumask_set_cpu(cpu, &work_cpumask); +spin_unlock_irqrestore(&cpumask_lock, flags); +} + +inline static int work_cpumask_test_and_clear(unsigned long cpu) { +unsigned long flags; +int res = 0; +spin_lock_irqsave(&cpumask_lock, flags); +res = cpumask_test_and_clear_cpu(cpu, &work_cpumask); +spin_unlock_irqrestore(&cpumask_lock, flags); +return res; +} + +inline static int target_freq(struct cpufreq_policy *policy, struct smartass_info_s *this_smartass, +int new_freq, int old_freq, int prefered_relation) { +int index, target; +struct cpufreq_frequency_table *table = this_smartass->freq_table; + +if (new_freq == old_freq) +return 0; +new_freq = validate_freq(policy,new_freq); +if (new_freq == old_freq) +return 0; + +if (table && +!cpufreq_frequency_table_target(policy,table,new_freq,prefered_relation,&index)) +{ +target = table[index].frequency; +if (target == old_freq) { +// if for example we are ramping up to *at most* current + ramp_up_step +// but there is no such frequency higher than the current, try also +// to ramp up to *at least* current + ramp_up_step. +if (new_freq > old_freq && prefered_relation==CPUFREQ_RELATION_H +&& !cpufreq_frequency_table_target(policy,table,new_freq, +CPUFREQ_RELATION_L,&index)) +target = table[index].frequency; +// simlarly for ramping down: +else if (new_freq < old_freq && prefered_relation==CPUFREQ_RELATION_L +&& !cpufreq_frequency_table_target(policy,table,new_freq, +CPUFREQ_RELATION_H,&index)) +target = table[index].frequency; +} + +if (target == old_freq) { +// We should not get here: +// If we got here we tried to change to a validated new_freq which is different +// from old_freq, so there is no reason for us to remain at same frequency. +printk(KERN_WARNING "Smartass: frequency change failed: %d to %d => %d\n", +old_freq,new_freq,target); +return 0; +} +} +else target = new_freq; + +__cpufreq_driver_target(policy, target, prefered_relation); + +dprintk(SMARTASS_DEBUG_JUMPS,"SmartassQ: jumping from %d to %d => %d (%d)\n", +old_freq,new_freq,target,policy->cur); + +return target; +} + +static void cpufreq_smartass_timer(unsigned long cpu) +{ +u64 delta_idle; +u64 delta_time; +int cpu_load; +int old_freq; +u64 update_time; +u64 now_idle; +int queued_work = 0; +struct smartass_info_s *this_smartass = &per_cpu(smartass_info, cpu); +struct cpufreq_policy *policy = this_smartass->cur_policy; + +now_idle = get_cpu_idle_time_us(cpu, &update_time); +old_freq = policy->cur; + +if (this_smartass->idle_exit_time == 0 || update_time == this_smartass->idle_exit_time) +return; + +delta_idle = cputime64_sub(now_idle, this_smartass->time_in_idle); +delta_time = cputime64_sub(update_time, this_smartass->idle_exit_time); + +// If timer ran less than 1ms after short-term sample started, retry. +if (delta_time < 1000) { +if (!timer_pending(&this_smartass->timer)) +reset_timer(cpu,this_smartass); +return; +} + +if (delta_idle > delta_time) +cpu_load = 0; +else +cpu_load = 100 * (unsigned int)(delta_time - delta_idle) / (unsigned int)delta_time; + +dprintk(SMARTASS_DEBUG_LOAD,"smartassT @ %d: load %d (delta_time %llu)\n", +old_freq,cpu_load,delta_time); + +this_smartass->cur_cpu_load = cpu_load; +this_smartass->old_freq = old_freq; + +// Scale up if load is above max or if there where no idle cycles since coming out of idle, +// additionally, if we are at or above the ideal_speed, verify we have been at this frequency +// for at least up_rate_us: +if (cpu_load > max_cpu_load || delta_idle == 0) +{ +if (old_freq < policy->max && +(old_freq < this_smartass->ideal_speed || delta_idle == 0 || +cputime64_sub(update_time, this_smartass->freq_change_time) >= up_rate_us)) +{ +dprintk(SMARTASS_DEBUG_ALG,"smartassT @ %d ramp up: load %d (delta_idle %llu)\n", +old_freq,cpu_load,delta_idle); +this_smartass->ramp_dir = 1; +work_cpumask_set(cpu); +queue_work(up_wq, &freq_scale_work); +queued_work = 1; +} +else this_smartass->ramp_dir = 0; +} +// Similarly for scale down: load should be below min and if we are at or below ideal +// frequency we require that we have been at this frequency for at least down_rate_us: +else if (cpu_load < min_cpu_load && old_freq > policy->min && +(old_freq > this_smartass->ideal_speed || +cputime64_sub(update_time, this_smartass->freq_change_time) >= down_rate_us)) +{ +dprintk(SMARTASS_DEBUG_ALG,"smartassT @ %d ramp down: load %d (delta_idle %llu)\n", +old_freq,cpu_load,delta_idle); +this_smartass->ramp_dir = -1; +work_cpumask_set(cpu); +queue_work(down_wq, &freq_scale_work); +queued_work = 1; +} +else this_smartass->ramp_dir = 0; + +// To avoid unnecessary load when the CPU is already at high load, we don't +// reset ourselves if we are at max speed. If and when there are idle cycles, +// the idle loop will activate the timer. +// Additionally, if we queued some work, the work task will reset the timer +// after it has done its adjustments. +if (!queued_work && old_freq < policy->max) +reset_timer(cpu,this_smartass); +} + +static void cpufreq_idle(void) +{ +struct smartass_info_s *this_smartass = &per_cpu(smartass_info, smp_processor_id()); +struct cpufreq_policy *policy = this_smartass->cur_policy; + +if (!this_smartass->enable) { +pm_idle_old(); +return; +} + +if (policy->cur == policy->min && timer_pending(&this_smartass->timer)) +del_timer(&this_smartass->timer); + +pm_idle_old(); + +if (!timer_pending(&this_smartass->timer)) +reset_timer(smp_processor_id(), this_smartass); +} + +/* We use the same work function to sale up and down */ +static void cpufreq_smartass_freq_change_time_work(struct work_struct *work) +{ +unsigned int cpu; +int new_freq; +int old_freq; +int ramp_dir; +struct smartass_info_s *this_smartass; +struct cpufreq_policy *policy; +unsigned int relation = CPUFREQ_RELATION_L; +unsigned int boosted; + +for_each_possible_cpu(cpu) { +this_smartass = &per_cpu(smartass_info, cpu); +if (!work_cpumask_test_and_clear(cpu)) +continue; + +ramp_dir = this_smartass->ramp_dir; +this_smartass->ramp_dir = 0; + +old_freq = this_smartass->old_freq; +policy = this_smartass->cur_policy; + +// boost pulse +boosted = 0; +if (boost_pulse > 0) { +u64 now = ktime_to_us(ktime_get()); +if (now <= boost_pulse_time + boost_pulse) { +// boost logic: +if (boost_enabled > 0 && +old_freq < this_smartass->ideal_speed) { +// Jump to ideal frequency +new_freq = this_smartass->ideal_speed; +relation = CPUFREQ_RELATION_H; +// Skip normal logic +boosted = 1; +dprintk(SMARTASS_DEBUG_ALG,"smartassQ @ %d boost %d\n", +old_freq,new_freq); +} +} +else { +// Reset boost pulse +boost_pulse = 0; +} +} + +if (boosted == 0) { +if (old_freq != policy->cur) { +// frequency was changed by someone else? +printk(KERN_WARNING "Smartass: frequency changed by 3rd party: %d to %d\n", +old_freq,policy->cur); +new_freq = old_freq; +} +else if (ramp_dir > 0 && nr_running() > 1) { +// ramp up logic: +if (old_freq < this_smartass->ideal_speed) +new_freq = this_smartass->ideal_speed; +else if (ramp_up_step) { +new_freq = old_freq + ramp_up_step; +relation = CPUFREQ_RELATION_H; +} +else { +new_freq = policy->max; +relation = CPUFREQ_RELATION_H; +} +dprintk(SMARTASS_DEBUG_ALG,"smartassQ @ %d ramp up: ramp_dir=%d ideal=%d\n", +old_freq,ramp_dir,this_smartass->ideal_speed); +} +else if (ramp_dir < 0) { +// ramp down logic: +if (old_freq > this_smartass->ideal_speed) { +new_freq = this_smartass->ideal_speed; +relation = CPUFREQ_RELATION_H; +} +else if (ramp_down_step) +new_freq = old_freq - ramp_down_step; +else { +// Load heuristics: Adjust new_freq such that, assuming a linear +// scaling of load vs. frequency, the load in the new frequency +// will be max_cpu_load: +new_freq = old_freq * this_smartass->cur_cpu_load / max_cpu_load; +if (new_freq > old_freq) // min_cpu_load > max_cpu_load ?! +new_freq = old_freq -1; +} +dprintk(SMARTASS_DEBUG_ALG,"smartassQ @ %d ramp down: ramp_dir=%d ideal=%d\n", +old_freq,ramp_dir,this_smartass->ideal_speed); +} +else { // ramp_dir==0 ?! Could the timer change its mind about a queued ramp up/down +// before the work task gets to run? +// This may also happen if we refused to ramp up because the nr_running()==1 +new_freq = old_freq; +dprintk(SMARTASS_DEBUG_ALG,"smartassQ @ %d nothing: ramp_dir=%d nr_running=%lu\n", +old_freq,ramp_dir,nr_running()); +} +} + +// do actual ramp up (returns 0, if frequency change failed): +new_freq = target_freq(policy,this_smartass,new_freq,old_freq,relation); +if (new_freq) +this_smartass->freq_change_time_in_idle = +get_cpu_idle_time_us(cpu,&this_smartass->freq_change_time); + +// reset timer: +if (new_freq < policy->max) +reset_timer(cpu,this_smartass); +// if we are maxed out, it is pointless to use the timer +// (idle cycles wake up the timer when the timer comes) +else if (timer_pending(&this_smartass->timer)) +del_timer(&this_smartass->timer); +} +} + +static ssize_t show_debug_mask(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%lu\n", debug_mask); +} + +static ssize_t store_debug_mask(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +debug_mask = input; +return count; +} + +static ssize_t show_up_rate_us(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%lu\n", up_rate_us); +} + +static ssize_t store_up_rate_us(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input >= 0 && input <= 100000000) +up_rate_us = input; +return count; +} + +static ssize_t show_down_rate_us(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%lu\n", down_rate_us); +} + +static ssize_t store_down_rate_us(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input >= 0 && input <= 100000000) +down_rate_us = input; +return count; +} + +static ssize_t show_sleep_ideal_freq(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%u\n", sleep_ideal_freq); +} + +static ssize_t store_sleep_ideal_freq(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input >= 0) { +sleep_ideal_freq = input; +if (suspended) +smartass_update_min_max_allcpus(); +} +return count; +} + +static ssize_t show_sleep_wakeup_freq(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%u\n", sleep_wakeup_freq); +} + +static ssize_t store_sleep_wakeup_freq(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input >= 0) +sleep_wakeup_freq = input; +return count; +} + +static ssize_t show_awake_ideal_freq(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%u\n", awake_ideal_freq); +} + +static ssize_t store_awake_ideal_freq(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input >= 0) { +awake_ideal_freq = input; +if (!suspended) +smartass_update_min_max_allcpus(); +} +return count; +} + +static ssize_t show_sample_rate_jiffies(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%u\n", sample_rate_jiffies); +} + +static ssize_t store_sample_rate_jiffies(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input > 0 && input <= 1000) +sample_rate_jiffies = input; +return count; +} + +static ssize_t show_ramp_up_step(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%u\n", ramp_up_step); +} + +static ssize_t store_ramp_up_step(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input >= 0) +ramp_up_step = input; +return count; +} + +static ssize_t show_ramp_down_step(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%u\n", ramp_down_step); +} + +static ssize_t store_ramp_down_step(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input >= 0) +ramp_down_step = input; +return count; +} + +static ssize_t show_max_cpu_load(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%lu\n", max_cpu_load); +} + +static ssize_t store_max_cpu_load(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input > 0 && input <= 100) +max_cpu_load = input; +return count; +} + +static ssize_t show_min_cpu_load(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%lu\n", min_cpu_load); +} + +static ssize_t store_min_cpu_load(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +if (input > 0 && input < 100) +min_cpu_load = input; +return count; +} + +static ssize_t show_boost_enabled(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%u\n", boost_enabled); +} + +static ssize_t store_boost_enabled(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +boost_enabled = (input == 0 ? 0 : 1); +return count; +} + +static ssize_t show_boost_pulse(struct kobject *kobj, struct attribute *attr, char *buf) +{ +return sprintf(buf, "%lu\n", boost_pulse); +} + +static ssize_t store_boost_pulse(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) +{ +ssize_t res; +unsigned long input; +res = strict_strtoul(buf, 0, &input); +if (res < 0) +return -EINVAL; +boost_pulse_time = ktime_to_us(ktime_get()); +if (input > MAX_BOOST_PULSE) +boost_pulse = MAX_BOOST_PULSE; +else if (input <= 1) +boost_pulse = DEFAULT_BOOST_PULSE; +else +boost_pulse = input; +dprintk(SMARTASS_DEBUG_ALG,"Smartass: boost pulse %lu/%lu enabled %d\n", +input,boost_pulse,boost_enabled); +return count; +} + +#define define_global_rw_attr(_name) \ +static struct global_attr _name##_attr = \ +__ATTR(_name, 0644, show_##_name, store_##_name) + +define_global_rw_attr(debug_mask); +define_global_rw_attr(up_rate_us); +define_global_rw_attr(down_rate_us); +define_global_rw_attr(sleep_ideal_freq); +define_global_rw_attr(sleep_wakeup_freq); +define_global_rw_attr(awake_ideal_freq); +define_global_rw_attr(sample_rate_jiffies); +define_global_rw_attr(ramp_up_step); +define_global_rw_attr(ramp_down_step); +define_global_rw_attr(max_cpu_load); +define_global_rw_attr(min_cpu_load); +define_global_rw_attr(boost_enabled); +define_global_rw_attr(boost_pulse); + +static struct attribute * smartass_attributes[] = { +&debug_mask_attr.attr, +&up_rate_us_attr.attr, +&down_rate_us_attr.attr, +&sleep_ideal_freq_attr.attr, +&sleep_wakeup_freq_attr.attr, +&awake_ideal_freq_attr.attr, +&sample_rate_jiffies_attr.attr, +&ramp_up_step_attr.attr, +&ramp_down_step_attr.attr, +&max_cpu_load_attr.attr, +&min_cpu_load_attr.attr, +&boost_enabled_attr.attr, +&boost_pulse_attr.attr, +NULL, +}; + +static struct attribute_group smartass_attr_group = { +.attrs = smartass_attributes, +.name = "smartassH3", +}; + +static int cpufreq_governor_smartass_h3(struct cpufreq_policy *new_policy, +unsigned int event) +{ +unsigned int cpu = new_policy->cpu; +int rc; +struct smartass_info_s *this_smartass = &per_cpu(smartass_info, cpu); + +switch (event) { +case CPUFREQ_GOV_START: +if ((!cpu_online(cpu)) || (!new_policy->cur)) +return -EINVAL; + +this_smartass->cur_policy = new_policy; + +this_smartass->enable = 1; + +smartass_update_min_max(this_smartass,new_policy,suspended); + +this_smartass->freq_table = cpufreq_frequency_get_table(cpu); +if (!this_smartass->freq_table) +printk(KERN_WARNING "Smartass: no frequency table for cpu %d?!\n",cpu); + +smp_wmb(); + +// Do not register the idle hook and create sysfs +// entries if we have already done so. +if (atomic_inc_return(&active_count) <= 1) { +rc = sysfs_create_group(cpufreq_global_kobject, +&smartass_attr_group); +if (rc) +return rc; + +pm_idle_old = pm_idle; +pm_idle = cpufreq_idle; +} + +if (this_smartass->cur_policy->cur < new_policy->max && !timer_pending(&this_smartass->timer)) +reset_timer(cpu,this_smartass); + +break; + +case CPUFREQ_GOV_LIMITS: +smartass_update_min_max(this_smartass,new_policy,suspended); + +if (this_smartass->cur_policy->cur > new_policy->max) { +dprintk(SMARTASS_DEBUG_JUMPS,"SmartassI: jumping to new max freq: %d\n",new_policy->max); +__cpufreq_driver_target(this_smartass->cur_policy, +new_policy->max, CPUFREQ_RELATION_H); +} +else if (this_smartass->cur_policy->cur < new_policy->min) { +dprintk(SMARTASS_DEBUG_JUMPS,"SmartassI: jumping to new min freq: %d\n",new_policy->min); +__cpufreq_driver_target(this_smartass->cur_policy, +new_policy->min, CPUFREQ_RELATION_L); +} + +if (this_smartass->cur_policy->cur < new_policy->max && !timer_pending(&this_smartass->timer)) +reset_timer(cpu,this_smartass); + +break; + +case CPUFREQ_GOV_STOP: +this_smartass->enable = 0; +smp_wmb(); +del_timer(&this_smartass->timer); +flush_work(&freq_scale_work); +this_smartass->idle_exit_time = 0; + +if (atomic_dec_return(&active_count) <= 1) { +sysfs_remove_group(cpufreq_global_kobject, +&smartass_attr_group); +pm_idle = pm_idle_old; +} +break; +} + +return 0; +} + +static void smartass_suspend(int cpu, int suspend) +{ +struct smartass_info_s *this_smartass = &per_cpu(smartass_info, smp_processor_id()); +struct cpufreq_policy *policy = this_smartass->cur_policy; +unsigned int new_freq; + +if (!this_smartass->enable) +return; + +smartass_update_min_max(this_smartass,policy,suspend); +if (!suspend) { // resume at max speed: +new_freq = validate_freq(policy,sleep_wakeup_freq); + +dprintk(SMARTASS_DEBUG_JUMPS,"SmartassS: awaking at %d\n",new_freq); + +__cpufreq_driver_target(policy, new_freq, +CPUFREQ_RELATION_L); +} else { +// to avoid wakeup issues with quick sleep/wakeup don't change actual frequency when entering sleep +// to allow some time to settle down. Instead we just reset our statistics (and reset the timer). +// Eventually, the timer will adjust the frequency if necessary. + +this_smartass->freq_change_time_in_idle = +get_cpu_idle_time_us(cpu,&this_smartass->freq_change_time); + +dprintk(SMARTASS_DEBUG_JUMPS,"SmartassS: suspending at %d\n",policy->cur); +} + +reset_timer(smp_processor_id(),this_smartass); +} + +static void smartass_early_suspend(struct early_suspend *handler) { +int i; +if (suspended || sleep_ideal_freq==0) // disable behavior for sleep_ideal_freq==0 +return; +suspended = 1; +for_each_online_cpu(i) +smartass_suspend(i,1); +} + +static void smartass_late_resume(struct early_suspend *handler) { +int i; +if (!suspended) // already not suspended so nothing to do +return; +suspended = 0; +for_each_online_cpu(i) +smartass_suspend(i,0); +} + +static struct early_suspend smartass_power_suspend = { +.suspend = smartass_early_suspend, +.resume = smartass_late_resume, +#ifdef CONFIG_MACH_HERO +.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, +#endif +}; + +static int __init cpufreq_smartass_init(void) +{ +unsigned int i; +struct smartass_info_s *this_smartass; +debug_mask = 0; +up_rate_us = DEFAULT_UP_RATE_US; +down_rate_us = DEFAULT_DOWN_RATE_US; +sleep_ideal_freq = DEFAULT_SLEEP_IDEAL_FREQ; +sleep_wakeup_freq = DEFAULT_SLEEP_WAKEUP_FREQ; +awake_ideal_freq = DEFAULT_AWAKE_IDEAL_FREQ; +sample_rate_jiffies = DEFAULT_SAMPLE_RATE_JIFFIES; +ramp_up_step = DEFAULT_RAMP_UP_STEP; +ramp_down_step = DEFAULT_RAMP_DOWN_STEP; +max_cpu_load = DEFAULT_MAX_CPU_LOAD; +min_cpu_load = DEFAULT_MIN_CPU_LOAD; +boost_enabled = DEFAULT_BOOST_ENABLED; +boost_pulse = 0; + +spin_lock_init(&cpumask_lock); + +suspended = 0; + +/* Initalize per-cpu data: */ +for_each_possible_cpu(i) { +this_smartass = &per_cpu(smartass_info, i); +this_smartass->enable = 0; +this_smartass->cur_policy = 0; +this_smartass->ramp_dir = 0; +this_smartass->time_in_idle = 0; +this_smartass->idle_exit_time = 0; +this_smartass->freq_change_time = 0; +this_smartass->freq_change_time_in_idle = 0; +this_smartass->cur_cpu_load = 0; +// intialize timer: +init_timer_deferrable(&this_smartass->timer); +this_smartass->timer.function = cpufreq_smartass_timer; +this_smartass->timer.data = i; +work_cpumask_test_and_clear(i); +} + +// Scale up is high priority +up_wq = alloc_workqueue("ksmartass_up", WQ_HIGHPRI, 1); +down_wq = alloc_workqueue("ksmartass_down", 0, 1); +if (!up_wq || !down_wq) +return -ENOMEM; + +INIT_WORK(&freq_scale_work, cpufreq_smartass_freq_change_time_work); + +register_early_suspend(&smartass_power_suspend); + +return cpufreq_register_governor(&cpufreq_gov_smartass_h3); +} + +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASSH3 +fs_initcall(cpufreq_smartass_init); +#else +module_init(cpufreq_smartass_init); +#endif + +static void __exit cpufreq_smartass_exit(void) +{ +cpufreq_unregister_governor(&cpufreq_gov_smartass_h3); +destroy_workqueue(up_wq); +destroy_workqueue(down_wq); +} + +module_exit(cpufreq_smartass_exit); + +MODULE_AUTHOR ("Erasmux, moded by H3ROS & C3C0"); +MODULE_DESCRIPTION ("'cpufreq_smartassH3' - A smart cpufreq governor"); +MODULE_LICENSE ("GPL"); + diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c index ec4f7474..59caec29 100644 --- a/drivers/crypto/msm/qce.c +++ b/drivers/crypto/msm/qce.c @@ -479,19 +479,6 @@ static int count_sg(struct scatterlist *sg, int nbytes) return i; } -static int dma_map_pmem_sg(struct buf_info *pmem, unsigned entries, - struct scatterlist *sg) -{ - int i = 0; - for (i = 0; i < entries; i++) { - - sg->dma_address = (dma_addr_t)pmem->offset; - sg++; - pmem++; - } - return 0; -} - static int _probe_ce_engine(struct qce_device *pce_dev) { unsigned int val; @@ -1058,52 +1045,6 @@ static int _ablk_cipher_complete(struct qce_device *pce_dev) return 0; }; -static int _ablk_cipher_use_pmem_complete(struct qce_device *pce_dev) -{ - struct ablkcipher_request *areq; - uint32_t iv_out[4]; - unsigned char iv[4 * sizeof(uint32_t)]; - uint32_t status; - - areq = (struct ablkcipher_request *) pce_dev->areq; - - /* check ce error status */ - status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG); - if (status & (1 << CRYPTO_SW_ERR)) { - pce_dev->err++; - dev_err(pce_dev->pdev, - "Qualcomm Crypto Error at 0x%x, status%x\n", - pce_dev->phy_iobase, status); - _init_ce_engine(pce_dev); - clk_disable(pce_dev->ce_clk); - pce_dev->qce_cb(areq, NULL, NULL, -ENXIO); - return 0; - }; - - /* get iv out */ - if (pce_dev->mode == QCE_MODE_ECB) { - clk_disable(pce_dev->ce_clk); - pce_dev->qce_cb(areq, NULL, NULL, pce_dev->chan_ce_in_status | - pce_dev->chan_ce_out_status); - } else { - iv_out[0] = readl_relaxed(pce_dev->iobase + - CRYPTO_CNTR0_IV0_REG); - iv_out[1] = readl_relaxed(pce_dev->iobase + - CRYPTO_CNTR1_IV1_REG); - iv_out[2] = readl_relaxed(pce_dev->iobase + - CRYPTO_CNTR2_IV2_REG); - iv_out[3] = readl_relaxed(pce_dev->iobase + - CRYPTO_CNTR3_IV3_REG); - - _net_words_to_byte_stream(iv_out, iv, sizeof(iv)); - clk_disable(pce_dev->ce_clk); - pce_dev->qce_cb(areq, NULL, iv, pce_dev->chan_ce_in_status | - pce_dev->chan_ce_out_status); - } - - return 0; -}; - static int qce_split_and_insert_dm_desc(struct dmov_desc *pdesc, unsigned int plen, unsigned int paddr, int *index) { @@ -1528,54 +1469,6 @@ static void _ablk_cipher_ce_out_call_back(struct msm_dmov_cmd *cmd_ptr, } }; - -static void _ablk_cipher_ce_in_call_back_pmem(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, struct msm_dmov_errdata *err) -{ - struct qce_device *pce_dev; - - pce_dev = (struct qce_device *) cmd_ptr->user; - if (result != ADM_STATUS_OK) { - dev_err(pce_dev->pdev, "Qualcomm ADM status error %x\n", - result); - pce_dev->chan_ce_in_status = -1; - } else - pce_dev->chan_ce_in_status = 0; - - pce_dev->chan_ce_in_state = QCE_CHAN_STATE_COMP; - if (pce_dev->chan_ce_out_state == QCE_CHAN_STATE_COMP) { - pce_dev->chan_ce_in_state = QCE_CHAN_STATE_IDLE; - pce_dev->chan_ce_out_state = QCE_CHAN_STATE_IDLE; - - /* done */ - _ablk_cipher_use_pmem_complete(pce_dev); - } -}; - -static void _ablk_cipher_ce_out_call_back_pmem(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, struct msm_dmov_errdata *err) -{ - struct qce_device *pce_dev; - - pce_dev = (struct qce_device *) cmd_ptr->user; - if (result != ADM_STATUS_OK) { - dev_err(pce_dev->pdev, "Qualcomm ADM status error %x\n", - result); - pce_dev->chan_ce_out_status = -1; - } else { - pce_dev->chan_ce_out_status = 0; - }; - - pce_dev->chan_ce_out_state = QCE_CHAN_STATE_COMP; - if (pce_dev->chan_ce_in_state == QCE_CHAN_STATE_COMP) { - pce_dev->chan_ce_in_state = QCE_CHAN_STATE_IDLE; - pce_dev->chan_ce_out_state = QCE_CHAN_STATE_IDLE; - - /* done */ - _ablk_cipher_use_pmem_complete(pce_dev); - } -}; - static int _setup_cmd_template(struct qce_device *pce_dev) { dmov_sg *pcmd; @@ -2157,13 +2050,9 @@ int qce_ablk_cipher_req(void *handle, struct qce_req *c_req) /* cipher input */ pce_dev->src_nents = count_sg(areq->src, areq->nbytes); - if (c_req->use_pmem != 1) - dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, + qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); - else - dma_map_pmem_sg(&c_req->pmem->src[0], pce_dev->src_nents, - areq->src); if (_chain_sg_buffer_in(pce_dev, areq->src, areq->nbytes) < 0) { rc = -ENOMEM; @@ -2176,9 +2065,6 @@ int qce_ablk_cipher_req(void *handle, struct qce_req *c_req) if (c_req->use_pmem != 1) dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents, DMA_FROM_DEVICE); - else - dma_map_pmem_sg(&c_req->pmem->dst[0], - pce_dev->dst_nents, areq->dst); }; if (_chain_sg_buffer_out(pce_dev, areq->dst, areq->nbytes) < 0) { rc = -ENOMEM; @@ -2215,15 +2101,9 @@ int qce_ablk_cipher_req(void *handle, struct qce_req *c_req) /* setup for callback, and issue command to adm */ pce_dev->areq = areq; pce_dev->qce_cb = c_req->qce_cb; - if (c_req->use_pmem == 1) { - pce_dev->chan_ce_in_cmd->complete_func = - _ablk_cipher_ce_in_call_back_pmem; - pce_dev->chan_ce_out_cmd->complete_func = - _ablk_cipher_ce_out_call_back_pmem; - } else { - pce_dev->chan_ce_in_cmd->complete_func = + pce_dev->chan_ce_in_cmd->complete_func = _ablk_cipher_ce_in_call_back; - pce_dev->chan_ce_out_cmd->complete_func = + pce_dev->chan_ce_out_cmd->complete_func = _ablk_cipher_ce_out_call_back; } rc = _qce_start_dma(pce_dev, true, true); @@ -2231,18 +2111,16 @@ int qce_ablk_cipher_req(void *handle, struct qce_req *c_req) if (rc == 0) return 0; bad: - if (c_req->use_pmem != 1) { - if (pce_dev->dst_nents) { - dma_unmap_sg(pce_dev->pdev, areq->dst, - pce_dev->dst_nents, DMA_FROM_DEVICE); - } - if (pce_dev->src_nents) { - dma_unmap_sg(pce_dev->pdev, areq->src, - pce_dev->src_nents, - (areq->src == areq->dst) ? - DMA_BIDIRECTIONAL : - DMA_TO_DEVICE); - } + if (pce_dev->dst_nents) { + qce_dma_unmap_sg(pce_dev->pdev, areq->dst, + pce_dev->dst_nents, DMA_FROM_DEVICE); + } + if (pce_dev->src_nents) { + qce_dma_unmap_sg(pce_dev->pdev, areq->src, + pce_dev->src_nents, + (areq->src == areq->dst) ? + DMA_BIDIRECTIONAL : + DMA_TO_DEVICE); } return rc; } diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index a105058b..906330d7 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -12,7 +12,6 @@ * GNU General Public License for more details. */ #include -#include #include #include #include @@ -456,11 +455,11 @@ static int start_cipher_req(struct qcedev_control *podev) qcedev_areq = podev->active_command; qcedev_areq->cipher_req.cookie = qcedev_areq->handle; - creq.use_pmem = qcedev_areq->cipher_op_req.use_pmem; - if (qcedev_areq->cipher_op_req.use_pmem == QCEDEV_USE_PMEM) - creq.pmem = &qcedev_areq->cipher_op_req.pmem; - else - creq.pmem = NULL; + if (qcedev_areq->cipher_op_req.use_pmem == QCEDEV_USE_PMEM) { + pr_err("%s: Use of PMEM is not supported\n", __func__); + goto unsupported; + } + creq.pmem = NULL; switch (qcedev_areq->cipher_op_req.alg) { case QCEDEV_ALG_DES: @@ -1263,224 +1262,6 @@ static int qcedev_hash_final(struct qcedev_async_req *areq, return qcedev_hmac_final(areq, handle); } -#ifdef CONFIG_ANDROID_PMEM -static int qcedev_pmem_ablk_cipher_max_xfer(struct qcedev_async_req *areq, - struct qcedev_handle *handle) -{ - int i = 0; - int err = 0; - struct scatterlist *sg_src = NULL; - struct scatterlist *sg_dst = NULL; - struct scatterlist *sg_ndex = NULL; - struct file *file_src = NULL; - struct file *file_dst = NULL; - unsigned long paddr; - unsigned long kvaddr; - unsigned long len; - - sg_src = kmalloc((sizeof(struct scatterlist) * - areq->cipher_op_req.entries), GFP_KERNEL); - if (sg_src == NULL) { - pr_err("%s: Can't Allocate memory:sg_src 0x%x\n", - __func__, (uint32_t)sg_src); - return -ENOMEM; - - } - memset(sg_src, 0, (sizeof(struct scatterlist) * - areq->cipher_op_req.entries)); - sg_ndex = sg_src; - areq->cipher_req.creq.src = sg_src; - - /* address src */ - get_pmem_file(areq->cipher_op_req.pmem.fd_src, &paddr, - &kvaddr, &len, &file_src); - - for (i = 0; i < areq->cipher_op_req.entries; i++) { - sg_set_buf(sg_ndex, - ((uint8_t *)(areq->cipher_op_req.pmem.src[i].offset) + kvaddr), - areq->cipher_op_req.pmem.src[i].len); - sg_ndex++; - } - sg_mark_end(--sg_ndex); - - for (i = 0; i < areq->cipher_op_req.entries; i++) - areq->cipher_op_req.pmem.src[i].offset += (uint32_t)paddr; - - /* address dst */ - /* If not place encryption/decryption */ - if (areq->cipher_op_req.in_place_op != 1) { - sg_dst = kmalloc((sizeof(struct scatterlist) * - areq->cipher_op_req.entries), GFP_KERNEL); - if (sg_dst == NULL) { - pr_err("%s: Can't Allocate memory: sg_dst 0x%x\n", - __func__, (uint32_t)sg_dst); - return -ENOMEM; - } - memset(sg_dst, 0, (sizeof(struct scatterlist) * - areq->cipher_op_req.entries)); - areq->cipher_req.creq.dst = sg_dst; - sg_ndex = sg_dst; - - get_pmem_file(areq->cipher_op_req.pmem.fd_dst, &paddr, - &kvaddr, &len, &file_dst); - for (i = 0; i < areq->cipher_op_req.entries; i++) - sg_set_buf(sg_ndex++, - ((uint8_t *)(areq->cipher_op_req.pmem.dst[i].offset) - + kvaddr), areq->cipher_op_req.pmem.dst[i].len); - sg_mark_end(--sg_ndex); - - for (i = 0; i < areq->cipher_op_req.entries; i++) - areq->cipher_op_req.pmem.dst[i].offset += - (uint32_t)paddr; - } else { - areq->cipher_req.creq.dst = sg_src; - for (i = 0; i < areq->cipher_op_req.entries; i++) { - areq->cipher_op_req.pmem.dst[i].offset = - areq->cipher_op_req.pmem.src[i].offset; - areq->cipher_op_req.pmem.dst[i].len = - areq->cipher_op_req.pmem.src[i].len; - } - } - - areq->cipher_req.creq.nbytes = areq->cipher_op_req.data_len; - areq->cipher_req.creq.info = areq->cipher_op_req.iv; - - err = submit_req(areq, handle); - - kfree(sg_src); - kfree(sg_dst); - - if (file_dst) - put_pmem_file(file_dst); - if (file_src) - put_pmem_file(file_src); - - return err; -}; - - -static int qcedev_pmem_ablk_cipher(struct qcedev_async_req *qcedev_areq, - struct qcedev_handle *handle) -{ - int err = 0; - int i = 0; - int j = 0; - int k = 0; - int num_entries = 0; - uint32_t total = 0; - struct qcedev_cipher_op_req *saved_req; - struct qcedev_cipher_op_req *creq = &qcedev_areq->cipher_op_req; - - saved_req = kmalloc(sizeof(struct qcedev_cipher_op_req), GFP_KERNEL); - if (saved_req == NULL) { - pr_err(KERN_ERR "%s:Can't Allocate mem:saved_req 0x%x\n", - __func__, (uint32_t)saved_req); - return -ENOMEM; - } - memcpy(saved_req, creq, sizeof(struct qcedev_cipher_op_req)); - - if (qcedev_areq->cipher_op_req.data_len > QCE_MAX_OPER_DATA) { - - struct qcedev_cipher_op_req req; - - /* save the original req structure */ - memcpy(&req, creq, sizeof(struct qcedev_cipher_op_req)); - - i = 0; - /* Address 32 KB at a time */ - while ((i < req.entries) && (err == 0)) { - if (creq->pmem.src[i].len > QCE_MAX_OPER_DATA) { - creq->pmem.src[0].len = QCE_MAX_OPER_DATA; - if (i > 0) { - creq->pmem.src[0].offset = - creq->pmem.src[i].offset; - } - - creq->data_len = QCE_MAX_OPER_DATA; - creq->entries = 1; - - err = - qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq, - handle); - - creq->pmem.src[i].len = req.pmem.src[i].len - - QCE_MAX_OPER_DATA; - creq->pmem.src[i].offset = - req.pmem.src[i].offset + - QCE_MAX_OPER_DATA; - req.pmem.src[i].offset = - creq->pmem.src[i].offset; - req.pmem.src[i].len = creq->pmem.src[i].len; - } else { - total = 0; - for (j = i; j < req.entries; j++) { - num_entries++; - if ((total + creq->pmem.src[j].len) - >= QCE_MAX_OPER_DATA) { - creq->pmem.src[j].len = - QCE_MAX_OPER_DATA - total; - total = QCE_MAX_OPER_DATA; - break; - } - total += creq->pmem.src[j].len; - } - - creq->data_len = total; - if (i > 0) - for (k = 0; k < num_entries; k++) { - creq->pmem.src[k].len = - creq->pmem.src[i+k].len; - creq->pmem.src[k].offset = - creq->pmem.src[i+k].offset; - } - creq->entries = num_entries; - - i = j; - err = - qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq, - handle); - num_entries = 0; - - creq->pmem.src[i].offset = - req.pmem.src[i].offset + - creq->pmem.src[i].len; - creq->pmem.src[i].len = - req.pmem.src[i].len - - creq->pmem.src[i].len; - req.pmem.src[i].offset = - creq->pmem.src[i].offset; - req.pmem.src[i].len = - creq->pmem.src[i].len; - - if (creq->pmem.src[i].len == 0) - i++; - } - - } /* end of while ((i < req.entries) && (err == 0)) */ - - } else - err = qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq, handle); - - /* Restore the original req structure */ - for (i = 0; i < saved_req->entries; i++) { - creq->pmem.src[i].len = saved_req->pmem.src[i].len; - creq->pmem.src[i].offset = saved_req->pmem.src[i].offset; - } - creq->entries = saved_req->entries; - creq->data_len = saved_req->data_len; - kfree(saved_req); - - return err; - -} -#else -static int qcedev_pmem_ablk_cipher(struct qcedev_async_req *qcedev_areq, - struct qcedev_handle *handle) -{ - return -EPERM; -} -#endif/*CONFIG_ANDROID_PMEM*/ - static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, int *di, struct qcedev_handle *handle, uint8_t *k_align_src) @@ -1742,6 +1523,10 @@ static int qcedev_vbuf_ablk_cipher(struct qcedev_async_req *areq, static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, struct qcedev_control *podev) { + if (req->use_pmem) { + pr_err("%s: Use of PMEM is not supported\n", __func__); + goto error; + } if ((req->entries == 0) || (req->data_len == 0)) goto error; if ((req->alg >= QCEDEV_ALG_LAST) || @@ -1781,15 +1566,6 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, if (req->byteoffset) { if (req->mode != QCEDEV_AES_MODE_CTR) goto error; - else { /* if using CTR mode make sure not using Pmem */ - if (req->use_pmem) - goto error; - } - } - /* if using PMEM with non-zero byteoffset, ensure it is in_place_op */ - if (req->use_pmem) { - if (!req->in_place_op) - goto error; } /* Ensure zer ivlen for ECB mode */ if (req->ivlen != 0) { @@ -1880,9 +1656,7 @@ static long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) return -EINVAL; if (qcedev_areq.cipher_op_req.use_pmem) - err = qcedev_pmem_ablk_cipher(&qcedev_areq, handle); - else - err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle); + err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle); if (err) return err; if (__copy_to_user((void __user *)arg, diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c index f5fa1503..b8b00f0d 100644 --- a/drivers/gpu/ion/ion.c +++ b/drivers/gpu/ion/ion.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include "ion_priv.h" @@ -41,15 +43,17 @@ /** * struct ion_device - the metadata of the ion device node * @dev: the actual misc device - * @buffers: an rb tree of all the existing buffers - * @lock: lock protecting the buffers & heaps trees + * @buffers: an rb tree of all the existing buffers + * @buffer_lock: lock protecting the tree of buffers + * @lock: rwsem protecting the tree of heaps and clients * @heaps: list of all the heaps in the system * @user_clients: list of all the clients created from userspace */ struct ion_device { struct miscdevice dev; struct rb_root buffers; - struct mutex lock; + struct mutex buffer_lock; + struct rw_semaphore lock; struct rb_root heaps; long (*custom_ioctl) (struct ion_client *client, unsigned int cmd, unsigned long arg); @@ -106,24 +110,6 @@ struct ion_handle { static void ion_iommu_release(struct kref *kref); -static int ion_validate_buffer_flags(struct ion_buffer *buffer, - unsigned long flags) -{ - if (buffer->kmap_cnt || buffer->dmap_cnt || buffer->umap_cnt || - buffer->iommu_map_cnt) { - if (buffer->flags != flags) { - pr_err("%s: buffer was already mapped with flags %lx," - " cannot map with flags %lx\n", __func__, - buffer->flags, flags); - return 1; - } - - } else { - buffer->flags = flags; - } - return 0; -} - /* this function should only be called while dev->lock is held */ static void ion_buffer_add(struct ion_device *dev, struct ion_buffer *buffer) @@ -231,6 +217,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, buffer->dev = dev; buffer->size = len; + buffer->flags = flags; table = buffer->heap->ops->map_dma(buffer->heap, buffer); if (IS_ERR_OR_NULL(table)) { @@ -241,7 +228,9 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, buffer->sg_table = table; mutex_init(&buffer->lock); + mutex_lock(&dev->buffer_lock); ion_buffer_add(dev, buffer); + mutex_unlock(&dev->buffer_lock); return buffer; } @@ -289,9 +278,9 @@ static void ion_buffer_destroy(struct kref *kref) ion_iommu_delayed_unmap(buffer); buffer->heap->ops->free(buffer); - mutex_lock(&dev->lock); + mutex_lock(&dev->buffer_lock); rb_erase(&buffer->node, &dev->buffers); - mutex_unlock(&dev->lock); + mutex_unlock(&dev->buffer_lock); kfree(buffer); } @@ -411,7 +400,8 @@ static void ion_handle_add(struct ion_client *client, struct ion_handle *handle) } struct ion_handle *ion_alloc(struct ion_client *client, size_t len, - size_t align, unsigned int flags) + size_t align, unsigned int heap_mask, + unsigned int flags) { struct rb_node *n; struct ion_handle *handle; @@ -435,17 +425,18 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, len = PAGE_ALIGN(len); - mutex_lock(&dev->lock); + down_read(&dev->lock); for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) { struct ion_heap *heap = rb_entry(n, struct ion_heap, node); /* if the client doesn't support this heap type */ if (!((1 << heap->type) & client->heap_mask)) continue; /* if the caller didn't specify this heap type */ - if (!((1 << heap->id) & flags)) + if (!((1 << heap->id) & heap_mask)) continue; /* Do not allow un-secure heap if secure is specified */ - if (secure_allocation && (heap->type != ION_HEAP_TYPE_CP)) + if (secure_allocation && + (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP)) continue; buffer = ion_buffer_create(heap, dev, len, align, flags); if (!IS_ERR_OR_NULL(buffer)) @@ -466,7 +457,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, } } } - mutex_unlock(&dev->lock); + up_read(&dev->lock); if (buffer == NULL) return ERR_PTR(-ENODEV); @@ -770,8 +761,7 @@ void ion_unmap_iommu(struct ion_client *client, struct ion_handle *handle, } EXPORT_SYMBOL(ion_unmap_iommu); -void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle, - unsigned long flags) +void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle) { struct ion_buffer *buffer; void *vaddr; @@ -793,11 +783,6 @@ void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle, return ERR_PTR(-ENODEV); } - if (ion_validate_buffer_flags(buffer, flags)) { - mutex_unlock(&client->lock); - return ERR_PTR(-EEXIST); - } - mutex_lock(&buffer->lock); vaddr = ion_handle_kmap_get(handle); mutex_unlock(&buffer->lock); @@ -819,31 +804,6 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_unmap_kernel); -static int check_vaddr_bounds(unsigned long start, unsigned long end) -{ - struct mm_struct *mm = current->active_mm; - struct vm_area_struct *vma; - int ret = 1; - - if (end < start) - goto out; - - down_read(&mm->mmap_sem); - vma = find_vma(mm, start); - if (vma && vma->vm_start < end) { - if (start < vma->vm_start) - goto out_up; - if (end > vma->vm_end) - goto out_up; - ret = 0; - } - -out_up: - up_read(&mm->mmap_sem); -out: - return ret; -} - int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, void *uaddr, unsigned long offset, unsigned long len, unsigned int cmd) @@ -909,7 +869,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) if (type == ION_HEAP_TYPE_SYSTEM_CONTIG || type == ION_HEAP_TYPE_CARVEOUT || - type == ION_HEAP_TYPE_CP) + type == (enum ion_heap_type) ION_HEAP_TYPE_CP) seq_printf(s, " : %12lx", handle->buffer->priv_phys); else seq_printf(s, " : %12s", "N/A"); @@ -997,7 +957,7 @@ struct ion_client *ion_client_create(struct ion_device *dev, client->task = task; client->pid = pid; - mutex_lock(&dev->lock); + down_write(&dev->lock); p = &dev->clients.rb_node; while (*p) { parent = *p; @@ -1015,7 +975,7 @@ struct ion_client *ion_client_create(struct ion_device *dev, client->debug_root = debugfs_create_file(name, 0664, dev->debug_root, client, &debug_client_fops); - mutex_unlock(&dev->lock); + up_write(&dev->lock); return client; } @@ -1031,12 +991,12 @@ void ion_client_destroy(struct ion_client *client) node); ion_handle_destroy(&handle->ref); } - mutex_lock(&dev->lock); + down_write(&dev->lock); if (client->task) put_task_struct(client->task); rb_erase(&client->node, &dev->clients); debugfs_remove_recursive(client->debug_root); - mutex_unlock(&dev->lock); + up_write(&dev->lock); kfree(client->name); kfree(client); @@ -1256,9 +1216,12 @@ static int ion_share_set_flags(struct ion_client *client, { struct ion_buffer *buffer; bool valid_handle; - unsigned long ion_flags = ION_SET_CACHE(CACHED); + unsigned long ion_flags = 0; if (flags & O_DSYNC) - ion_flags = ION_SET_CACHE(UNCACHED); + ion_flags = ION_SET_UNCACHED(ion_flags); + else + ion_flags = ION_SET_CACHED(ion_flags); + mutex_lock(&client->lock); valid_handle = ion_handle_validate(client, handle); @@ -1270,12 +1233,6 @@ static int ion_share_set_flags(struct ion_client *client, buffer = handle->buffer; - mutex_lock(&buffer->lock); - if (ion_validate_buffer_flags(buffer, ion_flags)) { - mutex_unlock(&buffer->lock); - return -EEXIST; - } - mutex_unlock(&buffer->lock); return 0; } @@ -1359,7 +1316,25 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_from_user(&data, (void __user *)arg, sizeof(data))) return -EFAULT; data.handle = ion_alloc(client, data.len, data.align, - data.flags); + data.heap_mask, data.flags); + + if (IS_ERR(data.handle)) + return PTR_ERR(data.handle); + + if (copy_to_user((void __user *)arg, &data, sizeof(data))) { + ion_free(client, data.handle); + return -EFAULT; + } + break; + } + case ION_IOC_ALLOC_COMPAT: + { + struct ion_allocation_data_old data; + + if (copy_from_user(&data, (void __user *)arg, sizeof(data))) + return -EFAULT; + data.handle = ion_alloc(client, data.len, data.align, + data.flags, data.flags); if (IS_ERR(data.handle)) return PTR_ERR(data.handle); @@ -1413,8 +1388,10 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) sizeof(struct ion_fd_data))) return -EFAULT; data.handle = ion_import_dma_buf(client, data.fd); - if (IS_ERR(data.handle)) + if (IS_ERR(data.handle)) { + ret = PTR_ERR(data.handle); data.handle = NULL; + } if (copy_to_user((void __user *)arg, &data, sizeof(struct ion_fd_data))) return -EFAULT; @@ -1435,65 +1412,21 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return dev->custom_ioctl(client, data.cmd, data.arg); } case ION_IOC_CLEAN_CACHES: + case ION_IOC_CLEAN_CACHES_COMPAT: + return client->dev->custom_ioctl(client, + ION_IOC_CLEAN_CACHES, arg); case ION_IOC_INV_CACHES: + case ION_IOC_INV_CACHES_COMPAT: + return client->dev->custom_ioctl(client, + ION_IOC_INV_CACHES, arg); case ION_IOC_CLEAN_INV_CACHES: - { - struct ion_flush_data data; - unsigned long start, end; - struct ion_handle *handle = NULL; - int ret; - - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_flush_data))) - return -EFAULT; - - start = (unsigned long) data.vaddr; - end = (unsigned long) data.vaddr + data.length; - - if (check_vaddr_bounds(start, end)) { - pr_err("%s: virtual address %p is out of bounds\n", - __func__, data.vaddr); - return -EINVAL; - } - - if (!data.handle) { - handle = ion_import_dma_buf(client, data.fd); - if (IS_ERR(handle)) { - pr_info("%s: Could not import handle: %d\n", - __func__, (int)handle); - return -EINVAL; - } - } - - ret = ion_do_cache_op(client, - data.handle ? data.handle : handle, - data.vaddr, data.offset, data.length, - cmd); - - if (!data.handle) - ion_free(client, handle); - - if (ret < 0) - return ret; - break; - - } + case ION_IOC_CLEAN_INV_CACHES_COMPAT: + return client->dev->custom_ioctl(client, + ION_IOC_CLEAN_INV_CACHES, arg); case ION_IOC_GET_FLAGS: - { - struct ion_flag_data data; - int ret; - if (copy_from_user(&data, (void __user *)arg, - sizeof(struct ion_flag_data))) - return -EFAULT; - - ret = ion_handle_get_flags(client, data.handle, &data.flags); - if (ret < 0) - return ret; - if (copy_to_user((void __user *)arg, &data, - sizeof(struct ion_flag_data))) - return -EFAULT; - break; - } + case ION_IOC_GET_FLAGS_COMPAT: + return client->dev->custom_ioctl(client, + ION_IOC_GET_FLAGS, arg); default: return -ENOTTY; } @@ -1551,80 +1484,6 @@ static size_t ion_debug_heap_total(struct ion_client *client, return size; } -/** - * Searches through a clients handles to find if the buffer is owned - * by this client. Used for debug output. - * @param client pointer to candidate owner of buffer - * @param buf pointer to buffer that we are trying to find the owner of - * @return 1 if found, 0 otherwise - */ -static int ion_debug_find_buffer_owner(const struct ion_client *client, - const struct ion_buffer *buf) -{ - struct rb_node *n; - - for (n = rb_first(&client->handles); n; n = rb_next(n)) { - const struct ion_handle *handle = rb_entry(n, - const struct ion_handle, - node); - if (handle->buffer == buf) - return 1; - } - return 0; -} - -/** - * Adds mem_map_data pointer to the tree of mem_map - * Used for debug output. - * @param mem_map The mem_map tree - * @param data The new data to add to the tree - */ -static void ion_debug_mem_map_add(struct rb_root *mem_map, - struct mem_map_data *data) -{ - struct rb_node **p = &mem_map->rb_node; - struct rb_node *parent = NULL; - struct mem_map_data *entry; - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct mem_map_data, node); - - if (data->addr < entry->addr) { - p = &(*p)->rb_left; - } else if (data->addr > entry->addr) { - p = &(*p)->rb_right; - } else { - pr_err("%s: mem_map_data already found.", __func__); - BUG(); - } - } - rb_link_node(&data->node, parent, p); - rb_insert_color(&data->node, mem_map); -} - -/** - * Search for an owner of a buffer by iterating over all ION clients. - * @param dev ion device containing pointers to all the clients. - * @param buffer pointer to buffer we are trying to find the owner of. - * @return name of owner. - */ -const char *ion_debug_locate_owner(const struct ion_device *dev, - const struct ion_buffer *buffer) -{ - struct rb_node *j; - const char *client_name = NULL; - - for (j = rb_first(&dev->clients); j && !client_name; - j = rb_next(j)) { - struct ion_client *client = rb_entry(j, struct ion_client, - node); - if (ion_debug_find_buffer_owner(client, buffer)) - client_name = client->name; - } - return client_name; -} - /** * Create a mem_map of the heap. * @param s seq_file to log error message to. @@ -1632,54 +1491,83 @@ const char *ion_debug_locate_owner(const struct ion_device *dev, * @param mem_map The mem map to be created. */ void ion_debug_mem_map_create(struct seq_file *s, struct ion_heap *heap, - struct rb_root *mem_map) + struct list_head *mem_map) { struct ion_device *dev = heap->dev; - struct rb_node *n; + struct rb_node *cnode; size_t size; + struct ion_client *client; if (!heap->ops->phys) return; - for (n = rb_first(&dev->buffers); n; n = rb_next(n)) { - struct ion_buffer *buffer = - rb_entry(n, struct ion_buffer, node); - if (buffer->heap->id == heap->id) { - struct mem_map_data *data = + down_read(&dev->lock); + for (cnode = rb_first(&dev->clients); cnode; cnode = rb_next(cnode)) { + struct rb_node *hnode; + client = rb_entry(cnode, struct ion_client, node); + + mutex_lock(&client->lock); + for (hnode = rb_first(&client->handles); + hnode; + hnode = rb_next(hnode)) { + struct ion_handle *handle = rb_entry( + hnode, struct ion_handle, node); + if (handle->buffer->heap == heap) { + struct mem_map_data *data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - seq_printf(s, "ERROR: out of memory. " - "Part of memory map will not be logged\n"); - break; + if (!data) + goto inner_error; + heap->ops->phys(heap, handle->buffer, + &(data->addr), &size); + data->size = (unsigned long) size; + data->addr_end = data->addr + data->size - 1; + data->client_name = kstrdup(client->name, + GFP_KERNEL); + if (!data->client_name) { + kfree(data); + goto inner_error; + } + list_add(&data->node, mem_map); } - - buffer->heap->ops->phys(buffer->heap, buffer, - &(data->addr), &size); - data->size = (unsigned long) size; - data->addr_end = data->addr + data->size - 1; - data->client_name = ion_debug_locate_owner(dev, buffer); - ion_debug_mem_map_add(mem_map, data); } + mutex_unlock(&client->lock); } + up_read(&dev->lock); + return; + +inner_error: + seq_puts(s, + "ERROR: out of memory. Part of memory map will not be logged\n"); + mutex_unlock(&client->lock); + up_read(&dev->lock); } /** * Free the memory allocated by ion_debug_mem_map_create * @param mem_map The mem map to free. */ -static void ion_debug_mem_map_destroy(struct rb_root *mem_map) +static void ion_debug_mem_map_destroy(struct list_head *mem_map) { if (mem_map) { - struct rb_node *n; - while ((n = rb_first(mem_map)) != 0) { - struct mem_map_data *data = - rb_entry(n, struct mem_map_data, node); - rb_erase(&data->node, mem_map); + struct mem_map_data *data, *tmp; + list_for_each_entry_safe(data, tmp, mem_map, node) { + list_del(&data->node); + kfree(data->client_name); kfree(data); } } } +static int mem_map_cmp(void *priv, struct list_head *a, struct list_head *b) +{ + struct mem_map_data *d1, *d2; + d1 = list_entry(a, struct mem_map_data, node); + d2 = list_entry(b, struct mem_map_data, node); + if (d1->addr == d2->addr) + return d1->size - d2->size; + return d1->addr - d2->addr; +} + /** * Print heap debug information. * @param s seq_file to log message to. @@ -1688,8 +1576,9 @@ static void ion_debug_mem_map_destroy(struct rb_root *mem_map) static void ion_heap_print_debug(struct seq_file *s, struct ion_heap *heap) { if (heap->ops->print_debug) { - struct rb_root mem_map = RB_ROOT; + struct list_head mem_map = LIST_HEAD_INIT(mem_map); ion_debug_mem_map_create(s, heap, &mem_map); + list_sort(NULL, &mem_map, mem_map_cmp); heap->ops->print_debug(heap, s, &mem_map); ion_debug_mem_map_destroy(&mem_map); } @@ -1701,9 +1590,9 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) struct ion_device *dev = heap->dev; struct rb_node *n; - mutex_lock(&dev->lock); seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size"); + down_read(&dev->lock); for (n = rb_first(&dev->clients); n; n = rb_next(n)) { struct ion_client *client = rb_entry(n, struct ion_client, node); @@ -1721,8 +1610,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) client->pid, size); } } + up_read(&dev->lock); ion_heap_print_debug(s, heap); - mutex_unlock(&dev->lock); return 0; } @@ -1750,7 +1639,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) __func__); heap->dev = dev; - mutex_lock(&dev->lock); + down_write(&dev->lock); while (*p) { parent = *p; entry = rb_entry(parent, struct ion_heap, node); @@ -1771,7 +1660,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) debugfs_create_file(heap->name, 0664, dev->debug_root, heap, &debug_heap_fops); end: - mutex_unlock(&dev->lock); + up_write(&dev->lock); } int ion_secure_heap(struct ion_device *dev, int heap_id, int version, @@ -1784,10 +1673,10 @@ int ion_secure_heap(struct ion_device *dev, int heap_id, int version, * traverse the list of heaps available in this system * and find the heap that is specified. */ - mutex_lock(&dev->lock); + down_write(&dev->lock); for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) { struct ion_heap *heap = rb_entry(n, struct ion_heap, node); - if (heap->type != ION_HEAP_TYPE_CP) + if (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP) continue; if (ION_HEAP(heap->id) != heap_id) continue; @@ -1797,7 +1686,7 @@ int ion_secure_heap(struct ion_device *dev, int heap_id, int version, ret_val = -EINVAL; break; } - mutex_unlock(&dev->lock); + up_write(&dev->lock); return ret_val; } EXPORT_SYMBOL(ion_secure_heap); @@ -1812,10 +1701,10 @@ int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version, * traverse the list of heaps available in this system * and find the heap that is specified. */ - mutex_lock(&dev->lock); + down_write(&dev->lock); for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) { struct ion_heap *heap = rb_entry(n, struct ion_heap, node); - if (heap->type != ION_HEAP_TYPE_CP) + if (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP) continue; if (ION_HEAP(heap->id) != heap_id) continue; @@ -1825,7 +1714,7 @@ int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version, ret_val = -EINVAL; break; } - mutex_unlock(&dev->lock); + up_write(&dev->lock); return ret_val; } EXPORT_SYMBOL(ion_unsecure_heap); @@ -1839,7 +1728,7 @@ static int ion_debug_leak_show(struct seq_file *s, void *unused) /* mark all buffers as 1 */ seq_printf(s, "%16.s %16.s %16.s %16.s\n", "buffer", "heap", "size", "ref cnt"); - mutex_lock(&dev->lock); + down_write(&dev->lock); for (n = rb_first(&dev->buffers); n; n = rb_next(n)) { struct ion_buffer *buf = rb_entry(n, struct ion_buffer, node); @@ -1874,7 +1763,7 @@ static int ion_debug_leak_show(struct seq_file *s, void *unused) (int)buf, buf->heap->name, buf->size, atomic_read(&buf->ref.refcount)); } - mutex_unlock(&dev->lock); + up_write(&dev->lock); return 0; } @@ -1920,7 +1809,8 @@ struct ion_device *ion_device_create(long (*custom_ioctl) idev->custom_ioctl = custom_ioctl; idev->buffers = RB_ROOT; - mutex_init(&idev->lock); + mutex_init(&idev->buffer_lock); + init_rwsem(&idev->lock); idev->heaps = RB_ROOT; idev->clients = RB_ROOT; debugfs_create_file("check_leaked_fds", 0664, idev->debug_root, idev, diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c index 3f9fe545..a6a5c2d9 100644 --- a/drivers/gpu/ion/ion_carveout_heap.c +++ b/drivers/gpu/ion/ion_carveout_heap.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include "ion_priv.h" @@ -31,6 +30,7 @@ #include #include #include +#include struct ion_carveout_heap { struct ion_heap heap; @@ -240,25 +240,78 @@ int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer, void *vaddr, unsigned int offset, unsigned int length, unsigned int cmd) { - void (*outer_cache_op)(phys_addr_t, phys_addr_t); + void (*outer_cache_op)(phys_addr_t, phys_addr_t) = NULL; struct ion_carveout_heap *carveout_heap = container_of(heap, struct ion_carveout_heap, heap); - - switch (cmd) { - case ION_IOC_CLEAN_CACHES: - dmac_clean_range(vaddr, vaddr + length); - outer_cache_op = outer_clean_range; - break; - case ION_IOC_INV_CACHES: - dmac_inv_range(vaddr, vaddr + length); - outer_cache_op = outer_inv_range; - break; - case ION_IOC_CLEAN_INV_CACHES: - dmac_flush_range(vaddr, vaddr + length); - outer_cache_op = outer_flush_range; - break; - default: - return -EINVAL; + unsigned int size_to_vmap, total_size; + int i, j; + void *ptr = NULL; + ion_phys_addr_t buff_phys = buffer->priv_phys; + + if (!vaddr) { + /* + * Split the vmalloc space into smaller regions in + * order to clean and/or invalidate the cache. + */ + size_to_vmap = ((VMALLOC_END - VMALLOC_START)/8); + total_size = buffer->size; + + for (i = 0; i < total_size; i += size_to_vmap) { + size_to_vmap = min(size_to_vmap, total_size - i); + for (j = 0; j < 10 && size_to_vmap; ++j) { + ptr = ioremap(buff_phys, size_to_vmap); + if (ptr) { + switch (cmd) { + case ION_IOC_CLEAN_CACHES: + dmac_clean_range(ptr, + ptr + size_to_vmap); + outer_cache_op = + outer_clean_range; + break; + case ION_IOC_INV_CACHES: + dmac_inv_range(ptr, + ptr + size_to_vmap); + outer_cache_op = + outer_inv_range; + break; + case ION_IOC_CLEAN_INV_CACHES: + dmac_flush_range(ptr, + ptr + size_to_vmap); + outer_cache_op = + outer_flush_range; + break; + default: + return -EINVAL; + } + buff_phys += size_to_vmap; + break; + } else { + size_to_vmap >>= 1; + } + } + if (!ptr) { + pr_err("Couldn't io-remap the memory\n"); + return -EINVAL; + } + iounmap(ptr); + } + } else { + switch (cmd) { + case ION_IOC_CLEAN_CACHES: + dmac_clean_range(vaddr, vaddr + length); + outer_cache_op = outer_clean_range; + break; + case ION_IOC_INV_CACHES: + dmac_inv_range(vaddr, vaddr + length); + outer_cache_op = outer_inv_range; + break; + case ION_IOC_CLEAN_INV_CACHES: + dmac_flush_range(vaddr, vaddr + length); + outer_cache_op = outer_flush_range; + break; + default: + return -EINVAL; + } } if (carveout_heap->has_outer_cache) { @@ -269,7 +322,7 @@ int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer, } static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s, - const struct rb_root *mem_map) + const struct list_head *mem_map) { struct ion_carveout_heap *carveout_heap = container_of(heap, struct ion_carveout_heap, heap); @@ -283,16 +336,14 @@ static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s, unsigned long size = carveout_heap->total_size; unsigned long end = base+size; unsigned long last_end = base; - struct rb_node *n; + struct mem_map_data *data; seq_printf(s, "\nMemory Map\n"); seq_printf(s, "%16.s %14.s %14.s %14.s\n", "client", "start address", "end address", "size (hex)"); - for (n = rb_first(mem_map); n; n = rb_next(n)) { - struct mem_map_data *data = - rb_entry(n, struct mem_map_data, node); + list_for_each_entry(data, mem_map, node) { const char *client_name = "(null)"; if (last_end < data->addr) { @@ -357,7 +408,7 @@ int ion_carveout_heap_map_iommu(struct ion_buffer *buffer, goto out1; } - sglist = vmalloc(sizeof(*sglist)); + sglist = kmalloc(sizeof(*sglist), GFP_KERNEL); if (!sglist) goto out1; @@ -381,13 +432,13 @@ int ion_carveout_heap_map_iommu(struct ion_buffer *buffer, if (ret) goto out2; } - vfree(sglist); + kfree(sglist); return ret; out2: iommu_unmap_range(domain, data->iova_addr, buffer->size); out1: - vfree(sglist); + kfree(sglist); msm_free_iova_address(data->iova_addr, domain_num, partition_num, data->mapped_size); diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c index bef6b6f0..9c606b30 100644 --- a/drivers/gpu/ion/ion_cma_heap.c +++ b/drivers/gpu/ion/ion_cma_heap.c @@ -25,6 +25,7 @@ #include #include +#include /* for ion_heap_ops structure */ #include "ion_priv.h" @@ -115,6 +116,7 @@ static void ion_cma_free(struct ion_buffer *buffer) dev_dbg(dev, "Release buffer %p\n", buffer); /* release memory */ dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); + sg_free_table(info->table); /* release sg table */ kfree(info->table); kfree(info); @@ -280,15 +282,30 @@ int ion_cma_cache_ops(struct ion_heap *heap, switch (cmd) { case ION_IOC_CLEAN_CACHES: - dmac_clean_range(vaddr, vaddr + length); + if (!vaddr) + dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_TO_DEVICE); + else + dmac_clean_range(vaddr, vaddr + length); outer_cache_op = outer_clean_range; break; case ION_IOC_INV_CACHES: - dmac_inv_range(vaddr, vaddr + length); + if (!vaddr) + dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_FROM_DEVICE); + else + dmac_inv_range(vaddr, vaddr + length); outer_cache_op = outer_inv_range; break; case ION_IOC_CLEAN_INV_CACHES: - dmac_flush_range(vaddr, vaddr + length); + if (!vaddr) { + dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_TO_DEVICE); + dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_FROM_DEVICE); + } else { + dmac_flush_range(vaddr, vaddr + length); + } outer_cache_op = outer_flush_range; break; default: diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c index 84ad9b0a..9ae79a86 100644 --- a/drivers/gpu/ion/ion_cp_heap.c +++ b/drivers/gpu/ion/ion_cp_heap.c @@ -2,7 +2,7 @@ * drivers/gpu/ion/ion_cp_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -15,20 +15,18 @@ * */ #include -#include + #include #include #include -#include +#include #include #include #include -#include #include #include #include #include -#include #include @@ -100,10 +98,7 @@ struct ion_cp_heap { int iommu_2x_map_domain; unsigned int has_outer_cache; atomic_t protect_cnt; - void *cpu_addr; - size_t heap_size; - dma_addr_t handle; - int cma; + int disallow_non_secure_allocation; }; enum { @@ -119,68 +114,6 @@ static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size, unsigned int permission_type, int version, void *data); -static int allocate_heap_memory(struct ion_heap *heap) -{ - struct device *dev = heap->priv; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - int ret; - int tries = 0; - - - if (cp_heap->cpu_addr) - return 0; - - while (!cp_heap->cpu_addr && (++tries < 500)) { - cp_heap->cpu_addr = dma_alloc_writecombine(dev, - cp_heap->heap_size, - &(cp_heap->handle), - 0); - if (!cp_heap->cpu_addr) - msleep(20); - } - - if (!cp_heap->cpu_addr) - goto out; - - cp_heap->base = cp_heap->handle; - - cp_heap->pool = gen_pool_create(12, -1); - if (!cp_heap->pool) - goto out_free; - - ret = gen_pool_add(cp_heap->pool, cp_heap->base, - cp_heap->heap_size, -1); - if (ret < 0) - goto out_pool; - - return 0; - -out_pool: - gen_pool_destroy(cp_heap->pool); -out_free: - dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr, - cp_heap->handle); -out: - return ION_CP_ALLOCATE_FAIL; -} - -static void free_heap_memory(struct ion_heap *heap) -{ - struct device *dev = heap->priv; - struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - /* release memory */ - dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr, - cp_heap->handle); - gen_pool_destroy(cp_heap->pool); - cp_heap->pool = NULL; - cp_heap->cpu_addr = 0; -} - - - /** * Get the total number of kernel mappings. * Must be called with heap->lock locked. @@ -202,12 +135,6 @@ static int ion_on_first_alloc(struct ion_heap *heap) if (ret_value) return 1; } - - if (cp_heap->cma) { - ret_value = allocate_heap_memory(heap); - if (ret_value) - return 1; - } return 0; } @@ -220,9 +147,6 @@ static void ion_on_last_free(struct ion_heap *heap) if (fmem_set_state(FMEM_T_STATE) != 0) pr_err("%s: unable to transition heap to T-state\n", __func__); - - if (cp_heap->cma) - free_heap_memory(heap); } /** @@ -238,9 +162,13 @@ static int ion_cp_protect(struct ion_heap *heap, int version, void *data) if (atomic_inc_return(&cp_heap->protect_cnt) == 1) { /* Make sure we are in C state when the heap is protected. */ - if (!cp_heap->allocated_bytes) - if (ion_on_first_alloc(heap)) + if (!cp_heap->allocated_bytes) { + ret_value = ion_on_first_alloc(heap); + if (ret_value) { + atomic_dec(&cp_heap->protect_cnt); goto out; + } + } ret_value = ion_cp_protect_mem(cp_heap->secure_base, cp_heap->secure_size, cp_heap->permission_type, @@ -262,7 +190,7 @@ static int ion_cp_protect(struct ion_heap *heap, int version, void *data) out: pr_debug("%s: protect count is %d\n", __func__, atomic_read(&cp_heap->protect_cnt)); - WARN_ON(atomic_read(&cp_heap->protect_cnt) < 0); + BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0); return ret_value; } @@ -294,7 +222,7 @@ static void ion_cp_unprotect(struct ion_heap *heap, int version, void *data) } pr_debug("%s: protect count is %d\n", __func__, atomic_read(&cp_heap->protect_cnt)); - WARN_ON(atomic_read(&cp_heap->protect_cnt) < 0); + BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0); } ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap, @@ -304,6 +232,7 @@ ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap, { unsigned long offset; unsigned long secure_allocation = flags & ION_SECURE; + unsigned long force_contig = flags & ION_FORCE_CONTIGUOUS; struct ion_cp_heap *cp_heap = container_of(heap, struct ion_cp_heap, heap); @@ -316,6 +245,14 @@ ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap, return ION_CP_ALLOCATE_FAIL; } + if (!force_contig && !secure_allocation && + cp_heap->disallow_non_secure_allocation) { + mutex_unlock(&cp_heap->lock); + pr_debug("%s: non-secure allocation disallowed from this heap\n", + __func__); + return ION_CP_ALLOCATE_FAIL; + } + if (secure_allocation && (cp_heap->umap_count > 0 || cp_heap->kmap_cached_count > 0)) { mutex_unlock(&cp_heap->lock); @@ -500,7 +437,6 @@ static int ion_cp_request_region(struct ion_cp_heap *cp_heap) if (cp_heap->heap_request_region) ret_value = cp_heap->heap_request_region( cp_heap->bus_id); - return ret_value; } @@ -544,7 +480,6 @@ void *ion_cp_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer) struct ion_cp_heap *cp_heap = container_of(heap, struct ion_cp_heap, heap); void *ret_value = NULL; - unsigned long start_phys = cp_heap->base; mutex_lock(&cp_heap->lock); if ((cp_heap->heap_protected == HEAP_NOT_PROTECTED) || @@ -559,9 +494,6 @@ void *ion_cp_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer) if (cp_heap->reusable) { ret_value = ion_map_fmem_buffer(buffer, cp_heap->base, cp_heap->reserved_vrange, buffer->flags); - } else if (cp_heap->cma) { - ret_value = cp_heap->cpu_addr + - (buffer->priv_phys - start_phys); } else { if (ION_IS_CACHED(buffer->flags)) ret_value = ioremap_cached(buffer->priv_phys, @@ -580,7 +512,6 @@ void *ion_cp_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer) ++cp_heap->kmap_uncached_count; } } - mutex_unlock(&cp_heap->lock); return ret_value; } @@ -593,7 +524,7 @@ void ion_cp_heap_unmap_kernel(struct ion_heap *heap, if (cp_heap->reusable) unmap_kernel_range((unsigned long)buffer->vaddr, buffer->size); - else if (!cp_heap->cma) + else __arm_iounmap(buffer->vaddr); buffer->vaddr = NULL; @@ -657,25 +588,77 @@ int ion_cp_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer, void *vaddr, unsigned int offset, unsigned int length, unsigned int cmd) { - void (*outer_cache_op)(phys_addr_t, phys_addr_t); + void (*outer_cache_op)(phys_addr_t, phys_addr_t) = NULL; struct ion_cp_heap *cp_heap = - container_of(heap, struct ion_cp_heap, heap); - - switch (cmd) { - case ION_IOC_CLEAN_CACHES: - dmac_clean_range(vaddr, vaddr + length); - outer_cache_op = outer_clean_range; - break; - case ION_IOC_INV_CACHES: - dmac_inv_range(vaddr, vaddr + length); - outer_cache_op = outer_inv_range; - break; - case ION_IOC_CLEAN_INV_CACHES: - dmac_flush_range(vaddr, vaddr + length); - outer_cache_op = outer_flush_range; - break; - default: - return -EINVAL; + container_of(heap, struct ion_cp_heap, heap); + unsigned int size_to_vmap, total_size; + int i, j; + void *ptr = NULL; + ion_phys_addr_t buff_phys = buffer->priv_phys; + + if (!vaddr) { + /* + * Split the vmalloc space into smaller regions in + * order to clean and/or invalidate the cache. + */ + size_to_vmap = (VMALLOC_END - VMALLOC_START)/8; + total_size = buffer->size; + for (i = 0; i < total_size; i += size_to_vmap) { + size_to_vmap = min(size_to_vmap, total_size - i); + for (j = 0; j < 10 && size_to_vmap; ++j) { + ptr = ioremap(buff_phys, size_to_vmap); + if (ptr) { + switch (cmd) { + case ION_IOC_CLEAN_CACHES: + dmac_clean_range(ptr, + ptr + size_to_vmap); + outer_cache_op = + outer_clean_range; + break; + case ION_IOC_INV_CACHES: + dmac_inv_range(ptr, + ptr + size_to_vmap); + outer_cache_op = + outer_inv_range; + break; + case ION_IOC_CLEAN_INV_CACHES: + dmac_flush_range(ptr, + ptr + size_to_vmap); + outer_cache_op = + outer_flush_range; + break; + default: + return -EINVAL; + } + buff_phys += size_to_vmap; + break; + } else { + size_to_vmap >>= 1; + } + } + if (!ptr) { + pr_err("Couldn't io-remap the memory\n"); + return -EINVAL; + } + iounmap(ptr); + } + } else { + switch (cmd) { + case ION_IOC_CLEAN_CACHES: + dmac_clean_range(vaddr, vaddr + length); + outer_cache_op = outer_clean_range; + break; + case ION_IOC_INV_CACHES: + dmac_inv_range(vaddr, vaddr + length); + outer_cache_op = outer_inv_range; + break; + case ION_IOC_CLEAN_INV_CACHES: + dmac_flush_range(vaddr, vaddr + length); + outer_cache_op = outer_flush_range; + break; + default: + return -EINVAL; + } } if (cp_heap->has_outer_cache) { @@ -686,7 +669,7 @@ int ion_cp_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer, } static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s, - const struct rb_root *mem_map) + const struct list_head *mem_map) { unsigned long total_alloc; unsigned long total_size; @@ -716,16 +699,14 @@ static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s, unsigned long size = cp_heap->total_size; unsigned long end = base+size; unsigned long last_end = base; - struct rb_node *n; + struct mem_map_data *data; seq_printf(s, "\nMemory Map\n"); seq_printf(s, "%16.s %14.s %14.s %14.s\n", "client", "start address", "end address", "size (hex)"); - for (n = rb_first(mem_map); n; n = rb_next(n)) { - struct mem_map_data *data = - rb_entry(n, struct mem_map_data, node); + list_for_each_entry(data, mem_map, node) { const char *client_name = "(null)"; if (last_end < data->addr) { @@ -1008,6 +989,14 @@ struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *heap_data) mutex_init(&cp_heap->lock); + cp_heap->pool = gen_pool_create(12, -1); + if (!cp_heap->pool) + goto free_heap; + + cp_heap->base = heap_data->base; + ret = gen_pool_add(cp_heap->pool, cp_heap->base, heap_data->size, -1); + if (ret < 0) + goto destroy_pool; cp_heap->allocated_bytes = 0; cp_heap->umap_count = 0; @@ -1015,13 +1004,11 @@ struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *heap_data) cp_heap->kmap_uncached_count = 0; cp_heap->total_size = heap_data->size; cp_heap->heap.ops = &cp_heap_ops; - cp_heap->heap.type = ION_HEAP_TYPE_CP; + cp_heap->heap.type = (enum ion_heap_type) ION_HEAP_TYPE_CP; cp_heap->heap_protected = HEAP_NOT_PROTECTED; - cp_heap->secure_base = heap_data->base; + cp_heap->secure_base = cp_heap->base; cp_heap->secure_size = heap_data->size; cp_heap->has_outer_cache = heap_data->has_outer_cache; - cp_heap->heap_size = heap_data->size; - atomic_set(&cp_heap->protect_cnt, 0); if (heap_data->extra_data) { struct ion_cp_heap_pdata *extra_data = @@ -1045,25 +1032,11 @@ struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *heap_data) extra_data->iommu_map_all; cp_heap->iommu_2x_map_domain = extra_data->iommu_2x_map_domain; - cp_heap->cma = extra_data->is_cma; - } - - if (cp_heap->cma) { - cp_heap->pool = NULL; - cp_heap->cpu_addr = 0; - cp_heap->heap.priv = heap_data->priv; - } else { - cp_heap->pool = gen_pool_create(12, -1); - if (!cp_heap->pool) - goto free_heap; - - cp_heap->base = heap_data->base; - ret = gen_pool_add(cp_heap->pool, cp_heap->base, - heap_data->size, -1); - if (ret < 0) - goto destroy_pool; + cp_heap->disallow_non_secure_allocation = + extra_data->no_nonsecure_alloc; } + return &cp_heap->heap; destroy_pool: diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c index 2b5d24c6..98c1a8c3 100644 --- a/drivers/gpu/ion/ion_heap.c +++ b/drivers/gpu/ion/ion_heap.c @@ -18,12 +18,13 @@ #include #include #include "ion_priv.h" +#include struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) { struct ion_heap *heap = NULL; - switch (heap_data->type) { + switch ((int) heap_data->type) { case ION_HEAP_TYPE_SYSTEM_CONTIG: heap = ion_system_contig_heap_create(heap_data); break; @@ -68,7 +69,7 @@ void ion_heap_destroy(struct ion_heap *heap) if (!heap) return; - switch (heap->type) { + switch ((int) heap->type) { case ION_HEAP_TYPE_SYSTEM_CONTIG: ion_system_contig_heap_destroy(heap); break; diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c index b94f1f53..49721fb6 100644 --- a/drivers/gpu/ion/ion_iommu_heap.c +++ b/drivers/gpu/ion/ion_iommu_heap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,56 +12,152 @@ */ #include #include -#include +#include #include +#include #include #include #include #include #include +#include #include "ion_priv.h" #include #include #include #include -#include struct ion_iommu_heap { struct ion_heap heap; unsigned int has_outer_cache; }; +/* + * We will attempt to allocate high-order pages and store those in an + * sg_list. However, some APIs expect an array of struct page * where + * each page is of size PAGE_SIZE. We use this extra structure to + * carry around an array of such pages (derived from the high-order + * pages with nth_page). + */ struct ion_iommu_priv_data { struct page **pages; + unsigned int pages_uses_vmalloc; int nrpages; unsigned long size; }; +#define MAX_VMAP_RETRIES 10 + +static const unsigned int orders[] = {8, 4, 0}; +static const int num_orders = ARRAY_SIZE(orders); + +struct page_info { + struct page *page; + unsigned int order; + struct list_head list; +}; + +static unsigned int order_to_size(int order) +{ + return PAGE_SIZE << order; +} + +static struct page_info *alloc_largest_available(unsigned long size, + unsigned int max_order) +{ + struct page *page; + struct page_info *info; + int i; + + for (i = 0; i < num_orders; i++) { + gfp_t gfp; + if (size < order_to_size(orders[i])) + continue; + if (max_order < orders[i]) + continue; + + gfp = __GFP_HIGHMEM; + + if (orders[i]) { + gfp |= __GFP_COMP | __GFP_NORETRY | + __GFP_NO_KSWAPD | __GFP_NOWARN; + } else { + gfp |= GFP_KERNEL; + } + page = alloc_pages(gfp, orders[i]); + if (!page) + continue; + + info = kmalloc(sizeof(struct page_info), GFP_KERNEL); + info->page = page; + info->order = orders[i]; + return info; + } + return NULL; +} + static int ion_iommu_heap_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long size, unsigned long align, unsigned long flags) { int ret, i; + struct list_head pages_list; + struct page_info *info, *tmp_info; struct ion_iommu_priv_data *data = NULL; if (msm_use_iommu()) { struct scatterlist *sg; struct sg_table *table; - unsigned int i; + int j; + void *ptr = NULL; + unsigned int npages_to_vmap, total_pages, num_large_pages = 0; + unsigned long size_remaining = PAGE_ALIGN(size); + unsigned int max_order = orders[0]; + unsigned int page_tbl_size; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + INIT_LIST_HEAD(&pages_list); + while (size_remaining > 0) { + info = alloc_largest_available(size_remaining, + max_order); + if (!info) { + ret = -ENOMEM; + goto err_free_data; + } + list_add_tail(&info->list, &pages_list); + size_remaining -= order_to_size(info->order); + max_order = info->order; + num_large_pages++; + } + data->size = PFN_ALIGN(size); data->nrpages = data->size >> PAGE_SHIFT; - data->pages = kzalloc(sizeof(struct page *)*data->nrpages, - GFP_KERNEL); + data->pages_uses_vmalloc = 0; + page_tbl_size = sizeof(struct page *) * data->nrpages; + + if (page_tbl_size > SZ_8K) { + /* + * Do fallback to ensure we have a balance between + * performance and availability. + */ + data->pages = kmalloc(page_tbl_size, + __GFP_COMP | __GFP_NORETRY | + __GFP_NO_KSWAPD | __GFP_NOWARN); + if (!data->pages) { + data->pages = vmalloc(page_tbl_size); + data->pages_uses_vmalloc = 1; + } + } else { + data->pages = kmalloc(page_tbl_size, GFP_KERNEL); + } if (!data->pages) { ret = -ENOMEM; - goto err1; + goto err_free_data; } table = buffer->sg_table = @@ -71,17 +167,55 @@ static int ion_iommu_heap_allocate(struct ion_heap *heap, ret = -ENOMEM; goto err1; } - ret = sg_alloc_table(table, data->nrpages, GFP_KERNEL); + ret = sg_alloc_table(table, num_large_pages, GFP_KERNEL); if (ret) goto err2; - for_each_sg(table->sgl, sg, table->nents, i) { - data->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!data->pages[i]) - goto err3; - - sg_set_page(sg, data->pages[i], PAGE_SIZE, 0); + i = 0; + sg = table->sgl; + list_for_each_entry_safe(info, tmp_info, &pages_list, list) { + struct page *page = info->page; + sg_set_page(sg, page, order_to_size(info->order), 0); sg_dma_address(sg) = sg_phys(sg); + sg = sg_next(sg); + for (j = 0; j < (1 << info->order); ++j) + data->pages[i++] = nth_page(page, j); + list_del(&info->list); + kfree(info); + } + + /* + * As an optimization, we omit __GFP_ZERO from + * alloc_page above and manually zero out all of the + * pages in one fell swoop here. To safeguard against + * insufficient vmalloc space, we only vmap + * `npages_to_vmap' at a time, starting with a + * conservative estimate of 1/8 of the total number of + * vmalloc pages available. Note that the `pages' + * array is composed of all 4K pages, irrespective of + * the size of the pages on the sg list. + */ + npages_to_vmap = ((VMALLOC_END - VMALLOC_START)/8) + >> PAGE_SHIFT; + total_pages = data->nrpages; + for (i = 0; i < total_pages; i += npages_to_vmap) { + npages_to_vmap = min(npages_to_vmap, total_pages - i); + for (j = 0; j < MAX_VMAP_RETRIES && npages_to_vmap; + ++j) { + ptr = vmap(&data->pages[i], npages_to_vmap, + VM_IOREMAP, pgprot_kernel); + if (ptr) + break; + else + npages_to_vmap >>= 1; + } + if (!ptr) { + pr_err("Couldn't vmap the pages for zeroing\n"); + ret = -ENOMEM; + goto err3; + } + memset(ptr, 0, npages_to_vmap * PAGE_SIZE); + vunmap(ptr); } if (!ION_IS_CACHED(flags)) @@ -101,29 +235,45 @@ static int ion_iommu_heap_allocate(struct ion_heap *heap, err2: kfree(buffer->sg_table); buffer->sg_table = 0; - - for (i = 0; i < data->nrpages; i++) { - if (data->pages[i]) - __free_page(data->pages[i]); - } - kfree(data->pages); err1: + if (data->pages_uses_vmalloc) + vfree(data->pages); + else + kfree(data->pages); +err_free_data: kfree(data); + + list_for_each_entry_safe(info, tmp_info, &pages_list, list) { + if (info->page) + __free_pages(info->page, info->order); + list_del(&info->list); + kfree(info); + } return ret; } static void ion_iommu_heap_free(struct ion_buffer *buffer) { - struct ion_iommu_priv_data *data = buffer->priv_virt; int i; + struct scatterlist *sg; + struct sg_table *table = buffer->sg_table; + struct ion_iommu_priv_data *data = buffer->priv_virt; + if (!table) + return; if (!data) return; - for (i = 0; i < data->nrpages; i++) - __free_page(data->pages[i]); + for_each_sg(table->sgl, sg, table->nents, i) + __free_pages(sg_page(sg), get_order(sg_dma_len(sg))); - kfree(data->pages); + sg_free_table(table); + kfree(table); + table = 0; + if (data->pages_uses_vmalloc) + vfree(data->pages); + else + kfree(data->pages); kfree(data); } @@ -137,7 +287,7 @@ void *ion_iommu_heap_map_kernel(struct ion_heap *heap, return NULL; if (!ION_IS_CACHED(buffer->flags)) - page_prot = pgprot_noncached(page_prot); + page_prot = pgprot_writecombine(page_prot); buffer->vaddr = vmap(data->pages, data->nrpages, VM_IOREMAP, page_prot); @@ -157,25 +307,34 @@ void ion_iommu_heap_unmap_kernel(struct ion_heap *heap, int ion_iommu_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, struct vm_area_struct *vma) { - struct ion_iommu_priv_data *data = buffer->priv_virt; + struct sg_table *table = buffer->sg_table; + unsigned long addr = vma->vm_start; + unsigned long offset = vma->vm_pgoff * PAGE_SIZE; + struct scatterlist *sg; int i; - unsigned long curr_addr; - if (!data) - return -EINVAL; if (!ION_IS_CACHED(buffer->flags)) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - curr_addr = vma->vm_start; - for (i = 0; i < data->nrpages && curr_addr < vma->vm_end; i++) { - if (vm_insert_page(vma, curr_addr, data->pages[i])) { - /* - * This will fail the mmap which will - * clean up the vma space properly. - */ - return -EINVAL; + for_each_sg(table->sgl, sg, table->nents, i) { + struct page *page = sg_page(sg); + unsigned long remainder = vma->vm_end - addr; + unsigned long len = sg_dma_len(sg); + + if (offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + continue; + } else if (offset) { + page += offset / PAGE_SIZE; + len = sg_dma_len(sg) - offset; + offset = 0; } - curr_addr += PAGE_SIZE; + len = min(len, remainder); + remap_pfn_range(vma, addr, page_to_pfn(page), len, + vma->vm_page_prot); + addr += len; + if (addr >= vma->vm_end) + return 0; } return 0; } @@ -199,6 +358,14 @@ int ion_iommu_heap_map_iommu(struct ion_buffer *buffer, data->mapped_size = iova_length; extra = iova_length - buffer->size; + /* Use the biggest alignment to allow bigger IOMMU mappings. + * Use the first entry since the first entry will always be the + * biggest entry. To take advantage of bigger mapping sizes both the + * VA and PA addresses have to be aligned to the biggest size. + */ + if (buffer->sg_table->sgl->length > align) + align = buffer->sg_table->sgl->length; + ret = msm_allocate_iova_address(domain_num, partition_num, data->mapped_size, align, &data->iova_addr); @@ -277,15 +444,30 @@ static int ion_iommu_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer, switch (cmd) { case ION_IOC_CLEAN_CACHES: - dmac_clean_range(vaddr, vaddr + length); + if (!vaddr) + dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_TO_DEVICE); + else + dmac_clean_range(vaddr, vaddr + length); outer_cache_op = outer_clean_range; break; case ION_IOC_INV_CACHES: - dmac_inv_range(vaddr, vaddr + length); + if (!vaddr) + dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_FROM_DEVICE); + else + dmac_inv_range(vaddr, vaddr + length); outer_cache_op = outer_inv_range; break; case ION_IOC_CLEAN_INV_CACHES: - dmac_flush_range(vaddr, vaddr + length); + if (!vaddr) { + dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_TO_DEVICE); + dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_FROM_DEVICE); + } else { + dmac_flush_range(vaddr, vaddr + length); + } outer_cache_op = outer_flush_range; break; default: @@ -316,10 +498,6 @@ static struct sg_table *ion_iommu_heap_map_dma(struct ion_heap *heap, static void ion_iommu_heap_unmap_dma(struct ion_heap *heap, struct ion_buffer *buffer) { - if (buffer->sg_table) - sg_free_table(buffer->sg_table); - kfree(buffer->sg_table); - buffer->sg_table = 0; } static struct ion_heap_ops iommu_heap_ops = { diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h index d494f7a7..37ababc3 100644 --- a/drivers/gpu/ion/ion_priv.h +++ b/drivers/gpu/ion/ion_priv.h @@ -144,7 +144,7 @@ struct ion_heap_ops { unsigned long flags); void (*unmap_iommu)(struct ion_iommu_map *data); int (*print_debug)(struct ion_heap *heap, struct seq_file *s, - const struct rb_root *mem_map); + const struct list_head *mem_map); int (*secure_heap)(struct ion_heap *heap, int version, void *data); int (*unsecure_heap)(struct ion_heap *heap, int version, void *data); }; @@ -178,7 +178,7 @@ struct ion_heap { /** * struct mem_map_data - represents information about the memory map for a heap - * @node: rb node used to store in the tree of mem_map_data + * @node: list node used to store in the list of mem_map_data * @addr: start address of memory region. * @addr: end address of memory region. * @size: size of memory region @@ -186,7 +186,7 @@ struct ion_heap { * */ struct mem_map_data { - struct rb_node node; + struct list_head node; unsigned long addr; unsigned long addr_end; unsigned long size; diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c index 6cac7c59..50ec2ecf 100644 --- a/drivers/gpu/ion/ion_system_heap.c +++ b/drivers/gpu/ion/ion_system_heap.c @@ -27,6 +27,8 @@ #include "ion_priv.h" #include #include +#include +#include static atomic_t system_heap_allocated; static atomic_t system_contig_heap_allocated; @@ -183,15 +185,30 @@ int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer, switch (cmd) { case ION_IOC_CLEAN_CACHES: - dmac_clean_range(vaddr, vaddr + length); + if (!vaddr) + dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_TO_DEVICE); + else + dmac_clean_range(vaddr, vaddr + length); outer_cache_op = outer_clean_range; break; case ION_IOC_INV_CACHES: - dmac_inv_range(vaddr, vaddr + length); + if (!vaddr) + dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_FROM_DEVICE); + else + dmac_inv_range(vaddr, vaddr + length); outer_cache_op = outer_inv_range; break; case ION_IOC_CLEAN_INV_CACHES: - dmac_flush_range(vaddr, vaddr + length); + if (!vaddr) { + dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_TO_DEVICE); + dma_sync_sg_for_cpu(NULL, buffer->sg_table->sgl, + buffer->sg_table->nents, DMA_FROM_DEVICE); + } else { + dmac_flush_range(vaddr, vaddr + length); + } outer_cache_op = outer_flush_range; break; default: @@ -221,7 +238,7 @@ int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer, } static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s, - const struct rb_root *unused) + const struct list_head *unused) { seq_printf(s, "total bytes currently allocated: %lx\n", (unsigned long) atomic_read(&system_heap_allocated)); @@ -254,6 +271,14 @@ int ion_system_heap_map_iommu(struct ion_buffer *buffer, data->mapped_size = iova_length; extra = iova_length - buffer->size; + /* Use the biggest alignment to allow bigger IOMMU mappings. + * Use the first entry since the first entry will always be the + * biggest entry. To take advantage of bigger mapping sizes both the + * VA and PA addresses have to be aligned to the biggest size. + */ + if (table->sgl->length > align) + align = table->sgl->length; + ret = msm_allocate_iova_address(domain_num, partition_num, data->mapped_size, align, &data->iova_addr); @@ -432,7 +457,7 @@ int ion_system_contig_heap_cache_ops(struct ion_heap *heap, static int ion_system_contig_print_debug(struct ion_heap *heap, struct seq_file *s, - const struct rb_root *unused) + const struct list_head *unused) { seq_printf(s, "total bytes currently allocated: %lx\n", (unsigned long) atomic_read(&system_contig_heap_allocated)); @@ -482,7 +507,7 @@ int ion_system_contig_heap_map_iommu(struct ion_buffer *buffer, } page = virt_to_page(buffer->vaddr); - sglist = vmalloc(sizeof(*sglist)); + sglist = kmalloc(sizeof(*sglist), GFP_KERNEL); if (!sglist) goto out1; @@ -504,13 +529,13 @@ int ion_system_contig_heap_map_iommu(struct ion_buffer *buffer, if (ret) goto out2; } - vfree(sglist); + kfree(sglist); return ret; out2: iommu_unmap_range(domain, data->iova_addr, buffer->size); out1: - vfree(sglist); + kfree(sglist); msm_free_iova_address(data->iova_addr, domain_num, partition_num, data->mapped_size); out: diff --git a/drivers/gpu/ion/msm/ion_cp_common.h b/drivers/gpu/ion/msm/ion_cp_common.h index 0c08d86b..eec66e6f 100644 --- a/drivers/gpu/ion/msm/ion_cp_common.h +++ b/drivers/gpu/ion/msm/ion_cp_common.h @@ -15,7 +15,7 @@ #define ION_CP_COMMON_H #include -#include +#include #define ION_CP_V1 1 #define ION_CP_V2 2 diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c index 0507dcd5..d896391c 100644 --- a/drivers/gpu/ion/msm/msm_ion.c +++ b/drivers/gpu/ion/msm/msm_ion.c @@ -13,20 +13,96 @@ #include #include -#include +#include #include #include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include "../ion_priv.h" #include "ion_cp_common.h" +#define ION_COMPAT_STR "qcom,msm-ion" +#define ION_COMPAT_MEM_RESERVE_STR "qcom,msm-ion-reserve" + static struct ion_device *idev; static int num_heaps; static struct ion_heap **heaps; +struct ion_heap_desc { + unsigned int id; + enum ion_heap_type type; + const char *name; + unsigned int permission_type; +}; + + +static struct ion_heap_desc ion_heap_meta[] = { + { + .id = ION_SYSTEM_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM, + .name = ION_VMALLOC_HEAP_NAME, + }, + { + .id = ION_SYSTEM_CONTIG_HEAP_ID, + .type = ION_HEAP_TYPE_SYSTEM_CONTIG, + .name = ION_KMALLOC_HEAP_NAME, + }, + { + .id = ION_CP_MM_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MM_HEAP_NAME, + .permission_type = IPT_TYPE_MM_CARVEOUT, + }, + { + .id = ION_MM_FIRMWARE_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_MM_FIRMWARE_HEAP_NAME, + }, + { + .id = ION_CP_MFC_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_MFC_HEAP_NAME, + .permission_type = IPT_TYPE_MFC_SHAREDMEM, + }, + { + .id = ION_SF_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_SF_HEAP_NAME, + }, + { + .id = ION_IOMMU_HEAP_ID, + .type = ION_HEAP_TYPE_IOMMU, + .name = ION_IOMMU_HEAP_NAME, + }, + { + .id = ION_QSECOM_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_QSECOM_HEAP_NAME, + }, + { + .id = ION_AUDIO_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_AUDIO_HEAP_NAME, + }, + { + .id = ION_CP_WB_HEAP_ID, + .type = ION_HEAP_TYPE_CP, + .name = ION_WB_HEAP_NAME, + }, + { + .id = ION_CAMERA_HEAP_ID, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = ION_CAMERA_HEAP_NAME, + }, +}; + struct ion_client *msm_ion_client_create(unsigned int heap_mask, const char *name) { @@ -101,22 +177,9 @@ static void ion_set_base_address(struct ion_platform_heap *heap, struct ion_co_heap_pdata *co_heap_data, struct ion_cp_heap_pdata *cp_data) { - if (cp_data->reusable) { - const struct fmem_data *fmem_info = fmem_get_info(); - - if (!fmem_info) { - pr_err("fmem info pointer NULL!\n"); - BUG(); - } - - heap->base = fmem_info->phys - fmem_info->reserved_size_low; - cp_data->virt_addr = fmem_info->virt; - pr_info("ION heap %s using FMEM\n", shared_heap->name); - } else { - heap->base = msm_ion_get_base(heap->size + shared_heap->size, - shared_heap->memory_type, - co_heap_data->align); - } + heap->base = msm_ion_get_base(heap->size + shared_heap->size, + shared_heap->memory_type, + co_heap_data->align); if (heap->base) { shared_heap->base = heap->base + heap->size; cp_data->secure_base = heap->base; @@ -142,15 +205,6 @@ static void allocate_co_memory(struct ion_platform_heap *heap, struct ion_cp_heap_pdata *cp_data = (struct ion_cp_heap_pdata *) shared_heap->extra_data; if (cp_data->fixed_position == FIXED_MIDDLE) { - const struct fmem_data *fmem_info = - fmem_get_info(); - - if (!fmem_info) { - pr_err("fmem info pointer NULL!\n"); - BUG(); - } - - cp_data->virt_addr = fmem_info->virt; if (!cp_data->secure_base) { cp_data->secure_base = heap->base; cp_data->secure_size = @@ -192,7 +246,7 @@ static void msm_ion_allocate(struct ion_platform_heap *heap) if (!heap->base && heap->extra_data) { unsigned int align = 0; - switch (heap->type) { + switch ((int) heap->type) { case ION_HEAP_TYPE_CARVEOUT: align = ((struct ion_co_heap_pdata *) heap->extra_data)->align; @@ -202,17 +256,6 @@ static void msm_ion_allocate(struct ion_platform_heap *heap) struct ion_cp_heap_pdata *data = (struct ion_cp_heap_pdata *) heap->extra_data; - if (data->reusable) { - const struct fmem_data *fmem_info = - fmem_get_info(); - heap->base = fmem_info->phys; - data->virt_addr = fmem_info->virt; - pr_info("ION heap %s using FMEM\n", heap->name); - } else if (data->mem_is_fmem) { - const struct fmem_data *fmem_info = - fmem_get_info(); - heap->base = fmem_info->phys + fmem_info->size; - } align = data->align; break; } @@ -269,11 +312,339 @@ static void check_for_heap_overlap(const struct ion_platform_heap heap_list[], } } +static int msm_init_extra_data(struct ion_platform_heap *heap, + const struct ion_heap_desc *heap_desc) +{ + int ret = 0; + + switch ((int) heap->type) { + case ION_HEAP_TYPE_CP: + { + heap->extra_data = kzalloc(sizeof(struct ion_cp_heap_pdata), + GFP_KERNEL); + if (!heap->extra_data) { + ret = -ENOMEM; + } else { + struct ion_cp_heap_pdata *extra = heap->extra_data; + extra->permission_type = heap_desc->permission_type; + } + break; + } + case ION_HEAP_TYPE_CARVEOUT: + { + heap->extra_data = kzalloc(sizeof(struct ion_co_heap_pdata), + GFP_KERNEL); + if (!heap->extra_data) + ret = -ENOMEM; + break; + } + default: + heap->extra_data = 0; + break; + } + return ret; +} + +static int msm_ion_populate_heap(struct ion_platform_heap *heap) +{ + unsigned int i; + int ret = -EINVAL; + unsigned int len = ARRAY_SIZE(ion_heap_meta); + for (i = 0; i < len; ++i) { + if (ion_heap_meta[i].id == heap->id) { + heap->name = ion_heap_meta[i].name; + heap->type = ion_heap_meta[i].type; + ret = msm_init_extra_data(heap, &ion_heap_meta[i]); + break; + } + } + if (ret) + pr_err("%s: Unable to populate heap, error: %d", __func__, ret); + return ret; +} + +static void free_pdata(const struct ion_platform_data *pdata) +{ + unsigned int i; + for (i = 0; i < pdata->nr; ++i) + kfree(pdata->heaps[i].extra_data); + kfree(pdata); +} + +static int memtype_to_ion_memtype[] = { + [MEMTYPE_SMI_KERNEL] = ION_SMI_TYPE, + [MEMTYPE_SMI] = ION_SMI_TYPE, + [MEMTYPE_EBI0] = ION_EBI_TYPE, + [MEMTYPE_EBI1] = ION_EBI_TYPE, +}; + +static void msm_ion_get_heap_align(struct device_node *node, + struct ion_platform_heap *heap) +{ + unsigned int val; + + int ret = of_property_read_u32(node, "qcom,heap-align", &val); + if (!ret) { + switch ((int) heap->type) { + case ION_HEAP_TYPE_CP: + { + struct ion_cp_heap_pdata *extra = + heap->extra_data; + extra->align = val; + break; + } + case ION_HEAP_TYPE_CARVEOUT: + { + struct ion_co_heap_pdata *extra = + heap->extra_data; + extra->align = val; + break; + } + default: + pr_err("ION-heap %s: Cannot specify alignment for this type of heap\n", + heap->name); + break; + } + } +} + +static int msm_ion_get_heap_size(struct device_node *node, + struct ion_platform_heap *heap) +{ + unsigned int val; + int ret = 0; + const char *memory_name_prop; + + ret = of_property_read_u32(node, "qcom,memory-reservation-size", &val); + if (!ret) { + heap->size = val; + ret = of_property_read_string(node, + "qcom,memory-reservation-type", + &memory_name_prop); + + if (!ret && memory_name_prop) { + val = msm_get_memory_type_from_name(memory_name_prop); + if (val < 0) { + ret = -EINVAL; + goto out; + } + heap->memory_type = memtype_to_ion_memtype[val]; + } + if (heap->size && (ret || !memory_name_prop)) { + pr_err("%s: Need to specify reservation type\n", + __func__); + ret = -EINVAL; + } + } else { + ret = 0; + } +out: + return ret; +} + + +static void msm_ion_get_heap_adjacent(struct device_node *node, + struct ion_platform_heap *heap) +{ + unsigned int val; + int ret = of_property_read_u32(node, "qcom,heap-adjacent", &val); + if (!ret) { + switch (heap->type) { + case ION_HEAP_TYPE_CARVEOUT: + { + struct ion_co_heap_pdata *extra = heap->extra_data; + extra->adjacent_mem_id = val; + break; + } + default: + pr_err("ION-heap %s: Cannot specify adjcent mem id for this type of heap\n", + heap->name); + break; + } + } else { + switch (heap->type) { + case ION_HEAP_TYPE_CARVEOUT: + { + struct ion_co_heap_pdata *extra = heap->extra_data; + extra->adjacent_mem_id = INVALID_HEAP_ID; + break; + } + default: + break; + } + } +} + +static struct ion_platform_data *msm_ion_parse_dt( + const struct device_node *dt_node) +{ + struct ion_platform_data *pdata = 0; + struct device_node *node; + uint32_t val = 0; + int ret = 0; + uint32_t num_heaps = 0; + int idx = 0; + + for_each_child_of_node(dt_node, node) + num_heaps++; + + if (!num_heaps) + return ERR_PTR(-EINVAL); + + pdata = kzalloc(sizeof(struct ion_platform_data) + + num_heaps*sizeof(struct ion_platform_heap), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->nr = num_heaps; + + for_each_child_of_node(dt_node, node) { + /** + * TODO: Replace this with of_get_address() when this patch + * gets merged: http:// + * permalink.gmane.org/gmane.linux.drivers.devicetree/18614 + */ + ret = of_property_read_u32(node, "reg", &val); + if (ret) { + pr_err("%s: Unable to find reg key", __func__); + goto free_heaps; + } + pdata->heaps[idx].id = val; + + ret = msm_ion_populate_heap(&pdata->heaps[idx]); + if (ret) + goto free_heaps; + + msm_ion_get_heap_align(node, &pdata->heaps[idx]); + + ret = msm_ion_get_heap_size(node, &pdata->heaps[idx]); + if (ret) + goto free_heaps; + + msm_ion_get_heap_adjacent(node, &pdata->heaps[idx]); + + ++idx; + } + return pdata; + +free_heaps: + free_pdata(pdata); + return ERR_PTR(ret); +} + +static int check_vaddr_bounds(unsigned long start, unsigned long end) +{ + struct mm_struct *mm = current->active_mm; + struct vm_area_struct *vma; + int ret = 1; + + if (end < start) + goto out; + + down_read(&mm->mmap_sem); + vma = find_vma(mm, start); + if (vma && vma->vm_start < end) { + if (start < vma->vm_start) + goto out_up; + if (end > vma->vm_end) + goto out_up; + ret = 0; + } + +out_up: + up_read(&mm->mmap_sem); +out: + return ret; +} + +static long msm_ion_custom_ioctl(struct ion_client *client, + unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case ION_IOC_CLEAN_CACHES: + case ION_IOC_INV_CACHES: + case ION_IOC_CLEAN_INV_CACHES: + { + struct ion_flush_data data; + unsigned long start, end; + struct ion_handle *handle = NULL; + int ret; + + if (copy_from_user(&data, (void __user *)arg, + sizeof(struct ion_flush_data))) + return -EFAULT; + + start = (unsigned long) data.vaddr; + end = (unsigned long) data.vaddr + data.length; + + if (start && check_vaddr_bounds(start, end)) { + pr_err("%s: virtual address %p is out of bounds\n", + __func__, data.vaddr); + return -EINVAL; + } + + if (!data.handle) { + handle = ion_import_dma_buf(client, data.fd); + if (IS_ERR(handle)) { + pr_info("%s: Could not import handle: %d\n", + __func__, (int)handle); + return -EINVAL; + } + } + + ret = ion_do_cache_op(client, + data.handle ? data.handle : handle, + data.vaddr, data.offset, data.length, + cmd); + + if (!data.handle) + ion_free(client, handle); + + if (ret < 0) + return ret; + break; + + } + case ION_IOC_GET_FLAGS: + { + struct ion_flag_data data; + int ret; + if (copy_from_user(&data, (void __user *)arg, + sizeof(struct ion_flag_data))) + return -EFAULT; + + ret = ion_handle_get_flags(client, data.handle, &data.flags); + if (ret < 0) + return ret; + if (copy_to_user((void __user *)arg, &data, + sizeof(struct ion_flag_data))) + return -EFAULT; + break; + } + default: + return -ENOTTY; + } + return 0; +} + static int msm_ion_probe(struct platform_device *pdev) { - struct ion_platform_data *pdata = pdev->dev.platform_data; - int err; + struct ion_platform_data *pdata; + unsigned int pdata_needs_to_be_freed; + int err = -1; int i; + if (pdev->dev.of_node) { + pdata = msm_ion_parse_dt(pdev->dev.of_node); + if (IS_ERR(pdata)) { + err = PTR_ERR(pdata); + goto out; + } + pdata_needs_to_be_freed = 1; + } else { + pdata = pdev->dev.platform_data; + pdata_needs_to_be_freed = 0; + } num_heaps = pdata->nr; @@ -284,7 +655,7 @@ static int msm_ion_probe(struct platform_device *pdev) goto out; } - idev = ion_device_create(NULL); + idev = ion_device_create(msm_ion_custom_ioctl); if (IS_ERR_OR_NULL(idev)) { err = PTR_ERR(idev); goto freeheaps; @@ -315,6 +686,8 @@ static int msm_ion_probe(struct platform_device *pdev) ion_device_add_heap(idev, heaps[i]); } + if (pdata_needs_to_be_freed) + free_pdata(pdata); check_for_heap_overlap(pdata->heaps, num_heaps); platform_set_drvdata(pdev, idev); @@ -322,6 +695,8 @@ static int msm_ion_probe(struct platform_device *pdev) freeheaps: kfree(heaps); + if (pdata_needs_to_be_freed) + free_pdata(pdata); out: return err; } @@ -339,10 +714,19 @@ static int msm_ion_remove(struct platform_device *pdev) return 0; } +static struct of_device_id msm_ion_match_table[] = { + {.compatible = ION_COMPAT_STR}, + {}, +}; +EXPORT_COMPAT(ION_COMPAT_MEM_RESERVE_STR); + static struct platform_driver msm_ion_driver = { .probe = msm_ion_probe, .remove = msm_ion_remove, - .driver = { .name = "ion-msm" } + .driver = { + .name = "ion-msm", + .of_match_table = msm_ion_match_table, + }, }; static int __init msm_ion_init(void) diff --git a/drivers/gpu/msm/Kconfig b/drivers/gpu/msm/Kconfig new file mode 100644 index 00000000..ba63fbcb --- /dev/null +++ b/drivers/gpu/msm/Kconfig @@ -0,0 +1,98 @@ +config MSM_KGSL + tristate "MSM 3D Graphics driver" + default n + depends on ARCH_MSM && !ARCH_MSM7X00A && !ARCH_MSM7X25 + select GENERIC_ALLOCATOR + select FW_LOADER + ---help--- + 3D graphics driver. Required to use hardware accelerated + OpenGL ES 2.0 and 1.1. + +config MSM_KGSL_CFF_DUMP + bool "Enable KGSL Common File Format (CFF) Dump Feature [Use with caution]" + default n + depends on MSM_KGSL + select RELAY + ---help--- + This is an analysis and diagnostic feature only, and should only be + turned on during KGSL GPU diagnostics and will slow down the KGSL + performance sigificantly, hence *do not use in production builds*. + When enabled, CFF Dump is on at boot. It can be turned off at runtime + via 'echo 0 > /d/kgsl/cff_dump'. The log can be captured via + /d/kgsl-cff/cpu[0|1]. + +config MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP + bool "When selected will disable KGSL CFF Dump for context switches" + default n + depends on MSM_KGSL_CFF_DUMP + ---help--- + Dumping all the memory for every context switch can produce quite + huge log files, to reduce this, turn this feature on. + +config MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL + bool "Disable human readable CP_STAT fields in post-mortem dump" + default n + depends on MSM_KGSL + ---help--- + For a more compact kernel log the human readable output of + CP_STAT can be turned off with this option. + +config MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP + bool "Disable dumping current IB1 and IB2 in post-mortem dump" + default n + depends on MSM_KGSL + ---help--- + For a more compact kernel log the IB1 and IB2 embedded dump + can be turned off with this option. Some IB dumps take up + so much space that vital other information gets cut from the + post-mortem dump. + +config MSM_KGSL_PSTMRTMDMP_RB_HEX + bool "Use hex version for ring-buffer in post-mortem dump" + default n + depends on MSM_KGSL + ---help--- + Use hex version for the ring-buffer in the post-mortem dump, instead + of the human readable version. + +config MSM_KGSL_2D + tristate "MSM 2D graphics driver. Required for OpenVG" + default y + depends on MSM_KGSL && !ARCH_MSM7X27 && !ARCH_MSM7X27A && !(ARCH_QSD8X50 && !MSM_SOC_REV_A) + +config MSM_KGSL_DRM + bool "Build a DRM interface for the MSM_KGSL driver" + depends on MSM_KGSL && DRM + +config KGSL_PER_PROCESS_PAGE_TABLE + bool "Enable Per Process page tables for the KGSL driver" + default n + depends on !MSM_KGSL_DRM + ---help--- + The MMU will use per process pagetables when enabled. + +config MSM_KGSL_PAGE_TABLE_SIZE + hex "Size of pagetables" + default 0xFFF0000 + ---help--- + Sets the pagetable size used by the MMU. The max value + is 0xFFF0000 or (256M - 64K). + +config MSM_KGSL_PAGE_TABLE_COUNT + int "Minimum of concurrent pagetables to support" + default 8 + depends on KGSL_PER_PROCESS_PAGE_TABLE + ---help--- + Specify the number of pagetables to allocate at init time + This is the number of concurrent processes that are guaranteed to + to run at any time. Additional processes can be created dynamically + assuming there is enough contiguous memory to allocate the pagetable. + +config MSM_KGSL_MMU_PAGE_FAULT + bool "Force the GPU MMU to page fault for unmapped regions" + default y + +config MSM_KGSL_DISABLE_SHADOW_WRITES + bool "Disable register shadow writes for context switches" + default n + depends on MSM_KGSL diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index dfc4b8da..fec53633 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -47,5 +47,3 @@ msm_z180-objs = $(msm_z180-y) obj-$(CONFIG_MSM_KGSL) += msm_kgsl_core.o obj-$(CONFIG_MSM_KGSL) += msm_adreno.o obj-$(CONFIG_MSM_KGSL_2D) += msm_z180.o - -CFLAGS_adreno.o += -Wframe-larger-than=2048 diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h index c70c4eb8..e1e2c153 100644 --- a/drivers/gpu/msm/a2xx_reg.h +++ b/drivers/gpu/msm/a2xx_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2012,2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -183,6 +183,7 @@ union reg_cp_rb_cntl { #define SQ_INT_CNTL__VS_WATCHDOG_MASK 0x00000002L #define RBBM_INT_CNTL__RDERR_INT_MASK 0x00000001L +#define RBBM_INT_CNTL__PROTECT_INT_MASK 0x00100000L #define RBBM_INT_CNTL__DISPLAY_UPDATE_INT_MASK 0x00000002L #define RBBM_INT_CNTL__GUI_IDLE_INT_MASK 0x00080000L @@ -291,6 +292,10 @@ union reg_cp_rb_cntl { #define REG_RBBM_PERFCOUNTER1_HI 0x0398 #define REG_RBBM_PERFCOUNTER1_LO 0x0397 +#define REG_SQ_PERFCOUNTER3_SELECT 0x0DCB +#define REG_SQ_PERFCOUNTER3_LO 0x0DD2 +#define REG_SQ_PERFCOUNTER3_HI 0x0DD3 + #define REG_MASTER_INT_SIGNAL 0x03B7 #define REG_PA_CL_VPORT_XSCALE 0x210F @@ -332,6 +337,24 @@ union reg_cp_rb_cntl { #define REG_RBBM_SOFT_RESET 0x003C #define REG_RBBM_STATUS 0x05D0 +/*A2XX Protection */ +#define REG_RBBM_PROTECT_0 0x0140 +#define REG_RBBM_PROTECT_1 0x0141 +#define REG_RBBM_PROTECT_2 0x0142 +#define REG_RBBM_PROTECT_3 0x0143 +#define REG_RBBM_PROTECT_4 0x0144 +#define REG_RBBM_PROTECT_5 0x0145 +#define REG_RBBM_PROTECT_6 0x0146 +#define REG_RBBM_PROTECT_7 0x0147 +#define REG_RBBM_PROTECT_8 0x0148 +#define REG_RBBM_PROTECT_9 0x0149 +#define REG_RBBM_PROTECT_A 0x014A +#define REG_RBBM_PROTECT_B 0x014B +#define REG_RBBM_PROTECT_C 0x014C +#define REG_RBBM_PROTECT_D 0x014D +#define REG_RBBM_PROTECT_E 0x014E +#define REG_RBBM_PROTECT_F 0x014F + #define REG_RB_COLORCONTROL 0x2202 #define REG_RB_COLOR_DEST_MASK 0x2326 #define REG_RB_COLOR_MASK 0x2104 @@ -401,6 +424,7 @@ union reg_cp_rb_cntl { #define REG_A225_GRAS_UCP0X 0x2340 #define REG_A225_GRAS_UCP5W 0x2357 #define REG_A225_GRAS_UCP_ENABLED 0x2360 +#define REG_VSC_BINNING_ENABLE 0x0C00 /* Debug registers used by snapshot */ #define REG_PA_SU_DEBUG_CNTL 0x0C80 diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h index be9f3ace..21d47595 100644 --- a/drivers/gpu/msm/a3xx_reg.h +++ b/drivers/gpu/msm/a3xx_reg.h @@ -66,15 +66,103 @@ #define A3XX_RBBM_INT_0_MASK 0x063 #define A3XX_RBBM_INT_0_STATUS 0x064 #define A3XX_RBBM_PERFCTR_CTL 0x80 +#define A3XX_RBBM_PERFCTR_LOAD_CMD0 0x81 +#define A3XX_RBBM_PERFCTR_LOAD_CMD1 0x82 +#define A3XX_RBBM_PERFCTR_LOAD_VALUE_LO 0x84 +#define A3XX_RBBM_PERFCTR_LOAD_VALUE_HI 0x85 +#define A3XX_RBBM_PERFCOUNTER0_SELECT 0x86 +#define A3XX_RBBM_PERFCOUNTER1_SELECT 0x87 #define A3XX_RBBM_GPU_BUSY_MASKED 0x88 +#define A3XX_RBBM_PERFCTR_CP_0_LO 0x90 +#define A3XX_RBBM_PERFCTR_CP_0_HI 0x91 +#define A3XX_RBBM_PERFCTR_RBBM_0_LO 0x92 +#define A3XX_RBBM_PERFCTR_RBBM_0_HI 0x93 +#define A3XX_RBBM_PERFCTR_RBBM_1_LO 0x94 +#define A3XX_RBBM_PERFCTR_RBBM_1_HI 0x95 +#define A3XX_RBBM_PERFCTR_PC_0_LO 0x96 +#define A3XX_RBBM_PERFCTR_PC_0_HI 0x97 +#define A3XX_RBBM_PERFCTR_PC_1_LO 0x98 +#define A3XX_RBBM_PERFCTR_PC_1_HI 0x99 +#define A3XX_RBBM_PERFCTR_PC_2_LO 0x9A +#define A3XX_RBBM_PERFCTR_PC_2_HI 0x9B +#define A3XX_RBBM_PERFCTR_PC_3_LO 0x9C +#define A3XX_RBBM_PERFCTR_PC_3_HI 0x9D +#define A3XX_RBBM_PERFCTR_VFD_0_LO 0x9E +#define A3XX_RBBM_PERFCTR_VFD_0_HI 0x9F +#define A3XX_RBBM_PERFCTR_VFD_1_LO 0xA0 +#define A3XX_RBBM_PERFCTR_VFD_1_HI 0xA1 +#define A3XX_RBBM_PERFCTR_HLSQ_0_LO 0xA2 +#define A3XX_RBBM_PERFCTR_HLSQ_0_HI 0xA3 +#define A3XX_RBBM_PERFCTR_HLSQ_1_LO 0xA4 +#define A3XX_RBBM_PERFCTR_HLSQ_1_HI 0xA5 +#define A3XX_RBBM_PERFCTR_HLSQ_2_LO 0xA6 +#define A3XX_RBBM_PERFCTR_HLSQ_2_HI 0xA7 +#define A3XX_RBBM_PERFCTR_HLSQ_3_LO 0xA8 +#define A3XX_RBBM_PERFCTR_HLSQ_3_HI 0xA9 +#define A3XX_RBBM_PERFCTR_HLSQ_4_LO 0xAA +#define A3XX_RBBM_PERFCTR_HLSQ_4_HI 0xAB +#define A3XX_RBBM_PERFCTR_HLSQ_5_LO 0xAC +#define A3XX_RBBM_PERFCTR_HLSQ_5_HI 0xAD +#define A3XX_RBBM_PERFCTR_VPC_0_LO 0xAE +#define A3XX_RBBM_PERFCTR_VPC_0_HI 0xAF +#define A3XX_RBBM_PERFCTR_VPC_1_LO 0xB0 +#define A3XX_RBBM_PERFCTR_VPC_1_HI 0xB1 +#define A3XX_RBBM_PERFCTR_TSE_0_LO 0xB2 +#define A3XX_RBBM_PERFCTR_TSE_0_HI 0xB3 +#define A3XX_RBBM_PERFCTR_TSE_1_LO 0xB4 +#define A3XX_RBBM_PERFCTR_TSE_1_HI 0xB5 +#define A3XX_RBBM_PERFCTR_RAS_0_LO 0xB6 +#define A3XX_RBBM_PERFCTR_RAS_0_HI 0xB7 +#define A3XX_RBBM_PERFCTR_RAS_1_LO 0xB8 +#define A3XX_RBBM_PERFCTR_RAS_1_HI 0xB9 +#define A3XX_RBBM_PERFCTR_UCHE_0_LO 0xBA +#define A3XX_RBBM_PERFCTR_UCHE_0_HI 0xBB +#define A3XX_RBBM_PERFCTR_UCHE_1_LO 0xBC +#define A3XX_RBBM_PERFCTR_UCHE_1_HI 0xBD +#define A3XX_RBBM_PERFCTR_UCHE_2_LO 0xBE +#define A3XX_RBBM_PERFCTR_UCHE_2_HI 0xBF +#define A3XX_RBBM_PERFCTR_UCHE_3_LO 0xC0 +#define A3XX_RBBM_PERFCTR_UCHE_3_HI 0xC1 +#define A3XX_RBBM_PERFCTR_UCHE_4_LO 0xC2 +#define A3XX_RBBM_PERFCTR_UCHE_4_HI 0xC3 +#define A3XX_RBBM_PERFCTR_UCHE_5_LO 0xC4 +#define A3XX_RBBM_PERFCTR_UCHE_5_HI 0xC5 +#define A3XX_RBBM_PERFCTR_TP_0_LO 0xC6 +#define A3XX_RBBM_PERFCTR_TP_0_HI 0xC7 +#define A3XX_RBBM_PERFCTR_TP_1_LO 0xC8 +#define A3XX_RBBM_PERFCTR_TP_1_HI 0xC9 +#define A3XX_RBBM_PERFCTR_TP_2_LO 0xCA +#define A3XX_RBBM_PERFCTR_TP_2_HI 0xCB +#define A3XX_RBBM_PERFCTR_TP_3_LO 0xCC +#define A3XX_RBBM_PERFCTR_TP_3_HI 0xCD +#define A3XX_RBBM_PERFCTR_TP_4_LO 0xCE +#define A3XX_RBBM_PERFCTR_TP_4_HI 0xCF +#define A3XX_RBBM_PERFCTR_TP_5_LO 0xD0 +#define A3XX_RBBM_PERFCTR_TP_5_HI 0xD1 +#define A3XX_RBBM_PERFCTR_SP_0_LO 0xD2 +#define A3XX_RBBM_PERFCTR_SP_0_HI 0xD3 +#define A3XX_RBBM_PERFCTR_SP_1_LO 0xD4 +#define A3XX_RBBM_PERFCTR_SP_1_HI 0xD5 +#define A3XX_RBBM_PERFCTR_SP_2_LO 0xD6 +#define A3XX_RBBM_PERFCTR_SP_2_HI 0xD7 +#define A3XX_RBBM_PERFCTR_SP_3_LO 0xD8 +#define A3XX_RBBM_PERFCTR_SP_3_HI 0xD9 +#define A3XX_RBBM_PERFCTR_SP_4_LO 0xDA +#define A3XX_RBBM_PERFCTR_SP_4_HI 0xDB #define A3XX_RBBM_PERFCTR_SP_5_LO 0xDC #define A3XX_RBBM_PERFCTR_SP_5_HI 0xDD #define A3XX_RBBM_PERFCTR_SP_6_LO 0xDE #define A3XX_RBBM_PERFCTR_SP_6_HI 0xDF #define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0 #define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1 +#define A3XX_RBBM_PERFCTR_RB_0_LO 0xE2 +#define A3XX_RBBM_PERFCTR_RB_0_HI 0xE3 +#define A3XX_RBBM_PERFCTR_RB_1_LO 0xE4 +#define A3XX_RBBM_PERFCTR_RB_1_HI 0xE5 + #define A3XX_RBBM_RBBM_CTL 0x100 -#define A3XX_RBBM_RBBM_CTL 0x100 +#define A3XX_RBBM_PERFCTR_PWR_0_LO 0x0EA +#define A3XX_RBBM_PERFCTR_PWR_0_HI 0x0EB #define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC #define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED #define A3XX_RBBM_DEBUG_BUS_CTL 0x111 @@ -90,6 +178,7 @@ #define A3XX_CP_MERCIU_DATA2 0x1D3 #define A3XX_CP_MEQ_ADDR 0x1DA #define A3XX_CP_MEQ_DATA 0x1DB +#define A3XX_CP_PERFCOUNTER_SELECT 0x445 #define A3XX_CP_HW_FAULT 0x45C #define A3XX_CP_AHB_FAULT 0x54D #define A3XX_CP_PROTECT_CTRL 0x45E @@ -138,6 +227,14 @@ #define A3XX_VSC_PIPE_CONFIG_7 0xC1B #define A3XX_VSC_PIPE_DATA_ADDRESS_7 0xC1C #define A3XX_VSC_PIPE_DATA_LENGTH_7 0xC1D +#define A3XX_PC_PERFCOUNTER0_SELECT 0xC48 +#define A3XX_PC_PERFCOUNTER1_SELECT 0xC49 +#define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A +#define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B +#define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88 +#define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89 +#define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A +#define A3XX_GRAS_PERFCOUNTER3_SELECT 0xC8B #define A3XX_GRAS_CL_USER_PLANE_X0 0xCA0 #define A3XX_GRAS_CL_USER_PLANE_Y0 0xCA1 #define A3XX_GRAS_CL_USER_PLANE_Z0 0xCA2 @@ -163,14 +260,42 @@ #define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6 #define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7 #define A3XX_RB_GMEM_BASE_ADDR 0xCC0 +#define A3XX_RB_PERFCOUNTER0_SELECT 0xCC6 +#define A3XX_RB_PERFCOUNTER1_SELECT 0xCC7 +#define A3XX_HLSQ_PERFCOUNTER0_SELECT 0xE00 +#define A3XX_HLSQ_PERFCOUNTER1_SELECT 0xE01 +#define A3XX_HLSQ_PERFCOUNTER2_SELECT 0xE02 +#define A3XX_HLSQ_PERFCOUNTER3_SELECT 0xE03 +#define A3XX_HLSQ_PERFCOUNTER4_SELECT 0xE04 +#define A3XX_HLSQ_PERFCOUNTER5_SELECT 0xE05 #define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44 +#define A3XX_VFD_PERFCOUNTER1_SELECT 0xE45 #define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61 #define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62 +#define A3XX_VPC_PERFCOUNTER0_SELECT 0xE64 +#define A3XX_VPC_PERFCOUNTER1_SELECT 0xE65 #define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82 +#define A3XX_UCHE_PERFCOUNTER0_SELECT 0xE84 +#define A3XX_UCHE_PERFCOUNTER1_SELECT 0xE85 +#define A3XX_UCHE_PERFCOUNTER2_SELECT 0xE86 +#define A3XX_UCHE_PERFCOUNTER3_SELECT 0xE87 +#define A3XX_UCHE_PERFCOUNTER4_SELECT 0xE88 +#define A3XX_UCHE_PERFCOUNTER5_SELECT 0xE89 #define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0 +#define A3XX_SP_PERFCOUNTER0_SELECT 0xEC4 +#define A3XX_SP_PERFCOUNTER1_SELECT 0xEC5 +#define A3XX_SP_PERFCOUNTER2_SELECT 0xEC6 +#define A3XX_SP_PERFCOUNTER3_SELECT 0xEC7 +#define A3XX_SP_PERFCOUNTER4_SELECT 0xEC8 #define A3XX_SP_PERFCOUNTER5_SELECT 0xEC9 #define A3XX_SP_PERFCOUNTER6_SELECT 0xECA #define A3XX_SP_PERFCOUNTER7_SELECT 0xECB +#define A3XX_TP_PERFCOUNTER0_SELECT 0xF04 +#define A3XX_TP_PERFCOUNTER1_SELECT 0xF05 +#define A3XX_TP_PERFCOUNTER2_SELECT 0xF06 +#define A3XX_TP_PERFCOUNTER3_SELECT 0xF07 +#define A3XX_TP_PERFCOUNTER4_SELECT 0xF08 +#define A3XX_TP_PERFCOUNTER5_SELECT 0xF09 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044 #define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048 @@ -232,12 +357,14 @@ #define A3XX_SP_VS_OUT_REG_7 0x22CE #define A3XX_SP_VS_VPC_DST_REG_0 0x22D0 #define A3XX_SP_VS_OBJ_OFFSET_REG 0x22D4 +#define A3XX_SP_VS_OBJ_START_REG 0x22D5 #define A3XX_SP_VS_PVT_MEM_ADDR_REG 0x22D7 #define A3XX_SP_VS_PVT_MEM_SIZE_REG 0x22D8 #define A3XX_SP_VS_LENGTH_REG 0x22DF #define A3XX_SP_FS_CTRL_REG0 0x22E0 #define A3XX_SP_FS_CTRL_REG1 0x22E1 #define A3XX_SP_FS_OBJ_OFFSET_REG 0x22E2 +#define A3XX_SP_FS_OBJ_START_REG 0x22E3 #define A3XX_SP_FS_PVT_MEM_ADDR_REG 0x22E5 #define A3XX_SP_FS_PVT_MEM_SIZE_REG 0x22E6 #define A3XX_SP_FS_FLAT_SHAD_MODE_REG_0 0x22E8 @@ -269,10 +396,25 @@ #define A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x3058 #define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E #define A3XX_VBIF_OUT_AXI_AOOO 0x305F +#define A3XX_VBIF_PERF_CNT_EN 0x3070 +#define A3XX_VBIF_PERF_CNT_CLR 0x3071 +#define A3XX_VBIF_PERF_CNT_SEL 0x3072 +#define A3XX_VBIF_PERF_CNT0_LO 0x3073 +#define A3XX_VBIF_PERF_CNT0_HI 0x3074 +#define A3XX_VBIF_PERF_CNT1_LO 0x3075 +#define A3XX_VBIF_PERF_CNT1_HI 0x3076 +#define A3XX_VBIF_PERF_PWR_CNT0_LO 0x3077 +#define A3XX_VBIF_PERF_PWR_CNT0_HI 0x3078 +#define A3XX_VBIF_PERF_PWR_CNT1_LO 0x3079 +#define A3XX_VBIF_PERF_PWR_CNT1_HI 0x307a +#define A3XX_VBIF_PERF_PWR_CNT2_LO 0x307b +#define A3XX_VBIF_PERF_PWR_CNT2_HI 0x307c /* Bit flags for RBBM_CTL */ -#define RBBM_RBBM_CTL_RESET_PWR_CTR1 (1 << 1) -#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1 (1 << 17) +#define RBBM_RBBM_CTL_RESET_PWR_CTR0 BIT(0) +#define RBBM_RBBM_CTL_RESET_PWR_CTR1 BIT(1) +#define RBBM_RBBM_CTL_ENABLE_PWR_CTR0 BIT(16) +#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1 BIT(17) /* Various flags used by the context switch code */ @@ -537,7 +679,13 @@ #define RBBM_BLOCK_ID_MARB_3 0x2b /* RBBM_CLOCK_CTL default value */ -#define A3XX_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF +#define A305_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAA +#define A320_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF +#define A330_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAE +#define A330v2_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAA + +#define A330_RBBM_GPR0_CTL_DEFAULT 0x0AE2B8AE +#define A330v2_RBBM_GPR0_CTL_DEFAULT 0x0AA2A8AA /* COUNTABLE FOR SP PERFCOUNTER */ #define SP_FS_FULL_ALU_INSTRUCTIONS 0x0E @@ -545,4 +693,20 @@ #define SP0_ICL1_MISSES 0x1A #define SP_FS_CFLOW_INSTRUCTIONS 0x0C +/* VBIF PERFCOUNTER ENA/CLR values */ +#define VBIF_PERF_CNT_0 BIT(0) +#define VBIF_PERF_CNT_1 BIT(1) +#define VBIF_PERF_PWR_CNT_0 BIT(2) +#define VBIF_PERF_PWR_CNT_1 BIT(3) +#define VBIF_PERF_PWR_CNT_2 BIT(4) + +/* VBIF PERFCOUNTER SEL values */ +#define VBIF_PERF_CNT_0_SEL 0 +#define VBIF_PERF_CNT_0_SEL_MASK 0x7f +#define VBIF_PERF_CNT_1_SEL 8 +#define VBIF_PERF_CNT_1_SEL_MASK 0x7f00 + +/* VBIF countables */ +#define VBIF_DDR_TOTAL_CYCLES 110 + #endif diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index b49261ce..8a1894e7 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -73,6 +73,13 @@ | (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT) \ | (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT)) +/*default log levels is error for everything*/ +#define KGSL_LOG_LEVEL_DEFAULT 3 + +#ifndef CONFIG_DEBUG_FS +unsigned int kgsl_cff_dump_enable; +#endif + static const struct kgsl_functable adreno_functable; static struct adreno_device device_3d0 = { @@ -101,6 +108,7 @@ static struct adreno_device device_3d0 = { }, .iomemname = KGSL_3D0_REG_MEMORY, .ftbl = &adreno_functable, +#if 0 #ifdef CONFIG_HAS_EARLYSUSPEND .display_off = { .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING, @@ -108,6 +116,14 @@ static struct adreno_device device_3d0 = { .resume = kgsl_late_resume_driver, }, #endif +#endif + .cmd_log = KGSL_LOG_LEVEL_DEFAULT, + .ctxt_log = KGSL_LOG_LEVEL_DEFAULT, + .drv_log = KGSL_LOG_LEVEL_DEFAULT, + .mem_log = KGSL_LOG_LEVEL_DEFAULT, + .pwr_log = KGSL_LOG_LEVEL_DEFAULT, + .ft_log = KGSL_LOG_LEVEL_DEFAULT, + .pm_dump_enable = 0, }, .gmem_base = 0, .gmem_size = SZ_256K, @@ -115,11 +131,15 @@ static struct adreno_device device_3d0 = { .pm4_fw = NULL, .wait_timeout = 0, /* in milliseconds, 0 means disabled */ .ib_check_level = 0, + .ft_policy = KGSL_FT_DEFAULT_POLICY, + .ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY, + .fast_hang_detect = 1, + .long_ib_detect = 1, }; /* This set of registers are used for Hang detection * If the values of these registers are same after - * KGSL_TIMEOUT_PART time, GPU hang is reported in + * KGSL_TIMEOUT_HANG_DETECT time, GPU hang is reported in * kernel log. * *****ALERT******ALERT********ALERT************* * Order of registers below is important, registers @@ -129,7 +149,7 @@ static struct adreno_device device_3d0 = { #define LONG_IB_DETECT_REG_INDEX_START 1 #define LONG_IB_DETECT_REG_INDEX_END 5 -unsigned int ft_detect_regs[] = { +unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT] = { A3XX_RBBM_STATUS, REG_CP_RB_RPTR, /* LONG_IB_DETECT_REG_INDEX_START */ REG_CP_IB1_BASE, @@ -144,8 +164,6 @@ unsigned int ft_detect_regs[] = { 0 }; -const unsigned int ft_detect_regs_count = ARRAY_SIZE(ft_detect_regs); - /* * This is the master list of all GPU cores that are supported by this * driver. @@ -206,11 +224,321 @@ static const struct { { ADRENO_REV_A320, 3, 2, ANY_ID, ANY_ID, "a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev, 512, 0, 2, SZ_512K, 0x3FF037, 0x3FF016 }, - { ADRENO_REV_A330, 3, 3, 0, 0, + { ADRENO_REV_A330, 3, 3, 0, ANY_ID, "a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev, 512, 0, 2, SZ_1M, NO_VER, NO_VER }, }; +static unsigned int adreno_isidle(struct kgsl_device *device); + +/** + * adreno_perfcounter_init: Reserve kernel performance counters + * @device: device to configure + * + * The kernel needs/wants a certain group of performance counters for + * its own activities. Reserve these performance counters at init time + * to ensure that they are always reserved for the kernel. The performance + * counters used by the kernel can be obtained by the user, but these + * performance counters will remain active as long as the device is alive. + */ + +static void adreno_perfcounter_init(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + if (adreno_dev->gpudev->perfcounter_init) + adreno_dev->gpudev->perfcounter_init(adreno_dev); +}; + +/** + * adreno_perfcounter_start: Enable performance counters + * @adreno_dev: Adreno device to configure + * + * Ensure all performance counters are enabled that are allocated. Since + * the device was most likely stopped, we can't trust that the counters + * are still valid so make it so. + */ + +static void adreno_perfcounter_start(struct adreno_device *adreno_dev) +{ + struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters; + struct adreno_perfcount_group *group; + unsigned int i, j; + + /* group id iter */ + for (i = 0; i < counters->group_count; i++) { + group = &(counters->groups[i]); + + /* countable iter */ + for (j = 0; j < group->reg_count; j++) { + if (group->regs[j].countable == + KGSL_PERFCOUNTER_NOT_USED) + continue; + + if (adreno_dev->gpudev->perfcounter_enable) + adreno_dev->gpudev->perfcounter_enable( + adreno_dev, i, j, + group->regs[j].countable); + } + } +} + +/** + * adreno_perfcounter_read_group: Determine which countables are in counters + * @adreno_dev: Adreno device to configure + * @reads: List of kgsl_perfcounter_read_groups + * @count: Length of list + * + * Read the performance counters for the groupid/countable pairs and return + * the 64 bit result for each pair + */ + +int adreno_perfcounter_read_group(struct adreno_device *adreno_dev, + struct kgsl_perfcounter_read_group __user *reads, unsigned int count) +{ + struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters; + struct adreno_perfcount_group *group; + struct kgsl_perfcounter_read_group *list = NULL; + unsigned int i, j; + int ret = 0; + + /* perfcounter get/put/query/read not allowed on a2xx */ + if (adreno_is_a2xx(adreno_dev)) + return -EINVAL; + + /* sanity check for later */ + if (!adreno_dev->gpudev->perfcounter_read) + return -EINVAL; + + /* sanity check params passed in */ + if (reads == NULL || count == 0 || count > 100) + return -EINVAL; + + list = kmalloc(sizeof(struct kgsl_perfcounter_read_group) * count, + GFP_KERNEL); + if (!list) + return -ENOMEM; + + if (copy_from_user(list, reads, + sizeof(struct kgsl_perfcounter_read_group) * count)) { + ret = -EFAULT; + goto done; + } + + /* list iterator */ + for (j = 0; j < count; j++) { + + list[j].value = 0; + + /* Verify that the group ID is within range */ + if (list[j].groupid >= counters->group_count) { + ret = -EINVAL; + goto done; + } + + group = &(counters->groups[list[j].groupid]); + + /* group/counter iterator */ + for (i = 0; i < group->reg_count; i++) { + if (group->regs[i].countable == list[j].countable) { + list[j].value = + adreno_dev->gpudev->perfcounter_read( + adreno_dev, list[j].groupid, + i, group->regs[i].offset); + break; + } + } + } + + /* write the data */ + if (copy_to_user(reads, list, + sizeof(struct kgsl_perfcounter_read_group) * + count) != 0) + ret = -EFAULT; + +done: + kfree(list); + return ret; +} + +/** + * adreno_perfcounter_query_group: Determine which countables are in counters + * @adreno_dev: Adreno device to configure + * @groupid: Desired performance counter group + * @countables: Return list of all countables in the groups counters + * @count: Max length of the array + * @max_counters: max counters for the groupid + * + * Query the current state of counters for the group. + */ + +int adreno_perfcounter_query_group(struct adreno_device *adreno_dev, + unsigned int groupid, unsigned int *countables, unsigned int count, + unsigned int *max_counters) +{ + struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters; + struct adreno_perfcount_group *group; + unsigned int i; + + *max_counters = 0; + + /* perfcounter get/put/query not allowed on a2xx */ + if (adreno_is_a2xx(adreno_dev)) + return -EINVAL; + + if (groupid >= counters->group_count) + return -EINVAL; + + group = &(counters->groups[groupid]); + *max_counters = group->reg_count; + + /* + * if NULL countable or *count of zero, return max reg_count in + * *max_counters and return success + */ + if (countables == NULL || count == 0) + return 0; + + /* + * Go through all available counters. Write upto *count * countable + * values. + */ + for (i = 0; i < group->reg_count && i < count; i++) { + if (copy_to_user(&countables[i], &(group->regs[i].countable), + sizeof(unsigned int)) != 0) + return -EFAULT; + } + + return 0; +} + +/** + * adreno_perfcounter_get: Try to put a countable in an available counter + * @adreno_dev: Adreno device to configure + * @groupid: Desired performance counter group + * @countable: Countable desired to be in a counter + * @offset: Return offset of the countable + * @flags: Used to setup kernel perf counters + * + * Try to place a countable in an available counter. If the countable is + * already in a counter, reference count the counter/countable pair resource + * and return success + */ + +int adreno_perfcounter_get(struct adreno_device *adreno_dev, + unsigned int groupid, unsigned int countable, unsigned int *offset, + unsigned int flags) +{ + struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters; + struct adreno_perfcount_group *group; + unsigned int i, empty = -1; + + /* always clear return variables */ + if (offset) + *offset = 0; + + /* perfcounter get/put/query not allowed on a2xx */ + if (adreno_is_a2xx(adreno_dev)) + return -EINVAL; + + if (groupid >= counters->group_count) + return -EINVAL; + + group = &(counters->groups[groupid]); + + /* + * Check if the countable is already associated with a counter. + * Refcount and return the offset, otherwise, try and find an empty + * counter and assign the countable to it. + */ + for (i = 0; i < group->reg_count; i++) { + if (group->regs[i].countable == countable) { + /* Countable already associated with counter */ + group->regs[i].refcount++; + group->regs[i].flags |= flags; + if (offset) + *offset = group->regs[i].offset; + return 0; + } else if (group->regs[i].countable == + KGSL_PERFCOUNTER_NOT_USED) { + /* keep track of unused counter */ + empty = i; + } + } + + /* no available counters, so do nothing else */ + if (empty == -1) + return -EBUSY; + + /* initialize the new counter */ + group->regs[empty].countable = countable; + group->regs[empty].refcount = 1; + + /* enable the new counter */ + adreno_dev->gpudev->perfcounter_enable(adreno_dev, groupid, empty, + countable); + + group->regs[empty].flags = flags; + + if (offset) + *offset = group->regs[empty].offset; + + return 0; +} + + +/** + * adreno_perfcounter_put: Release a countable from counter resource + * @adreno_dev: Adreno device to configure + * @groupid: Desired performance counter group + * @countable: Countable desired to be freed from a counter + * + * Put a performance counter/countable pair that was previously received. If + * noone else is using the countable, free up the counter for others. + */ +int adreno_perfcounter_put(struct adreno_device *adreno_dev, + unsigned int groupid, unsigned int countable) +{ + struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters; + struct adreno_perfcount_group *group; + + unsigned int i; + + /* perfcounter get/put/query not allowed on a2xx */ + if (adreno_is_a2xx(adreno_dev)) + return -EINVAL; + + if (groupid >= counters->group_count) + return -EINVAL; + + group = &(counters->groups[groupid]); + + for (i = 0; i < group->reg_count; i++) { + if (group->regs[i].countable == countable) { + if (group->regs[i].refcount > 0) { + group->regs[i].refcount--; + + /* + * book keeping to ensure we never free a + * perf counter used by kernel + */ + if (group->regs[i].flags && + group->regs[i].refcount == 0) + group->regs[i].refcount++; + + /* make available if not used */ + if (group->regs[i].refcount == 0) + group->regs[i].countable = + KGSL_PERFCOUNTER_NOT_USED; + } + + return 0; + } + } + + return -EINVAL; +} + static irqreturn_t adreno_irq_handler(struct kgsl_device *device) { irqreturn_t result; @@ -230,6 +558,8 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) /* Reset the time-out in our idle timer */ mod_timer_pending(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); + mod_timer_pending(&device->hang_timer, + (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT))); return result; } @@ -255,26 +585,29 @@ static int adreno_setup_pt(struct kgsl_device *device, struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; - result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc, - GSL_PT_PAGE_RV); + result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc); if (result) goto error; - result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc); if (result) goto unmap_buffer_desc; - result = kgsl_mmu_map_global(pagetable, &device->memstore, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + result = kgsl_mmu_map_global(pagetable, &device->memstore); if (result) goto unmap_memptrs_desc; - result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory); if (result) goto unmap_memstore_desc; + /* + * Set the mpu end to the last "normal" global memory we use. + * For the IOMMU, this will be used to restrict access to the + * mapped registers. + */ + device->mh.mpu_range = device->mmu.setstate_memory.gpuaddr + + device->mmu.setstate_memory.size; return result; unmap_memstore_desc: @@ -290,31 +623,62 @@ static int adreno_setup_pt(struct kgsl_device *device, return result; } +/* + * adreno_use_default_setstate() - Use CPU instead of the GPU to manage the mmu? + * @adreno_dev: the device + * + * In many cases it is preferable to poke the iommu or gpummu directly rather + * than using the GPU command stream. If we are idle or trying to go to a low + * power state, using the command stream will be slower and asynchronous, which + * needlessly complicates the power state transitions. Additionally, + * the hardware simulators do not support command stream MMU operations so + * the command stream can never be used if we are capturing CFF data. + * + */ +static bool adreno_use_default_setstate(struct adreno_device *adreno_dev) +{ + return (adreno_isidle(&adreno_dev->dev) || + KGSL_STATE_ACTIVE != adreno_dev->dev.state || + adreno_dev->dev.active_cnt == 0 || + kgsl_cff_dump_enable); +} + static void adreno_iommu_setstate(struct kgsl_device *device, unsigned int context_id, uint32_t flags) { unsigned int pt_val, reg_pt_val; - unsigned int link[250]; - unsigned int *cmds = &link[0]; - int sizedwords = 0; + unsigned int *link = NULL, *cmds; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int num_iommu_units, i; struct kgsl_context *context; struct adreno_context *adreno_ctx = NULL; - if (!adreno_dev->drawctxt_active) + /* + * If we're idle and we don't need to use the GPU to save context + * state, use the CPU instead of the GPU to reprogram the + * iommu for simplicity's sake. + */ + if (adreno_use_default_setstate(adreno_dev)) return kgsl_mmu_device_setstate(&device->mmu, flags); + num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu); - context = idr_find(&device->context_idr, context_id); + context = kgsl_context_get(device, context_id); + if (context == NULL) return; adreno_ctx = context->devctxt; + link = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (link == NULL) + goto done; + + cmds = link; + if (kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER)) - return; + goto done; cmds += __adreno_add_idle_indirect_cmds(cmds, device->mmu.setstate_memory.gpuaddr + @@ -413,25 +777,26 @@ static void adreno_iommu_setstate(struct kgsl_device *device, cmds += adreno_add_idle_cmds(adreno_dev, cmds); - sizedwords += (cmds - &link[0]); - if (sizedwords) { + if ((unsigned int) (cmds - link)) { /* invalidate all base pointers */ *cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1); *cmds++ = 0x7fff; - sizedwords += 2; /* This returns the per context timestamp but we need to * use the global timestamp for iommu clock disablement */ adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE, - &link[0], sizedwords); + link, (unsigned int)(cmds - link)); kgsl_mmu_disable_clk_on_ts(&device->mmu, - adreno_dev->ringbuffer.timestamp[KGSL_MEMSTORE_GLOBAL], true); + adreno_dev->ringbuffer.global_ts, true); } - if (sizedwords > (sizeof(link)/sizeof(unsigned int))) { + if ((unsigned int) (cmds - link) > (PAGE_SIZE / sizeof(unsigned int))) { KGSL_DRV_ERR(device, "Temp command buffer overflow\n"); BUG(); } +done: + kfree(link); + kgsl_context_put(context); } static void adreno_gpummu_setstate(struct kgsl_device *device, @@ -458,8 +823,8 @@ static void adreno_gpummu_setstate(struct kgsl_device *device, * writes For CFF dump we must idle and use the registers so that it is * easier to filter out the mmu accesses from the dump */ - if (!kgsl_cff_dump_enable && adreno_dev->drawctxt_active) { - context = idr_find(&device->context_idr, context_id); + if (!adreno_use_default_setstate(adreno_dev)) { + context = kgsl_context_get(device, context_id); if (context == NULL) return; adreno_ctx = context->devctxt; @@ -539,6 +904,8 @@ static void adreno_gpummu_setstate(struct kgsl_device *device, adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords); + + kgsl_context_put(context); } else { kgsl_mmu_device_setstate(&device->mmu, flags); } @@ -606,7 +973,7 @@ a2xx_getchipid(struct kgsl_device *device) /* 8x25 returns 0 for minor id, but it should be 1 */ if (cpu_is_qsd8x50()) patchid = 1; - else if (cpu_is_msm8625() && minorid == 0) + else if ((cpu_is_msm8625() || cpu_is_msm8625q()) && minorid == 0) minorid = 1; chipid |= (minorid << 8) | patchid; @@ -1172,6 +1539,8 @@ adreno_probe(struct platform_device *pdev) adreno_debugfs_init(device); + adreno_ft_init_sysfs(device); + kgsl_pwrscale_init(device); kgsl_pwrscale_attach_policy(device, ADRENO_DEFAULT_PWRSCALE_POLICY); @@ -1203,10 +1572,10 @@ static int __devexit adreno_remove(struct platform_device *pdev) return 0; } -static int adreno_start(struct kgsl_device *device, unsigned int init_ram) +static int adreno_init(struct kgsl_device *device) { - int status = -EINVAL; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; if (KGSL_STATE_DUMP_AND_FT != device->state) kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); @@ -1232,10 +1601,9 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram) if (adreno_dev->gpurev == ADRENO_REV_UNKNOWN) { KGSL_DRV_ERR(device, "Unknown chip ID %x\n", adreno_dev->chip_id); - goto error_clk_off; + BUG_ON(1); } - /* * Check if firmware supports the sync lock PM4 packets needed * for IOMMUv1 @@ -1247,7 +1615,36 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram) adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pfp_ver)) device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC; - /* Set up the MMU */ + rb->global_ts = 0; + + /* Assign correct RBBM status register to hang detect regs + */ + ft_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status; + + if (!adreno_is_a2xx(adreno_dev)) + adreno_perfcounter_init(device); + + /* Power down the device */ + kgsl_pwrctrl_disable(device); + + return 0; +} + +static int adreno_start(struct kgsl_device *device) +{ + int status = -EINVAL; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + unsigned int state = device->state; + + kgsl_cffdump_open(device); + + if (KGSL_STATE_DUMP_AND_FT != device->state) + kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); + + /* Power up the device */ + kgsl_pwrctrl_enable(device); + + /* Set up a2xx special case */ if (adreno_is_a2xx(adreno_dev)) { /* * the MH_CLNT_INTF_CTRL_CONFIG registers aren't present @@ -1291,22 +1688,58 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram) kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); device->ftbl->irqctrl(device, 1); - status = adreno_ringbuffer_start(&adreno_dev->ringbuffer, init_ram); - if (status == 0) { - /* While fault tolerance is on we do not want timer to - * fire and attempt to change any device state */ - if (KGSL_STATE_DUMP_AND_FT != device->state) - mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT); - return 0; + status = adreno_ringbuffer_start(&adreno_dev->ringbuffer); + if (status) + goto error_irq_off; + + /* + * While recovery is on we do not want timer to + * fire and attempt to change any device state + */ + + if (KGSL_STATE_DUMP_AND_FT != device->state) + mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT); + + if (!adreno_is_a2xx(adreno_dev)) + adreno_perfcounter_start(adreno_dev); + else { + unsigned int reg; + + kgsl_regread(device, REG_RBBM_PM_OVERRIDE2, ®); + kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, (reg | 0x40)); + + /* + * Select SP_ALU_INSTR_EXEC (0x85) to get number of + * ALU instructions executed. + */ + kgsl_regwrite(device, REG_SQ_PERFCOUNTER3_SELECT, 0x85); + + kgsl_regwrite(device, REG_CP_PERFMON_CNTL, + REG_PERF_MODE_CNT | REG_PERF_STATE_ENABLE); + + ft_detect_regs[6] = REG_SQ_PERFCOUNTER3_LO; + ft_detect_regs[7] = REG_SQ_PERFCOUNTER3_HI; } + mod_timer(&device->hang_timer, + (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT))); + + device->reset_counter++; + + return 0; + +error_irq_off: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); error_mmu_off: kgsl_mmu_stop(&device->mmu); error_clk_off: - kgsl_pwrctrl_disable(device); + if (KGSL_STATE_DUMP_AND_FT != device->state) { + kgsl_pwrctrl_disable(device); + /* set the state back to original state */ + kgsl_pwrctrl_set_state(device, state); + } return status; } @@ -1324,68 +1757,89 @@ static int adreno_stop(struct kgsl_device *device) device->ftbl->irqctrl(device, 0); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); del_timer_sync(&device->idle_timer); + del_timer_sync(&device->hang_timer); adreno_ocmem_gmem_free(adreno_dev); /* Power down the device */ kgsl_pwrctrl_disable(device); + kgsl_cffdump_close(device->id); + return 0; } -static void adreno_mark_context_status(struct kgsl_device *device, - int ft_status) +/* + * Set the reset status of all contexts to + * INNOCENT_CONTEXT_RESET_EXT except for the bad context + * since thats the guilty party, if fault tolerance failed then + * mark all as guilty + */ + +static int _mark_context_status(int id, void *ptr, void *data) { - struct kgsl_context *context; - int next = 0; - /* - * Set the reset status of all contexts to - * INNOCENT_CONTEXT_RESET_EXT except for the bad context - * since thats the guilty party, if fault tolerance failed then - * mark all as guilty - */ - while ((context = idr_get_next(&device->context_idr, &next))) { - struct adreno_context *adreno_context = context->devctxt; - if (ft_status) { - context->reset_status = - KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT; - adreno_context->flags |= CTXT_FLAGS_GPU_HANG; - } else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT != - context->reset_status) { - if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG | - CTXT_FLAGS_GPU_HANG_FT)) - context->reset_status = + unsigned int ft_status = *((unsigned int *) data); + struct kgsl_context *context = ptr; + struct adreno_context *adreno_context = context->devctxt; + + if (ft_status) { + context->reset_status = KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT; - else - context->reset_status = - KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT; - } - next = next + 1; + adreno_context->flags |= CTXT_FLAGS_GPU_HANG; + } else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT != + context->reset_status) { + if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG | + CTXT_FLAGS_GPU_HANG_FT)) + context->reset_status = + KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT; + else + context->reset_status = + KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT; } + + return 0; } -static void adreno_set_max_ts_for_bad_ctxs(struct kgsl_device *device) +static void adreno_mark_context_status(struct kgsl_device *device, + int ft_status) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; - struct kgsl_context *context; - struct adreno_context *temp_adreno_context; - int next = 0; + /* Mark the status for all the contexts in the device */ - while ((context = idr_get_next(&device->context_idr, &next))) { - temp_adreno_context = context->devctxt; - if (temp_adreno_context->flags & CTXT_FLAGS_GPU_HANG) { - kgsl_sharedmem_writel(&device->memstore, - KGSL_MEMSTORE_OFFSET(context->id, - soptimestamp), - rb->timestamp[context->id]); - kgsl_sharedmem_writel(&device->memstore, - KGSL_MEMSTORE_OFFSET(context->id, - eoptimestamp), - rb->timestamp[context->id]); - } - next = next + 1; + read_lock(&device->context_lock); + idr_for_each(&device->context_idr, _mark_context_status, &ft_status); + read_unlock(&device->context_lock); +} + +/* + * For hung contexts set the current memstore value to the most recent issued + * timestamp - this resets the status and lets the system continue on + */ + +static int _set_max_ts(int id, void *ptr, void *data) +{ + struct kgsl_device *device = data; + struct kgsl_context *context = ptr; + struct adreno_context *drawctxt = context->devctxt; + + if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) { + kgsl_sharedmem_writel(&device->memstore, + KGSL_MEMSTORE_OFFSET(context->id, + soptimestamp), + drawctxt->timestamp); + kgsl_sharedmem_writel(&device->memstore, + KGSL_MEMSTORE_OFFSET(context->id, + eoptimestamp), + drawctxt->timestamp); } + + return 0; +} + +static void adreno_set_max_ts_for_bad_ctxs(struct kgsl_device *device) +{ + read_lock(&device->context_lock); + idr_for_each(&device->context_idr, _set_max_ts, device); + read_unlock(&device->context_lock); } static void adreno_destroy_ft_data(struct adreno_ft_data *ft_data) @@ -1499,7 +1953,8 @@ static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb, } if (status) KGSL_FT_ERR(rb->device, - "Failed to find the command sequence after eop timestamp\n"); + "Failed to find the command sequence after eop timestamp %x\n", + global_eop); return status; } @@ -1612,46 +2067,43 @@ static void adreno_setup_ft_data(struct kgsl_device *device, ft_data->status = 0; /* find the start of bad command sequence in rb */ - context = idr_find(&device->context_idr, ft_data->context_id); - /* Look for the command stream that is right after the global eop */ - - if (!context) { - /* - * If there is no context then fault tolerance does not need to - * replay anything, just reset GPU and thats it - */ - return; - } + context = kgsl_context_get(device, ft_data->context_id); ft_data->ft_policy = adreno_dev->ft_policy; if (!adreno_dev->ft_policy) adreno_dev->ft_policy = KGSL_FT_DEFAULT_POLICY; + /* Look for the command stream that is right after the global eop */ ret = _find_cmd_seq_after_eop_ts(rb, &rb_rptr, ft_data->global_eop + 1, false); if (ret) { ft_data->ft_policy |= KGSL_FT_TEMP_DISABLE; - return; - } else + goto done; + } else { + ft_data->start_of_replay_cmds = rb_rptr; ft_data->ft_policy &= ~KGSL_FT_TEMP_DISABLE; + } - ft_data->start_of_replay_cmds = rb_rptr; - - adreno_context = context->devctxt; - if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) { - if (ft_data->ib1) { - ret = _find_hanging_ib_sequence(rb, - &rb_rptr, ft_data->ib1); - if (ret) { - KGSL_FT_ERR(device, - "Start not found for replay IB sequence\n"); - return; + if (context) { + adreno_context = context->devctxt; + if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) { + if (ft_data->ib1) { + ret = _find_hanging_ib_sequence(rb, + &rb_rptr, ft_data->ib1); + if (ret) { + KGSL_FT_ERR(device, + "Start not found for replay IB seq\n"); + goto done; + } + ft_data->start_of_replay_cmds = rb_rptr; + ft_data->replay_for_snapshot = rb_rptr; } - ft_data->start_of_replay_cmds = rb_rptr; - ft_data->replay_for_snapshot = rb_rptr; } } + +done: + kgsl_context_put(context); } static int @@ -1686,23 +2138,29 @@ static int _adreno_ft_restart_device(struct kgsl_device *device, struct kgsl_context *context) { - - struct adreno_context *adreno_context = context->devctxt; + struct adreno_context *adreno_context = NULL; /* restart device */ if (adreno_stop(device)) { KGSL_FT_ERR(device, "Device stop failed\n"); return 1; } + + if (adreno_init(device)) { + KGSL_FT_ERR(device, "Device start failed\n"); + return 1; + } - if (adreno_start(device, true)) { + if (adreno_start(device)) { KGSL_FT_ERR(device, "Device start failed\n"); return 1; } - if (context) + if ((context != NULL) && (context->devctxt != NULL)) { + adreno_context = context->devctxt; kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable, KGSL_MEMSTORE_GLOBAL); + } /* If iommu is used then we need to make sure that the iommu clocks * are on since there could be commands in pipeline that touch iommu */ @@ -1802,13 +2260,23 @@ _adreno_ft(struct kgsl_device *device, struct adreno_context *adreno_context = NULL; struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active; unsigned int long_ib = 0; + static int no_context_ft; + + context = kgsl_context_get(device, ft_data->context_id); - context = idr_find(&device->context_idr, ft_data->context_id); if (context == NULL) { KGSL_FT_ERR(device, "Last context unknown id:%d\n", ft_data->context_id); - goto play_good_cmds; + if (no_context_ft) { + /* + * If 2 consecutive no context ft occurred then + * just reset GPU + */ + no_context_ft = 0; + goto play_good_cmds; + } } else { + no_context_ft = 0; adreno_context = context->devctxt; adreno_context->flags |= CTXT_FLAGS_GPU_HANG; /* @@ -1838,7 +2306,7 @@ _adreno_ft(struct kgsl_device *device, /* Check if we detected a long running IB, * if true do not attempt replay of bad cmds */ - if (adreno_dev->long_ib) { + if ((adreno_context) && (adreno_dev->long_ib)) { long_ib = _adreno_check_long_ib(device); if (!long_ib) { adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG; @@ -1867,7 +2335,7 @@ _adreno_ft(struct kgsl_device *device, } /* Do not try the reply if hang is due to a pagefault */ - if (adreno_context->pagefault) { + if (adreno_context && adreno_context->pagefault) { if ((ft_data->context_id == adreno_context->id) && (ft_data->global_eop == adreno_context->pagefault_ts)) { ft_data->ft_policy &= ~KGSL_FT_REPLAY; @@ -1932,7 +2400,7 @@ _adreno_ft(struct kgsl_device *device, /* EOF not found in RB, discard till EOF in next IB submission */ - if (i == ft_data->bad_rb_size) { + if (adreno_context && (i == ft_data->bad_rb_size)) { adreno_context->flags |= CTXT_FLAGS_SKIP_EOF; KGSL_FT_INFO(device, "EOF not found in RB, skip next issueib till EOF\n"); @@ -1969,8 +2437,14 @@ _adreno_ft(struct kgsl_device *device, ft_data->good_rb_buffer, ft_data->good_rb_size); if (ret) { - /* If we fail here we can try to invalidate another - * context and try fault tolerance again */ + /* + * If we fail here we can try to invalidate another + * context and try fault tolerance again, although + * we will only try ft with no context once to avoid + * going into continuous loop of trying ft with no context + */ + if (!context) + no_context_ft = 1; ret = -EAGAIN; KGSL_FT_ERR(device, "Playing good commands unsuccessful\n"); goto done; @@ -1980,17 +2454,21 @@ _adreno_ft(struct kgsl_device *device, /* ringbuffer now has data from the last valid context id, * so restore the active_ctx to the last valid context */ if (ft_data->last_valid_ctx_id) { - struct kgsl_context *last_ctx = - idr_find(&device->context_idr, - ft_data->last_valid_ctx_id); + struct kgsl_context *last_ctx = kgsl_context_get(device, + ft_data->last_valid_ctx_id); + if (last_ctx) adreno_dev->drawctxt_active = last_ctx->devctxt; + + kgsl_context_put(last_ctx); } done: /* Turn off iommu clocks */ if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false); + + kgsl_context_put(context); return ret; } @@ -2001,15 +2479,14 @@ adreno_ft(struct kgsl_device *device, int ret = 0; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; - unsigned int timestamp; KGSL_FT_INFO(device, "Start Parameters: IB1: 0x%X, " "Bad context_id: %u, global_eop: 0x%x\n", ft_data->ib1, ft_data->context_id, ft_data->global_eop); - timestamp = rb->timestamp[KGSL_MEMSTORE_GLOBAL]; - KGSL_FT_INFO(device, "Last issued global timestamp: %x\n", timestamp); + KGSL_FT_INFO(device, "Last issued global timestamp: %x\n", + rb->global_ts); /* We may need to replay commands multiple times based on whether * multiple contexts hang the GPU */ @@ -2037,15 +2514,15 @@ adreno_ft(struct kgsl_device *device, /* Restore correct states after fault tolerance */ if (adreno_dev->drawctxt_active) - device->mmu.hwpagetable = - adreno_dev->drawctxt_active->pagetable; + kgsl_mmu_setstate(&device->mmu, + adreno_dev->drawctxt_active->pagetable, + adreno_dev->drawctxt_active->id); else - device->mmu.hwpagetable = device->mmu.defaultpagetable; - rb->timestamp[KGSL_MEMSTORE_GLOBAL] = timestamp; + kgsl_mmu_setstate(&device->mmu, + device->mmu.defaultpagetable, KGSL_MEMSTORE_GLOBAL); kgsl_sharedmem_writel(&device->memstore, KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, - eoptimestamp), - rb->timestamp[KGSL_MEMSTORE_GLOBAL]); + eoptimestamp), rb->global_ts); /* switch to NULL ctxt */ if (adreno_dev->drawctxt_active != NULL) @@ -2119,6 +2596,9 @@ adreno_dump_and_exec_ft(struct kgsl_device *device) } else { kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT); + mod_timer(&device->hang_timer, + (jiffies + + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT))); } complete_all(&device->ft_gate); } @@ -2127,6 +2607,264 @@ adreno_dump_and_exec_ft(struct kgsl_device *device) } EXPORT_SYMBOL(adreno_dump_and_exec_ft); +/** + * _ft_sysfs_store() - Common routine to write to FT sysfs files + * @buf: value to write + * @count: size of the value to write + * @sysfs_cfg: KGSL FT sysfs config to write + * + * This is a common routine to write to FT sysfs files. + */ +static int _ft_sysfs_store(const char *buf, size_t count, unsigned int *ptr) +{ + char temp[20]; + unsigned long val; + int rc; + + snprintf(temp, sizeof(temp), "%.*s", + (int)min(count, sizeof(temp) - 1), buf); + rc = kstrtoul(temp, 0, &val); + if (rc) + return rc; + + *ptr = val; + + return count; +} + +/** + * _get_adreno_dev() - Routine to get a pointer to adreno dev + * @dev: device ptr + * @attr: Device attribute + * @buf: value to write + * @count: size of the value to write + */ +struct adreno_device *_get_adreno_dev(struct device *dev) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + return device ? ADRENO_DEVICE(device) : NULL; +} + +/** + * _ft_policy_store() - Routine to configure FT policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value to write + * @count: size of the value to write + * + * FT policy can be set to any of the options below. + * KGSL_FT_DISABLE -> BIT(0) Set to disable FT + * KGSL_FT_REPLAY -> BIT(1) Set to enable replay + * KGSL_FT_SKIPIB -> BIT(2) Set to skip IB + * KGSL_FT_SKIPFRAME -> BIT(3) Set to skip frame + * by default set FT policy to KGSL_FT_DEFAULT_POLICY + */ +static int _ft_policy_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + int ret; + if (adreno_dev == NULL) + return 0; + + mutex_lock(&adreno_dev->dev.mutex); + ret = _ft_sysfs_store(buf, count, &adreno_dev->ft_policy); + mutex_unlock(&adreno_dev->dev.mutex); + + return ret; +} + +/** + * _ft_policy_show() - Routine to read FT policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value read + * + * This is a routine to read current FT policy + */ +static int _ft_policy_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + if (adreno_dev == NULL) + return 0; + return snprintf(buf, PAGE_SIZE, "0x%X\n", adreno_dev->ft_policy); +} + +/** + * _ft_pagefault_policy_store() - Routine to configure FT + * pagefault policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value to write + * @count: size of the value to write + * + * FT pagefault policy can be set to any of the options below. + * KGSL_FT_PAGEFAULT_INT_ENABLE -> BIT(0) set to enable pagefault INT + * KGSL_FT_PAGEFAULT_GPUHALT_ENABLE -> BIT(1) Set to enable GPU HALT on + * pagefaults. This stalls the GPU on a pagefault on IOMMU v1 HW. + * KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE -> BIT(2) Set to log only one + * pagefault per page. + * KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT -> BIT(3) Set to log only one + * pagefault per INT. + */ +static int _ft_pagefault_policy_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + int ret; + if (adreno_dev == NULL) + return 0; + + mutex_lock(&adreno_dev->dev.mutex); + ret = _ft_sysfs_store(buf, count, &adreno_dev->ft_pf_policy); + mutex_unlock(&adreno_dev->dev.mutex); + + return ret; +} + +/** + * _ft_pagefault_policy_show() - Routine to read FT pagefault + * policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value read + * + * This is a routine to read current FT pagefault policy + */ +static int _ft_pagefault_policy_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + if (adreno_dev == NULL) + return 0; + return snprintf(buf, PAGE_SIZE, "0x%X\n", adreno_dev->ft_pf_policy); +} + +/** + * _ft_fast_hang_detect_store() - Routine to configure FT fast + * hang detect policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value to write + * @count: size of the value to write + * + * 0x1 - Enable fast hang detection + * 0x0 - Disable fast hang detection + */ +static int _ft_fast_hang_detect_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + int ret; + if (adreno_dev == NULL) + return 0; + + mutex_lock(&adreno_dev->dev.mutex); + ret = _ft_sysfs_store(buf, count, &adreno_dev->fast_hang_detect); + mutex_unlock(&adreno_dev->dev.mutex); + + return ret; + +} + +/** + * _ft_fast_hang_detect_show() - Routine to read FT fast + * hang detect policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value read + */ +static int _ft_fast_hang_detect_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + if (adreno_dev == NULL) + return 0; + return snprintf(buf, PAGE_SIZE, "%d\n", + (adreno_dev->fast_hang_detect ? 1 : 0)); +} + +/** + * _ft_long_ib_detect_store() - Routine to configure FT long IB + * detect policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value to write + * @count: size of the value to write + * + * 0x0 - Enable long IB detection + * 0x1 - Disable long IB detection + */ +static int _ft_long_ib_detect_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + int ret; + if (adreno_dev == NULL) + return 0; + + mutex_lock(&adreno_dev->dev.mutex); + ret = _ft_sysfs_store(buf, count, &adreno_dev->long_ib_detect); + mutex_unlock(&adreno_dev->dev.mutex); + + return ret; + +} + +/** + * _ft_long_ib_detect_show() - Routine to read FT long IB + * detect policy + * @dev: device ptr + * @attr: Device attribute + * @buf: value read + */ +static int _ft_long_ib_detect_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adreno_device *adreno_dev = _get_adreno_dev(dev); + if (adreno_dev == NULL) + return 0; + return snprintf(buf, PAGE_SIZE, "%d\n", + (adreno_dev->long_ib_detect ? 1 : 0)); +} + + +#define FT_DEVICE_ATTR(name) \ + DEVICE_ATTR(name, 0644, _ ## name ## _show, _ ## name ## _store); + +FT_DEVICE_ATTR(ft_policy); +FT_DEVICE_ATTR(ft_pagefault_policy); +FT_DEVICE_ATTR(ft_fast_hang_detect); +FT_DEVICE_ATTR(ft_long_ib_detect); + + +const struct device_attribute *ft_attr_list[] = { + &dev_attr_ft_policy, + &dev_attr_ft_pagefault_policy, + &dev_attr_ft_fast_hang_detect, + &dev_attr_ft_long_ib_detect, + NULL, +}; + +int adreno_ft_init_sysfs(struct kgsl_device *device) +{ + return kgsl_create_device_sysfs_files(device->dev, ft_attr_list); +} + +void adreno_ft_uninit_sysfs(struct kgsl_device *device) +{ + kgsl_remove_device_sysfs_files(device->dev, ft_attr_list); +} + static int adreno_getproperty(struct kgsl_device *device, enum kgsl_property_type type, void *value, @@ -2277,13 +3015,10 @@ static int adreno_ringbuffer_drain(struct kgsl_device *device, unsigned long wait; unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT); - if (!(rb->flags & KGSL_FLAGS_STARTED)) - return 0; - /* * The first time into the loop, wait for 100 msecs and kick wptr again * to ensure that the hardware has updated correctly. After that, kick - * it periodically every KGSL_TIMEOUT_PART msecs until the timeout + * it periodically every KGSL_TIMEOUT_HANG_DETECT msecs until the timeout * expires */ @@ -2295,7 +3030,7 @@ static int adreno_ringbuffer_drain(struct kgsl_device *device, if (adreno_ft_detect(device, regs)) return -ETIMEDOUT; - wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART); + wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT); } GSL_RB_GET_READPTR(rb, &rb->rptr); @@ -2312,11 +3047,10 @@ static int adreno_ringbuffer_drain(struct kgsl_device *device, /* Caller must hold the device mutex. */ int adreno_idle(struct kgsl_device *device) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - unsigned int rbbm_status; unsigned long wait_time; unsigned long wait_time_part; - unsigned int prev_reg_val[ft_detect_regs_count]; + unsigned int prev_reg_val[FT_DETECT_REGS_COUNT]; + memset(prev_reg_val, 0, sizeof(prev_reg_val)); @@ -2331,26 +3065,18 @@ int adreno_idle(struct kgsl_device *device) /* now, wait for the GPU to finish its operations */ wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT); - wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART); + wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT); while (time_before(jiffies, wait_time)) { - adreno_regread(device, adreno_dev->gpudev->reg_rbbm_status, - &rbbm_status); - if (adreno_is_a2xx(adreno_dev)) { - if (rbbm_status == 0x110) - return 0; - } else { - if (!(rbbm_status & 0x80000000)) - return 0; - } + if (adreno_isidle(device)) + return 0; - /* Dont wait for timeout, detect hang faster. - */ + /* Dont wait for timeout, detect hang faster. */ if (time_after(jiffies, wait_time_part)) { - wait_time_part = jiffies + - msecs_to_jiffies(KGSL_TIMEOUT_PART); - if ((adreno_ft_detect(device, prev_reg_val))) - goto err; + wait_time_part = jiffies + + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT); + if ((adreno_ft_detect(device, prev_reg_val))) + goto err; } } @@ -2359,7 +3085,7 @@ int adreno_idle(struct kgsl_device *device) KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n"); if (KGSL_STATE_DUMP_AND_FT != device->state && !adreno_dump_and_exec_ft(device)) { - wait_time = jiffies + ADRENO_IDLE_TIMEOUT; + wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT); goto retry; } return -ETIMEDOUT; @@ -2400,12 +3126,11 @@ static unsigned int adreno_isidle(struct kgsl_device *device) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; - WARN_ON(device->state == KGSL_STATE_INIT); /* If the device isn't active, don't force it on. */ - if (device->state == KGSL_STATE_ACTIVE) { + if (kgsl_pwrctrl_isenabled(device)) { /* Is the ring buffer is empty? */ GSL_RB_GET_READPTR(rb, &rb->rptr); - if (!device->active_cnt && (rb->rptr == rb->wptr)) { + if (rb->rptr == rb->wptr) { /* * Are there interrupts pending? If so then pretend we * are not idle - this avoids the possiblity that we go @@ -2428,6 +3153,7 @@ static unsigned int adreno_isidle(struct kgsl_device *device) static int adreno_suspend_context(struct kgsl_device *device) { int status = 0; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); /* switch to NULL ctxt */ @@ -2447,7 +3173,10 @@ struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device, struct kgsl_context *context; struct adreno_context *adreno_context = NULL; int next = 0; + struct kgsl_memdesc *desc = NULL; + + read_lock(&device->context_lock); while (1) { context = idr_get_next(&device->context_idr, &next); if (context == NULL) @@ -2457,20 +3186,19 @@ struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device, if (kgsl_mmu_pt_equal(&device->mmu, adreno_context->pagetable, pt_base)) { - struct kgsl_memdesc *desc; - desc = &adreno_context->gpustate; if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) - return desc; + break; desc = &adreno_context->context_gmem_shadow.gmemshadow; if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) - return desc; + break; } next = next + 1; + desc = NULL; } - - return NULL; + read_unlock(&device->context_lock); + return desc; } struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device, @@ -2539,6 +3267,8 @@ void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords, if (!in_interrupt()) kgsl_pre_hwaccess(device); + kgsl_trace_regwrite(device, offsetwords, value); + kgsl_cffdump_regwrite(device->id, offsetwords << 2, value); reg = (unsigned int *)(device->reg_virt + (offsetwords << 2)); @@ -2624,7 +3354,7 @@ static unsigned int adreno_check_hw_ts(struct kgsl_device *device, if (context && device->state != KGSL_STATE_SLUMBER) adreno_ringbuffer_issuecmds(device, context->devctxt, - KGSL_CMD_FLAGS_NONE, NULL, 0); + KGSL_CMD_FLAGS_GET_INT, NULL, 0); } return 0; @@ -2671,7 +3401,8 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, unsigned int *prev_reg_val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - unsigned int curr_reg_val[ft_detect_regs_count]; + struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; + unsigned int curr_reg_val[FT_DETECT_REGS_COUNT]; unsigned int fast_hang_detected = 1; unsigned int long_ib_detected = 1; unsigned int i; @@ -2688,7 +3419,12 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, if (!adreno_dev->long_ib_detect) long_ib_detected = 0; - if (is_adreno_rbbm_status_idle(device)) { + if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED)) + return 0; + + if (is_adreno_rbbm_status_idle(device) && + (kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED) + == rb->global_ts)) { /* * On A20X if the RPTR != WPTR and the device is idle, then @@ -2708,8 +3444,8 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, } /* - * Time interval between hang detection should be KGSL_TIMEOUT_PART - * or more, if next hang detection is requested < KGSL_TIMEOUT_PART + * Time interval between hang detection should be KGSL_TIMEOUT_HANG_DETECT + * or more, if next hang detection is requested < KGSL_TIMEOUT_HANG_DETECT * from the last time do nothing. */ if ((next_hang_detect_time) && @@ -2717,10 +3453,10 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, return 0; else next_hang_detect_time = (jiffies + - msecs_to_jiffies(KGSL_TIMEOUT_PART-1)); + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT)); /* Read the current Hang detect reg values here */ - for (i = 0; i < ft_detect_regs_count; i++) { + for (i = 0; i < FT_DETECT_REGS_COUNT; i++) { if (ft_detect_regs[i] == 0) continue; adreno_regread(device, ft_detect_regs[i], @@ -2743,8 +3479,10 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, &curr_context_id, KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context)); - context = idr_find(&device->context_idr, - curr_context_id); + /* Make sure the memstore read has posted */ + mb(); + + context = kgsl_context_get(device, curr_context_id); if (context != NULL) { curr_context = context->devctxt; curr_context->ib_gpu_time_used = 0; @@ -2756,44 +3494,46 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, mb(); + for (i = 0; i < FT_DETECT_REGS_COUNT; i++) { + if (curr_reg_val[i] != prev_reg_val[i]) { + fast_hang_detected = 0; + + /* Check for long IB here */ + if ((i >= + LONG_IB_DETECT_REG_INDEX_START) + && + (i <= + LONG_IB_DETECT_REG_INDEX_END)) + long_ib_detected = 0; + } + } + + if (fast_hang_detected) { + KGSL_FT_ERR(device, + "Proc %s, ctxt_id %d ts %d triggered fault tolerance" + " on global ts %d\n", + curr_context ? curr_context->pid_name : "", + curr_context ? curr_context->id : 0, + (kgsl_readtimestamp(device, context, + KGSL_TIMESTAMP_RETIRED) + 1), + curr_global_ts + 1); + kgsl_context_put(context); + context = NULL; + curr_context = NULL; + return 1; + } + if (curr_context != NULL) { - curr_context->ib_gpu_time_used += KGSL_TIMEOUT_PART; + curr_context->ib_gpu_time_used += KGSL_TIMEOUT_HANG_DETECT; KGSL_FT_INFO(device, "Proc %s used GPU Time %d ms on timestamp 0x%X\n", curr_context->pid_name, curr_context->ib_gpu_time_used, curr_global_ts+1); - for (i = 0; i < ft_detect_regs_count; i++) { - if (curr_reg_val[i] != prev_reg_val[i]) { - fast_hang_detected = 0; - - /* Check for long IB here */ - if ((i >= - LONG_IB_DETECT_REG_INDEX_START) - && - (i <= - LONG_IB_DETECT_REG_INDEX_END)) - long_ib_detected = 0; - } - } - - if (fast_hang_detected) { - KGSL_FT_ERR(device, - "Proc %s, ctxt_id %d ts %d triggered fault tolerance" - " on global ts %d\n", - curr_context->pid_name, curr_context->id - , (kgsl_readtimestamp(device, context, - KGSL_TIMESTAMP_RETIRED)+1), - curr_global_ts+1); - return 1; - } - if ((long_ib_detected) && (!(curr_context->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE))) { - curr_context->ib_gpu_time_used += - KGSL_TIMEOUT_PART; if (curr_context->ib_gpu_time_used > KGSL_TIMEOUT_LONG_IB_DETECTION) { if (adreno_dev->long_ib_ts != @@ -2814,18 +3554,18 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, curr_global_ts; curr_context->ib_gpu_time_used = 0; + kgsl_context_put(context); + context = NULL; + curr_context = NULL; return 1; } } } - } else { - KGSL_FT_ERR(device, - "Last context unknown id:%d\n", - curr_context_id); } } else { /* GPU is moving forward */ prev_global_ts = curr_global_ts; + kgsl_context_put(context); context = NULL; curr_context = NULL; adreno_dev->long_ib = 0; @@ -2835,53 +3575,11 @@ unsigned int adreno_ft_detect(struct kgsl_device *device, /* If hangs are not detected copy the current reg values * to previous values and return no hang */ - for (i = 0; i < ft_detect_regs_count; i++) + for (i = 0; i < FT_DETECT_REGS_COUNT; i++) prev_reg_val[i] = curr_reg_val[i]; return 0; } -/** - * adreno_handle_hang - Process a hang detected in adreno_waittimestamp - * @device - pointer to a KGSL device structure - * @context - pointer to the active KGSL context - * @timestamp - the timestamp that the process was waiting for - * - * Process a possible GPU hang and try fault tolerance from it - * cleanly - */ -static int adreno_handle_hang(struct kgsl_device *device, - struct kgsl_context *context, unsigned int timestamp) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - unsigned int context_id = _get_context_id(context); - unsigned int ts_issued; - unsigned int rptr; - - /* Do one last check to see if we somehow made it through */ - if (kgsl_check_timestamp(device, context, timestamp)) - return 0; - - ts_issued = adreno_dev->ringbuffer.timestamp[context_id]; - - adreno_regread(device, REG_CP_RB_RPTR, &rptr); - mb(); - - KGSL_DRV_WARN(device, - "Device hang detected while waiting for timestamp: " - "<%d:0x%x>, last submitted timestamp: <%d:0x%x>, " - "retired timestamp: <%d:0x%x>, wptr: 0x%x, rptr: 0x%x\n", - context_id, timestamp, context_id, ts_issued, context_id, - kgsl_readtimestamp(device, context, - KGSL_TIMESTAMP_RETIRED), - adreno_dev->ringbuffer.wptr, rptr); - - /* Return 0 after a successful fault tolerance */ - if (!adreno_dump_and_exec_ft(device)) - return 0; - - return -ETIMEDOUT; -} - static int _check_pending_timestamp(struct kgsl_device *device, struct kgsl_context *context, unsigned int timestamp) { @@ -2892,7 +3590,7 @@ static int _check_pending_timestamp(struct kgsl_device *device, if (context_id == KGSL_CONTEXT_INVALID) return -EINVAL; - ts_issued = adreno_dev->ringbuffer.timestamp[context_id]; + ts_issued = adreno_context_timestamp(context, &adreno_dev->ringbuffer); if (timestamp_cmp(timestamp, ts_issued) <= 0) return 0; @@ -2930,14 +3628,11 @@ static int adreno_waittimestamp(struct kgsl_device *device, struct adreno_context *adreno_ctx = context ? context->devctxt : NULL; struct kgsl_pwrctrl *pwr = &device->pwrctrl; unsigned int context_id = _get_context_id(context); - unsigned int prev_reg_val[ft_detect_regs_count]; unsigned int time_elapsed = 0; unsigned int wait; int ts_compare = 1; int io, ret = -ETIMEDOUT; - /* Get out early if the context has already been destroyed */ - if (context_id == KGSL_CONTEXT_INVALID) { KGSL_DRV_WARN(device, "context was detached"); return -EINVAL; @@ -2958,10 +3653,6 @@ static int adreno_waittimestamp(struct kgsl_device *device, context->wait_on_invalid_ts = false; } - - /* Clear the registers used for hang detection */ - memset(prev_reg_val, 0, sizeof(prev_reg_val)); - /* * On the first time through the loop only wait 100ms. * this gives enough time for the engine to start moving and oddly @@ -2988,12 +3679,6 @@ static int adreno_waittimestamp(struct kgsl_device *device, break; } - /* Check to see if the GPU is hung */ - if (adreno_ft_detect(device, prev_reg_val)) { - ret = adreno_handle_hang(device, context, timestamp); - break; - } - /* * For proper power accounting sometimes we need to call * io_wait_interruptible_timeout and sometimes we need to call @@ -3028,6 +3713,7 @@ static int adreno_waittimestamp(struct kgsl_device *device, } time_elapsed += wait; + /* If user specified timestamps are being used, wait at least * KGSL_SYNCOBJ_SERVER_TIMEOUT msecs for the user driver to * issue a IB for a timestamp before checking to see if the @@ -3049,6 +3735,7 @@ static int adreno_waittimestamp(struct kgsl_device *device, * Reset the invalid timestamp flag on a valid * wait */ + context->wait_on_invalid_ts = false; } } @@ -3085,13 +3772,14 @@ static unsigned int adreno_readtimestamp(struct kgsl_device *device, switch (type) { case KGSL_TIMESTAMP_QUEUED: { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; - timestamp = rb->timestamp[context_id]; + timestamp = adreno_context_timestamp(context, + &adreno_dev->ringbuffer); break; } case KGSL_TIMESTAMP_CONSUMED: - adreno_regread(device, REG_CP_TIMESTAMP, ×tamp); + kgsl_sharedmem_readl(&device->memstore, ×tamp, + KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)); break; case KGSL_TIMESTAMP_RETIRED: kgsl_sharedmem_readl(&device->memstore, ×tamp, @@ -3107,27 +3795,58 @@ static unsigned int adreno_readtimestamp(struct kgsl_device *device, static long adreno_ioctl(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { + struct kgsl_device *device = dev_priv->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int result = 0; - struct kgsl_drawctxt_set_bin_base_offset *binbase; - struct kgsl_context *context; switch (cmd) { - case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET: + case IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET: { + struct kgsl_drawctxt_set_bin_base_offset *binbase = data; + struct kgsl_context *context; + binbase = data; - context = kgsl_find_context(dev_priv, binbase->drawctxt_id); + context = kgsl_context_get_owner(dev_priv, + binbase->drawctxt_id); if (context) { adreno_drawctxt_set_bin_base_offset( - dev_priv->device, context, binbase->offset); + device, context, binbase->offset); } else { result = -EINVAL; - KGSL_DRV_ERR(dev_priv->device, + KGSL_DRV_ERR(device, "invalid drawctxt drawctxt_id %d " "device_id=%d\n", - binbase->drawctxt_id, dev_priv->device->id); + binbase->drawctxt_id, device->id); } - break; + kgsl_context_put(context); + break; + } + case IOCTL_KGSL_PERFCOUNTER_GET: { + struct kgsl_perfcounter_get *get = data; + result = adreno_perfcounter_get(adreno_dev, get->groupid, + get->countable, &get->offset, PERFCOUNTER_FLAG_NONE); + break; + } + case IOCTL_KGSL_PERFCOUNTER_PUT: { + struct kgsl_perfcounter_put *put = data; + result = adreno_perfcounter_put(adreno_dev, put->groupid, + put->countable); + break; + } + case IOCTL_KGSL_PERFCOUNTER_QUERY: { + struct kgsl_perfcounter_query *query = data; + result = adreno_perfcounter_query_group(adreno_dev, + query->groupid, query->countables, + query->count, &query->max_counters); + break; + } + case IOCTL_KGSL_PERFCOUNTER_READ: { + struct kgsl_perfcounter_read *read = data; + result = adreno_perfcounter_read_group(adreno_dev, + read->reads, read->count); + break; + } default: KGSL_DRV_INFO(dev_priv->device, "invalid ioctl code %08x\n", cmd); @@ -3149,15 +3868,20 @@ static void adreno_power_stats(struct kgsl_device *device, { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - unsigned int cycles; + unsigned int cycles = 0; - /* Get the busy cycles counted since the counter was last reset */ - /* Calling this function also resets and restarts the counter */ - - cycles = adreno_dev->gpudev->busy_cycles(adreno_dev); + /* + * Get the busy cycles counted since the counter was last reset. + * If we're not currently active, there shouldn't have been + * any cycles since the last time this function was called. + */ + if (device->state == KGSL_STATE_ACTIVE) + cycles = adreno_dev->gpudev->busy_cycles(adreno_dev); - /* In order to calculate idle you have to have run the algorithm * - * at least once to get a start time. */ + /* + * In order to calculate idle you have to have run the algorithm + * at least once to get a start time. + */ if (pwr->time != 0) { s64 tmp = ktime_to_us(ktime_get()); stats->total_time = tmp - pwr->time; @@ -3204,6 +3928,7 @@ static const struct kgsl_functable adreno_functable = { .idle = adreno_idle, .isidle = adreno_isidle, .suspend_context = adreno_suspend_context, + .init = adreno_init, .start = adreno_start, .stop = adreno_stop, .getproperty = adreno_getproperty, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 8d16bfa0..a6d14ef0 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2012,2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,8 @@ #include "kgsl_iommu.h" #include +#include "a3xx_reg.h" + #define DEVICE_3D_NAME "kgsl-3d" #define DEVICE_3D0_NAME "kgsl-3d0" @@ -34,15 +36,18 @@ #define KGSL_CMD_FLAGS_NONE 0x00000000 #define KGSL_CMD_FLAGS_PMODE 0x00000001 #define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002 +#define KGSL_CMD_FLAGS_GET_INT 0x00000004 #define KGSL_CMD_FLAGS_EOF 0x00000100 /* Command identifiers */ #define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF #define KGSL_CMD_IDENTIFIER 0x2EEDFACE +#define KGSL_CMD_INTERNAL_IDENTIFIER 0x2EEDD00D #define KGSL_START_OF_IB_IDENTIFIER 0x2EADEABE #define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD #define KGSL_END_OF_FRAME_IDENTIFIER 0x2E0F2E0F #define KGSL_NOP_IB_IDENTIFIER 0x20F20F20 +#define KGSL_NOP_DATA_FILLER 0xFEEDFACE #ifdef CONFIG_MSM_SCM #define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz) @@ -52,8 +57,6 @@ #define ADRENO_DEFAULT_PWRSCALE_POLICY NULL #endif -void adreno_debugfs_init(struct kgsl_device *device); - #define ADRENO_ISTORE_START 0x5000 /* Istore offset */ #define ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW 50 @@ -111,6 +114,45 @@ struct adreno_device { unsigned int gpulist_index; struct ocmem_buf *ocmem_hdl; unsigned int ocmem_base; + unsigned int gpu_cycles; +}; + +#define PERFCOUNTER_FLAG_NONE 0x0 +#define PERFCOUNTER_FLAG_KERNEL 0x1 + +/* Structs to maintain the list of active performance counters */ + +/** + * struct adreno_perfcount_register: register state + * @countable: countable the register holds + * @refcount: number of users of the register + * @offset: register hardware offset + */ +struct adreno_perfcount_register { + unsigned int countable; + unsigned int refcount; + unsigned int offset; + unsigned int flags; +}; + +/** + * struct adreno_perfcount_group: registers for a hardware group + * @regs: available registers for this group + * @reg_count: total registers for this group + */ +struct adreno_perfcount_group { + struct adreno_perfcount_register *regs; + unsigned int reg_count; +}; + +/** + * adreno_perfcounts: all available perfcounter groups + * @groups: available groups for this device + * @group_count: total groups for this device + */ +struct adreno_perfcounters { + struct adreno_perfcount_group *groups; + unsigned int group_count; }; struct adreno_gpudev { @@ -124,6 +166,8 @@ struct adreno_gpudev { /* keeps track of when we need to execute the draw workaround code */ int ctx_switches_since_last_draw; + struct adreno_perfcounters *perfcounters; + /* GPU specific function hooks */ int (*ctxt_create)(struct adreno_device *, struct adreno_context *); void (*ctxt_save)(struct adreno_device *, struct adreno_context *); @@ -134,9 +178,15 @@ struct adreno_gpudev { void (*irq_control)(struct adreno_device *, int); unsigned int (*irq_pending)(struct adreno_device *); void * (*snapshot)(struct adreno_device *, void *, int *, int); - void (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *); + int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *); + void (*perfcounter_init)(struct adreno_device *); void (*start)(struct adreno_device *); unsigned int (*busy_cycles)(struct adreno_device *); + void (*perfcounter_enable)(struct adreno_device *, unsigned int group, + unsigned int counter, unsigned int countable); + uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev, + unsigned int group, unsigned int counter, + unsigned int offset); }; /* @@ -179,6 +229,8 @@ struct adreno_ft_data { unsigned int replay_for_snapshot; }; +#define FT_DETECT_REGS_COUNT 12 + /* Fault Tolerance policy flags */ #define KGSL_FT_DISABLE BIT(0) #define KGSL_FT_REPLAY BIT(1) @@ -188,10 +240,10 @@ struct adreno_ft_data { #define KGSL_FT_DEFAULT_POLICY (KGSL_FT_REPLAY + KGSL_FT_SKIPIB) /* Pagefault policy flags */ -#define KGSL_FT_PAGEFAULT_INT_ENABLE 0x00000001 -#define KGSL_FT_PAGEFAULT_GPUHALT_ENABLE 0x00000002 -#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE 0x00000004 -#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT 0x00000008 +#define KGSL_FT_PAGEFAULT_INT_ENABLE BIT(0) +#define KGSL_FT_PAGEFAULT_GPUHALT_ENABLE BIT(1) +#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE BIT(2) +#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT BIT(3) #define KGSL_FT_PAGEFAULT_DEFAULT_POLICY (KGSL_FT_PAGEFAULT_INT_ENABLE + \ KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) @@ -217,7 +269,6 @@ extern const unsigned int a330_registers[]; extern const unsigned int a330_registers_count; extern unsigned int ft_detect_regs[]; -extern const unsigned int ft_detect_regs_count; int adreno_idle(struct kgsl_device *device); @@ -227,6 +278,8 @@ void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value); int adreno_dump(struct kgsl_device *device, int manual); +unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device + *adreno_dev); struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device, unsigned int pt_base, @@ -250,6 +303,16 @@ void adreno_dump_rb(struct kgsl_device *device, const void *buf, unsigned int adreno_ft_detect(struct kgsl_device *device, unsigned int *prev_reg_val); +int adreno_perfcounter_get(struct adreno_device *adreno_dev, + unsigned int groupid, unsigned int countable, unsigned int *offset, + unsigned int flags); + +int adreno_perfcounter_put(struct adreno_device *adreno_dev, + unsigned int groupid, unsigned int countable); + +int adreno_ft_init_sysfs(struct kgsl_device *device); +void adreno_ft_uninit_sysfs(struct kgsl_device *device); + static inline int adreno_is_a200(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A200); @@ -311,12 +374,32 @@ static inline int adreno_is_a330(struct adreno_device *adreno_dev) return (adreno_dev->gpurev == ADRENO_REV_A330); } +static inline int adreno_is_a330v2(struct adreno_device *adreno_dev) +{ + return ((adreno_dev->gpurev == ADRENO_REV_A330) && + (ADRENO_CHIPID_PATCH(adreno_dev->chip_id) > 0)); +} + static inline int adreno_rb_ctxtswitch(unsigned int *cmd) { return (cmd[0] == cp_nop_packet(1) && cmd[1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER); } +static inline int adreno_context_timestamp(struct kgsl_context *k_ctxt, + struct adreno_ringbuffer *rb) +{ + struct adreno_context *a_ctxt = NULL; + + if (k_ctxt) + a_ctxt = k_ctxt->devctxt; + + if (a_ctxt && a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS) + return a_ctxt->timestamp; + + return rb->global_ts; +} + /** * adreno_encode_istore_size - encode istore size in CP format * @adreno_dev - The 3D device. @@ -401,6 +484,11 @@ static inline int adreno_add_read_cmds(struct kgsl_device *device, *cmds++ = val; *cmds++ = 0xFFFFFFFF; *cmds++ = 0xFFFFFFFF; + + /* WAIT_REG_MEM turns back on protected mode - push it off */ + *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1); + *cmds++ = 0; + cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr); return cmds - start; } @@ -427,4 +515,55 @@ static inline int adreno_add_idle_cmds(struct adreno_device *adreno_dev, return cmds - start; } +#ifdef CONFIG_DEBUG_FS +void adreno_debugfs_init(struct kgsl_device *device); +#else +static inline void adreno_debugfs_init(struct kgsl_device *device) { } +#endif + +/** + * adreno_set_protected_registers() - Protect the specified range of registers + * from being accessed by the GPU + * @device: pointer to the KGSL device + * @index: Pointer to the index of the protect mode register to write to + * @reg: Starting dword register to write + * @mask: Size of the mask to protect (A3xx# of registers = 2 ** mask, + * A2xx# Contains the address mask used to mask the protect base address) + * + * Add the range of registers to the list of protected mode registers that will + * cause an exception if the GPU accesses them. There are 16 available + * protected mode registers. Index is used to specify which register to write + * to - the intent is to call this function multiple times with the same index + * pointer for each range and the registers will be magically programmed in + * incremental fashion + */ +static inline void adreno_set_protected_registers(struct kgsl_device *device, + unsigned int *index, unsigned int reg, int mask) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + unsigned int val; + unsigned int protect_reg_offset; + + /* There are only 16 registers available */ + BUG_ON(*index >= 16); + + if (adreno_is_a3xx(adreno_dev)) { + val = 0x60000000 | ((mask & 0x1F) << 24) | + ((reg << 2) & 0x1FFFF); + protect_reg_offset = A3XX_CP_PROTECT_REG_0; + } else if (adreno_is_a2xx(adreno_dev)) { + val = 0xc0000000 | ((reg << 2) << 16) | (mask & 0xffff); + protect_reg_offset = REG_RBBM_PROTECT_0; + } else { + return; + } + + /* + * Write the protection range to the next available protection + * register + */ + + kgsl_regwrite(device, protect_reg_offset + *index, val); + *index = *index + 1; +} #endif /*__ADRENO_H */ diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c index d88494f2..05aa5056 100644 --- a/drivers/gpu/msm/adreno_a2xx.c +++ b/drivers/gpu/msm/adreno_a2xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1515,18 +1515,26 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev, "Current active context has caused gpu hang\n"); if (!(context->flags & CTXT_FLAGS_PREAMBLE)) { - + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->reg_save[1], + context->reg_save[2] << 2, true); /* save registers and constants. */ adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE, context->reg_save, 3); if (context->flags & CTXT_FLAGS_SHADER_SAVE) { + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->shader_save[1], + context->shader_save[2] << 2, true); /* save shader partitioning and instructions. */ adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_PMODE, context->shader_save, 3); + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->shader_fixup[1], + context->shader_fixup[2] << 2, true); /* * fixup shader partitioning parameter for * SET_SHADER_BASES. @@ -1541,6 +1549,9 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev, if ((context->flags & CTXT_FLAGS_GMEM_SAVE) && (context->flags & CTXT_FLAGS_GMEM_SHADOW)) { + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->context_gmem_shadow.gmem_save[1], + context->context_gmem_shadow.gmem_save[2] << 2, true); /* save gmem. * (note: changes shader. shader must already be saved.) */ @@ -1548,6 +1559,10 @@ static void a2xx_drawctxt_save(struct adreno_device *adreno_dev, KGSL_CMD_FLAGS_PMODE, context->context_gmem_shadow.gmem_save, 3); + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->chicken_restore[1], + context->chicken_restore[2] << 2, true); + /* Restore TP0_CHICKEN */ if (!(context->flags & CTXT_FLAGS_PREAMBLE)) { adreno_ringbuffer_issuecmds(device, context, @@ -1565,7 +1580,9 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev, struct adreno_context *context) { struct kgsl_device *device = &adreno_dev->dev; - unsigned int cmds[5]; + unsigned int link[10]; + unsigned int *cmds = &link[0]; + unsigned int sizedwords = 0; if (context == NULL) { /* No context - set the default apgetable and thats it */ @@ -1576,31 +1593,42 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev, KGSL_CTXT_INFO(device, "context flags %08x\n", context->flags); - cmds[0] = cp_nop_packet(1); - cmds[1] = KGSL_CONTEXT_TO_MEM_IDENTIFIER; - cmds[2] = cp_type3_packet(CP_MEM_WRITE, 2); - cmds[3] = device->memstore.gpuaddr + + /* Reset VSC Binning cntrol Regiseter */ + if (adreno_is_a225(adreno_dev)) { + *cmds++ = cp_type0_packet(REG_VSC_BINNING_ENABLE, 1); + *cmds++ = 0; + } + + *cmds++ = cp_nop_packet(1); + *cmds++ = KGSL_CONTEXT_TO_MEM_IDENTIFIER; + *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2); + *cmds++ = device->memstore.gpuaddr + KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context); - cmds[4] = context->id; + *cmds++ = context->id; + sizedwords = (cmds - &link[0]); + adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE, - cmds, 5); + &link[0], sizedwords); kgsl_mmu_setstate(&device->mmu, context->pagetable, context->id); -#ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP - kgsl_cffdump_syncmem(NULL, &context->gpustate, - context->gpustate.gpuaddr, LCC_SHADOW_SIZE + - REG_SHADOW_SIZE + CMD_BUFFER_SIZE + TEX_SHADOW_SIZE, false); -#endif - /* restore gmem. * (note: changes shader. shader must not already be restored.) */ if (context->flags & CTXT_FLAGS_GMEM_RESTORE) { + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->context_gmem_shadow.gmem_restore[1], + context->context_gmem_shadow.gmem_restore[2] << 2, + true); + adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_PMODE, context->context_gmem_shadow.gmem_restore, 3); if (!(context->flags & CTXT_FLAGS_PREAMBLE)) { + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->chicken_restore[1], + context->chicken_restore[2] << 2, true); + /* Restore TP0_CHICKEN */ adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE, @@ -1611,6 +1639,9 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev, } if (!(context->flags & CTXT_FLAGS_PREAMBLE)) { + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->reg_restore[1], + context->reg_restore[2] << 2, true); /* restore registers and constants. */ adreno_ringbuffer_issuecmds(device, context, @@ -1618,6 +1649,10 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev, /* restore shader instructions & partitioning. */ if (context->flags & CTXT_FLAGS_SHADER_RESTORE) { + kgsl_cffdump_syncmem(NULL, &context->gpustate, + context->shader_restore[1], + context->shader_restore[2] << 2, true); + adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE, context->shader_restore, 3); @@ -1643,7 +1678,8 @@ static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev, * managing the interrupts */ -#define RBBM_INT_MASK RBBM_INT_CNTL__RDERR_INT_MASK +#define RBBM_INT_MASK (RBBM_INT_CNTL__RDERR_INT_MASK | \ + RBBM_INT_CNTL__PROTECT_INT_MASK) #define CP_INT_MASK \ (CP_INT_CNTL__T0_PACKET_IN_IB_MASK | \ @@ -1764,6 +1800,16 @@ static void a2xx_rbbm_intrcallback(struct kgsl_device *device) KGSL_DRV_CRIT(device, "rbbm read error interrupt: %s reg: %04X\n", source, addr); + } else if (status & RBBM_INT_CNTL__PROTECT_INT_MASK) { + adreno_regread(device, REG_RBBM_READ_ERROR, &rderr); + source = (rderr & RBBM_READ_ERROR_REQUESTER) + ? "host" : "cp"; + /* convert to dword address */ + addr = (rderr & RBBM_READ_ERROR_ADDRESS_MASK) >> 2; + KGSL_DRV_CRIT(device, + "RBBM | Protected mode error |%s|%s| addr=%x\n", + rderr & (1 << 31) ? "WRITE" : "READ", source, + addr); } status &= RBBM_INT_MASK; @@ -1828,13 +1874,16 @@ static unsigned int a2xx_irq_pending(struct adreno_device *adreno_dev) MASTER_INT_SIGNAL__RBBM_INT_STAT)) ? 1 : 0; } -static void a2xx_rb_init(struct adreno_device *adreno_dev, +static int a2xx_rb_init(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { unsigned int *cmds, cmds_gpu; /* ME_INIT */ cmds = adreno_ringbuffer_allocspace(rb, NULL, 19); + if (cmds == NULL) + return -ENOMEM; + cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19); GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 18)); @@ -1874,19 +1923,18 @@ static void a2xx_rb_init(struct adreno_device *adreno_dev, /* NQ and External Memory Swap */ GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); - /* Protected mode error checking - * If iommu is used then protection needs to be turned off - * to enable context bank switching */ - if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) - GSL_RB_WRITE(cmds, cmds_gpu, 0); - else - GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL); + + /* Enable Protected mode registers for A2xx */ + GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL); + /* Disable header dumping and Header dump address */ GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); /* Header dump size */ GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); adreno_ringbuffer_submit(rb); + + return 0; } static unsigned int a2xx_busy_cycles(struct adreno_device *adreno_dev) @@ -1938,6 +1986,38 @@ static void a2xx_gmeminit(struct adreno_device *adreno_dev) adreno_regwrite(device, REG_RB_EDRAM_INFO, rb_edram_info.val); } +/** + * a2xx_protect_init() - Initializes register protection on a3xx + * @device: Pointer to the device structure + * Performs register writes to enable protected access to sensitive + * registers + */ +static void a2xx_protect_init(struct kgsl_device *device) +{ + int index = 0; + + /* Enable access protection to privileged registers */ + kgsl_regwrite(device, REG_RBBM_INT_CNTL, + RBBM_INT_CNTL__PROTECT_INT_MASK); + + /* RBBM_SOFT_RESET register */ + adreno_set_protected_registers(device, &index, 0x03C, 0x0); + /* RBBM_INT_CNTL & RBBM_INT_STATUS */ + adreno_set_protected_registers(device, &index, 0x3B4, 0x1); + /* RBBM_PROTECT_ registers */ + adreno_set_protected_registers(device, &index, 0x140, 0xF); + + /* CP registers */ + adreno_set_protected_registers(device, &index, 0x1C0, 0x20); + /* CP_STATE_DEBUG_INDEX & CP_STATE_DEBUG_DATA */ + adreno_set_protected_registers(device, &index, 0x1EC, 0x1); + /* CP_ME_CNTL,CP_ME_STATUS, CP_ME_RAM_ and CP_DEBUG registers */ + adreno_set_protected_registers(device, &index, 0x1F6, 0x7); + + /* MH_MMU_PT_BASE register */ + adreno_set_protected_registers(device, &index, 0x042, 0x0); +} + static void a2xx_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = &adreno_dev->dev; @@ -2000,6 +2080,9 @@ static void a2xx_start(struct adreno_device *adreno_dev) adreno_regwrite(device, REG_RBBM_DEBUG, 0x00080000); + /* Turn on protection */ + a2xx_protect_init(device); + /* Make sure interrupts are disabled */ adreno_regwrite(device, REG_RBBM_INT_CNTL, 0); adreno_regwrite(device, REG_CP_INT_CNTL, 0); diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c index 75795b13..2c86f82d 100644 --- a/drivers/gpu/msm/adreno_a2xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c @@ -224,6 +224,31 @@ static int a2xx_snapshot_miudebug(struct kgsl_device *device, void *snapshot, return DEBUG_SECTION_SZ(MIUDEBUG_COUNT); } +/* Snapshot the istore memory */ +static int a2xx_snapshot_istore(struct kgsl_device *device, void *snapshot, + int remain, void *priv) +{ + struct kgsl_snapshot_istore *header = snapshot; + unsigned int *data = snapshot + sizeof(*header); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + int count, i; + + count = adreno_dev->istore_size * adreno_dev->instruction_size; + + if (remain < (count * 4) + sizeof(*header)) { + KGSL_DRV_ERR(device, + "snapshot: Not enough memory for the istore section"); + return 0; + } + + header->count = adreno_dev->istore_size; + + for (i = 0; i < count; i++) + kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]); + + return (count * 4) + sizeof(*header); +} + /* A2XX GPU snapshot function - this is where all of the A2XX specific * bits and pieces are grabbed into the snapshot memory */ @@ -338,6 +363,18 @@ void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, } } + /* + * Only dump the istore on a hang - reading it on a running system + * has a non zero chance of hanging the GPU. + */ + + if (adreno_is_a2xx(adreno_dev) && hang) { + snapshot = kgsl_snapshot_add_section(device, + KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain, + a2xx_snapshot_istore, NULL); + } + + /* Reset the clock gating */ adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride); diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 019a6c78..9c1341d7 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -445,6 +445,21 @@ static void build_regconstantsave_cmds(struct adreno_device *adreno_dev, tmp_ctx.cmd = cmd; } +unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device + *adreno_dev) +{ + if (adreno_is_a305(adreno_dev)) + return A305_RBBM_CLOCK_CTL_DEFAULT; + else if (adreno_is_a320(adreno_dev)) + return A320_RBBM_CLOCK_CTL_DEFAULT; + else if (adreno_is_a330v2(adreno_dev)) + return A330v2_RBBM_CLOCK_CTL_DEFAULT; + else if (adreno_is_a330(adreno_dev)) + return A330_RBBM_CLOCK_CTL_DEFAULT; + + BUG_ON(1); +} + /* Copy GMEM contents to system memory shadow. */ static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev, struct adreno_context *drawctxt, @@ -454,7 +469,7 @@ static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev, unsigned int *start = cmds; *cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1); - *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT; + *cmds++ = adreno_a3xx_rbbm_clock_ctl_default(adreno_dev); *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3); *cmds++ = CP_REG(A3XX_RB_MODE_CONTROL); @@ -1250,7 +1265,7 @@ static unsigned int *build_sys2gmem_cmds(struct adreno_device *adreno_dev, unsigned int *start = cmds; *cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1); - *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT; + *cmds++ = adreno_a3xx_rbbm_clock_ctl_default(adreno_dev); *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5); *cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG); @@ -2400,6 +2415,11 @@ static void a3xx_drawctxt_save(struct adreno_device *adreno_dev, * already be saved.) */ + kgsl_cffdump_syncmem(NULL, + &context->gpustate, + context->context_gmem_shadow.gmem_save[1], + context->context_gmem_shadow.gmem_save[2] << 2, true); + adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_PMODE, context->context_gmem_shadow. @@ -2439,6 +2459,12 @@ static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev, */ if (context->flags & CTXT_FLAGS_GMEM_RESTORE) { + kgsl_cffdump_syncmem(NULL, + &context->gpustate, + context->context_gmem_shadow.gmem_restore[1], + context->context_gmem_shadow.gmem_restore[2] << 2, + true); + adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_PMODE, context->context_gmem_shadow. @@ -2471,11 +2497,14 @@ static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev, } } -static void a3xx_rb_init(struct adreno_device *adreno_dev, +static int a3xx_rb_init(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { unsigned int *cmds, cmds_gpu; cmds = adreno_ringbuffer_allocspace(rb, NULL, 18); + if (cmds == NULL) + return -ENOMEM; + cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint) * (rb->wptr - 18); GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 17)); @@ -2493,12 +2522,14 @@ static void a3xx_rb_init(struct adreno_device *adreno_dev, GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001); GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); - /* Protected mode control - turned off for A3XX */ - GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); + /* Enable protected mode registers for A3XX */ + GSL_RB_WRITE(cmds, cmds_gpu, 0x20000000); GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000); adreno_ringbuffer_submit(rb); + + return 0; } static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit) @@ -2554,9 +2585,16 @@ static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit) case A3XX_INT_CP_HW_FAULT: err = "ringbuffer hardware fault"; break; - case A3XX_INT_CP_REG_PROTECT_FAULT: - err = "ringbuffer protected mode error interrupt"; - break; + case A3XX_INT_CP_REG_PROTECT_FAULT: { + unsigned int reg; + kgsl_regread(device, A3XX_CP_PROTECT_STATUS, ®); + + KGSL_DRV_CRIT(device, + "CP | Protected mode error| %s | addr=%x\n", + reg & (1 << 24) ? "WRITE" : "READ", + (reg & 0x1FFFF) >> 2); + return; + } case A3XX_INT_CP_AHB_ERROR_HALT: err = "ringbuffer AHB error interrupt"; break; @@ -2583,6 +2621,272 @@ static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq) queue_work(device->work_queue, &device->ts_expired_ws); } +/** + * struct a3xx_perfcounter_register - Define a performance counter register + * @load_bit: the bit to set in RBBM_LOAD_CMD0/RBBM_LOAD_CMD1 to force the RBBM + * to load the reset value into the appropriate counter + * @select: The dword offset of the register to write the selected + * countable into + */ + +struct a3xx_perfcounter_register { + unsigned int load_bit; + unsigned int select; +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_cp[] = { + { 0, A3XX_CP_PERFCOUNTER_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rbbm[] = { + { 1, A3XX_RBBM_PERFCOUNTER0_SELECT }, + { 2, A3XX_RBBM_PERFCOUNTER1_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_pc[] = { + { 3, A3XX_PC_PERFCOUNTER0_SELECT }, + { 4, A3XX_PC_PERFCOUNTER1_SELECT }, + { 5, A3XX_PC_PERFCOUNTER2_SELECT }, + { 6, A3XX_PC_PERFCOUNTER3_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vfd[] = { + { 7, A3XX_VFD_PERFCOUNTER0_SELECT }, + { 8, A3XX_VFD_PERFCOUNTER1_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_hlsq[] = { + { 9, A3XX_HLSQ_PERFCOUNTER0_SELECT }, + { 10, A3XX_HLSQ_PERFCOUNTER1_SELECT }, + { 11, A3XX_HLSQ_PERFCOUNTER2_SELECT }, + { 12, A3XX_HLSQ_PERFCOUNTER3_SELECT }, + { 13, A3XX_HLSQ_PERFCOUNTER4_SELECT }, + { 14, A3XX_HLSQ_PERFCOUNTER5_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_vpc[] = { + { 15, A3XX_VPC_PERFCOUNTER0_SELECT }, + { 16, A3XX_VPC_PERFCOUNTER1_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tse[] = { + { 17, A3XX_GRAS_PERFCOUNTER0_SELECT }, + { 18, A3XX_GRAS_PERFCOUNTER1_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_ras[] = { + { 19, A3XX_GRAS_PERFCOUNTER2_SELECT }, + { 20, A3XX_GRAS_PERFCOUNTER3_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_uche[] = { + { 21, A3XX_UCHE_PERFCOUNTER0_SELECT }, + { 22, A3XX_UCHE_PERFCOUNTER1_SELECT }, + { 23, A3XX_UCHE_PERFCOUNTER2_SELECT }, + { 24, A3XX_UCHE_PERFCOUNTER3_SELECT }, + { 25, A3XX_UCHE_PERFCOUNTER4_SELECT }, + { 26, A3XX_UCHE_PERFCOUNTER5_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_tp[] = { + { 27, A3XX_TP_PERFCOUNTER0_SELECT }, + { 28, A3XX_TP_PERFCOUNTER1_SELECT }, + { 29, A3XX_TP_PERFCOUNTER2_SELECT }, + { 30, A3XX_TP_PERFCOUNTER3_SELECT }, + { 31, A3XX_TP_PERFCOUNTER4_SELECT }, + { 32, A3XX_TP_PERFCOUNTER5_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_sp[] = { + { 33, A3XX_SP_PERFCOUNTER0_SELECT }, + { 34, A3XX_SP_PERFCOUNTER1_SELECT }, + { 35, A3XX_SP_PERFCOUNTER2_SELECT }, + { 36, A3XX_SP_PERFCOUNTER3_SELECT }, + { 37, A3XX_SP_PERFCOUNTER4_SELECT }, + { 38, A3XX_SP_PERFCOUNTER5_SELECT }, + { 39, A3XX_SP_PERFCOUNTER6_SELECT }, + { 40, A3XX_SP_PERFCOUNTER7_SELECT }, +}; + +static struct a3xx_perfcounter_register a3xx_perfcounter_reg_rb[] = { + { 41, A3XX_RB_PERFCOUNTER0_SELECT }, + { 42, A3XX_RB_PERFCOUNTER1_SELECT }, +}; + +#define REGCOUNTER_GROUP(_x) { (_x), ARRAY_SIZE((_x)) } + +static struct { + struct a3xx_perfcounter_register *regs; + int count; +} a3xx_perfcounter_reglist[] = { + REGCOUNTER_GROUP(a3xx_perfcounter_reg_cp), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_rbbm), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_pc), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_vfd), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_hlsq), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_vpc), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_tse), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_ras), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_uche), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_tp), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_sp), + REGCOUNTER_GROUP(a3xx_perfcounter_reg_rb), +}; + +static void a3xx_perfcounter_enable_pwr(struct kgsl_device *device, + unsigned int countable) +{ + unsigned int in, out; + + adreno_regread(device, A3XX_RBBM_RBBM_CTL, &in); + + if (countable == 0) + out = in | RBBM_RBBM_CTL_RESET_PWR_CTR0; + else + out = in | RBBM_RBBM_CTL_RESET_PWR_CTR1; + + adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out); + + if (countable == 0) + out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR0; + else + out = in | RBBM_RBBM_CTL_ENABLE_PWR_CTR1; + + adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, out); + + return; +} + +static void a3xx_perfcounter_enable_vbif(struct kgsl_device *device, + unsigned int counter, + unsigned int countable) +{ + unsigned int in, out, bit, sel; + + if (counter > 1 || countable > 0x7f) + return; + + adreno_regread(device, A3XX_VBIF_PERF_CNT_EN, &in); + adreno_regread(device, A3XX_VBIF_PERF_CNT_SEL, &sel); + + if (counter == 0) { + bit = VBIF_PERF_CNT_0; + sel = (sel & ~VBIF_PERF_CNT_0_SEL_MASK) | countable; + } else { + bit = VBIF_PERF_CNT_1; + sel = (sel & ~VBIF_PERF_CNT_1_SEL_MASK) + | (countable << VBIF_PERF_CNT_1_SEL); + } + + out = in | bit; + + adreno_regwrite(device, A3XX_VBIF_PERF_CNT_SEL, sel); + + adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit); + adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0); + + adreno_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out); +} + +static void a3xx_perfcounter_enable_vbif_pwr(struct kgsl_device *device, + unsigned int countable) +{ + unsigned int in, out, bit; + + adreno_regread(device, A3XX_VBIF_PERF_CNT_EN, &in); + if (countable == 0) + bit = VBIF_PERF_PWR_CNT_0; + else if (countable == 1) + bit = VBIF_PERF_PWR_CNT_1; + else + bit = VBIF_PERF_PWR_CNT_2; + + out = in | bit; + + adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, bit); + adreno_regwrite(device, A3XX_VBIF_PERF_CNT_CLR, 0); + + adreno_regwrite(device, A3XX_VBIF_PERF_CNT_EN, out); +} + +/* + * a3xx_perfcounter_enable - Configure a performance counter for a countable + * @adreno_dev - Adreno device to configure + * @group - Desired performance counter group + * @counter - Desired performance counter in the group + * @countable - Desired countable + * + * Physically set up a counter within a group with the desired countable + */ + +static void a3xx_perfcounter_enable(struct adreno_device *adreno_dev, + unsigned int group, unsigned int counter, unsigned int countable) +{ + struct kgsl_device *device = &adreno_dev->dev; + unsigned int val = 0; + struct a3xx_perfcounter_register *reg; + + if (group >= ARRAY_SIZE(a3xx_perfcounter_reglist)) + return; + + if (counter >= a3xx_perfcounter_reglist[group].count) + return; + + /* Special cases */ + if (group == KGSL_PERFCOUNTER_GROUP_PWR) + return a3xx_perfcounter_enable_pwr(device, countable); + else if (group == KGSL_PERFCOUNTER_GROUP_VBIF) + return a3xx_perfcounter_enable_vbif(device, counter, countable); + else if (group == KGSL_PERFCOUNTER_GROUP_VBIF_PWR) + return a3xx_perfcounter_enable_vbif_pwr(device, countable); + + reg = &(a3xx_perfcounter_reglist[group].regs[counter]); + + /* Select the desired perfcounter */ + adreno_regwrite(device, reg->select, countable); + + if (reg->load_bit < 32) { + val = 1 << reg->load_bit; + adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD0, val); + } else { + val = 1 << (reg->load_bit - 32); + adreno_regwrite(device, A3XX_RBBM_PERFCTR_LOAD_CMD1, val); + } +} + +static uint64_t a3xx_perfcounter_read(struct adreno_device *adreno_dev, + unsigned int group, unsigned int counter, + unsigned int offset) +{ + struct kgsl_device *device = &adreno_dev->dev; + struct a3xx_perfcounter_register *reg = NULL; + unsigned int lo = 0, hi = 0; + unsigned int val; + + if (group >= ARRAY_SIZE(a3xx_perfcounter_reglist)) + return 0; + + if (counter >= a3xx_perfcounter_reglist[group].count) + return 0; + + reg = &(a3xx_perfcounter_reglist[group].regs[counter]); + + /* Freeze the counter */ + adreno_regread(device, A3XX_RBBM_PERFCTR_CTL, &val); + val &= ~reg->load_bit; + adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val); + + /* Read the values */ + adreno_regread(device, offset, &lo); + adreno_regread(device, offset + 1, &hi); + + /* Re-Enable the counter */ + val |= reg->load_bit; + adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, val); + + return (((uint64_t) hi) << 32) | lo; +} + #define A3XX_IRQ_CALLBACK(_c) { .func = _c } #define A3XX_INT_MASK \ @@ -2684,26 +2988,22 @@ static unsigned int a3xx_irq_pending(struct adreno_device *adreno_dev) static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev) { struct kgsl_device *device = &adreno_dev->dev; - unsigned int reg, val; - - /* Freeze the counter */ - adreno_regread(device, A3XX_RBBM_RBBM_CTL, ®); - reg &= ~RBBM_RBBM_CTL_ENABLE_PWR_CTR1; - adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg); + unsigned int val; + unsigned int ret = 0; /* Read the value */ adreno_regread(device, A3XX_RBBM_PERFCTR_PWR_1_LO, &val); - /* Reset the counter */ - reg |= RBBM_RBBM_CTL_RESET_PWR_CTR1; - adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg); - - /* Re-enable the counter */ - reg &= ~RBBM_RBBM_CTL_RESET_PWR_CTR1; - reg |= RBBM_RBBM_CTL_ENABLE_PWR_CTR1; - adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, reg); + /* Return 0 for the first read */ + if (adreno_dev->gpu_cycles != 0) { + if (val < adreno_dev->gpu_cycles) + ret = (0xFFFFFFFF - adreno_dev->gpu_cycles) + val; + else + ret = val - adreno_dev->gpu_cycles; + } - return val; + adreno_dev->gpu_cycles = val; + return ret; } struct a3xx_vbif_data { @@ -2781,17 +3081,123 @@ static struct a3xx_vbif_data a330_vbif[] = { {0, 0}, }; +/* + * Most of the VBIF registers on 8974v2 have the correct values at power on, so + * we won't modify those if we don't need to + */ +static struct a3xx_vbif_data a330v2_vbif[] = { + /* Enable 1k sort */ + { A3XX_VBIF_ABIT_SORT, 0x0001003F }, + { A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 }, + /* Enable WR-REQ */ + { A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F }, + { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 }, + /* Set up VBIF_ROUND_ROBIN_QOS_ARB */ + { A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003 }, + /* Disable VBIF clock gating. This is to enable AXI running + * higher frequency than GPU. + */ + { A3XX_VBIF_CLKON, 1 }, + {0, 0}, +}; + +static struct { + int(*devfunc)(struct adreno_device *); + struct a3xx_vbif_data *vbif; +} a3xx_vbif_platforms[] = { + { adreno_is_a305, a305_vbif }, + { adreno_is_a320, a320_vbif }, + /* A330v2 needs to be ahead of A330 so the right device matches */ + { adreno_is_a330v2, a330v2_vbif }, + { adreno_is_a330, a330_vbif }, +}; + +static void a3xx_perfcounter_init(struct adreno_device *adreno_dev) +{ + /* + * Set SP to count SP_ALU_ACTIVE_CYCLES, it includes + * all ALU instruction execution regardless precision or shader ID. + * Set SP to count SP0_ICL1_MISSES, It counts + * USP L1 instruction miss request. + * Set SP to count SP_FS_FULL_ALU_INSTRUCTIONS, it + * counts USP flow control instruction execution. + * we will use this to augment our hang detection + */ + if (adreno_dev->fast_hang_detect) { + adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP, + SP_ALU_ACTIVE_CYCLES, &ft_detect_regs[6], + PERFCOUNTER_FLAG_KERNEL); + ft_detect_regs[7] = ft_detect_regs[6] + 1; + adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP, + SP0_ICL1_MISSES, &ft_detect_regs[8], + PERFCOUNTER_FLAG_KERNEL); + ft_detect_regs[9] = ft_detect_regs[8] + 1; + adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP, + SP_FS_CFLOW_INSTRUCTIONS, &ft_detect_regs[10], + PERFCOUNTER_FLAG_KERNEL); + ft_detect_regs[11] = ft_detect_regs[10] + 1; + } + + adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_SP, + SP_FS_FULL_ALU_INSTRUCTIONS, NULL, PERFCOUNTER_FLAG_KERNEL); + + /* Reserve and start countable 1 in the PWR perfcounter group */ + adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1, + NULL, PERFCOUNTER_FLAG_KERNEL); +} + +/** + * a3xx_protect_init() - Initializes register protection on a3xx + * @device: Pointer to the device structure + * Performs register writes to enable protected access to sensitive + * registers + */ +static void a3xx_protect_init(struct kgsl_device *device) +{ + int index = 0; + + /* enable access protection to privileged registers */ + kgsl_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007); + + /* RBBM registers */ + adreno_set_protected_registers(device, &index, 0x18, 0); + adreno_set_protected_registers(device, &index, 0x20, 2); + adreno_set_protected_registers(device, &index, 0x33, 0); + adreno_set_protected_registers(device, &index, 0x42, 0); + adreno_set_protected_registers(device, &index, 0x50, 4); + adreno_set_protected_registers(device, &index, 0x63, 0); + adreno_set_protected_registers(device, &index, 0x100, 4); + + /* CP registers */ + adreno_set_protected_registers(device, &index, 0x1C0, 5); + adreno_set_protected_registers(device, &index, 0x1EC, 1); + adreno_set_protected_registers(device, &index, 0x1F6, 1); + adreno_set_protected_registers(device, &index, 0x1F8, 2); + adreno_set_protected_registers(device, &index, 0x45E, 2); + adreno_set_protected_registers(device, &index, 0x460, 4); + + /* RB registers */ + adreno_set_protected_registers(device, &index, 0xCC0, 0); + + /* VBIF registers */ + adreno_set_protected_registers(device, &index, 0x3000, 6); + + /* SMMU registers */ + adreno_set_protected_registers(device, &index, 0x4000, 14); +} + static void a3xx_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = &adreno_dev->dev; struct a3xx_vbif_data *vbif = NULL; + int i; - if (adreno_is_a305(adreno_dev)) - vbif = a305_vbif; - else if (adreno_is_a320(adreno_dev)) - vbif = a320_vbif; - else if (adreno_is_a330(adreno_dev)) - vbif = a330_vbif; + for (i = 0; i < ARRAY_SIZE(a3xx_vbif_platforms); i++) { + if (a3xx_vbif_platforms[i].devfunc(adreno_dev)) { + vbif = a3xx_vbif_platforms[i].vbif; + break; + } + } BUG_ON(vbif == NULL); @@ -2829,36 +3235,153 @@ static void a3xx_start(struct adreno_device *adreno_dev) /* Enable Clock gating */ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, - A3XX_RBBM_CLOCK_CTL_DEFAULT); + adreno_a3xx_rbbm_clock_ctl_default(adreno_dev)); + + if (adreno_is_a330v2(adreno_dev)) + adreno_regwrite(device, A3XX_RBBM_GPR0_CTL, + A330v2_RBBM_GPR0_CTL_DEFAULT); + else if (adreno_is_a330(adreno_dev)) + adreno_regwrite(device, A3XX_RBBM_GPR0_CTL, + A330_RBBM_GPR0_CTL_DEFAULT); /* Set the OCMEM base address for A330 */ if (adreno_is_a330(adreno_dev)) { adreno_regwrite(device, A3XX_RB_GMEM_BASE_ADDR, (unsigned int)(adreno_dev->ocmem_base >> 14)); } + /* Turn on protection */ + a3xx_protect_init(device); /* Turn on performance counters */ adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01); - /* - * Set SP perfcounter 5 to count SP_ALU_ACTIVE_CYCLES, it includes - * all ALU instruction execution regardless precision or shader ID. - * Set SP perfcounter 6 to count SP0_ICL1_MISSES, It counts - * USP L1 instruction miss request. - * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS, it - * counts USP flow control instruction execution. - * we will use this to augment our hang detection - */ - if (adreno_dev->fast_hang_detect) { - adreno_regwrite(device, A3XX_SP_PERFCOUNTER5_SELECT, - SP_ALU_ACTIVE_CYCLES); - adreno_regwrite(device, A3XX_SP_PERFCOUNTER6_SELECT, - SP0_ICL1_MISSES); - adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT, - SP_FS_CFLOW_INSTRUCTIONS); - } + /* Turn on the GPU busy counter and let it run free */ + + adreno_dev->gpu_cycles = 0; } +/* + * Define the available perfcounter groups - these get used by + * adreno_perfcounter_get and adreno_perfcounter_put + */ + +static struct adreno_perfcount_register a3xx_perfcounters_cp[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_CP_0_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_rbbm[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RBBM_1_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_pc[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_1_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_2_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PC_3_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_vfd[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VFD_1_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_hlsq[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_1_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_2_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_3_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_4_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_HLSQ_5_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_vpc[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_VPC_1_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_tse[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TSE_1_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_ras[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RAS_1_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_uche[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_1_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_2_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_3_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_4_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_UCHE_5_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_tp[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_1_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_2_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_3_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_4_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_TP_5_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_sp[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_1_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_2_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_3_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_4_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_5_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_6_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_SP_7_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_rb[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_RB_1_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_pwr[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_0_LO, 0 }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_RBBM_PERFCTR_PWR_1_LO, 0 }, +}; + +static struct adreno_perfcount_register a3xx_perfcounters_vbif[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_CNT0_LO }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_CNT1_LO }, +}; +static struct adreno_perfcount_register a3xx_perfcounters_vbif_pwr[] = { + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT0_LO }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT1_LO }, + { KGSL_PERFCOUNTER_NOT_USED, 0, A3XX_VBIF_PERF_PWR_CNT2_LO }, +}; + +static struct adreno_perfcount_group a3xx_perfcounter_groups[] = { + { a3xx_perfcounters_cp, ARRAY_SIZE(a3xx_perfcounters_cp) }, + { a3xx_perfcounters_rbbm, ARRAY_SIZE(a3xx_perfcounters_rbbm) }, + { a3xx_perfcounters_pc, ARRAY_SIZE(a3xx_perfcounters_pc) }, + { a3xx_perfcounters_vfd, ARRAY_SIZE(a3xx_perfcounters_vfd) }, + { a3xx_perfcounters_hlsq, ARRAY_SIZE(a3xx_perfcounters_hlsq) }, + { a3xx_perfcounters_vpc, ARRAY_SIZE(a3xx_perfcounters_vpc) }, + { a3xx_perfcounters_tse, ARRAY_SIZE(a3xx_perfcounters_tse) }, + { a3xx_perfcounters_ras, ARRAY_SIZE(a3xx_perfcounters_ras) }, + { a3xx_perfcounters_uche, ARRAY_SIZE(a3xx_perfcounters_uche) }, + { a3xx_perfcounters_tp, ARRAY_SIZE(a3xx_perfcounters_tp) }, + { a3xx_perfcounters_sp, ARRAY_SIZE(a3xx_perfcounters_sp) }, + { a3xx_perfcounters_rb, ARRAY_SIZE(a3xx_perfcounters_rb) }, + { a3xx_perfcounters_pwr, ARRAY_SIZE(a3xx_perfcounters_pwr) }, + { a3xx_perfcounters_vbif, ARRAY_SIZE(a3xx_perfcounters_vbif) }, + { a3xx_perfcounters_vbif_pwr, ARRAY_SIZE(a3xx_perfcounters_vbif_pwr) }, +}; + +static struct adreno_perfcounters a3xx_perfcounters = { + a3xx_perfcounter_groups, + ARRAY_SIZE(a3xx_perfcounter_groups), +}; + /* Defined in adreno_a3xx_snapshot.c */ void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, int *remain, int hang); @@ -2867,16 +3390,20 @@ struct adreno_gpudev adreno_a3xx_gpudev = { .reg_rbbm_status = A3XX_RBBM_STATUS, .reg_cp_pfp_ucode_addr = A3XX_CP_PFP_UCODE_ADDR, .reg_cp_pfp_ucode_data = A3XX_CP_PFP_UCODE_DATA, + .perfcounters = &a3xx_perfcounters, .ctxt_create = a3xx_drawctxt_create, .ctxt_save = a3xx_drawctxt_save, .ctxt_restore = a3xx_drawctxt_restore, .ctxt_draw_workaround = NULL, .rb_init = a3xx_rb_init, + .perfcounter_init = a3xx_perfcounter_init, .irq_control = a3xx_irq_control, .irq_handler = a3xx_irq_handler, .irq_pending = a3xx_irq_pending, .busy_cycles = a3xx_busy_cycles, .start = a3xx_start, .snapshot = a3xx_snapshot, + .perfcounter_enable = a3xx_perfcounter_enable, + .perfcounter_read = a3xx_perfcounter_read, }; diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c index d9d5ec82..b939fa00 100644 --- a/drivers/gpu/msm/adreno_a3xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012,2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,22 @@ #define SHADER_MEMORY_SIZE 0x4000 +/** + * _rbbm_debug_bus_read - Helper function to read data from the RBBM + * debug bus. + * @device - GPU device to read/write registers + * @block_id - Debug bus block to read from + * @index - Index in the debug bus block to read + * @ret - Value of the register read + */ +static void _rbbm_debug_bus_read(struct kgsl_device *device, + unsigned int block_id, unsigned int index, unsigned int *val) +{ + unsigned int block = (block_id << 8) | 1 << 16; + adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, block | index); + adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS, val); +} + static int a3xx_snapshot_shader_memory(struct kgsl_device *device, void *snapshot, int remain, void *priv) { @@ -243,11 +259,8 @@ static int a3xx_snapshot_debugbus_block(struct kgsl_device *device, header->id = id; header->count = DEBUGFS_BLOCK_SIZE; - for (i = 0; i < DEBUGFS_BLOCK_SIZE; i++) { - adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, val | i); - adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS, - &data[i]); - } + for (i = 0; i < DEBUGFS_BLOCK_SIZE; i++) + _rbbm_debug_bus_read(device, id, i, &data[i]); return size; } @@ -309,18 +322,58 @@ static void _snapshot_hlsq_regs(struct kgsl_snapshot_registers *regs, struct kgsl_snapshot_registers_list *list, struct adreno_device *adreno_dev) { - /* HLSQ specific registers */ + struct kgsl_device *device = &adreno_dev->dev; + /* - * Don't dump any a3xx HLSQ registers just yet. Reading the HLSQ - * registers can cause the device to hang if the HLSQ block is - * busy. Add specific checks for each a3xx core as the requirements - * are discovered. Disable by default for now. + * Trying to read HLSQ registers when the HLSQ block is busy + * will cause the device to hang. The RBBM_DEBUG_BUS has information + * that will tell us if the HLSQ block is busy or not. Read values + * from the debug bus to ensure the HLSQ block is not busy (this + * is hardware dependent). If the HLSQ block is busy do not + * dump the registers, otherwise dump the HLSQ registers. */ - if (!adreno_is_a3xx(adreno_dev)) { - regs[list->count].regs = (unsigned int *) a3xx_hlsq_registers; - regs[list->count].count = a3xx_hlsq_registers_count; - list->count++; + + if (adreno_is_a330(adreno_dev)) { + /* + * stall_ctxt_full status bit: RBBM_BLOCK_ID_HLSQ index 49 [27] + * + * if (!stall_context_full) + * then dump HLSQ registers + */ + unsigned int stall_context_full = 0; + + _rbbm_debug_bus_read(device, RBBM_BLOCK_ID_HLSQ, 49, + &stall_context_full); + stall_context_full &= 0x08000000; + + if (stall_context_full) + return; + } else { + /* + * tpif status bits: RBBM_BLOCK_ID_HLSQ index 4 [4:0] + * spif status bits: RBBM_BLOCK_ID_HLSQ index 7 [5:0] + * + * if ((tpif == 0, 1, 28) && (spif == 0, 1, 10)) + * then dump HLSQ registers + */ + unsigned int next_pif = 0; + + /* check tpif */ + _rbbm_debug_bus_read(device, RBBM_BLOCK_ID_HLSQ, 4, &next_pif); + next_pif &= 0x1f; + if (next_pif != 0 && next_pif != 1 && next_pif != 28) + return; + + /* check spif */ + _rbbm_debug_bus_read(device, RBBM_BLOCK_ID_HLSQ, 7, &next_pif); + next_pif &= 0x3f; + if (next_pif != 0 && next_pif != 1 && next_pif != 10) + return; } + + regs[list->count].regs = (unsigned int *) a3xx_hlsq_registers; + regs[list->count].count = a3xx_hlsq_registers_count; + list->count++; } static void _snapshot_a330_regs(struct kgsl_snapshot_registers *regs, @@ -390,6 +443,22 @@ void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, /* Reading these will hang the GPU if it isn't already hung */ if (hang) { + unsigned int reg; + + /* + * Reading the microcode while the CP will is running will + * basically basically move the CP instruction pointer to + * whatever address we read. Big badaboom ensues. Stop the CP + * (if it isn't already stopped) to ensure that we are safe. + * We do this here and not earlier to avoid corrupting the RBBM + * status and CP registers - by the time we get here we don't + * care about the contents of the CP anymore. + */ + + adreno_regread(device, REG_CP_ME_CNTL, ®); + reg |= (1 << 27) | (1 << 28); + adreno_regwrite(device, REG_CP_ME_CNTL, reg); + snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_pfp_ram, NULL); @@ -414,7 +483,7 @@ void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, /* Enable Clock gating */ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, - A3XX_RBBM_CLOCK_CTL_DEFAULT); + adreno_a3xx_rbbm_clock_ctl_default(adreno_dev)); return snapshot; } diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 890c8a18..86dcc430 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -60,43 +60,6 @@ void adreno_debugfs_init(struct kgsl_device *device) &adreno_dev->wait_timeout); debugfs_create_u32("ib_check", 0644, device->d_debugfs, &adreno_dev->ib_check_level); - /* By Default enable fast hang detection */ - adreno_dev->fast_hang_detect = 1; - debugfs_create_u32("fast_hang_detect", 0644, device->d_debugfs, - &adreno_dev->fast_hang_detect); - - /* Top level switch to enable/disable userspace FT control */ - adreno_dev->ft_user_control = 0; - debugfs_create_u32("ft_user_control", 0644, device->d_debugfs, - &adreno_dev->ft_user_control); - /* - * FT policy can be set to any of the options below. - * KGSL_FT_DISABLE -> BIT(0) Set to disable FT - * KGSL_FT_REPLAY -> BIT(1) Set to enable replay - * KGSL_FT_SKIPIB -> BIT(2) Set to skip IB - * KGSL_FT_SKIPFRAME -> BIT(3) Set to skip frame - * by default set FT policy to KGSL_FT_DEFAULT_POLICY - */ - adreno_dev->ft_policy = KGSL_FT_DEFAULT_POLICY; - debugfs_create_u32("ft_policy", 0644, device->d_debugfs, - &adreno_dev->ft_policy); - - /* By default enable long IB detection */ - adreno_dev->long_ib_detect = 1; - debugfs_create_u32("long_ib_detect", 0644, device->d_debugfs, - &adreno_dev->long_ib_detect); - - /* - * FT pagefault policy can be set to any of the options below. - * KGSL_FT_PAGEFAULT_INT_ENABLE -> BIT(0) set to enable pagefault INT - * KGSL_FT_PAGEFAULT_GPUHALT_ENABLE -> BIT(1) Set to enable GPU HALT on - * pagefaults. This stalls the GPU on a pagefault on IOMMU v1 HW. - * KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE -> BIT(2) Set to log only one - * pagefault per page. - * KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT -> BIT(3) Set to log only one - * pagefault per INT. - */ - adreno_dev->ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY; - debugfs_create_u32("ft_pagefault_policy", 0644, device->d_debugfs, - &adreno_dev->ft_pf_policy); + debugfs_create_u32("active_cnt", 0444, device->d_debugfs, + &device->active_cnt); } diff --git a/drivers/gpu/msm/adreno_debugfs.h b/drivers/gpu/msm/adreno_debugfs.h new file mode 100644 index 00000000..af7e797b --- /dev/null +++ b/drivers/gpu/msm/adreno_debugfs.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2002,2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __ADRENO_DEBUGFS_H +#define __ADRENO_DEBUGFS_H + +#ifdef CONFIG_DEBUG_FS + +int adreno_debugfs_init(struct kgsl_device *device); + +extern int adreno_pm_regs_enabled; +extern int adreno_pm_ib_enabled; + +static inline int is_adreno_pm_regs_enabled(void) +{ + return adreno_pm_regs_enabled; +} + +static inline int is_adreno_pm_ib_enabled(void) +{ + return adreno_pm_ib_enabled; +} + +#else +static inline int adreno_debugfs_init(struct kgsl_device *device) +{ + return 0; +} + +static inline int kgsl_pmregs_enabled(void) +{ + /* If debugfs is turned off, then always print registers */ + return 1; +} +#endif + +#endif /* __ADRENO_DEBUGFS_H */ diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c new file mode 100644 index 00000000..72b73b6f --- /dev/null +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -0,0 +1,1415 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include + +#include "kgsl.h" +#include "adreno.h" +#include "adreno_ringbuffer.h" +#include "adreno_trace.h" + +#define ADRENO_DISPATCHER_ACTIVE 0 +#define ADRENO_DISPATCHER_PAUSE 1 + +#define ADRENO_DISPATCHER_SOFT_FAULT 1 +#define ADRENO_DISPATCHER_HARD_FAULT 2 +#define ADRENO_DISPATCHER_TIMEOUT_FAULT 3 + +#define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s)) + +/* Number of commands that can be queued in a context before it sleeps */ +static unsigned int _context_cmdqueue_size = 50; + +/* Number of milliseconds to wait for the context queue to clear */ +static unsigned int _context_queue_wait = 10000; + +/* Number of command batches sent at a time from a single context */ +static unsigned int _context_cmdbatch_burst = 5; + +/* Number of command batches inflight in the ringbuffer at any time */ +static unsigned int _dispatcher_inflight = 15; + +/* Command batch timeout (in milliseconds) */ +static unsigned int _cmdbatch_timeout = 2000; + +/* Interval for reading and comparing fault detection registers */ +static unsigned int _fault_timer_interval = 100; + +/* Local array for the current set of fault detect registers */ +static unsigned int *fault_detect_regs; + +/** + * fault_detect_read() - Read the set of fault detect registers + * @device: Pointer to the KGSL device struct + * + * Read the set of fault detect registers and store them in the local array. + * This is for the initial values that are compared later with + * fault_detect_read_compare + */ +static void fault_detect_read(struct kgsl_device *device) +{ + int i; + + for (i = 0; i < FT_DETECT_REGS_COUNT; i++) { + if (ft_detect_regs[i] == 0) + continue; + adreno_regread(device, ft_detect_regs[i], + &fault_detect_regs[i]); + } +} + +/** + * fault_detect_read_compare() - Read the fault detect registers and compare + * them to the current value + * @device: Pointer to the KGSL device struct + * + * Read the set of fault detect registers and compare them to the current set + * of registers. Return 1 if any of the register values changed + */ +static int fault_detect_read_compare(struct kgsl_device *device) +{ + int i, ret = 0; + + for (i = 0; i < FT_DETECT_REGS_COUNT; i++) { + unsigned int val; + + if (ft_detect_regs[i] == 0) + continue; + adreno_regread(device, ft_detect_regs[i], &val); + if (val != fault_detect_regs[i]) + ret = 1; + fault_detect_regs[i] = val; + } + + return ret; +} + +/** + * adreno_context_get_cmdbatch() - Get a new command from a context queue + * @drawctxt: Pointer to the adreno draw context + * + * Dequeue a new command batch from the context list + */ +static inline struct kgsl_cmdbatch *adreno_context_get_cmdbatch( + struct adreno_context *drawctxt) +{ + struct kgsl_cmdbatch *cmdbatch = NULL; + + mutex_lock(&drawctxt->mutex); + if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { + cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; + + /* + * Don't dequeue a cmdbatch that is still waiting for other + * events + */ + if (kgsl_cmdbatch_sync_pending(cmdbatch)) { + cmdbatch = ERR_PTR(-EAGAIN); + goto done; + } + + drawctxt->cmdqueue_head = + CMDQUEUE_NEXT(drawctxt->cmdqueue_head, + ADRENO_CONTEXT_CMDQUEUE_SIZE); + drawctxt->queued--; + } + +done: + mutex_unlock(&drawctxt->mutex); + + return cmdbatch; +} + +/** + * adreno_context_requeue_cmdbatch() - Put a command back on the context queue + * @drawctxt: Pointer to the adreno draw context + * @cmdbatch: Pointer to the KGSL cmdbatch to requeue + * + * Failure to submit a command to the ringbuffer isn't the fault of the command + * being submitted so if a failure happens, push it back on the head of the the + * context queue to be reconsidered again + */ +static inline void adreno_context_requeue_cmdbatch( + struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch) +{ + unsigned int prev; + mutex_lock(&drawctxt->mutex); + + prev = drawctxt->cmdqueue_head - 1; + + if (prev < 0) + prev = ADRENO_CONTEXT_CMDQUEUE_SIZE - 1; + + /* + * The maximum queue size always needs to be one less then the size of + * the ringbuffer queue so there is "room" to put the cmdbatch back in + */ + + BUG_ON(prev == drawctxt->cmdqueue_tail); + + drawctxt->cmdqueue[prev] = cmdbatch; + drawctxt->queued++; + + /* Reset the command queue head to reflect the newly requeued change */ + drawctxt->cmdqueue_head = prev; + mutex_unlock(&drawctxt->mutex); +} + +/** + * dispatcher_queue_context() - Queue a context in the dispatcher pending list + * @dispatcher: Pointer to the adreno dispatcher struct + * @drawctxt: Pointer to the adreno draw context + * + * Add a context to the dispatcher pending list. + */ +static void dispatcher_queue_context(struct adreno_device *adreno_dev, + struct adreno_context *drawctxt) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + spin_lock(&dispatcher->plist_lock); + + + if (plist_node_empty(&drawctxt->pending)) { + /* Get a reference to the context while it sits on the list */ + _kgsl_context_get(&drawctxt->base); + trace_dispatch_queue_context(drawctxt); + plist_add(&drawctxt->pending, &dispatcher->pending); + } + + spin_unlock(&dispatcher->plist_lock); +} + +/** + * sendcmd() - Send a command batch to the GPU hardware + * @dispatcher: Pointer to the adreno dispatcher struct + * @cmdbatch: Pointer to the KGSL cmdbatch being sent + * + * Send a KGSL command batch to the GPU hardware + */ +static int sendcmd(struct adreno_device *adreno_dev, + struct kgsl_cmdbatch *cmdbatch) +{ + struct kgsl_device *device = &adreno_dev->dev; + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + int ret; + + dispatcher->inflight++; + + mutex_lock(&device->mutex); + + if (dispatcher->inflight == 1) { + /* Time to make the donuts. Turn on the GPU */ + ret = kgsl_active_count_get(device); + if (ret) { + dispatcher->inflight--; + mutex_unlock(&device->mutex); + return ret; + } + } + + ret = adreno_ringbuffer_submitcmd(adreno_dev, cmdbatch); + + /* + * On the first command, if the submission was successful, then read the + * fault registers. If it failed then turn off the GPU. Sad face. + */ + + if (dispatcher->inflight == 1) { + if (ret == 0) + fault_detect_read(device); + else + kgsl_active_count_put(device); + } + + mutex_unlock(&device->mutex); + + if (ret) { + dispatcher->inflight--; + KGSL_DRV_ERR(device, + "Unable to submit command to the ringbuffer\n"); + return ret; + } + + trace_adreno_cmdbatch_submitted(cmdbatch, dispatcher->inflight); + + dispatcher->cmdqueue[dispatcher->tail] = cmdbatch; + dispatcher->tail = (dispatcher->tail + 1) % + ADRENO_DISPATCH_CMDQUEUE_SIZE; + + /* + * If this is the first command in the pipe then the GPU will + * immediately start executing it so we can start the expiry timeout on + * the command batch here. Subsequent command batches will have their + * timer started when the previous command batch is retired + */ + if (dispatcher->inflight == 1) { + cmdbatch->expires = jiffies + + msecs_to_jiffies(_cmdbatch_timeout); + mod_timer(&dispatcher->timer, cmdbatch->expires); + + /* Start the fault detection timer */ + if (adreno_dev->fast_hang_detect) + mod_timer(&dispatcher->fault_timer, + jiffies + + msecs_to_jiffies(_fault_timer_interval)); + } + + return 0; +} + +/** + * dispatcher_context_sendcmds() - Send commands from a context to the GPU + * @adreno_dev: Pointer to the adreno device struct + * @drawctxt: Pointer to the adreno context to dispatch commands from + * + * Dequeue and send a burst of commands from the specified context to the GPU + */ +static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev, + struct adreno_context *drawctxt) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + int count = 0; + + /* + * Each context can send a specific number of command batches per cycle + */ + for ( ; count < _context_cmdbatch_burst && + dispatcher->inflight < _dispatcher_inflight; count++) { + int ret; + struct kgsl_cmdbatch *cmdbatch = + adreno_context_get_cmdbatch(drawctxt); + + if (cmdbatch == NULL) + break; + + /* + * adreno_context_get_cmdbatch returns -EAGAIN if the current + * cmdbatch has pending sync points so no more to do here. + * When the sync points are satisfied then the context will get + * reqeueued + */ + + if (IS_ERR(cmdbatch)) + return count; + + /* + * If this is a synchronization submission then there are no + * commands to submit. Discard it and get the next item from + * the queue. Decrement count so this packet doesn't count + * against the burst for the context + */ + + if (cmdbatch->flags & KGSL_CONTEXT_SYNC) { + count--; + kgsl_cmdbatch_destroy(cmdbatch); + continue; + } + + ret = sendcmd(adreno_dev, cmdbatch); + + /* + * There are various reasons why we can't submit a command (no + * memory for the commands, full ringbuffer, etc) but none of + * these are actually the current command's fault. Requeue it + * back on the context and let it come back around again if + * conditions improve + */ + if (ret) { + adreno_context_requeue_cmdbatch(drawctxt, cmdbatch); + break; + } + } + + /* + * If the context successfully submitted commands, then + * unconditionally put it back on the queue to be considered the + * next time around. This might seem a little wasteful but it is + * reasonable to think that a busy context will stay busy. + */ + + if (count) { + dispatcher_queue_context(adreno_dev, drawctxt); + + /* + * If we submitted something there will be room in the + * context queue so ping the context wait queue on the + * chance that the context is snoozing + */ + + wake_up_interruptible_all(&drawctxt->wq); + } + + return count; +} + +/** + * _adreno_dispatcher_issuecmds() - Issue commmands from pending contexts + * @adreno_dev: Pointer to the adreno device struct + * + * Issue as many commands as possible (up to inflight) from the pending contexts + * This function assumes the dispatcher mutex has been locked. + */ +static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + /* Don't do anything if the dispatcher is paused */ + if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE) + return 0; + + while (dispatcher->inflight < _dispatcher_inflight) { + struct adreno_context *drawctxt = NULL; + + spin_lock(&dispatcher->plist_lock); + + if (!plist_head_empty(&dispatcher->pending)) { + drawctxt = plist_first_entry(&dispatcher->pending, + struct adreno_context, pending); + + plist_del(&drawctxt->pending, &dispatcher->pending); + } + + spin_unlock(&dispatcher->plist_lock); + + if (drawctxt == NULL) + break; + + if (kgsl_context_detached(&drawctxt->base) || + drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) { + kgsl_context_put(&drawctxt->base); + continue; + } + + dispatcher_context_sendcmds(adreno_dev, drawctxt); + kgsl_context_put(&drawctxt->base); + } + + return 0; +} + +/** + * adreno_dispatcher_issuecmds() - Issue commmands from pending contexts + * @adreno_dev: Pointer to the adreno device struct + * + * Lock the dispatcher and call _adreno_dispatcher_issueibcmds + */ +int adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + int ret; + + mutex_lock(&dispatcher->mutex); + ret = _adreno_dispatcher_issuecmds(adreno_dev); + mutex_unlock(&dispatcher->mutex); + + return ret; +} + +static int _check_context_queue(struct adreno_context *drawctxt) +{ + int ret; + + mutex_lock(&drawctxt->mutex); + + /* + * Wake up if there is room in the context or if the whole thing got + * invalidated while we were asleep + */ + + if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) + ret = 1; + else + ret = drawctxt->queued < _context_cmdqueue_size ? 1 : 0; + + mutex_unlock(&drawctxt->mutex); + + return ret; +} + +/** + * get_timestamp() - Return the next timestamp for the context + * @drawctxt - Pointer to an adreno draw context struct + * @cmdbatch - Pointer to a command batch + * @timestamp - Pointer to a timestamp value possibly passed from the user + * + * Assign a timestamp based on the settings of the draw context and the command + * batch. + */ +static int get_timestamp(struct adreno_context *drawctxt, + struct kgsl_cmdbatch *cmdbatch, unsigned int *timestamp) +{ + /* Synchronization commands don't get a timestamp */ + if (cmdbatch->flags & KGSL_CONTEXT_SYNC) { + *timestamp = 0; + return 0; + } + + if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) { + /* + * User specified timestamps need to be greater than the last + * issued timestamp in the context + */ + if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) + return -ERANGE; + + drawctxt->timestamp = *timestamp; + } else + drawctxt->timestamp++; + + *timestamp = drawctxt->timestamp; + return 0; +} + +/** + * adreno_context_queue_cmd() - Queue a new command in the context + * @adreno_dev: Pointer to the adreno device struct + * @drawctxt: Pointer to the adreno draw context + * @cmdbatch: Pointer to the command batch being submitted + * @timestamp: Pointer to the requested timestamp + * + * Queue a command in the context - if there isn't any room in the queue, then + * block until there is + */ +int adreno_context_queue_cmd(struct adreno_device *adreno_dev, + struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch, + uint32_t *timestamp) +{ + int ret; + + mutex_lock(&drawctxt->mutex); + + if (drawctxt->flags & CTXT_FLAGS_BEING_DESTROYED) { + mutex_unlock(&drawctxt->mutex); + return -EINVAL; + } + + /* + * After skipping to the end of the frame we need to force the preamble + * to run (if it exists) regardless of the context state. + */ + + if (drawctxt->flags & CTXT_FLAGS_FORCE_PREAMBLE) { + cmdbatch->priv |= CMDBATCH_FLAG_FORCE_PREAMBLE; + drawctxt->flags &= ~CTXT_FLAGS_FORCE_PREAMBLE; + } + + /* + * If we are waiting for the end of frame and it hasn't appeared yet, + * then mark the command batch as skipped. It will still progress + * through the pipeline but it won't actually send any commands + */ + + if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) { + cmdbatch->priv |= CMDBATCH_FLAG_SKIP; + + /* + * If this command batch represents the EOF then clear the way + * for the dispatcher to continue submitting + */ + + if (cmdbatch->flags & KGSL_CONTEXT_END_OF_FRAME) { + drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF; + + /* + * Force the preamble on the next command to ensure that + * the state is correct + */ + + drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE; + } + } + + /* Wait for room in the context queue */ + + while (drawctxt->queued >= _context_cmdqueue_size) { + trace_adreno_context_sleep(drawctxt); + mutex_unlock(&drawctxt->mutex); + + ret = wait_event_interruptible_timeout(drawctxt->wq, + _check_context_queue(drawctxt), + msecs_to_jiffies(_context_queue_wait)); + + mutex_lock(&drawctxt->mutex); + trace_adreno_context_wake(drawctxt); + + if (ret <= 0) { + mutex_unlock(&drawctxt->mutex); + return (ret == 0) ? -ETIMEDOUT : (int) ret; + } + + /* + * Account for the possiblity that the context got invalidated + * while we were sleeping + */ + + if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) { + mutex_unlock(&drawctxt->mutex); + return -EDEADLK; + } + } + + ret = get_timestamp(drawctxt, cmdbatch, timestamp); + if (ret) { + mutex_unlock(&drawctxt->mutex); + return ret; + } + + cmdbatch->timestamp = *timestamp; + + /* The batch fault policy is the current system fault policy */ + cmdbatch->fault_policy = adreno_dev->ft_policy; + + /* Put the command into the queue */ + drawctxt->cmdqueue[drawctxt->cmdqueue_tail] = cmdbatch; + drawctxt->cmdqueue_tail = (drawctxt->cmdqueue_tail + 1) % + ADRENO_CONTEXT_CMDQUEUE_SIZE; + + drawctxt->queued++; + trace_adreno_cmdbatch_queued(cmdbatch, drawctxt->queued); + + + mutex_unlock(&drawctxt->mutex); + + /* Add the context to the dispatcher pending list */ + dispatcher_queue_context(adreno_dev, drawctxt); + + /* + * Only issue commands if inflight is less than burst -this prevents us + * from sitting around waiting for the mutex on a busy system - the work + * loop will schedule it for us. Inflight is mutex protected but the + * worse that can happen is that it will go to 0 after we check and if + * it goes to 0 it is because the work loop decremented it and the work + * queue will try to schedule new commands anyway. + */ + + if (adreno_dev->dispatcher.inflight < _context_cmdbatch_burst) + adreno_dispatcher_issuecmds(adreno_dev); + + return 0; +} + +/* + * If an IB inside of the command batch has a gpuaddr that matches the base + * passed in then zero the size which effectively skips it when it is submitted + * in the ringbuffer. + */ +static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base) +{ + int i; + + for (i = 0; i < cmdbatch->ibcount; i++) { + if (cmdbatch->ibdesc[i].gpuaddr == base) { + cmdbatch->ibdesc[i].sizedwords = 0; + return; + } + } +} + +static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch, + struct kgsl_cmdbatch **replay, int count) +{ + struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context); + int skip = 1; + int i; + + for (i = 0; i < count; i++) { + + /* + * Only operate on command batches that belong to the + * faulting context + */ + + if (replay[i]->context->id != cmdbatch->context->id) + continue; + + /* + * Skip all the command batches in this context until + * the EOF flag is seen. If the EOF flag is seen then + * force the preamble for the next command. + */ + + if (skip) { + replay[i]->priv |= CMDBATCH_FLAG_SKIP; + + if (replay[i]->flags & KGSL_CONTEXT_END_OF_FRAME) + skip = 0; + } else { + replay[i]->priv |= CMDBATCH_FLAG_FORCE_PREAMBLE; + return; + } + } + + /* + * If the EOF flag hasn't been seen yet then set the flag in the + * drawctxt to keep looking for it + */ + + if (skip && drawctxt) + drawctxt->flags |= CTXT_FLAGS_SKIP_EOF; + + /* + * If we did see the EOF flag then force the preamble on for the + * next command issued on this context + */ + + if (!skip && drawctxt) + drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE; +} + +static void remove_invalidated_cmdbatches(struct kgsl_device *device, + struct kgsl_cmdbatch **replay, int count) +{ + int i; + + for (i = 0; i < count; i++) { + struct kgsl_cmdbatch *cmd = replay[i]; + struct adreno_context *drawctxt; + + if (cmd == NULL) + continue; + + drawctxt = ADRENO_CONTEXT(cmd->context); + + if (kgsl_context_detached(cmd->context) || + drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) { + replay[i] = NULL; + + mutex_lock(&device->mutex); + kgsl_cancel_events_timestamp(device, cmd->context, + cmd->timestamp); + mutex_unlock(&device->mutex); + + kgsl_cmdbatch_destroy(cmd); + } + } +} + +static void dispatcher_do_fault(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + unsigned int ptr; + unsigned int reg, base; + struct kgsl_cmdbatch **replay = NULL; + struct kgsl_cmdbatch *cmdbatch; + int ret, i, count = 0; + + BUG_ON(dispatcher->inflight == 0); + + /* Turn off all the timers */ + del_timer_sync(&dispatcher->timer); + del_timer_sync(&dispatcher->fault_timer); + + mutex_lock(&device->mutex); + + cmdbatch = dispatcher->cmdqueue[dispatcher->head]; + + /* + * If the fault was due to a timeout then stop the CP to ensure we don't + * get activity while we are trying to dump the state of the system + */ + + if (dispatcher->fault == ADRENO_DISPATCHER_TIMEOUT_FAULT) { + kgsl_regread(device, REG_CP_ME_CNTL, ®); + reg |= (1 << 27) | (1 << 28); + kgsl_regwrite(device, REG_CP_ME_CNTL, reg); + + /* Skip the PM dump for a timeout because it confuses people */ + cmdbatch->fault_policy |= KGSL_FT_SKIP_PMDUMP; + } + + kgsl_regread(device, REG_CP_IB1_BASE, &base); + + /* + * Dump the postmortem and snapshot information if this is the first + * detected fault for the oldest active command batch + */ + + if (!(cmdbatch->fault_policy & KGSL_FT_SKIP_PMDUMP)) { + kgsl_postmortem_dump(device, 0); + kgsl_device_snapshot(device, 1); + } + + mutex_unlock(&device->mutex); + + /* Allocate memory to store the inflight commands */ + replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL); + + if (replay == NULL) { + unsigned int ptr = dispatcher->head; + + while (ptr != dispatcher->tail) { + struct kgsl_context *context = + dispatcher->cmdqueue[ptr]->context; + + adreno_drawctxt_invalidate(device, context); + kgsl_cmdbatch_destroy(dispatcher->cmdqueue[ptr]); + + ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE); + } + + /* + * Set the replay count to zero - this will ensure that the + * hardware gets reset but nothing else goes played + */ + + count = 0; + goto replay; + } + + /* Copy the inflight command batches into the temporary storage */ + ptr = dispatcher->head; + + while (ptr != dispatcher->tail) { + replay[count++] = dispatcher->cmdqueue[ptr]; + ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE); + } + + /* + * For the purposes of replay, we assume that the oldest command batch + * that hasn't retired a timestamp is "hung". + */ + + cmdbatch = replay[0]; + + /* + * Set a flag so we don't print another PM dump if the cmdbatch fails + * again on replay + */ + + cmdbatch->fault_policy |= KGSL_FT_SKIP_PMDUMP; + + /* + * A hardware fault generally means something was deterministically + * wrong with the command batch - no point in trying to replay it + * Clear the replay bit and move on to the next policy level + */ + + if (dispatcher->fault == ADRENO_DISPATCHER_HARD_FAULT) + cmdbatch->fault_policy &= ~KGSL_FT_REPLAY; + + /* + * A timeout fault means the IB timed out - don't be silly and replay + * it, because it will probably timeout again + */ + + if (dispatcher->fault == ADRENO_DISPATCHER_TIMEOUT_FAULT) + cmdbatch->fault_policy &= ~KGSL_FT_REPLAY; + + /* + * Execute the fault tolerance policy. Each command batch stores the + * current fault policy that was set when it was queued. + * As the options are tried in descending priority + * (REPLAY -> SKIPIBS -> SKIPFRAME -> NOTHING) the bits are cleared + * from the cmdbatch policy so the next thing can be tried if the + * change comes around again + */ + + /* Replay the hanging command batch again */ + if (cmdbatch->fault_policy & KGSL_FT_REPLAY) { + cmdbatch->fault_policy &= ~KGSL_FT_REPLAY; + goto replay; + } + + /* + * Skip the last IB1 that was played but replay everything else. + * Note that the last IB1 might not be in the "hung" command batch + * because the CP may have caused a page-fault while it was prefetching + * the next IB1/IB2. walk all outstanding commands and zap the + * supposedly bad IB1 where ever it lurks. + */ + + if (cmdbatch->fault_policy & KGSL_FT_SKIPIB) { + cmdbatch->fault_policy &= ~KGSL_FT_SKIPIB; + + for (i = 0; i < count; i++) { + if (replay[i] != NULL) + cmdbatch_skip_ib(replay[i], base); + } + + goto replay; + } + + if (cmdbatch->fault_policy & KGSL_FT_SKIPFRAME) { + + cmdbatch->fault_policy &= ~KGSL_FT_SKIPFRAME; + + /* + * Skip all the pending command batches for this context until + * the EOF frame is seen + */ + cmdbatch_skip_frame(cmdbatch, replay, count); + goto replay; + } + + /* If we get here then all the policies failed or FT is disabled */ + + /* Invalidate the context */ + adreno_drawctxt_invalidate(device, cmdbatch->context); + + /* Remove any pending command batches that have been invalidated */ + remove_invalidated_cmdbatches(device, replay, count); + +replay: + /* Reset the dispatcher queue */ + dispatcher->inflight = 0; + dispatcher->head = dispatcher->tail = 0; + + /* Reset the GPU */ + mutex_lock(&device->mutex); + ret = adreno_reset(device); + mutex_unlock(&device->mutex); + + /* If adreno_reset() fails then what hope do we have for the future? */ + BUG_ON(ret); + + /* + * Force the preamble on the first command (if applicable) to avoid any + * strange stage issues + */ + + if (replay[0]) + replay[0]->priv |= CMDBATCH_FLAG_FORCE_PREAMBLE; + + /* Replay the pending command buffers */ + for (i = 0; i < count; i++) { + + int ret; + + if (replay[i] == NULL) + continue; + + /* + * Force each command batch to wait for idle - this avoids wierd + * CP parse issues + */ + + replay[i]->flags |= KGSL_CMD_FLAGS_WFI; + + ret = sendcmd(adreno_dev, replay[i]); + + /* + * If sending the command fails, then try to recover by + * invalidating the context + */ + + if (ret) { + adreno_drawctxt_invalidate(device, cmdbatch->context); + + remove_invalidated_cmdbatches(device, &replay[i], + count - i); + } + } + + mutex_lock(&device->mutex); + kgsl_active_count_put(device); + mutex_unlock(&device->mutex); + + kfree(replay); +} + +static inline int cmdbatch_consumed(struct kgsl_cmdbatch *cmdbatch, + unsigned int consumed, unsigned int retired) +{ + return ((timestamp_cmp(cmdbatch->timestamp, consumed) >= 0) && + (timestamp_cmp(retired, cmdbatch->timestamp) < 0)); +} + +/** + * adreno_dispatcher_work() - Master work handler for the dispatcher + * @work: Pointer to the work struct for the current work queue + * + * Process expired commands and send new ones. + */ +static void adreno_dispatcher_work(struct work_struct *work) +{ + struct adreno_dispatcher *dispatcher = + container_of(work, struct adreno_dispatcher, work); + struct adreno_device *adreno_dev = + container_of(dispatcher, struct adreno_device, dispatcher); + struct kgsl_device *device = &adreno_dev->dev; + int count = 0; + + mutex_lock(&dispatcher->mutex); + + while (dispatcher->head != dispatcher->tail) { + uint32_t consumed, retired = 0; + struct kgsl_cmdbatch *cmdbatch = + dispatcher->cmdqueue[dispatcher->head]; + struct adreno_context *drawctxt; + BUG_ON(cmdbatch == NULL); + + drawctxt = ADRENO_CONTEXT(cmdbatch->context); + + /* + * First try to expire the timestamp. This happens if the + * context is valid and the timestamp expired normally or if the + * context was destroyed before the command batch was finished + * in the GPU. Either way retire the command batch advance the + * pointers and continue processing the queue + */ + + if (!kgsl_context_detached(cmdbatch->context)) + retired = kgsl_readtimestamp(device, cmdbatch->context, + KGSL_TIMESTAMP_RETIRED); + + if (kgsl_context_detached(cmdbatch->context) || + (timestamp_cmp(cmdbatch->timestamp, retired) <= 0)) { + + trace_adreno_cmdbatch_retired(cmdbatch, + dispatcher->inflight - 1); + + /* Reduce the number of inflight command batches */ + dispatcher->inflight--; + + /* Zero the old entry*/ + dispatcher->cmdqueue[dispatcher->head] = NULL; + + /* Advance the buffer head */ + dispatcher->head = CMDQUEUE_NEXT(dispatcher->head, + ADRENO_DISPATCH_CMDQUEUE_SIZE); + + /* Destroy the retired command batch */ + kgsl_cmdbatch_destroy(cmdbatch); + + /* Update the expire time for the next command batch */ + + if (dispatcher->inflight > 0) { + cmdbatch = + dispatcher->cmdqueue[dispatcher->head]; + cmdbatch->expires = jiffies + + msecs_to_jiffies(_cmdbatch_timeout); + } + + count++; + continue; + } + + /* + * If we got a fault from the interrupt handler, this command + * is to blame. Invalidate it, reset and replay + */ + + if (dispatcher->fault) { + dispatcher_do_fault(device); + dispatcher->fault = 0; + goto done; + } + + /* Get the last consumed timestamp */ + consumed = kgsl_readtimestamp(device, cmdbatch->context, + KGSL_TIMESTAMP_CONSUMED); + + /* + * Break here if fault detection is dsiabled for the context or + * if the long running IB detection is disabled device wide + * Long running command buffers will be allowed to run to + * completion - but badly behaving command buffers (infinite + * shaders etc) can end up running forever. + */ + + if (!adreno_dev->long_ib_detect || + drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE) + break; + + /* + * The last line of defense is to check if the command batch has + * timed out. If we get this far but the timeout hasn't expired + * yet then the GPU is still ticking away + */ + + if (time_is_after_jiffies(cmdbatch->expires)) + break; + + /* Boom goes the dynamite */ + + KGSL_DRV_ERR(device, + "Context %d, timestamp %d ran too long\n", + drawctxt->base.id, drawctxt->timestamp); + + dispatcher->fault = ADRENO_DISPATCHER_TIMEOUT_FAULT; + + dispatcher_do_fault(device); + break; + } + + /* + * Decrement the active count to 0 - this will allow the system to go + * into suspend even if there are queued command batches + */ + + if (count && dispatcher->inflight == 0) { + mutex_lock(&device->mutex); + kgsl_active_count_put(device); + mutex_unlock(&device->mutex); + } + + /* Dispatch new commands if we have the room */ + if (dispatcher->inflight < _dispatcher_inflight) + _adreno_dispatcher_issuecmds(adreno_dev); + +done: + /* Either update the timer for the next command batch or disable it */ + if (dispatcher->inflight) { + struct kgsl_cmdbatch *cmdbatch + = dispatcher->cmdqueue[dispatcher->head]; + + /* Update the timeout timer for the next command batch */ + mod_timer(&dispatcher->timer, cmdbatch->expires); + } else { + del_timer_sync(&dispatcher->timer); + del_timer_sync(&dispatcher->fault_timer); + } + + /* Before leaving update the pwrscale information */ + mutex_lock(&device->mutex); + kgsl_pwrscale_idle(device); + mutex_unlock(&device->mutex); + + mutex_unlock(&dispatcher->mutex); +} + +void adreno_dispatcher_schedule(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + queue_work(device->work_queue, &dispatcher->work); +} + +/** + * adreno_dispatcher_queue_context() - schedule a drawctxt in the dispatcher + * device: pointer to the KGSL device + * drawctxt: pointer to the drawctxt to schedule + * + * Put a draw context on the dispatcher pending queue and schedule the + * dispatcher. This is used to reschedule changes that might have been blocked + * for sync points or other concerns + */ +void adreno_dispatcher_queue_context(struct kgsl_device *device, + struct adreno_context *drawctxt) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + dispatcher_queue_context(adreno_dev, drawctxt); + adreno_dispatcher_schedule(device); +} + +/* + * This is called on a regular basis while command batches are inflight. Fault + * detection registers are read and compared to the existing values - if they + * changed then the GPU is still running. If they are the same between + * subsequent calls then the GPU may have faulted + */ + +void adreno_dispatcher_fault_timer(unsigned long data) +{ + struct adreno_device *adreno_dev = (struct adreno_device *) data; + struct kgsl_device *device = &adreno_dev->dev; + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + /* Leave if the user decided to turn off fast hang detection */ + if (adreno_dev->fast_hang_detect == 0) + return; + + /* Don't do anything if the dispatcher is idle or faulted */ + if (dispatcher->inflight == 0 || dispatcher->fault) + return; + + /* Make sure the device is active before trying a read */ + if (device->state != KGSL_STATE_ACTIVE) + return; + + /* + * Read the fault registers - if it returns 0 then they haven't changed + * so mark the dispatcher as faulted and schedule the work loop. + */ + + if (!fault_detect_read_compare(device)) { + dispatcher->fault = ADRENO_DISPATCHER_SOFT_FAULT; + adreno_dispatcher_schedule(device); + } else { + mod_timer(&dispatcher->fault_timer, + jiffies + msecs_to_jiffies(_fault_timer_interval)); + } +} + +/* + * This is called when the timer expires - it either means the GPU is hung or + * the IB is taking too long to execute + */ +void adreno_dispatcher_timer(unsigned long data) +{ + struct adreno_device *adreno_dev = (struct adreno_device *) data; + struct kgsl_device *device = &adreno_dev->dev; + + adreno_dispatcher_schedule(device); +} +/** + * adreno_dispatcher_irq_fault() - Trigger a fault in the dispatcher + * @device: Pointer to the KGSL device + * + * Called from an interrupt context this will trigger a fault in the + * dispatcher for the oldest pending command batch + */ +void adreno_dispatcher_irq_fault(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + dispatcher->fault = ADRENO_DISPATCHER_HARD_FAULT; + adreno_dispatcher_schedule(device); +} + +/** + * adreno_dispatcher_pause() - stop the dispatcher + * @adreno_dev: pointer to the adreno device structure + * + * Pause the dispather so it doesn't accept any new commands + */ +void adreno_dispatcher_pause(struct adreno_device *adreno_dev) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + /* + * This will probably get called while holding other mutexes so don't + * take the dispatcher mutex. The biggest penalty is that another + * command might be submitted while we are in here but thats okay + * because whoever is waiting for the drain will just have another + * command batch to wait for + */ + + dispatcher->state = ADRENO_DISPATCHER_PAUSE; +} + +/** + * adreno_dispatcher_start() - activate the dispatcher + * @adreno_dev: pointer to the adreno device structure + * + * Set the disaptcher active and start the loop once to get things going + */ +void adreno_dispatcher_start(struct adreno_device *adreno_dev) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + dispatcher->state = ADRENO_DISPATCHER_ACTIVE; + + /* Schedule the work loop to get things going */ + adreno_dispatcher_schedule(&adreno_dev->dev); +} + +/** + * adreno_dispatcher_stop() - stop the dispatcher + * @adreno_dev: pointer to the adreno device structure + * + * Stop the dispatcher and close all the timers + */ +void adreno_dispatcher_stop(struct adreno_device *adreno_dev) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + del_timer_sync(&dispatcher->timer); + del_timer_sync(&dispatcher->fault_timer); +} + +/** + * adreno_dispatcher_close() - close the dispatcher + * @adreno_dev: pointer to the adreno device structure + * + * Close the dispatcher and free all the oustanding commands and memory + */ +void adreno_dispatcher_close(struct adreno_device *adreno_dev) +{ + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + mutex_lock(&dispatcher->mutex); + del_timer_sync(&dispatcher->timer); + del_timer_sync(&dispatcher->fault_timer); + + while (dispatcher->head != dispatcher->tail) { + kgsl_cmdbatch_destroy(dispatcher->cmdqueue[dispatcher->head]); + dispatcher->head = (dispatcher->head + 1) + % ADRENO_DISPATCH_CMDQUEUE_SIZE; + } + + kfree(fault_detect_regs); + fault_detect_regs = NULL; + + mutex_unlock(&dispatcher->mutex); + + kobject_put(&dispatcher->kobj); +} + +struct dispatcher_attribute { + struct attribute attr; + ssize_t (*show)(struct adreno_dispatcher *, + struct dispatcher_attribute *, char *); + ssize_t (*store)(struct adreno_dispatcher *, + struct dispatcher_attribute *, const char *buf, + size_t count); + unsigned int max; + unsigned int *value; +}; + +#define DISPATCHER_UINT_ATTR(_name, _mode, _max, _value) \ + struct dispatcher_attribute dispatcher_attr_##_name = { \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .show = _show_uint, \ + .store = _store_uint, \ + .max = _max, \ + .value = &(_value), \ + } + +#define to_dispatcher_attr(_a) \ + container_of((_a), struct dispatcher_attribute, attr) +#define to_dispatcher(k) container_of(k, struct adreno_dispatcher, kobj) + +static ssize_t _store_uint(struct adreno_dispatcher *dispatcher, + struct dispatcher_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + int ret = kstrtoul(buf, 0, &val); + + if (ret) + return ret; + + if (!val || (attr->max && (val > attr->max))) + return -EINVAL; + + *((unsigned int *) attr->value) = val; + return size; +} + +static ssize_t _show_uint(struct adreno_dispatcher *dispatcher, + struct dispatcher_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + *((unsigned int *) attr->value)); +} + +static DISPATCHER_UINT_ATTR(inflight, 0644, ADRENO_DISPATCH_CMDQUEUE_SIZE, + _dispatcher_inflight); +/* + * Our code that "puts back" a command from the context is much cleaner + * if we are sure that there will always be enough room in the + * ringbuffer so restrict the maximum size of the context queue to + * ADRENO_CONTEXT_CMDQUEUE_SIZE - 1 + */ +static DISPATCHER_UINT_ATTR(context_cmdqueue_size, 0644, + ADRENO_CONTEXT_CMDQUEUE_SIZE - 1, _context_cmdqueue_size); +static DISPATCHER_UINT_ATTR(context_burst_count, 0644, 0, + _context_cmdbatch_burst); +static DISPATCHER_UINT_ATTR(cmdbatch_timeout, 0644, 0, _cmdbatch_timeout); +static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait); +static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0, + _fault_timer_interval); + +static struct attribute *dispatcher_attrs[] = { + &dispatcher_attr_inflight.attr, + &dispatcher_attr_context_cmdqueue_size.attr, + &dispatcher_attr_context_burst_count.attr, + &dispatcher_attr_cmdbatch_timeout.attr, + &dispatcher_attr_context_queue_wait.attr, + &dispatcher_attr_fault_detect_interval.attr, + NULL, +}; + +static ssize_t dispatcher_sysfs_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct adreno_dispatcher *dispatcher = to_dispatcher(kobj); + struct dispatcher_attribute *pattr = to_dispatcher_attr(attr); + ssize_t ret = -EIO; + + if (pattr->show) + ret = pattr->show(dispatcher, pattr, buf); + + return ret; +} + +static ssize_t dispatcher_sysfs_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count) +{ + struct adreno_dispatcher *dispatcher = to_dispatcher(kobj); + struct dispatcher_attribute *pattr = to_dispatcher_attr(attr); + ssize_t ret = -EIO; + + if (pattr->store) + ret = pattr->store(dispatcher, pattr, buf, count); + + return ret; +} + +static void dispatcher_sysfs_release(struct kobject *kobj) +{ +} + +static const struct sysfs_ops dispatcher_sysfs_ops = { + .show = dispatcher_sysfs_show, + .store = dispatcher_sysfs_store +}; + +static struct kobj_type ktype_dispatcher = { + .sysfs_ops = &dispatcher_sysfs_ops, + .default_attrs = dispatcher_attrs, + .release = dispatcher_sysfs_release +}; + +/** + * adreno_dispatcher_init() - Initialize the dispatcher + * @adreno_dev: pointer to the adreno device structure + * + * Initialize the dispatcher + */ +int adreno_dispatcher_init(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = &adreno_dev->dev; + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + int ret; + + memset(dispatcher, 0, sizeof(*dispatcher)); + + mutex_init(&dispatcher->mutex); + + setup_timer(&dispatcher->timer, adreno_dispatcher_timer, + (unsigned long) adreno_dev); + + setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer, + (unsigned long) adreno_dev); + + INIT_WORK(&dispatcher->work, adreno_dispatcher_work); + + plist_head_init(&dispatcher->pending); + spin_lock_init(&dispatcher->plist_lock); + + dispatcher->state = ADRENO_DISPATCHER_ACTIVE; + + ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher, + &device->dev->kobj, "dispatch"); + + fault_detect_regs = kzalloc(FT_DETECT_REGS_COUNT * sizeof(unsigned int), + GFP_KERNEL); + + if (fault_detect_regs == NULL) + ret = -ENOMEM; + + return ret; +} diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index 6fbcdee9..dac4f8c7 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,6 +12,7 @@ */ #include +#include #include "kgsl.h" #include "kgsl_sharedmem.h" @@ -143,11 +144,10 @@ void build_quad_vtxbuff(struct adreno_context *drawctxt, */ int adreno_drawctxt_create(struct kgsl_device *device, struct kgsl_pagetable *pagetable, - struct kgsl_context *context, uint32_t flags) + struct kgsl_context *context, uint32_t *flags) { struct adreno_context *drawctxt; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer; int ret; drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL); @@ -160,28 +160,38 @@ int adreno_drawctxt_create(struct kgsl_device *device, drawctxt->pagetable = pagetable; drawctxt->bin_base_offset = 0; drawctxt->id = context->id; - rb->timestamp[context->id] = 0; + drawctxt->timestamp = 0; - if (flags & KGSL_CONTEXT_PREAMBLE) + *flags &= (KGSL_CONTEXT_PREAMBLE | + KGSL_CONTEXT_NO_GMEM_ALLOC | + KGSL_CONTEXT_PER_CONTEXT_TS | + KGSL_CONTEXT_USER_GENERATED_TS | + KGSL_CONTEXT_NO_FAULT_TOLERANCE | + KGSL_CONTEXT_TYPE_MASK); + + if (*flags & KGSL_CONTEXT_PREAMBLE) drawctxt->flags |= CTXT_FLAGS_PREAMBLE; - if (flags & KGSL_CONTEXT_NO_GMEM_ALLOC) + if (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC) drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC; - if (flags & KGSL_CONTEXT_PER_CONTEXT_TS) + if (*flags & KGSL_CONTEXT_PER_CONTEXT_TS) drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS; - if (flags & KGSL_CONTEXT_USER_GENERATED_TS) { - if (!(flags & KGSL_CONTEXT_PER_CONTEXT_TS)) { + if (*flags & KGSL_CONTEXT_USER_GENERATED_TS) { + if (!(*flags & KGSL_CONTEXT_PER_CONTEXT_TS)) { ret = -EINVAL; goto err; } drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS; } - if (flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE) + if (*flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE) drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE; + drawctxt->type = + (*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT; + ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt); if (ret) goto err; diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h index c91bfc01..dfa4277a 100644 --- a/drivers/gpu/msm/adreno_drawctxt.h +++ b/drivers/gpu/msm/adreno_drawctxt.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,6 +57,14 @@ /* Context no fault tolerance */ #define CTXT_FLAGS_NO_FAULT_TOLERANCE BIT(16) +/* Symbolic table for the adreno draw context type */ +#define ADRENO_DRAWCTXT_TYPES \ + { KGSL_CONTEXT_TYPE_ANY, "any" }, \ + { KGSL_CONTEXT_TYPE_GL, "GL" }, \ + { KGSL_CONTEXT_TYPE_CL, "CL" }, \ + { KGSL_CONTEXT_TYPE_C2D, "C2D" }, \ + { KGSL_CONTEXT_TYPE_RS, "RS" } + struct kgsl_device; struct adreno_device; struct kgsl_device_private; @@ -92,9 +100,11 @@ struct adreno_context { char pid_name[TASK_COMM_LEN]; unsigned int id; unsigned int ib_gpu_time_used; + unsigned int timestamp; uint32_t flags; uint32_t pagefault; unsigned long pagefault_ts; + unsigned int type; struct kgsl_pagetable *pagetable; struct kgsl_memdesc gpustate; unsigned int reg_restore[3]; @@ -127,7 +137,7 @@ struct adreno_context { int adreno_drawctxt_create(struct kgsl_device *device, struct kgsl_pagetable *pagetable, struct kgsl_context *context, - uint32_t flags); + uint32_t *flags); void adreno_drawctxt_destroy(struct kgsl_device *device, struct kgsl_context *context); diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c index 5fdcf194..ee82bd65 100644 --- a/drivers/gpu/msm/adreno_postmortem.c +++ b/drivers/gpu/msm/adreno_postmortem.c @@ -740,7 +740,9 @@ int adreno_dump(struct kgsl_device *device, int manual) (unsigned int *) &context_id, KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context)); - context = idr_find(&device->context_idr, context_id); + + context = kgsl_context_get(device, context_id); + if (context) { ts_processed = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED); @@ -749,6 +751,8 @@ int adreno_dump(struct kgsl_device *device, int manual) } else KGSL_LOG_DUMP(device, "BAD CTXT: %d\n", context_id); + kgsl_context_put(context); + num_item = adreno_ringbuffer_count(&adreno_dev->ringbuffer, cp_rb_rptr); if (num_item <= 0) diff --git a/drivers/gpu/msm/adreno_postmortem.h b/drivers/gpu/msm/adreno_postmortem.h new file mode 100644 index 00000000..a1745ba0 --- /dev/null +++ b/drivers/gpu/msm/adreno_postmortem.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __ADRENO_POSTMORTEM_H +#define __ADRENO_POSTMORTEM_H + +struct kgsl_device; + +int adreno_postmortem_dump(struct kgsl_device *device, int manual); + +#endif /* __ADRENO_POSTMORTEM_H */ diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c old mode 100644 new mode 100755 index 48367fae..edc4a720 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,14 +57,14 @@ adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, struct adreno_context *context, unsigned int numcmds, int wptr_ahead) { - int nopcount; + int nopcount, i; unsigned int freecmds; unsigned int *cmds; uint cmds_gpu; unsigned long wait_time; unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT); unsigned long wait_time_part; - unsigned int prev_reg_val[ft_detect_regs_count]; + unsigned int prev_reg_val[FT_DETECT_REGS_COUNT]; memset(prev_reg_val, 0, sizeof(prev_reg_val)); @@ -78,6 +78,13 @@ adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount)); + /* + * Fill remaining ring buffer data with KGSL_NOP_DATA_FILLER + * to avoid misinterpretation in recovery extraction logic. + */ + for (i = 0; i < nopcount; i++) + GSL_RB_WRITE(cmds, cmds_gpu, KGSL_NOP_DATA_FILLER); + /* Make sure that rptr is not 0 before submitting * commands at the end of ringbuffer. We do not * want the rptr and wptr to become equal when @@ -319,7 +326,7 @@ int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device) return 0; } -int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram) +int adreno_ringbuffer_start(struct adreno_ringbuffer *rb) { int status; /*cp_rb_cntl_u cp_rb_cntl; */ @@ -331,9 +338,6 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram) if (rb->flags & KGSL_FLAGS_STARTED) return 0; - if (init_ram) - rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0; - kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0, sizeof(struct kgsl_rbmemptrs)); @@ -383,32 +387,6 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram) rb->memptrs_desc.gpuaddr + GSL_RB_MEMPTRS_RPTR_OFFSET); - if (adreno_is_a3xx(adreno_dev)) { - /* enable access protection to privileged registers */ - adreno_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007); - - /* RBBM registers */ - adreno_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400); - - /* CP registers */ - adreno_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178); - adreno_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180); - - /* RB registers */ - adreno_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300); - - /* VBIF registers */ - adreno_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000); - } - if (adreno_is_a2xx(adreno_dev)) { /* explicitly clear all cp interrupts */ adreno_regwrite(device, REG_CP_INT_ACK, 0xFFFFFFFF); @@ -443,7 +421,9 @@ int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram) adreno_regwrite(device, REG_CP_ME_CNTL, 0); /* ME init is GPU specific, so jump into the sub-function */ - adreno_dev->gpudev->rb_init(adreno_dev, rb); + status = adreno_dev->gpudev->rb_init(adreno_dev, rb); + if (status) + return status; /* idle device to validate ME INIT */ status = adreno_idle(device); @@ -481,6 +461,7 @@ int adreno_ringbuffer_init(struct kgsl_device *device) */ rb->sizedwords = KGSL_RB_SIZE >> 2; + rb->buffer_desc.flags = KGSL_MEMFLAGS_GPUREADONLY; /* allocate memory for ringbuffer */ status = kgsl_allocate_contiguous(&rb->buffer_desc, (rb->sizedwords << 2)); @@ -523,40 +504,32 @@ void adreno_ringbuffer_close(struct adreno_ringbuffer *rb) memset(rb, 0, sizeof(struct adreno_ringbuffer)); } -static uint32_t +static int adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, struct adreno_context *context, unsigned int flags, unsigned int *cmds, - int sizedwords, uint32_t timestamp) + int sizedwords) { struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device); unsigned int *ringcmds; unsigned int total_sizedwords = sizedwords; unsigned int i; unsigned int rcmd_gpu; - unsigned int context_id = KGSL_MEMSTORE_GLOBAL; + unsigned int context_id; unsigned int gpuaddr = rb->device->memstore.gpuaddr; + unsigned int timestamp; /* * if the context was not created with per context timestamp * support, we must use the global timestamp since issueibcmds - * will be returning that one. + * will be returning that one, or if an internal issue then + * use global timestamp. */ - if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS) + if ((context && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) && + !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) context_id = context->id; - - if ((context && context->flags & CTXT_FLAGS_USER_GENERATED_TS) && - (!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))) { - if (timestamp_cmp(rb->timestamp[context_id], - timestamp) >= 0) { - KGSL_DRV_ERR(rb->device, - "Invalid user generated ts <%d:0x%x>, " - "less than last issued ts <%d:0x%x>\n", - context_id, timestamp, context_id, - rb->timestamp[context_id]); - return -ERANGE; - } - } + else + context_id = KGSL_MEMSTORE_GLOBAL; /* reserve space to temporarily turn off protected mode * error checking if needed @@ -564,38 +537,37 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0; /* 2 dwords to store the start of command sequence */ total_sizedwords += 2; + /* internal ib command identifier for the ringbuffer */ + total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0; /* Add CP_COND_EXEC commands to generate CP_INTERRUPT */ total_sizedwords += context ? 13 : 0; + if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) && + (flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE | + KGSL_CMD_FLAGS_GET_INT))) + total_sizedwords += 2; + if (adreno_is_a3xx(adreno_dev)) total_sizedwords += 7; if (adreno_is_a2xx(adreno_dev)) total_sizedwords += 2; /* CP_WAIT_FOR_IDLE */ - total_sizedwords += 2; /* scratchpad ts for fault tolerance */ - if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS && - !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) { - total_sizedwords += 3; /* sop timestamp */ - total_sizedwords += 4; /* eop timestamp */ + total_sizedwords += 2; /* scratchpad ts for recovery */ + total_sizedwords += 3; /* sop timestamp */ + total_sizedwords += 4; /* eop timestamp */ + + if (KGSL_MEMSTORE_GLOBAL != context_id) total_sizedwords += 3; /* global timestamp without cache * flush for non-zero context */ - } else { - total_sizedwords += 4; /* global timestamp for fault tolerance*/ - } if (flags & KGSL_CMD_FLAGS_EOF) total_sizedwords += 2; ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords); - if (!ringcmds) { - /* - * We could not allocate space in ringbuffer, just return the - * last timestamp - */ - return rb->timestamp[context_id]; - } + if (!ringcmds) + return -ENOSPC; rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-total_sizedwords); @@ -603,6 +575,29 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1)); GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER); + if (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) { + GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_INTERNAL_IDENTIFIER); + } + + /* always increment the global timestamp. once. */ + rb->global_ts++; + + if (KGSL_MEMSTORE_GLOBAL != context_id) + timestamp = context->timestamp; + else + timestamp = rb->global_ts; + + /* scratchpad ts for recovery */ + GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->global_ts); + + /* start-of-pipeline timestamp */ + GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_MEM_WRITE, 2)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr + + KGSL_MEMSTORE_OFFSET(context_id, soptimestamp))); + GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp); + if (flags & KGSL_CMD_FLAGS_PMODE) { /* disable protected mode error checking */ GSL_RB_WRITE(ringcmds, rcmd_gpu, @@ -622,21 +617,6 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, GSL_RB_WRITE(ringcmds, rcmd_gpu, 1); } - /* always increment the global timestamp. once. */ - rb->timestamp[KGSL_MEMSTORE_GLOBAL]++; - - /* Do not update context's timestamp for internal submissions */ - if (context && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) { - if (context_id == KGSL_MEMSTORE_GLOBAL) - rb->timestamp[context->id] = - rb->timestamp[KGSL_MEMSTORE_GLOBAL]; - else if (context->flags & CTXT_FLAGS_USER_GENERATED_TS) - rb->timestamp[context_id] = timestamp; - else - rb->timestamp[context_id]++; - } - timestamp = rb->timestamp[context_id]; - /* HW Workaround for MMU Page fault * due to memory getting free early before * GPU completes it. @@ -647,14 +627,10 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00); } - /* scratchpad ts for fault tolerance */ - GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1)); - GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]); - if (adreno_is_a3xx(adreno_dev)) { /* - * FLush HLSQ lazy updates to make sure there are no - * rsources pending for indirect loads after the timestamp + * Flush HLSQ lazy updates to make sure there are no + * resources pending for indirect loads after the timestamp */ GSL_RB_WRITE(ringcmds, rcmd_gpu, @@ -665,39 +641,24 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00); } - if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS - && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) { - /* start-of-pipeline timestamp */ - GSL_RB_WRITE(ringcmds, rcmd_gpu, - cp_type3_packet(CP_MEM_WRITE, 2)); - GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr + - KGSL_MEMSTORE_OFFSET(context_id, soptimestamp))); - GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp); - - /* end-of-pipeline timestamp */ - GSL_RB_WRITE(ringcmds, rcmd_gpu, - cp_type3_packet(CP_EVENT_WRITE, 3)); - GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS); - GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr + - KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp))); - GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp); + /* + * end-of-pipeline timestamp. If per context timestamps is not + * enabled, then context_id will be KGSL_MEMSTORE_GLOBAL so all + * eop timestamps will work out. + */ + GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_EVENT_WRITE, 3)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS); + GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr + + KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp))); + GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp); + if (KGSL_MEMSTORE_GLOBAL != context_id) { GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_MEM_WRITE, 2)); GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr + - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, - eoptimestamp))); - GSL_RB_WRITE(ringcmds, rcmd_gpu, - rb->timestamp[KGSL_MEMSTORE_GLOBAL]); - } else { - GSL_RB_WRITE(ringcmds, rcmd_gpu, - cp_type3_packet(CP_EVENT_WRITE, 3)); - GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS); - GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr + - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, - eoptimestamp))); - GSL_RB_WRITE(ringcmds, rcmd_gpu, - rb->timestamp[KGSL_MEMSTORE_GLOBAL]); + KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, + eoptimestamp))); + GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->global_ts); } if (context) { /* Conditional execution based on memory values */ @@ -735,6 +696,19 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK); } + /* + * If per context timestamps are enabled and any of the kgsl + * internal commands want INT to be generated trigger the INT + */ + if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) && + (flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE | + KGSL_CMD_FLAGS_GET_INT))) { + GSL_RB_WRITE(ringcmds, rcmd_gpu, + cp_type3_packet(CP_INTERRUPT, 1)); + GSL_RB_WRITE(ringcmds, rcmd_gpu, + CP_INT_CNTL__RB_INT_MASK); + } + if (adreno_is_a3xx(adreno_dev)) { /* Dummy set-constant to trigger context rollover */ GSL_RB_WRITE(ringcmds, rcmd_gpu, @@ -751,7 +725,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, adreno_ringbuffer_submit(rb); - return timestamp; + return 0; } unsigned int @@ -771,7 +745,7 @@ adreno_ringbuffer_issuecmds(struct kgsl_device *device, flags |= KGSL_CMD_FLAGS_INTERNAL_ISSUE; return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, - sizedwords, 0); + sizedwords); } static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr, @@ -865,10 +839,8 @@ static bool _parse_ibs(struct kgsl_device_private *dev_priv, buffer */ struct kgsl_mem_entry *entry; - spin_lock(&dev_priv->process_priv->mem_lock); entry = kgsl_sharedmem_find_region(dev_priv->process_priv, gpuaddr, sizedwords * sizeof(uint)); - spin_unlock(&dev_priv->process_priv->mem_lock); if (entry == NULL) { KGSL_CMD_ERR(dev_priv->device, "no mapping for gpuaddr: 0x%08x\n", gpuaddr); @@ -976,25 +948,31 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, { struct kgsl_device *device = dev_priv->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - unsigned int *link; + unsigned int *link = 0; unsigned int *cmds; unsigned int i; - struct adreno_context *drawctxt; + struct adreno_context *drawctxt = NULL; unsigned int start_index = 0; + int ret = 0; - if (device->state & KGSL_STATE_HUNG) - return -EBUSY; - if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) || - context == NULL || ibdesc == 0 || numibs == 0) - return -EINVAL; + if (device->state & KGSL_STATE_HUNG) { + ret = -EBUSY; + goto done; + } + if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) || + context == NULL || ibdesc == 0 || numibs == 0) { + ret = -EINVAL; + goto done; + } drawctxt = context->devctxt; if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) { KGSL_CTXT_ERR(device, "proc %s failed fault tolerance" " will not accept commands for context %d\n", drawctxt->pid_name, drawctxt->id); - return -EDEADLK; + ret = -EDEADLK; + goto done; } if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) { @@ -1010,9 +988,8 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4), GFP_KERNEL); if (!link) { - KGSL_CORE_ERR("kzalloc(%d) failed\n", - sizeof(unsigned int) * (numibs * 3 + 4)); - return -ENOMEM; + ret = -ENOMEM; + goto done; } /*When preamble is enabled, the preamble buffer with state restoration @@ -1037,9 +1014,15 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, if (unlikely(adreno_dev->ib_check_level >= 1 && !_parse_ibs(dev_priv, ibdesc[i].gpuaddr, ibdesc[i].sizedwords))) { - kfree(link); - return -EINVAL; + ret = -EINVAL; + goto done; + } + + if (ibdesc[i].sizedwords == 0) { + ret = -EINVAL; + goto done; } + *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD; *cmds++ = ibdesc[i].gpuaddr; *cmds++ = ibdesc[i].sizedwords; @@ -1054,15 +1037,30 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, adreno_drawctxt_switch(adreno_dev, drawctxt, flags); - *timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer, + if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) { + if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) { + KGSL_DRV_ERR(device, + "Invalid user generated ts <%d:0x%x>, " + "less than last issued ts <%d:0x%x>\n", + drawctxt->id, *timestamp, drawctxt->id, + drawctxt->timestamp); + return -ERANGE; + } + drawctxt->timestamp = *timestamp; + } else + drawctxt->timestamp++; + + ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer, drawctxt, (flags & KGSL_CMD_FLAGS_EOF), - &link[0], (cmds - link), *timestamp); - - KGSL_CMD_INFO(device, "ctxt %d g %08x numibs %d ts %d\n", - context->id, (unsigned int)ibdesc, numibs, *timestamp); + &link[0], (cmds - link)); + if (ret) + goto done; - kfree(link); + if (drawctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS) + *timestamp = drawctxt->timestamp; + else + *timestamp = adreno_dev->ringbuffer.global_ts; #ifdef CONFIG_MSM_KGSL_CFF_DUMP /* @@ -1079,9 +1077,16 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, */ if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_FT) { drawctxt->flags &= ~CTXT_FLAGS_GPU_HANG_FT; - return -EPROTO; - } else - return 0; + ret = -EPROTO; + } + +done: + kgsl_trace_issueibcmds(device, context ? context->id : 0, ibdesc, + numibs, *timestamp, flags, ret, + drawctxt ? drawctxt->type : 0); + + kfree(link); + return ret; } static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb, @@ -1156,11 +1161,13 @@ void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb, if (0xFFFFFFFF == ft_data->start_of_replay_cmds) return; - k_ctxt = idr_find(&device->context_idr, ft_data->context_id); + k_ctxt = kgsl_context_get(device, ft_data->context_id); + if (k_ctxt) { a_ctxt = k_ctxt->devctxt; if (a_ctxt->flags & CTXT_FLAGS_PREAMBLE) _turn_preamble_on_for_ib_seq(rb, rb_rptr); + kgsl_context_put(k_ctxt); } k_ctxt = NULL; @@ -1191,7 +1198,8 @@ void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb, /* if context switches to a context that did not cause * hang then start saving the rb contents as those * commands can be executed */ - k_ctxt = idr_find(&rb->device->context_idr, val2); + k_ctxt = kgsl_context_get(rb->device, val2); + if (k_ctxt) { a_ctxt = k_ctxt->devctxt; @@ -1229,6 +1237,7 @@ void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb, copy_rb_contents = 0; } } + kgsl_context_put(k_ctxt); } if (copy_rb_contents) diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index fa03c059..66ea3d6f 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -56,7 +56,7 @@ struct adreno_ringbuffer { unsigned int wptr; /* write pointer offset in dwords from baseaddr */ unsigned int rptr; /* read pointer offset in dwords from baseaddr */ - unsigned int timestamp[KGSL_MEMSTORE_MAX]; + unsigned int global_ts; }; @@ -97,8 +97,7 @@ int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, int adreno_ringbuffer_init(struct kgsl_device *device); -int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, - unsigned int init_ram); +int adreno_ringbuffer_start(struct adreno_ringbuffer *rb); void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb); diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index f23586ee..967e4abc 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -161,6 +161,12 @@ static unsigned int vfd_control_0; static unsigned int sp_vs_pvt_mem_addr; static unsigned int sp_fs_pvt_mem_addr; +/* + * Cached value of SP_VS_OBJ_START_REG and SP_FS_OBJ_START_REG. + */ +static unsigned int sp_vs_obj_start_reg; +static unsigned int sp_fs_obj_start_reg; + /* * Each load state block has two possible types. Each type has a different * number of dwords per unit. Use this handy lookup table to make sure @@ -373,6 +379,26 @@ static int ib_parse_draw_indx(struct kgsl_device *device, unsigned int *pkt, sp_fs_pvt_mem_addr = 0; } + if (sp_vs_obj_start_reg) { + ret = kgsl_snapshot_get_object(device, ptbase, + sp_vs_obj_start_reg & 0xFFFFFFE0, 0, + SNAPSHOT_GPU_OBJECT_GENERIC); + if (ret < 0) + return -EINVAL; + snapshot_frozen_objsize += ret; + sp_vs_obj_start_reg = 0; + } + + if (sp_fs_obj_start_reg) { + ret = kgsl_snapshot_get_object(device, ptbase, + sp_fs_obj_start_reg & 0xFFFFFFE0, 0, + SNAPSHOT_GPU_OBJECT_GENERIC); + if (ret < 0) + return -EINVAL; + snapshot_frozen_objsize += ret; + sp_fs_obj_start_reg = 0; + } + /* Finally: VBOs */ /* The number of active VBOs is stored in VFD_CONTROL_O[31:27] */ @@ -444,7 +470,7 @@ static void ib_parse_type0(struct kgsl_device *device, unsigned int *ptr, int offset = type0_pkt_offset(*ptr); int i; - for (i = 0; i < size; i++, offset++) { + for (i = 0; i < size - 1; i++, offset++) { /* Visiblity stream buffer */ @@ -505,11 +531,20 @@ static void ib_parse_type0(struct kgsl_device *device, unsigned int *ptr, case A3XX_SP_FS_PVT_MEM_ADDR_REG: sp_fs_pvt_mem_addr = ptr[i + 1]; break; + case A3XX_SP_VS_OBJ_START_REG: + sp_vs_obj_start_reg = ptr[i + 1]; + break; + case A3XX_SP_FS_OBJ_START_REG: + sp_fs_obj_start_reg = ptr[i + 1]; + break; } } } } +static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase, + unsigned int gpuaddr, unsigned int dwords); + /* Add an IB as a GPU object, but first, parse it to find more goodies within */ static int ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase, @@ -549,32 +584,12 @@ static int ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase, if (adreno_cmd_is_ib(src[i])) { unsigned int gpuaddr = src[i + 1]; unsigned int size = src[i + 2]; - unsigned int ibbase; - /* Address of the last processed IB2 */ - kgsl_regread(device, REG_CP_IB2_BASE, &ibbase); + ret = parse_ib(device, ptbase, gpuaddr, size); - /* - * If this is the last IB2 that was executed, - * then push it to make sure it goes into the - * static space - */ - - if (ibbase == gpuaddr) - push_object(device, - SNAPSHOT_OBJ_TYPE_IB, ptbase, - gpuaddr, size); - else { - ret = ib_add_gpu_object(device, - ptbase, gpuaddr, size); - - /* - * If adding the IB failed then stop - * parsing - */ - if (ret < 0) - goto done; - } + /* If adding the IB failed then stop parsing */ + if (ret < 0) + goto done; } else { ret = ib_parse_type3(device, &src[i], ptbase); /* @@ -604,29 +619,34 @@ static int ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase, return ret; } -/* Snapshot the istore memory */ -static int snapshot_istore(struct kgsl_device *device, void *snapshot, - int remain, void *priv) +/* + * We want to store the last executed IB1 and IB2 in the static region to ensure + * that we get at least some information out of the snapshot even if we can't + * access the dynamic data from the sysfs file. Push all other IBs on the + * dynamic list + */ +static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase, + unsigned int gpuaddr, unsigned int dwords) { - struct kgsl_snapshot_istore *header = snapshot; - unsigned int *data = snapshot + sizeof(*header); - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - int count, i; - - count = adreno_dev->istore_size * adreno_dev->instruction_size; + unsigned int ib1base, ib2base; + int ret = 0; - if (remain < (count * 4) + sizeof(*header)) { - KGSL_DRV_ERR(device, - "snapshot: Not enough memory for the istore section"); - return 0; - } + /* + * Check the IB address - if it is either the last executed IB1 or the + * last executed IB2 then push it into the static blob otherwise put + * it in the dynamic list + */ - header->count = adreno_dev->istore_size; + kgsl_regread(device, REG_CP_IB1_BASE, &ib1base); + kgsl_regread(device, REG_CP_IB2_BASE, &ib2base); - for (i = 0; i < count; i++) - kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]); + if (gpuaddr == ib1base || gpuaddr == ib2base) + push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase, + gpuaddr, dwords); + else + ret = ib_add_gpu_object(device, ptbase, gpuaddr, dwords); - return (count * 4) + sizeof(*header); + return ret; } /* Snapshot the ringbuffer memory */ @@ -765,13 +785,13 @@ static int snapshot_rb(struct kgsl_device *device, void *snapshot, struct kgsl_memdesc *memdesc = adreno_find_ctxtmem(device, ptbase, ibaddr, - ibsize); + ibsize << 2); /* IOMMU uses a NOP IB placed in setsate memory */ if (NULL == memdesc) if (kgsl_gpuaddr_in_memdesc( &device->mmu.setstate_memory, - ibaddr, ibsize)) + ibaddr, ibsize << 2)) memdesc = &device->mmu.setstate_memory; /* * The IB from CP_IB1_BASE and the IBs for legacy @@ -779,12 +799,11 @@ static int snapshot_rb(struct kgsl_device *device, void *snapshot, * others get marked at GPU objects */ - if (ibaddr == ibbase || memdesc != NULL) + if (memdesc != NULL) push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase, ibaddr, ibsize); else - ib_add_gpu_object(device, ptbase, ibaddr, - ibsize); + parse_ib(device, ptbase, ibaddr, ibsize); } index = index + 1; @@ -799,6 +818,64 @@ static int snapshot_rb(struct kgsl_device *device, void *snapshot, return size + sizeof(*header); } +static int snapshot_capture_mem_list(struct kgsl_device *device, void *snapshot, + int remain, void *priv) +{ + struct kgsl_snapshot_replay_mem_list *header = snapshot; + struct kgsl_process_private *private; + unsigned int ptbase; + struct rb_node *node; + struct kgsl_mem_entry *entry = NULL; + int num_mem; + unsigned int *data = snapshot + sizeof(*header); + + ptbase = kgsl_mmu_get_current_ptbase(&device->mmu); + mutex_lock(&kgsl_driver.process_mutex); + list_for_each_entry(private, &kgsl_driver.process_list, list) { + if (kgsl_mmu_pt_equal(&device->mmu, private->pagetable, + ptbase)) + break; + } + mutex_unlock(&kgsl_driver.process_mutex); + if (!private) { + KGSL_DRV_ERR(device, + "Failed to get pointer to process private structure\n"); + return 0; + } + /* We need to know the number of memory objects that the process has */ + spin_lock(&private->mem_lock); + for (node = rb_first(&private->mem_rb), num_mem = 0; node; ) { + entry = rb_entry(node, struct kgsl_mem_entry, node); + node = rb_next(&entry->node); + num_mem++; + } + + if (remain < ((num_mem * 3 * sizeof(unsigned int)) + + sizeof(*header))) { + KGSL_DRV_ERR(device, + "snapshot: Not enough memory for the mem list section"); + spin_unlock(&private->mem_lock); + return 0; + } + header->num_entries = num_mem; + header->ptbase = ptbase; + /* + * Walk throught the memory list and store the + * tuples(gpuaddr, size, memtype) in snapshot + */ + for (node = rb_first(&private->mem_rb); node; ) { + entry = rb_entry(node, struct kgsl_mem_entry, node); + node = rb_next(&entry->node); + + *data++ = entry->memdesc.gpuaddr; + *data++ = entry->memdesc.size; + *data++ = (entry->memdesc.priv & KGSL_MEMTYPE_MASK) >> + KGSL_MEMTYPE_SHIFT; + } + spin_unlock(&private->mem_lock); + return sizeof(*header) + (num_mem * 3 * sizeof(unsigned int)); +} + /* Snapshot the memory for an indirect buffer */ static int snapshot_ib(struct kgsl_device *device, void *snapshot, int remain, void *priv) @@ -829,15 +906,14 @@ static int snapshot_ib(struct kgsl_device *device, void *snapshot, continue; if (adreno_cmd_is_ib(*src)) - push_object(device, SNAPSHOT_OBJ_TYPE_IB, - obj->ptbase, src[1], src[2]); - else { + ret = parse_ib(device, obj->ptbase, src[1], + src[2]); + else ret = ib_parse_type3(device, src, obj->ptbase); - /* Stop parsing if the type3 decode fails */ - if (ret < 0) - break; - } + /* Stop parsing if the type3 decode fails */ + if (ret < 0) + break; } } @@ -902,6 +978,13 @@ void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain, snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB, snapshot, remain, snapshot_rb, NULL); + /* + * Add a section that lists (gpuaddr, size, memtype) tuples of the + * hanging process + */ + snapshot = kgsl_snapshot_add_section(device, + KGSL_SNAPSHOT_SECTION_MEMLIST, snapshot, remain, + snapshot_capture_mem_list, NULL); /* * Make sure that the last IB1 that was being executed is dumped. * Since this was the last IB1 that was processed, we should have @@ -950,17 +1033,6 @@ void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain, for (i = 0; i < objbufptr; i++) snapshot = dump_object(device, i, snapshot, remain); - /* - * Only dump the istore on a hang - reading it on a running system - * has a non 0 chance of hanging the GPU - */ - - if (hang) { - snapshot = kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain, - snapshot_istore, NULL); - } - /* Add GPU specific sections - registers mainly, but other stuff too */ if (adreno_dev->gpudev->snapshot) snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot, diff --git a/drivers/gpu/msm/adreno_trace.c b/drivers/gpu/msm/adreno_trace.c new file mode 100644 index 00000000..607ba8c4 --- /dev/null +++ b/drivers/gpu/msm/adreno_trace.c @@ -0,0 +1,18 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "adreno.h" + +/* Instantiate tracepoints */ +#define CREATE_TRACE_POINTS +#include "adreno_trace.h" diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h new file mode 100644 index 00000000..8993afb3 --- /dev/null +++ b/drivers/gpu/msm/adreno_trace.h @@ -0,0 +1,169 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#if !defined(_ADRENO_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _ADRENO_TRACE_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM kgsl +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE adreno_trace + +#include + +TRACE_EVENT(adreno_cmdbatch_queued, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int queued), + TP_ARGS(cmdbatch, queued), + TP_STRUCT__entry( + __field(unsigned int, id) + __field(unsigned int, timestamp) + __field(unsigned int, queued) + ), + TP_fast_assign( + __entry->id = cmdbatch->context->id; + __entry->timestamp = cmdbatch->timestamp; + __entry->queued = queued; + ), + TP_printk( + "ctx=%u ts=%u queued=%u", + __entry->id, __entry->timestamp, __entry->queued + ) +); + +DECLARE_EVENT_CLASS(adreno_cmdbatch_template, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight), + TP_ARGS(cmdbatch, inflight), + TP_STRUCT__entry( + __field(unsigned int, id) + __field(unsigned int, timestamp) + __field(unsigned int, inflight) + ), + TP_fast_assign( + __entry->id = cmdbatch->context->id; + __entry->timestamp = cmdbatch->timestamp; + __entry->inflight = inflight; + ), + TP_printk( + "ctx=%u ts=%u inflight=%u", + __entry->id, __entry->timestamp, + __entry->inflight + ) +); + +DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_retired, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight), + TP_ARGS(cmdbatch, inflight) +); + +DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_submitted, + TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight), + TP_ARGS(cmdbatch, inflight) +); + +DECLARE_EVENT_CLASS(adreno_drawctxt_template, + TP_PROTO(struct adreno_context *drawctxt), + TP_ARGS(drawctxt), + TP_STRUCT__entry( + __field(unsigned int, id) + ), + TP_fast_assign( + __entry->id = drawctxt->base.id; + ), + TP_printk("ctx=%u", __entry->id) +); + +DEFINE_EVENT(adreno_drawctxt_template, adreno_context_sleep, + TP_PROTO(struct adreno_context *drawctxt), + TP_ARGS(drawctxt) +); + +DEFINE_EVENT(adreno_drawctxt_template, adreno_context_wake, + TP_PROTO(struct adreno_context *drawctxt), + TP_ARGS(drawctxt) +); + +DEFINE_EVENT(adreno_drawctxt_template, dispatch_queue_context, + TP_PROTO(struct adreno_context *drawctxt), + TP_ARGS(drawctxt) +); + +TRACE_EVENT(adreno_drawctxt_wait_start, + TP_PROTO(unsigned int id, unsigned int ts), + TP_ARGS(id, ts), + TP_STRUCT__entry( + __field(unsigned int, id) + __field(unsigned int, ts) + ), + TP_fast_assign( + __entry->id = id; + __entry->ts = ts; + ), + TP_printk( + "ctx=%u ts=%u", + __entry->id, __entry->ts + ) +); + +TRACE_EVENT(adreno_drawctxt_wait_done, + TP_PROTO(unsigned int id, unsigned int ts, int status), + TP_ARGS(id, ts, status), + TP_STRUCT__entry( + __field(unsigned int, id) + __field(unsigned int, ts) + __field(int, status) + ), + TP_fast_assign( + __entry->id = id; + __entry->ts = ts; + __entry->status = status; + ), + TP_printk( + "ctx=%u ts=%u status=%d", + __entry->id, __entry->ts, __entry->status + ) +); + +TRACE_EVENT(adreno_gpu_fault, + TP_PROTO(unsigned int status, unsigned int rptr, unsigned int wptr, + unsigned int ib1base, unsigned int ib1size, + unsigned int ib2base, unsigned int ib2size), + TP_ARGS(status, rptr, wptr, ib1base, ib1size, ib2base, ib2size), + TP_STRUCT__entry( + __field(unsigned int, status) + __field(unsigned int, rptr) + __field(unsigned int, wptr) + __field(unsigned int, ib1base) + __field(unsigned int, ib1size) + __field(unsigned int, ib2base) + __field(unsigned int, ib2size) + ), + TP_fast_assign( + __entry->status = status; + __entry->rptr = rptr; + __entry->wptr = wptr; + __entry->ib1base = ib1base; + __entry->ib1size = ib1size; + __entry->ib2base = ib2base; + __entry->ib2size = ib2size; + ), + TP_printk("status=%X RB=%X/%X IB1=%X/%X IB2=%X/%X", + __entry->status, __entry->wptr, __entry->rptr, + __entry->ib1base, __entry->ib1size, __entry->ib2base, + __entry->ib2size) +); + +#endif /* _ADRENO_TRACE_H */ + +/* This part must be outside protection */ +#include diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 52d6acbd..6b7add93 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2012,2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,16 +18,17 @@ #include #include #include -#include + #include #include #include #include #include #include -#include +#include #include #include +#include #include "kgsl.h" #include "kgsl_debugfs.h" @@ -37,6 +38,7 @@ #include "kgsl_device.h" #include "kgsl_trace.h" #include "kgsl_sync.h" +#include "adreno.h" #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "kgsl." @@ -52,15 +54,214 @@ MODULE_PARM_DESC(ksgl_mmu_type, static struct ion_client *kgsl_ion_client; +static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry); + +/* + * The memfree list contains the last N blocks of memory that have been freed. + * On a GPU fault we walk the list to see if the faulting address had been + * recently freed and print out a message to that effect + */ + +#define MEMFREE_ENTRIES 512 + +static DEFINE_SPINLOCK(memfree_lock); + +struct memfree_entry { + unsigned long gpuaddr; + unsigned long size; + pid_t pid; + unsigned int flags; +}; + +static struct { + struct memfree_entry *list; + unsigned int head; + unsigned int tail; +} memfree; + +/** + * kgsl_hang_check() - Check for GPU hang + * data: KGSL device structure + * + * This function is called every KGSL_TIMEOUT_HANG_DETECT time when + * GPU is active to check for hang. If a hang is detected we + * trigger fault tolerance. + */ +void kgsl_hang_check(struct work_struct *work) +{ + struct kgsl_device *device = container_of(work, struct kgsl_device, + hang_check_ws); + static unsigned int prev_reg_val[FT_DETECT_REGS_COUNT]; + + mutex_lock(&device->mutex); + + if (device->state == KGSL_STATE_ACTIVE) { + + /* Check to see if the GPU is hung */ + if (adreno_ft_detect(device, prev_reg_val)) + adreno_dump_and_exec_ft(device); + + mod_timer(&device->hang_timer, + (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT))); + } + + mutex_unlock(&device->mutex); +} + +/** + * hang_timer() - Hang timer function + * data: KGSL device structure + * + * This function is called when hang timer expires, in this + * function we check if GPU is in active state and queue the + * work on device workqueue to check for the hang. We restart + * the timer after KGSL_TIMEOUT_HANG_DETECT time. + */ +void hang_timer(unsigned long data) +{ + struct kgsl_device *device = (struct kgsl_device *) data; + + /* check Hang only for 3d device */ + if (device->id == KGSL_DEVICE_3D0) { + if (device->state == KGSL_STATE_ACTIVE) { + + /* Have work run in a non-interrupt context. */ + queue_work(device->work_queue, &device->hang_check_ws); + } + } +} + +/** + * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy + * device: KGSL device + * id: ID of the context submitting the command + * ibdesc: Pointer to the list of IB descriptors + * numib: Number of IBs in the list + * timestamp: Timestamp assigned to the command batch + * flags: Flags sent by the user + * result: Result of the submission attempt + * type: Type of context issuing the command + * + * Wrap the issueibcmds ftrace hook into a function that can be called from the + * GPU specific modules. + */ +void kgsl_trace_issueibcmds(struct kgsl_device *device, int id, + struct kgsl_ibdesc *ibdesc, int numibs, + unsigned int timestamp, unsigned int flags, + int result, unsigned int type) +{ + trace_kgsl_issueibcmds(device, id, ibdesc, numibs, + timestamp, flags, result, type); +} +EXPORT_SYMBOL(kgsl_trace_issueibcmds); + +/** + * kgsl_trace_regwrite - call regwrite ftrace function by proxy + * device: KGSL device + * offset: dword offset of the register being written + * value: Value of the register being written + * + * Wrap the regwrite ftrace hook into a function that can be called from the + * GPU specific modules. + */ +void kgsl_trace_regwrite(struct kgsl_device *device, unsigned int offset, + unsigned int value) +{ + trace_kgsl_regwrite(device, offset, value); +} +EXPORT_SYMBOL(kgsl_trace_regwrite); + +int kgsl_memfree_init(void) +{ + memfree.list = kzalloc(MEMFREE_ENTRIES * sizeof(struct memfree_entry), + GFP_KERNEL); + + return (memfree.list) ? 0 : -ENOMEM; +} + +void kgsl_memfree_exit(void) +{ + kfree(memfree.list); + memset(&memfree, 0, sizeof(memfree)); +} + +int kgsl_memfree_find_entry(pid_t pid, unsigned long *gpuaddr, + unsigned long *size, unsigned int *flags) +{ + int ptr; + + if (memfree.list == NULL) + return 0; + + spin_lock(&memfree_lock); + + ptr = memfree.head - 1; + if (ptr < 0) + ptr = MEMFREE_ENTRIES - 1; + + /* Walk backwards through the list looking for the last match */ + while (ptr != memfree.tail) { + struct memfree_entry *entry = &memfree.list[ptr]; + + if ((entry->pid == pid) && + (*gpuaddr >= entry->gpuaddr && + *gpuaddr < (entry->gpuaddr + entry->size))) { + *gpuaddr = entry->gpuaddr; + *flags = entry->flags; + *size = entry->size; + + spin_unlock(&memfree_lock); + return 1; + } + + ptr = ptr - 1; + + if (ptr < 0) + ptr = MEMFREE_ENTRIES - 1; + } + + spin_unlock(&memfree_lock); + return 0; +} + +static void kgsl_memfree_add(pid_t pid, unsigned int gpuaddr, + unsigned int size, int flags) + +{ + struct memfree_entry *entry; + + if (memfree.list == NULL) + return; + + spin_lock(&memfree_lock); + + entry = &memfree.list[memfree.head]; + + entry->pid = pid; + entry->gpuaddr = gpuaddr; + entry->size = size; + entry->flags = flags; + + memfree.head = (memfree.head + 1) % MEMFREE_ENTRIES; + + if (memfree.head == memfree.tail) + memfree.tail = (memfree.tail + 1) % MEMFREE_ENTRIES; + + spin_unlock(&memfree_lock); +} + /* kgsl_get_mem_entry - get the mem_entry structure for the specified object * @device - Pointer to the device structure * @ptbase - the pagetable base of the object * @gpuaddr - the GPU address of the object * @size - Size of the region to search + * + * Caller must kgsl_mem_entry_put() the returned entry when finished using it. */ -struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device, - unsigned int ptbase, unsigned int gpuaddr, unsigned int size) +struct kgsl_mem_entry * __must_check +kgsl_get_mem_entry(struct kgsl_device *device, unsigned int ptbase, + unsigned int gpuaddr, unsigned int size) { struct kgsl_process_private *priv; struct kgsl_mem_entry *entry; @@ -70,15 +271,12 @@ struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device, list_for_each_entry(priv, &kgsl_driver.process_list, list) { if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase)) continue; - spin_lock(&priv->mem_lock); entry = kgsl_sharedmem_find_region(priv, gpuaddr, size); if (entry) { - spin_unlock(&priv->mem_lock); mutex_unlock(&kgsl_driver.process_mutex); return entry; } - spin_unlock(&priv->mem_lock); } mutex_unlock(&kgsl_driver.process_mutex); @@ -106,6 +304,9 @@ kgsl_mem_entry_destroy(struct kref *kref) struct kgsl_mem_entry, refcount); + /* Detach from process list */ + kgsl_mem_entry_detach_process(entry); + if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) kgsl_driver.stats.mapped -= entry->memdesc.size; @@ -136,14 +337,47 @@ kgsl_mem_entry_destroy(struct kref *kref) } EXPORT_SYMBOL(kgsl_mem_entry_destroy); -static -void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, - struct kgsl_process_private *process) +/** + * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree and + * assign it with a gpu address space before insertion + * @process: the process that owns the memory + * @entry: the memory entry + * + * @returns - 0 on succcess else error code + * + * Insert the kgsl_mem_entry in to the rb_tree for searching by GPU address. + * The assignment of gpu address and insertion into list needs to + * happen with the memory lock held to avoid race conditions between + * gpu address being selected and some other thread looking through the + * rb list in search of memory based on gpuaddr + * This function should be called with processes memory spinlock held + */ +static int +kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process, + struct kgsl_mem_entry *entry) { + int ret = 0; struct rb_node **node; struct rb_node *parent = NULL; - spin_lock(&process->mem_lock); + assert_spin_locked(&process->mem_lock); + /* + * If cpu=gpu map is used then caller needs to set the + * gpu address + */ + if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) { + if (!entry->memdesc.gpuaddr) + goto done; + } else if (entry->memdesc.gpuaddr) { + WARN_ONCE(1, "gpuaddr assigned w/o holding memory lock\n"); + ret = -EINVAL; + goto done; + } + if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) { + ret = kgsl_mmu_get_gpuaddr(process->pagetable, &entry->memdesc); + if (ret) + goto done; + } node = &process->mem_rb.rb_node; @@ -162,9 +396,89 @@ void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, rb_link_node(&entry->node, parent, node); rb_insert_color(&entry->node, &process->mem_rb); - spin_unlock(&process->mem_lock); +done: + return ret; +} + +/** + * kgsl_mem_entry_untrack_gpuaddr() - Untrack memory that is previously tracked + * process - Pointer to process private to which memory belongs + * entry - Memory entry to untrack + * + * Function just does the opposite of kgsl_mem_entry_track_gpuaddr. Needs to be + * called with processes spin lock held + */ +static void +kgsl_mem_entry_untrack_gpuaddr(struct kgsl_process_private *process, + struct kgsl_mem_entry *entry) +{ + assert_spin_locked(&process->mem_lock); + if (entry->memdesc.gpuaddr) { + kgsl_mmu_put_gpuaddr(process->pagetable, &entry->memdesc); + rb_erase(&entry->node, &entry->priv->mem_rb); + } +} +/** + * kgsl_mem_entry_attach_process - Attach a mem_entry to its owner process + * @entry: the memory entry + * @process: the owner process + * + * Attach a newly created mem_entry to its owner process so that + * it can be found later. The mem_entry will be added to mem_idr and have + * its 'id' field assigned. If the GPU address has been set, the entry + * will also be added to the mem_rb tree. + * + * @returns - 0 on success or error code on failure. + */ +static int +kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, + struct kgsl_device_private *dev_priv) +{ + int ret; + struct kgsl_process_private *process = dev_priv->process_priv; + + ret = kgsl_process_private_get(process); + if (!ret) + return -EBADF; + + while (1) { + if (idr_pre_get(&process->mem_idr, GFP_KERNEL) == 0) { + ret = -ENOMEM; + goto err_put_proc_priv; + } + + spin_lock(&process->mem_lock); + ret = idr_get_new_above(&process->mem_idr, entry, 1, + &entry->id); + spin_unlock(&process->mem_lock); + + if (ret == 0) + break; + else if (ret != -EAGAIN) + goto err_put_proc_priv; + } entry->priv = process; + entry->dev_priv = dev_priv; + + spin_lock(&process->mem_lock); + ret = kgsl_mem_entry_track_gpuaddr(process, entry); + if (ret) + idr_remove(&process->mem_idr, entry->id); + spin_unlock(&process->mem_lock); + if (ret) + goto err_put_proc_priv; + /* map the memory after unlocking if gpuaddr has been assigned */ + if (entry->memdesc.gpuaddr) { + ret = kgsl_mmu_map(process->pagetable, &entry->memdesc); + if (ret) + kgsl_mem_entry_detach_process(entry); + } + return ret; + +err_put_proc_priv: + kgsl_process_private_put(process); + return ret; } /* Detach a memory entry from a process and unmap it from the MMU */ @@ -174,12 +488,21 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) if (entry == NULL) return; - entry->priv->stats[entry->memtype].cur -= entry->memdesc.size; - entry->priv = NULL; + /* Unmap here so that below we can call kgsl_mmu_put_gpuaddr */ + kgsl_mmu_unmap(entry->priv->pagetable, &entry->memdesc); + + spin_lock(&entry->priv->mem_lock); - kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc); + kgsl_mem_entry_untrack_gpuaddr(entry->priv, entry); + if (entry->id != 0) + idr_remove(&entry->priv->mem_idr, entry->id); + entry->id = 0; - kgsl_mem_entry_put(entry); + entry->priv->stats[entry->memtype].cur -= entry->memdesc.size; + spin_unlock(&entry->priv->mem_lock); + kgsl_process_private_put(entry->priv); + + entry->priv = NULL; } /* Allocate a new context id */ @@ -187,50 +510,49 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) static struct kgsl_context * kgsl_create_context(struct kgsl_device_private *dev_priv) { + struct kgsl_device *device = dev_priv->device; struct kgsl_context *context; - int ret, id; + int ret, id = 0; context = kzalloc(sizeof(*context), GFP_KERNEL); if (context == NULL) - return NULL; + return ERR_PTR(-ENOMEM); + while (1) { - if (idr_pre_get(&dev_priv->device->context_idr, - GFP_KERNEL) == 0) { - kfree(context); - return NULL; + if (idr_pre_get(&device->context_idr, GFP_KERNEL) == 0) { + KGSL_DRV_INFO(device, "idr_pre_get: ENOMEM\n"); + ret = -ENOMEM; + break; } - ret = idr_get_new_above(&dev_priv->device->context_idr, - context, 1, &id); + write_lock(&device->context_lock); + ret = idr_get_new_above(&device->context_idr, context, 1, &id); + context->id = id; + write_unlock(&device->context_lock); if (ret != -EAGAIN) break; } - if (ret) { - kfree(context); - return NULL; - } + if (ret) + goto func_end; /* MAX - 1, there is one memdesc in memstore for device info */ if (id >= KGSL_MEMSTORE_MAX) { - KGSL_DRV_ERR(dev_priv->device, "cannot have more than %d " + KGSL_DRV_INFO(device, "cannot have more than %d " "ctxts due to memstore limitation\n", KGSL_MEMSTORE_MAX); - idr_remove(&dev_priv->device->context_idr, id); - kfree(context); - return NULL; + ret = -ENOSPC; + goto fail_free_id; } kref_init(&context->refcount); - context->id = id; context->dev_priv = dev_priv; - - if (kgsl_sync_timeline_create(context)) { - idr_remove(&dev_priv->device->context_idr, id); - goto func_end; + ret = kgsl_sync_timeline_create(context); + if (ret) { + goto fail_free_id; } /* Initialize the pending event list */ @@ -247,10 +569,17 @@ kgsl_create_context(struct kgsl_device_private *dev_priv) INIT_LIST_HEAD(&context->events_list); +fail_free_id: + if (ret) { + write_lock(&device->context_lock); + idr_remove(&device->context_idr, id); + write_unlock(&device->context_lock); + } + func_end: if (ret) { kfree(context); - return NULL; + return ERR_PTR(ret); } return context; @@ -286,9 +615,13 @@ kgsl_context_detach(struct kgsl_context *context) * destroyed, to avoid possibly freeing memory while * it is still in use by the GPU. */ - kgsl_cancel_events_ctxt(device, context); - idr_remove(&device->context_idr, id); + kgsl_context_cancel_events(device, context); + + write_lock(&device->context_lock); context->id = KGSL_CONTEXT_INVALID; + idr_remove(&device->context_idr, id); + write_unlock(&device->context_lock); + context->dev_priv = NULL; kgsl_context_put(context); } @@ -301,27 +634,6 @@ kgsl_context_destroy(struct kref *kref) kfree(context); } -static void kgsl_check_idle_locked(struct kgsl_device *device) -{ - if (device->pwrctrl.nap_allowed == true && - device->state == KGSL_STATE_ACTIVE && - device->requested_state == KGSL_STATE_NONE) { - kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP); - kgsl_pwrscale_idle(device); - if (kgsl_pwrctrl_sleep(device) != 0) - mod_timer(&device->idle_timer, - jiffies + - device->pwrctrl.interval_timeout); - } -} - -static void kgsl_check_idle(struct kgsl_device *device) -{ - mutex_lock(&device->mutex); - kgsl_check_idle_locked(device); - mutex_unlock(&device->mutex); -} - struct kgsl_device *kgsl_get_device(int dev_idx) { int i; @@ -368,7 +680,8 @@ int kgsl_check_timestamp(struct kgsl_device *device, EXPORT_SYMBOL(kgsl_check_timestamp); static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) -{ +{ +#if 0 int status = -EINVAL; unsigned int nap_allowed_saved; struct kgsl_pwrscale_policy *policy_saved; @@ -384,15 +697,16 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) policy_saved = device->pwrscale.policy; device->pwrscale.policy = NULL; kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND); - /* Make sure no user process is waiting for a timestamp * - * before supending */ - if (device->state == KGSL_STATE_ACTIVE && device->active_cnt != 0) { - mutex_unlock(&device->mutex); - wait_for_completion(&device->suspend_gate); - mutex_lock(&device->mutex); - } + + /* + * Make sure no user process is waiting for a timestamp + * before supending. + */ + kgsl_active_count_wait(device); + /* Don't let the timer wake us during suspended sleep. */ del_timer_sync(&device->idle_timer); + del_timer_sync(&device->hang_timer); switch (device->state) { case KGSL_STATE_INIT: break; @@ -401,6 +715,9 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) device->ftbl->idle(device); case KGSL_STATE_NAP: case KGSL_STATE_SLEEP: + /* make sure power is on to stop the device */ + kgsl_pwrctrl_enable(device); + kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); /* Get the completion ready to be waited upon. */ INIT_COMPLETION(device->hwaccess_gate); device->ftbl->suspend_context(device); @@ -425,14 +742,15 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) end: mutex_unlock(&device->mutex); +#endif KGSL_PWR_WARN(device, "suspend end\n"); - return status; + + return 0; } static int kgsl_resume_device(struct kgsl_device *device) { - int status = -EINVAL; - +#if 0 if (!device) return -EINVAL; @@ -440,14 +758,27 @@ static int kgsl_resume_device(struct kgsl_device *device) mutex_lock(&device->mutex); if (device->state == KGSL_STATE_SUSPEND) { kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); - status = 0; complete_all(&device->hwaccess_gate); + } else if (device->state != KGSL_STATE_INIT) { + /* + * This is an error situation,so wait for the device + * to idle and then put the device to SLUMBER state. + * This will put the device to the right state when + * we resume. + */ + if (device->state == KGSL_STATE_ACTIVE) + device->ftbl->idle(device); + kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); + kgsl_pwrctrl_sleep(device); + KGSL_PWR_ERR(device, + "resume invoked without a suspend\n"); } kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); mutex_unlock(&device->mutex); +#endif KGSL_PWR_WARN(device, "resume end\n"); - return status; + return 0; } static int kgsl_suspend(struct device *dev) @@ -481,21 +812,26 @@ const struct dev_pm_ops kgsl_pm_ops = { .runtime_resume = kgsl_runtime_resume, }; EXPORT_SYMBOL(kgsl_pm_ops); - +#if 0 void kgsl_early_suspend_driver(struct early_suspend *h) { struct kgsl_device *device = container_of(h, struct kgsl_device, display_off); KGSL_PWR_WARN(device, "early suspend start\n"); mutex_lock(&device->mutex); - device->pwrctrl.restore_slumber = true; - kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); - kgsl_pwrctrl_sleep(device); + + /* Only go to slumber if active_cnt is 0 */ + if (device->active_cnt == 0) { + device->pwrctrl.restore_slumber = true; + kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); + kgsl_pwrctrl_sleep(device); + } + mutex_unlock(&device->mutex); KGSL_PWR_WARN(device, "early suspend end\n"); } EXPORT_SYMBOL(kgsl_early_suspend_driver); - +#endif int kgsl_suspend_driver(struct platform_device *pdev, pm_message_t state) { @@ -510,7 +846,7 @@ int kgsl_resume_driver(struct platform_device *pdev) return kgsl_resume_device(device); } EXPORT_SYMBOL(kgsl_resume_driver); - +#if 0 void kgsl_late_resume_driver(struct early_suspend *h) { struct kgsl_device *device = container_of(h, @@ -520,96 +856,199 @@ void kgsl_late_resume_driver(struct early_suspend *h) device->pwrctrl.restore_slumber = false; if (device->pwrscale.policy == NULL) kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO); - kgsl_pwrctrl_wake(device); + + if (kgsl_pwrctrl_wake(device) != 0) { + mutex_unlock(&device->mutex); + return; + } + /* + * We don't have a way to go directly from + * a deeper sleep state to NAP, which is + * the desired state here. + * + * Except if active_cnt is non zero which means that + * we probably went to early_suspend with it non zero + * and thus the system is still in an active state. + */ + + if (device->active_cnt == 0) { + kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP); + kgsl_pwrctrl_sleep(device); + } + mutex_unlock(&device->mutex); - kgsl_check_idle(device); KGSL_PWR_WARN(device, "late resume end\n"); } EXPORT_SYMBOL(kgsl_late_resume_driver); +#endif +/* + * kgsl_destroy_process_private() - Cleanup function to free process private + * @kref: - Pointer to object being destroyed's kref struct + * Free struct object and all other resources attached to it. + * Since the function can be used when not all resources inside process + * private have been allocated, there is a check to (before each resource + * cleanup) see if the struct member being cleaned is in fact allocated or not. + * If the value is not NULL, resource is freed. + */ +static void kgsl_destroy_process_private(struct kref *kref) +{ + struct kgsl_process_private *private = container_of(kref, + struct kgsl_process_private, refcount); -/* file operations */ -static struct kgsl_process_private * -kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv) + /* + * Remove this process from global process list + * We do not acquire a lock first as it is expected that + * kgsl_destroy_process_private() is only going to be called + * through kref_put() which is only called after acquiring + * the lock. + */ + if (!private) { + KGSL_CORE_ERR("Cannot destroy null process private\n"); + mutex_unlock(&kgsl_driver.process_mutex); + return; + } + + if (private->kobj.parent) + kgsl_process_uninit_sysfs(private); + if (private->debug_root) + debugfs_remove_recursive(private->debug_root); + + list_del(&private->list); + mutex_unlock(&kgsl_driver.process_mutex); + + kgsl_mmu_putpagetable(private->pagetable); + idr_destroy(&private->mem_idr); + + kfree(private); + return; +} + +void +kgsl_process_private_put(struct kgsl_process_private *private) +{ + mutex_lock(&kgsl_driver.process_mutex); + + /* + * kref_put() returns 1 when the refcnt has reached 0 and the destroy + * function is called. Mutex is released in the destroy function if + * its called, so only release mutex if kref_put() return 0 + */ + if (!kref_put(&private->refcount, kgsl_destroy_process_private)) + mutex_unlock(&kgsl_driver.process_mutex); + return; +} + +/** + * kgsl_process_private_find() - Find the process associated with the specified + * name + * @name: pid_t of the process to search for + * Return the process struct for the given ID. + */ +struct kgsl_process_private *kgsl_process_private_find(pid_t pid) +{ + struct kgsl_process_private *p, *private = NULL; + + mutex_lock(&kgsl_driver.process_mutex); + list_for_each_entry(p, &kgsl_driver.process_list, list) { + if (p->pid == pid) { + if (kgsl_process_private_get(p)) + private = p; + break; + } + } + mutex_unlock(&kgsl_driver.process_mutex); + return private; +} + +/** + * kgsl_process_private_new() - Helper function to search for process private + * Returns: Pointer to the found/newly created private struct + */ +static struct kgsl_process_private *kgsl_process_private_new(void) { struct kgsl_process_private *private; + /* Search in the process list */ mutex_lock(&kgsl_driver.process_mutex); list_for_each_entry(private, &kgsl_driver.process_list, list) { if (private->pid == task_tgid_nr(current)) { - private->refcnt++; - goto out; + if (!kgsl_process_private_get(private)) + private = NULL; + goto done; } } /* no existing process private found for this dev_priv, create one */ private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL); - if (private == NULL) { - KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n", - sizeof(struct kgsl_process_private)); - goto out; - } - - spin_lock_init(&private->mem_lock); - private->refcnt = 1; - private->pid = task_tgid_nr(current); - private->mem_rb = RB_ROOT; - - if (kgsl_mmu_enabled()) - { - unsigned long pt_name; + if (private == NULL) + goto done; - pt_name = task_tgid_nr(current); - private->pagetable = kgsl_mmu_getpagetable(pt_name); - if (private->pagetable == NULL) { - kfree(private); - private = NULL; - goto out; - } - } + kref_init(&private->refcount); + private->pid = task_tgid_nr(current); + spin_lock_init(&private->mem_lock); + mutex_init(&private->process_private_mutex); + /* Add the newly created process struct obj to the process list */ list_add(&private->list, &kgsl_driver.process_list); - - kgsl_process_init_sysfs(private); - kgsl_process_init_debugfs(private); - -out: +done: mutex_unlock(&kgsl_driver.process_mutex); return private; } -static void -kgsl_put_process_private(struct kgsl_device *device, - struct kgsl_process_private *private) +/* + * kgsl_get_process_private() - Used to find the process private structure + * @cur_dev_priv: Current device pointer + * Finds or creates a new porcess private structire and initializes its members + * Returns: Pointer to the private process struct obj found/created or + * NULL if pagetable creation for this process private obj failed. + */ +static struct kgsl_process_private * +kgsl_get_process_private(struct kgsl_device *device) { - struct kgsl_mem_entry *entry = NULL; - struct rb_node *node; + struct kgsl_process_private *private; - if (!private) - return; + private = kgsl_process_private_new(); - mutex_lock(&kgsl_driver.process_mutex); + if (!private) + return NULL; - if (--private->refcnt) - goto unlock; + mutex_lock(&private->process_private_mutex); - kgsl_process_uninit_sysfs(private); - debugfs_remove_recursive(private->debug_root); + if (test_bit(KGSL_PROCESS_INIT, &private->priv)) + goto done; - list_del(&private->list); + private->mem_rb = RB_ROOT; + idr_init(&private->mem_idr); - for (node = rb_first(&private->mem_rb); node; ) { - entry = rb_entry(node, struct kgsl_mem_entry, node); - node = rb_next(&entry->node); + if ((!private->pagetable) && kgsl_mmu_enabled()) { + unsigned long pt_name; - rb_erase(&entry->node, &private->mem_rb); - kgsl_mem_entry_detach_process(entry); + pt_name = task_tgid_nr(current); + private->pagetable = + kgsl_mmu_getpagetable(pt_name); + if (private->pagetable == NULL) + goto error; } - kgsl_mmu_putpagetable(private->pagetable); - kfree(private); -unlock: - mutex_unlock(&kgsl_driver.process_mutex); + + if (kgsl_process_init_sysfs(private)) + goto error; + + if (kgsl_process_init_debugfs(private)) + goto error; + + set_bit(KGSL_PROCESS_INIT, &private->priv); + +done: + mutex_unlock(&private->process_private_mutex); + return private; + +error: + mutex_unlock(&private->process_private_mutex); + kgsl_process_private_put(private); + return NULL; } + static int kgsl_release(struct inode *inodep, struct file *filep) { int result = 0; @@ -617,15 +1056,19 @@ static int kgsl_release(struct inode *inodep, struct file *filep) struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_device *device = dev_priv->device; struct kgsl_context *context; + struct kgsl_mem_entry *entry; int next = 0; filep->private_data = NULL; mutex_lock(&device->mutex); - kgsl_check_suspended(device); + kgsl_active_count_get(device); while (1) { + read_lock(&device->context_lock); context = idr_get_next(&device->context_idr, &next); + read_unlock(&device->context_lock); + if (context == NULL) break; @@ -634,6 +1077,25 @@ static int kgsl_release(struct inode *inodep, struct file *filep) next = next + 1; } + next = 0; + while (1) { + spin_lock(&private->mem_lock); + entry = idr_get_next(&private->mem_idr, &next); + spin_unlock(&private->mem_lock); + if (entry == NULL) + break; + /* + * If the free pending flag is not set it means that user space + * did not free it's reference to this entry, in that case + * free a reference to this entry, other references are from + * within kgsl so they will be freed eventually by kgsl + */ + if (entry->dev_priv == dev_priv && !entry->pending_free) { + entry->pending_free = 1; + kgsl_mem_entry_put(entry); + } + next = next + 1; + } /* * Clean up any to-be-freed entries that belong to this * process and this device. This is done after the context @@ -644,14 +1106,21 @@ static int kgsl_release(struct inode *inodep, struct file *filep) device->open_count--; if (device->open_count == 0) { + BUG_ON(device->active_cnt > 1); result = device->ftbl->stop(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); + /* + * active_cnt special case: we just stopped the device, + * so no need to use kgsl_active_count_put() + */ + device->active_cnt--; + } else { + kgsl_active_count_put(device); } - mutex_unlock(&device->mutex); kfree(dev_priv); - kgsl_put_process_private(device, private); + kgsl_process_private_put(private); pm_runtime_put(device->parentdev); return result; @@ -692,40 +1161,68 @@ static int kgsl_open(struct inode *inodep, struct file *filep) dev_priv->device = device; filep->private_data = dev_priv; - /* Get file (per process) private struct */ - dev_priv->process_priv = kgsl_get_process_private(dev_priv); - if (dev_priv->process_priv == NULL) { - result = -ENOMEM; - goto err_freedevpriv; - } - mutex_lock(&device->mutex); - kgsl_check_suspended(device); if (device->open_count == 0) { + /* + * active_cnt special case: we are starting up for the first + * time, so use this sequence instead of the kgsl_pwrctrl_wake() + * which will be called by kgsl_active_count_get(). + */ + device->active_cnt++; kgsl_sharedmem_set(&device->memstore, 0, 0, device->memstore.size); - result = device->ftbl->start(device, true); + result = device->ftbl->init(device); + if (result) + goto err_freedevpriv; - if (result) { - mutex_unlock(&device->mutex); - goto err_putprocess; - } + result = device->ftbl->start(device); + if (result) + goto err_freedevpriv; + /* + * Make sure the gates are open, so they don't block until + * we start suspend or FT. + */ + complete_all(&device->ft_gate); + complete_all(&device->hwaccess_gate); kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); + kgsl_active_count_put(device); } device->open_count++; mutex_unlock(&device->mutex); + /* + * Get file (per process) private struct. This must be done + * after the first start so that the global pagetable mappings + * are set up before we create the per-process pagetable. + */ + dev_priv->process_priv = kgsl_get_process_private(device); + if (dev_priv->process_priv == NULL) { + result = -ENOMEM; + goto err_stop; + } + KGSL_DRV_INFO(device, "Initialized %s: mmu=%s pagetable_count=%d\n", device->name, kgsl_mmu_enabled() ? "on" : "off", kgsl_pagetable_count); return result; -err_putprocess: - kgsl_put_process_private(device, dev_priv->process_priv); +err_stop: + mutex_lock(&device->mutex); + device->open_count--; + if (device->open_count == 0) { + /* make sure power is on to stop the device */ + kgsl_pwrctrl_enable(device); + result = device->ftbl->stop(device); + kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); + } err_freedevpriv: + /* only the first open takes an active count */ + if (device->open_count == 0) + device->active_cnt--; + mutex_unlock(&device->mutex); filep->private_data = NULL; kfree(dev_priv); err_pmruntime: @@ -733,46 +1230,174 @@ static int kgsl_open(struct inode *inodep, struct file *filep) return result; } -/*call with private->mem_lock locked */ -struct kgsl_mem_entry * +/** + * kgsl_sharedmem_find_region() - Find a gpu memory allocation + * + * @private: private data for the process to check. + * @gpuaddr: start address of the region + * @size: size of the region + * + * Find a gpu allocation. Caller must kgsl_mem_entry_put() + * the returned entry when finished using it. + */ +struct kgsl_mem_entry * __must_check kgsl_sharedmem_find_region(struct kgsl_process_private *private, unsigned int gpuaddr, size_t size) { - struct rb_node *node = private->mem_rb.rb_node; + struct rb_node *node; if (!kgsl_mmu_gpuaddr_in_range(gpuaddr)) return NULL; + spin_lock(&private->mem_lock); + node = private->mem_rb.rb_node; while (node != NULL) { struct kgsl_mem_entry *entry; entry = rb_entry(node, struct kgsl_mem_entry, node); - - if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) + if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) { + if (!kgsl_mem_entry_get(entry)) + break; + spin_unlock(&private->mem_lock); return entry; - + } if (gpuaddr < entry->memdesc.gpuaddr) node = node->rb_left; else if (gpuaddr >= (entry->memdesc.gpuaddr + entry->memdesc.size)) node = node->rb_right; else { + spin_unlock(&private->mem_lock); return NULL; } } + spin_unlock(&private->mem_lock); return NULL; } EXPORT_SYMBOL(kgsl_sharedmem_find_region); -/*call with private->mem_lock locked */ -static inline struct kgsl_mem_entry * +/** + * kgsl_sharedmem_find() - Find a gpu memory allocation + * + * @private: private data for the process to check. + * @gpuaddr: start address of the region + * + * Find a gpu allocation. Caller must kgsl_mem_entry_put() + * the returned entry when finished using it. + */ +static inline struct kgsl_mem_entry * __must_check kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr) { return kgsl_sharedmem_find_region(private, gpuaddr, 1); } +/** + * kgsl_sharedmem_region_empty() - Check if an addression region is empty + * + * @private: private data for the process to check. + * @gpuaddr: start address of the region + * @size: length of the region. + * + * Checks that there are no existing allocations within an address + * region. This function should be called with processes spin lock + * held. + */ +static int +kgsl_sharedmem_region_empty(struct kgsl_process_private *private, + unsigned int gpuaddr, size_t size) +{ + int result = 1; + unsigned int gpuaddr_end = gpuaddr + size; + + struct rb_node *node; + + assert_spin_locked(&private->mem_lock); + + if (!kgsl_mmu_gpuaddr_in_range(gpuaddr)) + return 0; + + /* don't overflow */ + if (gpuaddr_end < gpuaddr) + return 0; + + node = private->mem_rb.rb_node; + while (node != NULL) { + struct kgsl_mem_entry *entry; + unsigned int memdesc_start, memdesc_end; + + entry = rb_entry(node, struct kgsl_mem_entry, node); + + memdesc_start = entry->memdesc.gpuaddr; + memdesc_end = memdesc_start + + kgsl_memdesc_mmapsize(&entry->memdesc); + + if (gpuaddr_end <= memdesc_start) + node = node->rb_left; + else if (memdesc_end <= gpuaddr) + node = node->rb_right; + else { + result = 0; + break; + } + } + return result; +} + +/** + * kgsl_sharedmem_find_id() - find a memory entry by id + * @process: the owning process + * @id: id to find + * + * @returns - the mem_entry or NULL + * + * Caller must kgsl_mem_entry_put() the returned entry, when finished using + * it. + */ +static inline struct kgsl_mem_entry * __must_check +kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id) +{ + int result = 0; + struct kgsl_mem_entry *entry; + + rcu_read_lock(); + entry = idr_find(&process->mem_idr, id); + if (entry) + result = kgsl_mem_entry_get(entry); + rcu_read_unlock(); + + if (!result) + return NULL; + return entry; +} + +/** + * kgsl_mem_entry_set_pend() - Set the pending free flag of a memory entry + * @entry - The memory entry + * + * @returns - true if pending flag was 0 else false + * + * This function will set the pending free flag if it is previously unset. Used + * to prevent race condition between ioctls calling free/freememontimestamp + * on the same entry. Whichever thread set's the flag first will do the free. + */ +static inline bool kgsl_mem_entry_set_pend(struct kgsl_mem_entry *entry) +{ + bool ret = false; + + if (entry == NULL) + return false; + + spin_lock(&entry->priv->mem_lock); + if (!entry->pending_free) { + entry->pending_free = 1; + ret = true; + } + spin_unlock(&entry->priv->mem_lock); + return ret; +} + /*call all ioctl sub functions with driver locked*/ static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) @@ -815,7 +1440,7 @@ static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, result = -EFAULT; break; } - context = kgsl_find_context(dev_priv, id); + context = kgsl_context_get_owner(dev_priv, id); if (!context) { result = -EINVAL; break; @@ -825,12 +1450,14 @@ static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, * the out parameter */ if (copy_to_user(param->value, &(context->reset_status), - sizeof(unsigned int))) { + sizeof(unsigned int))) result = -EFAULT; - break; + else { + /* Clear reset status once its been queried */ + context->reset_status = KGSL_CTX_STAT_NO_ERROR; } - /* Clear reset status once its been queried */ - context->reset_status = KGSL_CTX_STAT_NO_ERROR; + + kgsl_context_put(context); break; } default: @@ -867,10 +1494,6 @@ static long _device_waittimestamp(struct kgsl_device_private *dev_priv, struct kgsl_device *device = dev_priv->device; unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL; - /* Set the active count so that suspend doesn't do the wrong thing */ - - device->active_cnt++; - trace_kgsl_waittimestamp_entry(device, context_id, kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED), @@ -884,9 +1507,6 @@ static long _device_waittimestamp(struct kgsl_device_private *dev_priv, KGSL_TIMESTAMP_RETIRED), result); - /* Fire off any pending suspend operations that are in flight */ - kgsl_active_count_put(dev_priv->device); - return result; } @@ -906,19 +1526,14 @@ static long kgsl_ioctl_device_waittimestamp_ctxtid(struct kgsl_device_private { struct kgsl_device_waittimestamp_ctxtid *param = data; struct kgsl_context *context; - int result; + long result = -EINVAL; - context = kgsl_find_context(dev_priv, param->context_id); - if (context == NULL) - return -EINVAL; - /* - * A reference count is needed here, because waittimestamp may - * block with the device mutex unlocked and userspace could - * request for the context to be destroyed during that time. - */ - kgsl_context_get(context); - result = _device_waittimestamp(dev_priv, context, + context = kgsl_context_get_owner(dev_priv, param->context_id); + + if (context) + result = _device_waittimestamp(dev_priv, context, param->timestamp, param->timeout); + kgsl_context_put(context); return result; } @@ -931,7 +1546,7 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, struct kgsl_ibdesc *ibdesc; struct kgsl_context *context; - context = kgsl_find_context(dev_priv, param->drawctxt_id); + context = kgsl_context_get_owner(dev_priv, param->drawctxt_id); if (context == NULL) { result = -EINVAL; goto done; @@ -1004,12 +1619,10 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv, ¶m->timestamp, param->flags); - trace_kgsl_issueibcmds(dev_priv->device, param, ibdesc, result); - free_ibdesc: kfree(ibdesc); done: - + kgsl_context_put(context); return result; } @@ -1042,25 +1655,26 @@ static long kgsl_ioctl_cmdstream_readtimestamp_ctxtid(struct kgsl_device_private { struct kgsl_cmdstream_readtimestamp_ctxtid *param = data; struct kgsl_context *context; + long result = -EINVAL; - context = kgsl_find_context(dev_priv, param->context_id); - if (context == NULL) - return -EINVAL; - + context = kgsl_context_get_owner(dev_priv, param->context_id); - return _cmdstream_readtimestamp(dev_priv, context, + if (context) + result = _cmdstream_readtimestamp(dev_priv, context, param->type, ¶m->timestamp); + + kgsl_context_put(context); + return result; } static void kgsl_freemem_event_cb(struct kgsl_device *device, - void *priv, u32 id, u32 timestamp) + void *priv, u32 id, u32 timestamp, u32 type) { struct kgsl_mem_entry *entry = priv; - spin_lock(&entry->priv->mem_lock); - rb_erase(&entry->node, &entry->priv->mem_rb); - spin_unlock(&entry->priv->mem_lock); + + /* Free the memory for all event types */ trace_kgsl_mem_timestamp_free(device, entry, id, timestamp, 0); - kgsl_mem_entry_detach_process(entry); + kgsl_mem_entry_put(entry); } static long _cmdstream_freememontimestamp(struct kgsl_device_private *dev_priv, @@ -1072,15 +1686,18 @@ static long _cmdstream_freememontimestamp(struct kgsl_device_private *dev_priv, struct kgsl_device *device = dev_priv->device; unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL; - spin_lock(&dev_priv->process_priv->mem_lock); entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr); - spin_unlock(&dev_priv->process_priv->mem_lock); if (!entry) { KGSL_DRV_ERR(dev_priv->device, "invalid gpuaddr %08x\n", gpuaddr); - result = -EINVAL; - goto done; + return -EINVAL; + } + if (!kgsl_mem_entry_set_pend(entry)) { + KGSL_DRV_WARN(dev_priv->device, + "Cannot set pending bit for gpuaddr %08x\n", gpuaddr); + kgsl_mem_entry_put(entry); + return -EBUSY; } trace_kgsl_mem_timestamp_queue(device, entry, context_id, kgsl_readtimestamp(device, context, @@ -1088,7 +1705,7 @@ static long _cmdstream_freememontimestamp(struct kgsl_device_private *dev_priv, timestamp); result = kgsl_add_event(dev_priv->device, context_id, timestamp, kgsl_freemem_event_cb, entry, dev_priv); -done: + kgsl_mem_entry_put(entry); return result; } @@ -1109,16 +1726,14 @@ static long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid( { struct kgsl_cmdstream_freememontimestamp_ctxtid *param = data; struct kgsl_context *context; + long result = -EINVAL; - context = kgsl_find_context(dev_priv, param->context_id); - if (context == NULL) { - KGSL_DRV_ERR(dev_priv->device, - "invalid drawctxt context_id %d\n", param->context_id); - return -EINVAL; - } - - return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr, + context = kgsl_context_get_owner(dev_priv, param->context_id); + if (context) + result = _cmdstream_freememontimestamp(dev_priv, param->gpuaddr, context, param->timestamp, param->type); + kgsl_context_put(context); + return result; } static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv, @@ -1130,22 +1745,22 @@ static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv, context = kgsl_create_context(dev_priv); - if (context == NULL) { - result = -ENOMEM; + if (IS_ERR(context)) { + result = PTR_ERR(context); goto done; } if (dev_priv->device->ftbl->drawctxt_create) { result = dev_priv->device->ftbl->drawctxt_create( dev_priv->device, dev_priv->process_priv->pagetable, - context, param->flags); + context, ¶m->flags); if (result) goto done; } trace_kgsl_context_create(dev_priv->device, context, param->flags); param->drawctxt_id = context->id; done: - if (result && context) + if (result && !IS_ERR(context)) kgsl_context_detach(context); return result; @@ -1154,46 +1769,76 @@ static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv, static long kgsl_ioctl_drawctxt_destroy(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { - int result = 0; struct kgsl_drawctxt_destroy *param = data; struct kgsl_context *context; + long result = -EINVAL; - context = kgsl_find_context(dev_priv, param->drawctxt_id); + context = kgsl_context_get_owner(dev_priv, param->drawctxt_id); - if (context == NULL) { - result = -EINVAL; - goto done; + if (context) { + kgsl_context_detach(context); + result = 0; } - kgsl_context_detach(context); -done: + kgsl_context_put(context); return result; } +static long _sharedmem_free_entry(struct kgsl_mem_entry *entry) +{ + if (!kgsl_mem_entry_set_pend(entry)) { + kgsl_mem_entry_put(entry); + return -EBUSY; + } + + trace_kgsl_mem_free(entry); + + kgsl_memfree_add(entry->priv->pid, entry->memdesc.gpuaddr, + entry->memdesc.size, entry->memdesc.flags); + + /* + * First kgsl_mem_entry_put is for the reference that we took in + * this function when calling kgsl_sharedmem_find, second one is + * to free the memory since this is a free ioctl + */ + kgsl_mem_entry_put(entry); + kgsl_mem_entry_put(entry); + + return 0; +} + static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { - int result = 0; struct kgsl_sharedmem_free *param = data; struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_mem_entry *entry = NULL; - spin_lock(&private->mem_lock); entry = kgsl_sharedmem_find(private, param->gpuaddr); - if (entry) - rb_erase(&entry->node, &private->mem_rb); + if (!entry) { + KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n", + param->gpuaddr); + return -EINVAL; + } - spin_unlock(&private->mem_lock); + return _sharedmem_free_entry(entry); +} - if (entry) { - trace_kgsl_mem_free(entry); - kgsl_mem_entry_detach_process(entry); - } else { - KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr); - result = -EINVAL; +static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_gpumem_free_id *param = data; + struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_mem_entry *entry = NULL; + + entry = kgsl_sharedmem_find_id(private, param->id); + + if (!entry) { + KGSL_MEM_INFO(dev_priv->device, "invalid id %d\n", param->id); + return -EINVAL; } - return result; + return _sharedmem_free_entry(entry); } static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr) @@ -1224,11 +1869,10 @@ static int kgsl_get_phys_file(int fd, unsigned long *start, unsigned long *len, dev_t rdev; struct fb_info *info; + *start = 0; + *vstart = 0; + *len = 0; *filep = NULL; -#ifdef CONFIG_ANDROID_PMEM - if (!get_pmem_file(fd, start, vstart, len, filep)) - return 0; -#endif fbfile = fget(fd); if (fbfile == NULL) { @@ -1310,6 +1954,8 @@ static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry, entry->memdesc.size = size; entry->memdesc.physaddr = phys + offset; entry->memdesc.hostptr = (void *) (virt + offset); + /* USE_CPU_MAP is not impemented for PMEM. */ + entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP; ret = memdesc_sg_phys(&entry->memdesc, phys + offset, size); if (ret) @@ -1317,18 +1963,14 @@ static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry, return 0; err: -#ifdef CONFIG_ANDROID_PMEM - put_pmem_file(filep); -#endif return ret; } static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, - void *addr, int size) + unsigned long paddr, int size) { int i; int sglen = PAGE_ALIGN(size) / PAGE_SIZE; - unsigned long paddr = (unsigned long) addr; memdesc->sg = kgsl_sg_alloc(sglen); @@ -1379,34 +2021,33 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, return -EINVAL; } -static int kgsl_setup_hostptr(struct kgsl_mem_entry *entry, +static int kgsl_setup_useraddr(struct kgsl_mem_entry *entry, struct kgsl_pagetable *pagetable, - void *hostptr, unsigned int offset, + unsigned long useraddr, unsigned int offset, size_t size) { struct vm_area_struct *vma; unsigned int len; down_read(¤t->mm->mmap_sem); - vma = find_vma(current->mm, (unsigned int) hostptr); + vma = find_vma(current->mm, useraddr); up_read(¤t->mm->mmap_sem); if (!vma) { - KGSL_CORE_ERR("find_vma(%p) failed\n", hostptr); + KGSL_CORE_ERR("find_vma(%lx) failed\n", useraddr); return -EINVAL; } /* We don't necessarily start at vma->vm_start */ - len = vma->vm_end - (unsigned long) hostptr; + len = vma->vm_end - useraddr; if (offset >= len) return -EINVAL; - if (!KGSL_IS_PAGE_ALIGNED((unsigned long) hostptr) || + if (!KGSL_IS_PAGE_ALIGNED(useraddr) || !KGSL_IS_PAGE_ALIGNED(len)) { - KGSL_CORE_ERR("user address len(%u)" - "and start(%p) must be page" - "aligned\n", len, hostptr); + KGSL_CORE_ERR("bad alignment: start(%lx) len(%u)\n", + useraddr, len); return -EINVAL; } @@ -1427,28 +2068,29 @@ static int kgsl_setup_hostptr(struct kgsl_mem_entry *entry, entry->memdesc.pagetable = pagetable; entry->memdesc.size = size; - entry->memdesc.hostptr = hostptr + (offset & PAGE_MASK); + entry->memdesc.useraddr = useraddr + (offset & PAGE_MASK); + if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) + entry->memdesc.gpuaddr = entry->memdesc.useraddr; - return memdesc_sg_virt(&entry->memdesc, - hostptr + (offset & PAGE_MASK), size); + return memdesc_sg_virt(&entry->memdesc, entry->memdesc.useraddr, + size); } #ifdef CONFIG_ASHMEM static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry, struct kgsl_pagetable *pagetable, - int fd, void *hostptr, size_t size) + int fd, unsigned long useraddr, size_t size) { int ret; struct vm_area_struct *vma; struct file *filep, *vmfile; unsigned long len; - unsigned int hostaddr = (unsigned int) hostptr; - vma = kgsl_get_vma_from_start_addr(hostaddr); + vma = kgsl_get_vma_from_start_addr(useraddr); if (vma == NULL) return -EINVAL; - if (vma->vm_pgoff || vma->vm_start != hostaddr) { + if (vma->vm_pgoff || vma->vm_start != useraddr) { KGSL_CORE_ERR("Invalid vma region\n"); return -EINVAL; } @@ -1459,8 +2101,8 @@ static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry, size = len; if (size != len) { - KGSL_CORE_ERR("Invalid size %d for vma region %p\n", - size, hostptr); + KGSL_CORE_ERR("Invalid size %d for vma region %lx\n", + size, useraddr); return -EINVAL; } @@ -1480,9 +2122,11 @@ static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry, entry->priv_data = filep; entry->memdesc.pagetable = pagetable; entry->memdesc.size = ALIGN(size, PAGE_SIZE); - entry->memdesc.hostptr = hostptr; + entry->memdesc.useraddr = useraddr; + if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) + entry->memdesc.gpuaddr = entry->memdesc.useraddr; - ret = memdesc_sg_virt(&entry->memdesc, hostptr, size); + ret = memdesc_sg_virt(&entry->memdesc, useraddr, size); if (ret) goto err; @@ -1495,7 +2139,7 @@ static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry, #else static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry, struct kgsl_pagetable *pagetable, - int fd, void *hostptr, size_t size) + int fd, unsigned long useraddr, size_t size) { return -EINVAL; } @@ -1521,6 +2165,8 @@ static int kgsl_setup_ion(struct kgsl_mem_entry *entry, entry->priv_data = handle; entry->memdesc.pagetable = pagetable; entry->memdesc.size = 0; + /* USE_CPU_MAP is not impemented for ION. */ + entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP; sg_table = ion_sg_table(kgsl_ion_client, handle); @@ -1544,6 +2190,13 @@ static int kgsl_setup_ion(struct kgsl_mem_entry *entry, return -ENOMEM; } +static inline int +can_use_cpu_map(void) +{ + return (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU + && kgsl_mmu_is_perprocess()); +} + static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { @@ -1563,7 +2216,23 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, else memtype = param->memtype; + /* + * Mask off unknown flags from userspace. This way the caller can + * check if a flag is supported by looking at the returned flags. + * Note: CACHEMODE is ignored for this call. Caching should be + * determined by type of allocation being mapped. + */ + param->flags &= KGSL_MEMFLAGS_GPUREADONLY + | KGSL_MEMTYPE_MASK + | KGSL_MEMALIGN_MASK + | KGSL_MEMFLAGS_USE_CPU_MAP; + entry->memdesc.flags = param->flags; + if (!can_use_cpu_map()) + entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP; + + if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) + entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; switch (memtype) { case KGSL_USER_MEM_TYPE_PMEM: @@ -1589,8 +2258,8 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, if (param->hostptr == 0) break; - result = kgsl_setup_hostptr(entry, private->pagetable, - (void *) param->hostptr, + result = kgsl_setup_useraddr(entry, private->pagetable, + param->hostptr, param->offset, param->len); entry->memtype = KGSL_MEM_ENTRY_USER; break; @@ -1607,7 +2276,7 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, break; result = kgsl_setup_ashmem(entry, private->pagetable, - param->fd, (void *) param->hostptr, + param->fd, param->hostptr, param->len); entry->memtype = KGSL_MEM_ENTRY_ASHMEM; @@ -1629,12 +2298,12 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, else if (entry->memdesc.size >= SZ_64K) kgsl_memdesc_set_align(&entry->memdesc, ilog2(SZ_64)); - result = kgsl_mmu_map(private->pagetable, - &entry->memdesc, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + /* echo back flags */ + param->flags = entry->memdesc.flags; + result = kgsl_mem_entry_attach_process(entry, dev_priv); if (result) - goto error_put_file_ptr; + goto error_attach; /* Adjust the returned value for a non 4k aligned offset */ param->gpuaddr = entry->memdesc.gpuaddr + (param->offset & ~PAGE_MASK); @@ -1644,13 +2313,11 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, kgsl_process_add_stats(private, entry->memtype, param->len); - kgsl_mem_entry_attach_process(entry, private); trace_kgsl_mem_map(entry, param->fd); - kgsl_check_idle(dev_priv->device); return result; -error_put_file_ptr: +error_attach: switch (entry->memtype) { case KGSL_MEM_ENTRY_PMEM: case KGSL_MEM_ENTRY_ASHMEM: @@ -1665,37 +2332,143 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, } error: kfree(entry); - kgsl_check_idle(dev_priv->device); return result; } -/*This function flushes a graphics memory allocation from CPU cache - *when caching is enabled with MMU*/ +static int _kgsl_gpumem_sync_cache(struct kgsl_mem_entry *entry, int op) +{ + int ret = 0; + int cacheop; + int mode; + + /* + * Flush is defined as (clean | invalidate). If both bits are set, then + * do a flush, otherwise check for the individual bits and clean or inv + * as requested + */ + + if ((op & KGSL_GPUMEM_CACHE_FLUSH) == KGSL_GPUMEM_CACHE_FLUSH) + cacheop = KGSL_CACHE_OP_FLUSH; + else if (op & KGSL_GPUMEM_CACHE_CLEAN) + cacheop = KGSL_CACHE_OP_CLEAN; + else if (op & KGSL_GPUMEM_CACHE_INV) + cacheop = KGSL_CACHE_OP_INV; + else { + ret = -EINVAL; + goto done; + } + + mode = kgsl_memdesc_get_cachemode(&entry->memdesc); + if (mode != KGSL_CACHEMODE_UNCACHED + && mode != KGSL_CACHEMODE_WRITECOMBINE) + kgsl_cache_range_op(&entry->memdesc, cacheop); + +done: + return ret; +} + +/* New cache sync function - supports both directions (clean and invalidate) */ + +static long +kgsl_ioctl_gpumem_sync_cache(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_gpumem_sync_cache *param = data; + struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_mem_entry *entry = NULL; + long ret; + + if (param->id != 0) { + entry = kgsl_sharedmem_find_id(private, param->id); + if (entry == NULL) { + KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n", + param->id); + return -EINVAL; + } + } else if (param->gpuaddr != 0) { + entry = kgsl_sharedmem_find(private, param->gpuaddr); + if (entry == NULL) { + KGSL_MEM_INFO(dev_priv->device, + "can't find gpuaddr %x\n", + param->gpuaddr); + return -EINVAL; + } + } else { + return -EINVAL; + } + + ret = _kgsl_gpumem_sync_cache(entry, param->op); + kgsl_mem_entry_put(entry); + return ret; +} + +/* Legacy cache function, does a flush (clean + invalidate) */ + static long kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { - int result = 0; - struct kgsl_mem_entry *entry; struct kgsl_sharedmem_free *param = data; struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_mem_entry *entry = NULL; + long ret; - spin_lock(&private->mem_lock); entry = kgsl_sharedmem_find(private, param->gpuaddr); - if (!entry) { - KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr); - result = -EINVAL; - goto done; - } - if (!entry->memdesc.hostptr) { - KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n", - param->gpuaddr); - goto done; + if (entry == NULL) { + KGSL_MEM_INFO(dev_priv->device, + "can't find gpuaddr %x\n", + param->gpuaddr); + return -EINVAL; } + ret = _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH); + kgsl_mem_entry_put(entry); + return ret; +} - kgsl_cache_range_op(&entry->memdesc, KGSL_CACHE_OP_CLEAN); -done: - spin_unlock(&private->mem_lock); +/* + * The common parts of kgsl_ioctl_gpumem_alloc and kgsl_ioctl_gpumem_alloc_id. + */ +int +_gpumem_alloc(struct kgsl_device_private *dev_priv, + struct kgsl_mem_entry **ret_entry, + unsigned int size, unsigned int flags) +{ + int result; + struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_mem_entry *entry; + + /* + * Mask off unknown flags from userspace. This way the caller can + * check if a flag is supported by looking at the returned flags. + */ + flags &= KGSL_MEMFLAGS_GPUREADONLY + | KGSL_CACHEMODE_MASK + | KGSL_MEMTYPE_MASK + | KGSL_MEMALIGN_MASK + | KGSL_MEMFLAGS_USE_CPU_MAP; + + if (!can_use_cpu_map()) + flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP; + + entry = kgsl_mem_entry_create(); + if (entry == NULL) + return -ENOMEM; + + if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) + entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; + + result = kgsl_allocate_user(&entry->memdesc, private->pagetable, size, + flags); + if (result != 0) + goto err; + + entry->memtype = KGSL_MEM_ENTRY_KERNEL; + + *ret_entry = entry; + return result; +err: + kfree(entry); + *ret_entry = NULL; return result; } @@ -1705,29 +2478,105 @@ kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv, { struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_gpumem_alloc *param = data; - struct kgsl_mem_entry *entry; + struct kgsl_mem_entry *entry = NULL; int result; - entry = kgsl_mem_entry_create(); - if (entry == NULL) - return -ENOMEM; + param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP; + result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags); + if (result) + return result; + + result = kgsl_mem_entry_attach_process(entry, dev_priv); + if (result != 0) + goto err; + + kgsl_process_add_stats(private, entry->memtype, param->size); + trace_kgsl_mem_alloc(entry); + + param->gpuaddr = entry->memdesc.gpuaddr; + param->size = entry->memdesc.size; + param->flags = entry->memdesc.flags; + return result; +err: + kgsl_sharedmem_free(&entry->memdesc); + kfree(entry); + return result; +} + +static long +kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_gpumem_alloc_id *param = data; + struct kgsl_mem_entry *entry = NULL; + int result; + + if (!can_use_cpu_map()) + param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP; + + result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags); + if (result != 0) + goto err; + + result = kgsl_mem_entry_attach_process(entry, dev_priv); + if (result != 0) + goto err; - result = kgsl_allocate_user(&entry->memdesc, private->pagetable, - param->size, param->flags); + kgsl_process_add_stats(private, entry->memtype, param->size); + trace_kgsl_mem_alloc(entry); + + param->id = entry->id; + param->flags = entry->memdesc.flags; + param->size = entry->memdesc.size; + param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc); + param->gpuaddr = entry->memdesc.gpuaddr; + return result; +err: + if (entry) + kgsl_sharedmem_free(&entry->memdesc); + kfree(entry); + return result; +} - if (result == 0) { - entry->memtype = KGSL_MEM_ENTRY_KERNEL; - kgsl_mem_entry_attach_process(entry, private); - param->gpuaddr = entry->memdesc.gpuaddr; +static long +kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_gpumem_get_info *param = data; + struct kgsl_mem_entry *entry = NULL; + int result = 0; - kgsl_process_add_stats(private, entry->memtype, param->size); - trace_kgsl_mem_alloc(entry); - } else - kfree(entry); + if (param->id != 0) { + entry = kgsl_sharedmem_find_id(private, param->id); + if (entry == NULL) { + KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n", + param->id); + return -EINVAL; + } + } else if (param->gpuaddr != 0) { + entry = kgsl_sharedmem_find(private, param->gpuaddr); + if (entry == NULL) { + KGSL_MEM_INFO(dev_priv->device, + "can't find gpuaddr %lx\n", + param->gpuaddr); + return -EINVAL; + } + } else { + return -EINVAL; + } + param->gpuaddr = entry->memdesc.gpuaddr; + param->id = entry->id; + param->flags = entry->memdesc.flags; + param->size = entry->memdesc.size; + param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc); + param->useraddr = entry->memdesc.useraddr; - kgsl_check_idle(dev_priv->device); + kgsl_mem_entry_put(entry); return result; } + static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { @@ -1736,14 +2585,14 @@ static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv, struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_mem_entry *entry = NULL; - spin_lock(&private->mem_lock); entry = kgsl_sharedmem_find_region(private, param->gpuaddr, param->len); - if (entry) - kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr, - param->len, true); - else - result = -EINVAL; - spin_unlock(&private->mem_lock); + if (!entry) + return -EINVAL; + + kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr, + param->len, true); + + kgsl_mem_entry_put(entry); return result; } @@ -1776,11 +2625,12 @@ struct kgsl_genlock_event_priv { */ static void kgsl_genlock_event_cb(struct kgsl_device *device, - void *priv, u32 context_id, u32 timestamp) + void *priv, u32 context_id, u32 timestamp, u32 type) { struct kgsl_genlock_event_priv *ev = priv; int ret; + /* Signal the lock for every event type */ ret = genlock_lock(ev->handle, GENLOCK_UNLOCK, 0, 0); if (ret) KGSL_CORE_ERR("Error while unlocking genlock: %d\n", ret); @@ -1895,7 +2745,7 @@ static const struct { } kgsl_ioctl_funcs[] = { KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY, kgsl_ioctl_device_getproperty, - KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE), + KGSL_IOCTL_LOCK), KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP, kgsl_ioctl_device_waittimestamp, KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE), @@ -1913,13 +2763,13 @@ static const struct { KGSL_IOCTL_LOCK), KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP, kgsl_ioctl_cmdstream_freememontimestamp, - KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE), + KGSL_IOCTL_LOCK), KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID, kgsl_ioctl_cmdstream_freememontimestamp_ctxtid, - KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE), + KGSL_IOCTL_LOCK), KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE, kgsl_ioctl_drawctxt_create, - KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE), + KGSL_IOCTL_LOCK), KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY, kgsl_ioctl_drawctxt_destroy, KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE), @@ -1942,7 +2792,15 @@ static const struct { KGSL_IOCTL_LOCK), KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY, kgsl_ioctl_device_setproperty, - KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE) + KGSL_IOCTL_LOCK), + KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID, + kgsl_ioctl_gpumem_alloc_id, 0), + KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID, + kgsl_ioctl_gpumem_free_id, 0), + KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO, + kgsl_ioctl_gpumem_get_info, 0), + KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE, + kgsl_ioctl_gpumem_sync_cache, 0), }; static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) @@ -2023,14 +2881,19 @@ static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) if (lock) { mutex_lock(&dev_priv->device->mutex); - if (use_hw) - kgsl_check_suspended(dev_priv->device); + if (use_hw) { + ret = kgsl_active_count_get(dev_priv->device); + if (ret < 0) + goto unlock; + } } ret = func(dev_priv, cmd, uptr); +unlock: if (lock) { - kgsl_check_idle_locked(dev_priv->device); + if (use_hw) + kgsl_active_count_put(dev_priv->device); mutex_unlock(&dev_priv->device->mutex); } @@ -2084,7 +2947,8 @@ kgsl_mmap_memstore(struct kgsl_device *device, struct vm_area_struct *vma) static void kgsl_gpumem_vm_open(struct vm_area_struct *vma) { struct kgsl_mem_entry *entry = vma->vm_private_data; - kgsl_mem_entry_get(entry); + if (!kgsl_mem_entry_get(entry)) + vma->vm_private_data = NULL; } static int @@ -2092,6 +2956,8 @@ kgsl_gpumem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct kgsl_mem_entry *entry = vma->vm_private_data; + if (!entry) + return VM_FAULT_SIGBUS; if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault) return VM_FAULT_SIGBUS; @@ -2102,6 +2968,11 @@ static void kgsl_gpumem_vm_close(struct vm_area_struct *vma) { struct kgsl_mem_entry *entry = vma->vm_private_data; + + if (!entry) + return; + + entry->memdesc.useraddr = 0; kgsl_mem_entry_put(entry); } @@ -2111,8 +2982,186 @@ static struct vm_operations_struct kgsl_gpumem_vm_ops = { .close = kgsl_gpumem_vm_close, }; +static int +get_mmap_entry(struct kgsl_process_private *private, + struct kgsl_mem_entry **out_entry, unsigned long pgoff, + unsigned long len) +{ + int ret = 0; + struct kgsl_mem_entry *entry; + + entry = kgsl_sharedmem_find_id(private, pgoff); + if (entry == NULL) { + entry = kgsl_sharedmem_find(private, pgoff << PAGE_SHIFT); + } + + if (!entry) + return -EINVAL; + + if (!entry->memdesc.ops || + !entry->memdesc.ops->vmflags || + !entry->memdesc.ops->vmfault) { + ret = -EINVAL; + goto err_put; + } + + if (entry->memdesc.useraddr != 0) { + ret = -EBUSY; + goto err_put; + } + + if (len != kgsl_memdesc_mmapsize(&entry->memdesc)) { + ret = -ERANGE; + goto err_put; + } + + *out_entry = entry; + return 0; +err_put: + kgsl_mem_entry_put(entry); + return ret; +} + +static inline bool +mmap_range_valid(unsigned long addr, unsigned long len) +{ + return ((ULONG_MAX - addr) > len) && ((addr + len) < TASK_SIZE); +} + +static unsigned long +kgsl_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + unsigned long ret = 0, orig_len = len; + unsigned long vma_offset = pgoff << PAGE_SHIFT; + struct kgsl_device_private *dev_priv = file->private_data; + struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_device *device = dev_priv->device; + struct kgsl_mem_entry *entry = NULL; + unsigned int align; + unsigned int retry = 0; + + if (vma_offset == device->memstore.gpuaddr) + return get_unmapped_area(NULL, addr, len, pgoff, flags); + + ret = get_mmap_entry(private, &entry, pgoff, len); + if (ret) + return ret; + + if (!kgsl_memdesc_use_cpu_map(&entry->memdesc) || (flags & MAP_FIXED)) { + /* + * If we're not going to use the same mapping on the gpu, + * any address is fine. + * For MAP_FIXED, hopefully the caller knows what they're doing, + * but we may fail in mmap() if there is already something + * at the virtual address chosen. + */ + ret = get_unmapped_area(NULL, addr, len, pgoff, flags); + goto put; + } + if (entry->memdesc.gpuaddr != 0) { + KGSL_MEM_INFO(device, + "pgoff %lx already mapped to gpuaddr %x\n", + pgoff, entry->memdesc.gpuaddr); + ret = -EBUSY; + goto put; + } + + align = kgsl_memdesc_get_align(&entry->memdesc); + if (align >= ilog2(SZ_1M)) + align = ilog2(SZ_1M); + else if (align >= ilog2(SZ_64K)) + align = ilog2(SZ_64K); + else if (align <= PAGE_SHIFT) + align = 0; + + if (align) + len += 1 << align; + + if (!mmap_range_valid(addr, len)) + addr = 0; + do { + ret = get_unmapped_area(NULL, addr, len, pgoff, flags); + if (IS_ERR_VALUE(ret)) { + /* + * If we are really fragmented, there may not be room + * for the alignment padding, so try again without it. + */ + if (!retry && (ret == (unsigned long)-ENOMEM) + && (align > PAGE_SHIFT)) { + align = 0; + addr = 0; + len = orig_len; + retry = 1; + continue; + } + break; + } + if (align) + ret = ALIGN(ret, (1 << align)); + + /*make sure there isn't a GPU only mapping at this address */ + spin_lock(&private->mem_lock); + if (kgsl_sharedmem_region_empty(private, ret, orig_len)) { + int ret_val; + /* + * We found a free memory map, claim it here with + * memory lock held + */ + entry->memdesc.gpuaddr = ret; + /* This should never fail */ + ret_val = kgsl_mem_entry_track_gpuaddr(private, entry); + spin_unlock(&private->mem_lock); + BUG_ON(ret_val); + /* map cannot be called with lock held */ + ret_val = kgsl_mmu_map(private->pagetable, + &entry->memdesc); + if (ret_val) { + spin_lock(&private->mem_lock); + kgsl_mem_entry_untrack_gpuaddr(private, entry); + spin_unlock(&private->mem_lock); + ret = ret_val; + } + break; + } + spin_unlock(&private->mem_lock); + + trace_kgsl_mem_unmapped_area_collision(entry, addr, orig_len, + ret); + + /* + * If we collided, bump the hint address so that + * get_umapped_area knows to look somewhere else. + */ + addr = (addr == 0) ? ret + orig_len : addr + orig_len; + + /* + * The addr hint can be set by userspace to be near + * the end of the address space. Make sure we search + * the whole address space at least once by wrapping + * back around once. + */ + if (!retry && !mmap_range_valid(addr, len)) { + addr = 0; + retry = 1; + } else { + ret = -EBUSY; + } + } while (mmap_range_valid(addr, len)); + + if (IS_ERR_VALUE(ret)) + KGSL_MEM_ERR(device, + "pid %d pgoff %lx len %ld failed error %ld\n", + private->pid, pgoff, len, ret); +put: + kgsl_mem_entry_put(entry); + return ret; +} + static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) { + unsigned int ret, cache; unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT; struct kgsl_device_private *dev_priv = file->private_data; struct kgsl_process_private *private = dev_priv->process_priv; @@ -2124,31 +3173,64 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) if (vma_offset == device->memstore.gpuaddr) return kgsl_mmap_memstore(device, vma); - /* Find a chunk of GPU memory */ - - spin_lock(&private->mem_lock); - entry = kgsl_sharedmem_find(private, vma_offset); + /* + * The reference count on the entry that we get from + * get_mmap_entry() will be held until kgsl_gpumem_vm_close(). + */ + ret = get_mmap_entry(private, &entry, vma->vm_pgoff, + vma->vm_end - vma->vm_start); + if (ret) + return ret; - if (entry) - kgsl_mem_entry_get(entry); + vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc); - spin_unlock(&private->mem_lock); + vma->vm_private_data = entry; - if (entry == NULL) - return -EINVAL; + /* Determine user-side caching policy */ - if (!entry->memdesc.ops || - !entry->memdesc.ops->vmflags || - !entry->memdesc.ops->vmfault) - return -EINVAL; + cache = kgsl_memdesc_get_cachemode(&entry->memdesc); - vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc); + switch (cache) { + case KGSL_CACHEMODE_UNCACHED: + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + break; + case KGSL_CACHEMODE_WRITETHROUGH: + vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot); + break; + case KGSL_CACHEMODE_WRITEBACK: + vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot); + break; + case KGSL_CACHEMODE_WRITECOMBINE: + default: + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + break; + } - vma->vm_private_data = entry; - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_ops = &kgsl_gpumem_vm_ops; + + if (cache == KGSL_CACHEMODE_WRITEBACK + || cache == KGSL_CACHEMODE_WRITETHROUGH) { + struct scatterlist *s; + int i; + int sglen = entry->memdesc.sglen; + unsigned long addr = vma->vm_start; + + for_each_sg(entry->memdesc.sg, s, sglen, i) { + int j; + for (j = 0; j < (sg_dma_len(s) >> PAGE_SHIFT); j++) { + struct page *page = sg_page(s); + page = nth_page(page, j); + vm_insert_page(vma, addr, page); + addr += PAGE_SIZE; + } + } + } + vma->vm_file = file; + entry->memdesc.useraddr = vma->vm_start; + + trace_kgsl_mem_mmap(entry); return 0; } @@ -2165,6 +3247,7 @@ static const struct file_operations kgsl_fops = { .release = kgsl_release, .open = kgsl_open, .mmap = kgsl_mmap, + .get_unmapped_area = kgsl_get_unmapped_area, .unlocked_ioctl = kgsl_ioctl, }; @@ -2312,13 +3395,15 @@ int kgsl_device_platform_probe(struct kgsl_device *device) device->id, device->reg_phys, device->reg_len, device->reg_virt); + rwlock_init(&device->context_lock); + result = kgsl_drm_init(pdev); if (result) goto error_pwrctrl_close; - kgsl_cffdump_open(device->id); setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device); + setup_timer(&device->hang_timer, hang_timer, (unsigned long) device); status = kgsl_create_device_workqueue(device); if (status) goto error_pwrctrl_close; @@ -2374,11 +3459,7 @@ int kgsl_postmortem_dump(struct kgsl_device *device, int manual) /* For a manual dump, make sure that the system is idle */ if (manual) { - if (device->active_cnt != 0) { - mutex_unlock(&device->mutex); - wait_for_completion(&device->suspend_gate); - mutex_lock(&device->mutex); - } + kgsl_active_count_wait(device); if (device->state == KGSL_STATE_ACTIVE) kgsl_idle(device); @@ -2398,9 +3479,7 @@ int kgsl_postmortem_dump(struct kgsl_device *device, int manual) /* Disable the idle timer so we don't get interrupted */ del_timer_sync(&device->idle_timer); - mutex_unlock(&device->mutex); - flush_workqueue(device->work_queue); - mutex_lock(&device->mutex); + del_timer_sync(&device->hang_timer); /* Turn off napping to make sure we have the clocks full attention through the following process */ @@ -2440,7 +3519,6 @@ void kgsl_device_platform_remove(struct kgsl_device *device) { kgsl_device_snapshot_close(device); - kgsl_cffdump_close(device->id); kgsl_pwrctrl_uninit_sysfs(device); pm_qos_remove_request(&device->pm_qos_req_dma); @@ -2496,6 +3574,7 @@ static void kgsl_core_exit(void) kgsl_driver.class = NULL; } + kgsl_memfree_exit(); unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX); } @@ -2561,12 +3640,14 @@ static int __init kgsl_core_init(void) kgsl_mmu_set_mmutype(ksgl_mmu_type); - if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()) { + if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()) { result = kgsl_ptdata_init(); if (result) goto err; } + kgsl_memfree_init(); + return 0; err: diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 39351648..22fc1844 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -129,11 +129,16 @@ struct kgsl_memdesc_ops { #define KGSL_MEMDESC_GUARD_PAGE BIT(0) /* Set if the memdesc is mapped into all pagetables */ #define KGSL_MEMDESC_GLOBAL BIT(1) +/* The memdesc is frozen during a snapshot */ +#define KGSL_MEMDESC_FROZEN BIT(2) +/* The memdesc is mapped into a pagetable */ +#define KGSL_MEMDESC_MAPPED BIT(3) /* shared memory allocation */ struct kgsl_memdesc { struct kgsl_pagetable *pagetable; - void *hostptr; + void *hostptr; /* kernel virtual address */ + unsigned long useraddr; /* userspace address */ unsigned int gpuaddr; unsigned int physaddr; unsigned int size; @@ -154,21 +159,20 @@ struct kgsl_memdesc { #define KGSL_MEM_ENTRY_ION 4 #define KGSL_MEM_ENTRY_MAX 5 -/* List of flags */ - -#define KGSL_MEM_ENTRY_FROZEN (1 << 0) - struct kgsl_mem_entry { struct kref refcount; struct kgsl_memdesc memdesc; int memtype; - int flags; void *priv_data; struct rb_node node; + unsigned int id; unsigned int context_id; /* back pointer to private structure under whose context this * allocation is made */ struct kgsl_process_private *priv; + /* Initialized to 0, set to 1 when entry is marked for freeing */ + int pending_free; + struct kgsl_device_private *dev_priv; }; #ifdef CONFIG_MSM_KGSL_MMU_PAGE_FAULT @@ -177,6 +181,7 @@ struct kgsl_mem_entry { #define MMU_CONFIG 1 #endif +void kgsl_hang_check(struct work_struct *work); void kgsl_mem_entry_destroy(struct kref *kref); int kgsl_postmortem_dump(struct kgsl_device *device, int manual); @@ -189,16 +194,16 @@ struct kgsl_mem_entry *kgsl_sharedmem_find_region( void kgsl_get_memory_usage(char *str, size_t len, unsigned int memflags); -int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, - void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv, - void *owner); +void kgsl_signal_event(struct kgsl_device *device, + struct kgsl_context *context, unsigned int timestamp, + unsigned int type); + +void kgsl_signal_events(struct kgsl_device *device, + struct kgsl_context *context, unsigned int type); void kgsl_cancel_events(struct kgsl_device *device, void *owner); -void kgsl_cancel_events_ctxt(struct kgsl_device *device, - struct kgsl_context *context); - extern const struct dev_pm_ops kgsl_pm_ops; struct early_suspend; @@ -207,6 +212,14 @@ int kgsl_resume_driver(struct platform_device *pdev); void kgsl_early_suspend_driver(struct early_suspend *h); void kgsl_late_resume_driver(struct early_suspend *h); +void kgsl_trace_regwrite(struct kgsl_device *device, unsigned int offset, + unsigned int value); + +void kgsl_trace_issueibcmds(struct kgsl_device *device, int id, + struct kgsl_ibdesc *ibdesc, int numibs, + unsigned int timestamp, unsigned int flags, + int result, unsigned int type); + #ifdef CONFIG_MSM_KGSL_DRM extern int kgsl_drm_init(struct platform_device *dev); extern void kgsl_drm_exit(void); @@ -224,6 +237,14 @@ static inline void kgsl_drm_exit(void) static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc, unsigned int gpuaddr, unsigned int size) { + /* set a minimum size to search for */ + if (!size) + size = 1; + + /* don't overflow */ + if (size > UINT_MAX - gpuaddr) + return 0; + if (gpuaddr >= memdesc->gpuaddr && ((gpuaddr + size) <= (memdesc->gpuaddr + memdesc->size))) { return 1; @@ -272,10 +293,10 @@ static inline int timestamp_cmp(unsigned int a, unsigned int b) return ((a > b) && (a - b <= KGSL_TIMESTAMP_WINDOW)) ? 1 : -1; } -static inline void +static inline int kgsl_mem_entry_get(struct kgsl_mem_entry *entry) { - kref_get(&entry->refcount); + return kref_get_unless_zero(&entry->refcount); } static inline void diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c index e06c94d6..f1271dcc 100644 --- a/drivers/gpu/msm/kgsl_cffdump.c +++ b/drivers/gpu/msm/kgsl_cffdump.c @@ -28,6 +28,7 @@ #include "kgsl_log.h" #include "kgsl_sharedmem.h" #include "adreno_pm4types.h" +#include "adreno.h" static struct rchan *chan; static struct dentry *dir; @@ -334,7 +335,7 @@ void kgsl_cffdump_init() return; } - kgsl_cff_dump_enable = 1; + kgsl_cff_dump_enable = 0; spin_lock_init(&cffdump_lock); @@ -356,38 +357,60 @@ void kgsl_cffdump_destroy() debugfs_remove(dir); } -void kgsl_cffdump_open(enum kgsl_deviceid device_id) +void kgsl_cffdump_open(struct kgsl_device *device) { - kgsl_cffdump_memory_base(device_id, KGSL_PAGETABLE_BASE, - kgsl_mmu_get_ptsize(), SZ_256K); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + if (!kgsl_cff_dump_enable) + return; + + if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) { + kgsl_cffdump_memory_base(device->id, + kgsl_mmu_get_base_addr(&device->mmu), + kgsl_mmu_get_ptsize(&device->mmu) + + KGSL_IOMMU_GLOBAL_MEM_SIZE, adreno_dev->gmem_size); + } else { + kgsl_cffdump_memory_base(device->id, + kgsl_mmu_get_base_addr(&device->mmu), + kgsl_mmu_get_ptsize(&device->mmu), + adreno_dev->gmem_size); + } } void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base, unsigned int range, unsigned gmemsize) { + if (!kgsl_cff_dump_enable) + return; cffdump_printline(device_id, CFF_OP_MEMORY_BASE, base, range, gmemsize, 0, 0); } void kgsl_cffdump_hang(enum kgsl_deviceid device_id) { + if (!kgsl_cff_dump_enable) + return; cffdump_printline(device_id, CFF_OP_HANG, 0, 0, 0, 0, 0); } void kgsl_cffdump_close(enum kgsl_deviceid device_id) { + if (!kgsl_cff_dump_enable) + return; cffdump_printline(device_id, CFF_OP_EOF, 0, 0, 0, 0, 0); } + void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1, unsigned int op2, unsigned int op3, unsigned int op4, unsigned int op5) { + if (!kgsl_cff_dump_enable) + return; cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5); } void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv, - const struct kgsl_memdesc *memdesc, uint gpuaddr, uint sizebytes, + struct kgsl_memdesc *memdesc, uint gpuaddr, uint sizebytes, bool clean_cache) { const void *src; @@ -399,10 +422,8 @@ void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv, if (memdesc == NULL) { struct kgsl_mem_entry *entry; - spin_lock(&dev_priv->process_priv->mem_lock); entry = kgsl_sharedmem_find_region(dev_priv->process_priv, gpuaddr, sizebytes); - spin_unlock(&dev_priv->process_priv->mem_lock); if (entry == NULL) { KGSL_CORE_ERR("did not find mapping " "for gpuaddr: 0x%08x\n", gpuaddr); @@ -522,7 +543,7 @@ static int subbuf_start_handler(struct rchan_buf *buf, } static struct dentry *create_buf_file_handler(const char *filename, - struct dentry *parent, int mode, struct rchan_buf *buf, + struct dentry *parent, unsigned short mode, struct rchan_buf *buf, int *is_global) { return debugfs_create_file(filename, mode, parent, buf, diff --git a/drivers/gpu/msm/kgsl_cffdump.h b/drivers/gpu/msm/kgsl_cffdump.h index 2733cc3f..d5656f80 100644 --- a/drivers/gpu/msm/kgsl_cffdump.h +++ b/drivers/gpu/msm/kgsl_cffdump.h @@ -22,10 +22,10 @@ void kgsl_cffdump_init(void); void kgsl_cffdump_destroy(void); -void kgsl_cffdump_open(enum kgsl_deviceid device_id); +void kgsl_cffdump_open(struct kgsl_device *device); void kgsl_cffdump_close(enum kgsl_deviceid device_id); void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv, - const struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes, + struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes, bool clean_cache); void kgsl_cffdump_setmem(uint addr, uint value, uint sizebytes); void kgsl_cffdump_regwrite(enum kgsl_deviceid device_id, uint addr, @@ -49,7 +49,7 @@ void kgsl_cffdump_hang(enum kgsl_deviceid device_id); #define kgsl_cffdump_init() (void)0 #define kgsl_cffdump_destroy() (void)0 -#define kgsl_cffdump_open(device_id) (void)0 +#define kgsl_cffdump_open(device) (void)0 #define kgsl_cffdump_close(device_id) (void)0 #define kgsl_cffdump_syncmem(dev_priv, memdesc, addr, sizebytes, clean_cache) \ (void) 0 diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index b41bd6b4..3b20c233 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2008-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2008-2012,2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,8 +18,6 @@ #include "kgsl_device.h" #include "kgsl_sharedmem.h" -/*default log levels is error for everything*/ -#define KGSL_LOG_LEVEL_DEFAULT 3 #define KGSL_LOG_LEVEL_MAX 7 struct dentry *kgsl_debugfs_dir; @@ -134,13 +132,6 @@ void kgsl_device_debugfs_init(struct kgsl_device *device) if (!device->d_debugfs || IS_ERR(device->d_debugfs)) return; - device->cmd_log = KGSL_LOG_LEVEL_DEFAULT; - device->ctxt_log = KGSL_LOG_LEVEL_DEFAULT; - device->drv_log = KGSL_LOG_LEVEL_DEFAULT; - device->mem_log = KGSL_LOG_LEVEL_DEFAULT; - device->pwr_log = KGSL_LOG_LEVEL_DEFAULT; - device->ft_log = KGSL_LOG_LEVEL_DEFAULT; - debugfs_create_file("log_level_cmd", 0644, device->d_debugfs, device, &cmd_log_fops); debugfs_create_file("log_level_ctxt", 0644, device->d_debugfs, device, @@ -151,8 +142,6 @@ void kgsl_device_debugfs_init(struct kgsl_device *device) &mem_log_fops); debugfs_create_file("log_level_pwr", 0644, device->d_debugfs, device, &pwr_log_fops); - debugfs_create_file("log_level_ft", 0644, device->d_debugfs, device, - &ft_log_fops); /* Create postmortem dump control files */ @@ -167,7 +156,6 @@ void kgsl_device_debugfs_init(struct kgsl_device *device) &pm_regs_enabled_fops); debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device, &pm_ib_enabled_fops); - device->pm_dump_enable = 0; debugfs_create_file("enable", 0644, pm_d_debugfs, device, &pm_enabled_fops); @@ -198,60 +186,146 @@ static char get_alignflag(const struct kgsl_memdesc *m) return '-'; } +static char get_cacheflag(const struct kgsl_memdesc *m) +{ + static const char table[] = { + [KGSL_CACHEMODE_WRITECOMBINE] = '-', + [KGSL_CACHEMODE_UNCACHED] = 'u', + [KGSL_CACHEMODE_WRITEBACK] = 'b', + [KGSL_CACHEMODE_WRITETHROUGH] = 't', + }; + return table[kgsl_memdesc_get_cachemode(m)]; +} + +static void print_mem_entry(struct seq_file *s, struct kgsl_mem_entry *entry) +{ + char flags[6]; + char usage[16]; + struct kgsl_memdesc *m = &entry->memdesc; + + flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-'; + flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-'; + flags[2] = get_alignflag(m); + flags[3] = get_cacheflag(m); + flags[4] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-'; + flags[5] = '\0'; + + kgsl_get_memory_usage(usage, sizeof(usage), m->flags); + + seq_printf(s, "%pK %pK %8zd %5d %5s %10s %16s %5d\n", + (unsigned long *) m->gpuaddr, + (unsigned long *) m->useraddr, + m->size, entry->id, flags, + memtype_str(entry->memtype), usage, m->sglen); +} + static int process_mem_print(struct seq_file *s, void *unused) { struct kgsl_mem_entry *entry; struct rb_node *node; struct kgsl_process_private *private = s->private; - char flags[4]; - char usage[16]; + int next = 0; + + seq_printf(s, "%8s %8s %8s %5s %5s %10s %16s %5s\n", + "gpuaddr", "useraddr", "size", "id", "flags", "type", + "usage", "sglen"); + /* print all entries with a GPU address */ spin_lock(&private->mem_lock); - seq_printf(s, "%8s %8s %5s %10s %16s %5s\n", - "gpuaddr", "size", "flags", "type", "usage", "sglen"); - for (node = rb_first(&private->mem_rb); node; node = rb_next(node)) { - struct kgsl_memdesc *m; + for (node = rb_first(&private->mem_rb); node; node = rb_next(node)) { entry = rb_entry(node, struct kgsl_mem_entry, node); - m = &entry->memdesc; - - flags[0] = m->priv & KGSL_MEMDESC_GLOBAL ? 'g' : '-'; - flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-'; - flags[2] = get_alignflag(m); - flags[3] = '\0'; + print_mem_entry(s, entry); + } - kgsl_get_memory_usage(usage, sizeof(usage), m->flags); + spin_unlock(&private->mem_lock); - seq_printf(s, "%08x %8d %5s %10s %16s %5d\n", - m->gpuaddr, m->size, flags, - memtype_str(entry->memtype), usage, m->sglen); + /* now print all the unbound entries */ + while (1) { + rcu_read_lock(); + entry = idr_get_next(&private->mem_idr, &next); + rcu_read_unlock(); + + if (entry == NULL) + break; + if (entry->memdesc.gpuaddr == 0) + print_mem_entry(s, entry); + next++; } - spin_unlock(&private->mem_lock); + return 0; } static int process_mem_open(struct inode *inode, struct file *file) { - return single_open(file, process_mem_print, inode->i_private); + int ret; + pid_t pid = (pid_t) (unsigned long) inode->i_private; + struct kgsl_process_private *private = NULL; + + private = kgsl_process_private_find(pid); + + if (!private) + return -ENODEV; + + ret = single_open(file, process_mem_print, private); + if (ret) + kgsl_process_private_put(private); + + return ret; +} + +static int process_mem_release(struct inode *inode, struct file *file) +{ + struct kgsl_process_private *private = + ((struct seq_file *)file->private_data)->private; + + if (private) + kgsl_process_private_put(private); + + return single_release(inode, file); } static const struct file_operations process_mem_fops = { .open = process_mem_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = process_mem_release, }; -void +int kgsl_process_init_debugfs(struct kgsl_process_private *private) { unsigned char name[16]; - + int ret = 0; + struct dentry *dentry; snprintf(name, sizeof(name), "%d", private->pid); private->debug_root = debugfs_create_dir(name, proc_d_debugfs); - debugfs_create_file("mem", 0400, private->debug_root, private, - &process_mem_fops); + + if (!private->debug_root) + return -EINVAL; + + /* + * debugfs_create_dir() and debugfs_create_file() both + * return -ENODEV if debugfs is disabled in the kernel. + * We make a distinction between these two functions + * failing and debugfs being disabled in the kernel. + * In the first case, we abort process private struct + * creation, in the second we continue without any changes. + * So if debugfs is disabled in kernel, return as + * success. + */ + dentry = debugfs_create_file("mem", 0444, private->debug_root, + (void *) ((unsigned long) private->pid), &process_mem_fops); + + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + + if (ret == -ENODEV) + ret = 0; + } + + return ret; } void kgsl_core_debugfs_init(void) diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h index ae5601fb..8d6a9dd5 100644 --- a/drivers/gpu/msm/kgsl_debugfs.h +++ b/drivers/gpu/msm/kgsl_debugfs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2008-2011, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2008-2011,2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,7 +35,7 @@ static inline void kgsl_core_debugfs_init(void) { } static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { } static inline void kgsl_core_debugfs_close(void) { } static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; } -static inline int kgsl_process_init_debugfs(struct kgsl_process_private *) +static inline int kgsl_process_init_debugfs(struct kgsl_process_private *priv) { return 0; } diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index f6ff824a..6013e7d0 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2012,2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ #define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF #define KGSL_TIMEOUT_PART 50 /* 50 msec */ #define KGSL_TIMEOUT_LONG_IB_DETECTION 2000 /* 2 sec*/ +#define KGSL_TIMEOUT_HANG_DETECT 200 /* 200 msec */ #define FIRST_TIMEOUT (HZ / 2) @@ -54,6 +55,14 @@ #define KGSL_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK))) +/* + * KGSL event types - these are passed to the event callback when the event + * expires or is cancelled + */ + +#define KGSL_EVENT_TIMESTAMP_RETIRED 0 +#define KGSL_EVENT_CANCELLED 1 + struct kgsl_device; struct platform_device; struct kgsl_device_private; @@ -73,7 +82,8 @@ struct kgsl_functable { int (*idle) (struct kgsl_device *device); unsigned int (*isidle) (struct kgsl_device *device); int (*suspend_context) (struct kgsl_device *device); - int (*start) (struct kgsl_device *device, unsigned int init_ram); + int (*init) (struct kgsl_device *device); + int (*start) (struct kgsl_device *device); int (*stop) (struct kgsl_device *device); int (*getproperty) (struct kgsl_device *device, enum kgsl_property_type type, void *value, @@ -105,7 +115,7 @@ struct kgsl_functable { uint32_t flags); int (*drawctxt_create) (struct kgsl_device *device, struct kgsl_pagetable *pagetable, struct kgsl_context *context, - uint32_t flags); + uint32_t *flags); void (*drawctxt_destroy) (struct kgsl_device *device, struct kgsl_context *context); long (*ioctl) (struct kgsl_device_private *dev_priv, @@ -127,10 +137,12 @@ struct kgsl_mh { int mpu_range; }; +typedef void (*kgsl_event_func)(struct kgsl_device *, void *, u32, u32, u32); + struct kgsl_event { struct kgsl_context *context; uint32_t timestamp; - void (*func)(struct kgsl_device *, void *, u32, u32); + kgsl_event_func func; void *priv; struct list_head list; void *owner; @@ -156,7 +168,9 @@ struct kgsl_device { struct completion hwaccess_gate; const struct kgsl_functable *ftbl; struct work_struct idle_check_ws; + struct work_struct hang_check_ws; struct timer_list idle_timer; + struct timer_list hang_timer; struct kgsl_pwrctrl pwrctrl; int open_count; @@ -174,6 +188,7 @@ struct kgsl_device { struct dentry *d_debugfs; struct idr context_idr; struct early_suspend display_off; + rwlock_t context_lock; void *snapshot; /* Pointer to the snapshot memory region */ int snapshot_maxsize; /* Max size of the snapshot region */ @@ -209,6 +224,8 @@ struct kgsl_device { /* Postmortem Control switches */ int pm_regs_enabled; int pm_ib_enabled; + + int reset_counter; /* Track how many GPU core resets have occured */ }; void kgsl_process_events(struct work_struct *work); @@ -220,6 +237,8 @@ void kgsl_check_fences(struct work_struct *work); .ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\ .idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\ kgsl_idle_check),\ + .hang_check_ws = __WORK_INITIALIZER((_dev).hang_check_ws,\ + kgsl_hang_check),\ .ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\ kgsl_process_events),\ .context_idr = IDR_INIT((_dev).context_idr),\ @@ -259,11 +278,33 @@ struct kgsl_context { struct list_head events_list; }; +/** + * struct kgsl_process_private - Private structure for a KGSL process (across + * all devices) + * @priv: Internal flags, use KGSL_PROCESS_* values + * @pid: ID for the task owner of the process + * @mem_lock: Spinlock to protect the process memory lists + * @refcount: kref object for reference counting the process + * @process_private_mutex: Mutex to synchronize access to the process struct + * @mem_rb: RB tree node for the memory owned by this process + * @idr: Iterator for assigning IDs to memory allocations + * @pagetable: Pointer to the pagetable owned by this process + * @kobj: Pointer to a kobj for the sysfs directory for this process + * @debug_root: Pointer to the debugfs root for this process + * @stats: Memory allocation statistics for this process + */ struct kgsl_process_private { - unsigned int refcnt; + unsigned long priv; pid_t pid; spinlock_t mem_lock; + + /* General refcount for process private struct obj */ + struct kref refcount; + /* Mutex to synchronize access to each process_private struct obj */ + struct mutex process_private_mutex; + struct rb_root mem_rb; + struct idr mem_idr; struct kgsl_pagetable *pagetable; struct list_head list; struct kobject kobj; @@ -275,6 +316,14 @@ struct kgsl_process_private { } stats[KGSL_MEM_ENTRY_MAX]; }; +/** + * enum kgsl_process_priv_flags - Private flags for kgsl_process_private + * @KGSL_PROCESS_INIT: Set if the process structure has been set up + */ +enum kgsl_process_priv_flags { + KGSL_PROCESS_INIT = 0, +}; + struct kgsl_device_private { struct kgsl_device *device; struct kgsl_process_private *process_priv; @@ -287,6 +336,9 @@ struct kgsl_power_stats { struct kgsl_device *kgsl_get_device(int dev_idx); +int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, + kgsl_event_func func, void *priv, void *owner); + static inline void kgsl_process_add_stats(struct kgsl_process_private *priv, unsigned int type, size_t size) { @@ -374,17 +426,7 @@ static inline int kgsl_create_device_workqueue(struct kgsl_device *device) return 0; } -static inline struct kgsl_context * -kgsl_find_context(struct kgsl_device_private *dev_priv, uint32_t id) -{ - struct kgsl_context *ctxt = - idr_find(&dev_priv->device->context_idr, id); - - /* Make sure that the context belongs to the current instance so - that other processes can't guess context IDs and mess things up */ - return (ctxt && ctxt->dev_priv == dev_priv) ? ctxt : NULL; -} int kgsl_check_timestamp(struct kgsl_device *device, struct kgsl_context *context, unsigned int timestamp); @@ -408,51 +450,155 @@ kgsl_device_get_drvdata(struct kgsl_device *dev) return pdev->dev.platform_data; } +void kgsl_context_destroy(struct kref *kref); + +int kgsl_memfree_find_entry(pid_t pid, unsigned long *gpuaddr, + unsigned long *size, unsigned int *flags); + /** - * kgsl_context_get - Get context reference count + * kgsl_context_put - Release context reference count * @context * - * Asynchronous code that holds a pointer to a context - * must hold a reference count on it. The kgsl device - * mutex must be held while the context reference count - * is changed. */ static inline void -kgsl_context_get(struct kgsl_context *context) +kgsl_context_put(struct kgsl_context *context) { - kref_get(&context->refcount); + if (context) + kref_put(&context->refcount, kgsl_context_destroy); } -void kgsl_context_destroy(struct kref *kref); +/** + * _kgsl_context_get() - lightweight function to just increment the ref count + * @context: Pointer to the KGSL context + * + * Get a reference to the specified KGSL context structure. This is a + * lightweight way to just increase the refcount on a known context rather then + * walking through kgsl_context_get and searching the iterator + */ +static inline int _kgsl_context_get(struct kgsl_context *context) +{ + int ret = 0; + if (context) + ret = kref_get_unless_zero(&context->refcount); + return ret; +} /** - * kgsl_context_put - Release context reference count - * @context + * kgsl_context_get - get a pointer to a KGSL context + * @devicex - Pointer to the KGSL device that owns the context + * @id - Context ID to return * + * Find the context associated with the given ID number, increase the reference + * count on it and return it. The caller must make sure that this call is + * paired with a kgsl_context_put. This function is for internal use because it + * doesn't validate the ownership of the context with the calling process - use + * kgsl_context_get_owner for that */ -static inline void -kgsl_context_put(struct kgsl_context *context) +static inline struct kgsl_context *kgsl_context_get(struct kgsl_device *device, + uint32_t id) { - kref_put(&context->refcount, kgsl_context_destroy); + int result = 0; + struct kgsl_context *context = NULL; + + read_lock(&device->context_lock); + + context = idr_find(&device->context_idr, id); + + result = _kgsl_context_get(context); + + read_unlock(&device->context_lock); + + if (!result) + return NULL; + return context; } /** - * kgsl_active_count_put - Decrease the device active count - * @device: Pointer to a KGSL device + * kgsl_context_get_owner - get a pointer to a KGSL context + * @dev_priv - Pointer to the owner of the requesting process + * @id - Context ID to return * - * Decrease the active count for the KGSL device and trigger the suspend_gate - * completion if it hits zero + * Find the context associated with the given ID number, increase the reference + * count on it and return it. The caller must make sure that this call is + * paired with a kgsl_context_put. This function validates that the context id + * given is owned by the dev_priv instancet that is passed in. see + * kgsl_context_get for the internal version that doesn't do the check */ -static inline void -kgsl_active_count_put(struct kgsl_device *device) +static inline struct kgsl_context *kgsl_context_get_owner( + struct kgsl_device_private *dev_priv, uint32_t id) +{ + struct kgsl_context *context; + + context = kgsl_context_get(dev_priv->device, id); + + /* Verify that the context belongs to the dev_priv instance */ + if (context && context->dev_priv != dev_priv) { + kgsl_context_put(context); + return NULL; + } + + return context; +} + +static inline void kgsl_context_cancel_events(struct kgsl_device *device, + struct kgsl_context *context) +{ + kgsl_signal_events(device, context, KGSL_EVENT_CANCELLED); +} + +/** + * kgsl_context_cancel_events_timestamp - cancel events for a given timestamp + * @device: Pointer to the KGSL device that owns the context + * @cotnext: Pointer to the context that owns the event or NULL for global + * @timestamp: Timestamp to cancel events for + * + * Cancel events pending for a specific timestamp + */ +static inline void kgsl_cancel_events_timestamp(struct kgsl_device *device, + struct kgsl_context *context, unsigned int timestamp) { - if (device->active_cnt == 1) - INIT_COMPLETION(device->suspend_gate); + kgsl_signal_event(device, context, timestamp, KGSL_EVENT_CANCELLED); +} - device->active_cnt--; - if (device->active_cnt == 0) - complete(&device->suspend_gate); +/** +* kgsl_process_private_get() - increment the refcount on a kgsl_process_private +* struct +* @process: Pointer to the KGSL process_private +* +* Returns 0 if the structure is invalid and a reference count could not be +* obtained, nonzero otherwise. +*/ +static inline int kgsl_process_private_get(struct kgsl_process_private *process) +{ + int ret = 0; + if (process != NULL) + ret = kref_get_unless_zero(&process->refcount); + return ret; } +void kgsl_process_private_put(struct kgsl_process_private *private); + + +struct kgsl_process_private *kgsl_process_private_find(pid_t pid); + +/** + * kgsl_sysfs_store() - parse a string from a sysfs store function + * @buf: Incoming string to parse + * @ptr: Pointer to an unsigned int to store the value + */ +static inline int kgsl_sysfs_store(const char *buf, unsigned int *ptr) +{ + unsigned int val; + int rc; + + rc = kstrtou32(buf, 0, &val); + if (rc) + return rc; + + if (ptr) + *ptr = val; + + return 0; +} #endif /* __KGSL_DEVICE_H */ diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c index 2a5a5fac..f6dd6b3d 100644 --- a/drivers/gpu/msm/kgsl_drm.c +++ b/drivers/gpu/msm/kgsl_drm.c @@ -16,7 +16,6 @@ */ #include "drmP.h" #include "drm.h" -#include #include "kgsl.h" #include "kgsl_device.h" diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index b1b11cc2..af803110 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -18,6 +18,12 @@ #include "kgsl_trace.h" +static inline struct list_head *_get_list_head(struct kgsl_device *device, + struct kgsl_context *context) +{ + return (context) ? &context->events : &device->events; +} + static void _add_event_to_list(struct list_head *head, struct kgsl_event *event) { struct list_head *n; @@ -36,30 +42,168 @@ static void _add_event_to_list(struct list_head *head, struct kgsl_event *event) list_add_tail(&event->list, head); } +static inline void _do_signal_event(struct kgsl_device *device, + struct kgsl_event *event, unsigned int timestamp, + unsigned int type) +{ + int id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL; + + trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created); + + if (event->func) + event->func(device, event->priv, id, timestamp, type); + + list_del(&event->list); + kgsl_context_put(event->context); + kfree(event); + + kgsl_active_count_put(device); +} + +static void _retire_events(struct kgsl_device *device, + struct list_head *head, unsigned int timestamp) +{ + struct kgsl_event *event, *tmp; + + list_for_each_entry_safe(event, tmp, head, list) { + if (timestamp_cmp(timestamp, event->timestamp) < 0) + break; + + _do_signal_event(device, event, event->timestamp, + KGSL_EVENT_TIMESTAMP_RETIRED); + } +} + +static struct kgsl_event *_find_event(struct kgsl_device *device, + struct list_head *head, unsigned int timestamp, + kgsl_event_func func, void *priv) +{ + struct kgsl_event *event, *tmp; + + list_for_each_entry_safe(event, tmp, head, list) { + if (timestamp == event->timestamp && func == event->func && + event->priv == priv) + return event; + } + + return NULL; +} + +/** + * _signal_event - send a signal to a specific event in the list + * @device - KGSL device + * @head - Pointer to the event list to process + * @timestamp - timestamp of the event to signal + * @cur - timestamp value to send to the callback + * @type - Signal ID to send to the callback + * + * Send the specified signal to the events in the list with the specified + * timestamp. The timestamp 'cur' is sent to the callback so it knows + * when the signal was delivered + */ +static void _signal_event(struct kgsl_device *device, + struct list_head *head, unsigned int timestamp, + unsigned int cur, unsigned int type) +{ + struct kgsl_event *event, *tmp; + + list_for_each_entry_safe(event, tmp, head, list) { + if (timestamp_cmp(timestamp, event->timestamp) == 0) + _do_signal_event(device, event, cur, type); + } +} + +/** + * _signal_events - send a signal to all the events in a list + * @device - KGSL device + * @head - Pointer to the event list to process + * @timestamp - Timestamp to pass to the events (this should be the current + * timestamp when the signal is sent) + * @type - Signal ID to send to the callback + * + * Send the specified signal to all the events in the list and destroy them + */ +static void _signal_events(struct kgsl_device *device, + struct list_head *head, uint32_t timestamp, + unsigned int type) +{ + struct kgsl_event *event, *tmp; + + list_for_each_entry_safe(event, tmp, head, list) + _do_signal_event(device, event, timestamp, type); + +} + +void kgsl_signal_event(struct kgsl_device *device, + struct kgsl_context *context, unsigned int timestamp, + unsigned int type) +{ + struct list_head *head = _get_list_head(device, context); + uint32_t cur; + + BUG_ON(!mutex_is_locked(&device->mutex)); + + cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED); + _signal_event(device, head, timestamp, cur, type); + + if (context && list_empty(&context->events)) + list_del_init(&context->events_list); +} +EXPORT_SYMBOL(kgsl_signal_event); + +void kgsl_signal_events(struct kgsl_device *device, + struct kgsl_context *context, unsigned int type) +{ + struct list_head *head = _get_list_head(device, context); + uint32_t cur; + + BUG_ON(!mutex_is_locked(&device->mutex)); + + /* + * Send the current timestamp to the callback so it knows when the + * signal occured + */ + + cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED); + + _signal_events(device, head, cur, type); + + /* + * Remove the context from the master list since we know everything on + * it has been removed + */ + + if (context) + list_del_init(&context->events_list); +} +EXPORT_SYMBOL(kgsl_signal_events); + /** * kgsl_add_event - Add a new timstamp event for the KGSL device * @device - KGSL device for the new event * @id - the context ID that the event should be added to * @ts - the timestamp to trigger the event on - * @cb - callback function to call when the timestamp expires + * @func - callback function to call when the timestamp expires * @priv - private data for the specific event type * @owner - driver instance that owns this event * * @returns - 0 on success or error code on failure */ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, - void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv, - void *owner) + kgsl_event_func func, void *priv, void *owner) { + int ret; struct kgsl_event *event; unsigned int cur_ts; struct kgsl_context *context = NULL; - if (cb == NULL) + BUG_ON(!mutex_is_locked(&device->mutex)); + + if (func == NULL) return -EINVAL; if (id != KGSL_MEMSTORE_GLOBAL) { - context = idr_find(&device->context_idr, id); + context = kgsl_context_get(device, id); if (context == NULL) return -EINVAL; } @@ -73,28 +217,38 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, */ if (timestamp_cmp(cur_ts, ts) >= 0) { - trace_kgsl_fire_event(id, ts, 0); - cb(device, priv, id, ts); + trace_kgsl_fire_event(id, cur_ts, ts, 0); + + func(device, priv, id, ts, KGSL_EVENT_TIMESTAMP_RETIRED); + kgsl_context_put(context); return 0; } event = kzalloc(sizeof(*event), GFP_KERNEL); - if (event == NULL) + if (event == NULL) { + kgsl_context_put(context); return -ENOMEM; + } + + /* + * Increase the active count on the device to avoid going into power + * saving modes while events are pending + */ + ret = kgsl_active_count_get(device); + if (ret < 0) { + kfree(event); + return ret; + } event->context = context; event->timestamp = ts; event->priv = priv; - event->func = cb; + event->func = func; event->owner = owner; event->created = jiffies; trace_kgsl_register_event(id, ts); - /* inc refcount to avoid race conditions in cleanup */ - if (context) - kgsl_context_get(context); - /* Add the event to either the owning context or the global list */ if (context) { @@ -112,144 +266,52 @@ int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts, } else _add_event_to_list(&device->events, event); - /* - * Increase the active count on the device to avoid going into power - * saving modes while events are pending - */ - - device->active_cnt++; - queue_work(device->work_queue, &device->ts_expired_ws); return 0; } EXPORT_SYMBOL(kgsl_add_event); -/** - * kgsl_cancel_events_ctxt - Cancel all events for a context - * @device - KGSL device for the events to cancel - * @context - context whose events we want to cancel - * - */ -void kgsl_cancel_events_ctxt(struct kgsl_device *device, - struct kgsl_context *context) -{ - struct kgsl_event *event, *event_tmp; - unsigned int id, cur; - - cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED); - id = context->id; - - /* - * Increment the refcount to avoid freeing the context while - * cancelling its events - */ - kgsl_context_get(context); - - /* Remove ourselves from the master pending list */ - list_del_init(&context->events_list); - - list_for_each_entry_safe(event, event_tmp, &context->events, list) { - /* - * "cancel" the events by calling their callback. - * Currently, events are used for lock and memory - * management, so if the process is dying the right - * thing to do is release or free. - * - * Send the current timestamp so the event knows how far the - * system got before the event was canceled - */ - list_del(&event->list); - - trace_kgsl_fire_event(id, cur, jiffies - event->created); - - if (event->func) - event->func(device, event->priv, id, cur); - - kgsl_context_put(context); - kfree(event); - - kgsl_active_count_put(device); - } - kgsl_context_put(context); -} - /** * kgsl_cancel_events - Cancel all generic events for a process * @device - KGSL device for the events to cancel * @owner - driver instance that owns the events to cancel * */ -void kgsl_cancel_events(struct kgsl_device *device, - void *owner) +void kgsl_cancel_events(struct kgsl_device *device, void *owner) { struct kgsl_event *event, *event_tmp; unsigned int cur; + BUG_ON(!mutex_is_locked(&device->mutex)); + cur = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED); list_for_each_entry_safe(event, event_tmp, &device->events, list) { if (event->owner != owner) continue; - /* - * "cancel" the events by calling their callback. - * Currently, events are used for lock and memory - * management, so if the process is dying the right - * thing to do is release or free. Send the current timestamp so - * the callback knows how far the GPU made it before things went - * explosion - */ - list_del(&event->list); - - trace_kgsl_fire_event(KGSL_MEMSTORE_GLOBAL, cur, - jiffies - event->created); - - if (event->func) - event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL, - cur); - - if (event->context) - kgsl_context_put(event->context); - kfree(event); - - kgsl_active_count_put(device); + _do_signal_event(device, event, cur, KGSL_EVENT_CANCELLED); } } EXPORT_SYMBOL(kgsl_cancel_events); -static void _process_event_list(struct kgsl_device *device, - struct list_head *head, unsigned int timestamp) +void kgsl_cancel_event(struct kgsl_device *device, struct kgsl_context *context, + unsigned int timestamp, kgsl_event_func func, + void *priv) { - struct kgsl_event *event, *tmp; - unsigned int id; - - list_for_each_entry_safe(event, tmp, head, list) { - if (timestamp_cmp(timestamp, event->timestamp) < 0) - break; - - id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL; - - /* - * Send the timestamp of the expired event, not the current - * timestamp. This prevents the event handlers from getting - * confused if they don't bother comparing the current timetamp - * to the timestamp they wanted - */ - list_del(&event->list); - - trace_kgsl_fire_event(id, event->timestamp, - jiffies - event->created); + struct kgsl_event *event; + struct list_head *head = _get_list_head(device, context); - if (event->func) - event->func(device, event->priv, id, event->timestamp); + event = _find_event(device, head, timestamp, func, priv); - if (event->context) - kgsl_context_put(event->context); - kfree(event); + if (event) { + unsigned int cur = kgsl_readtimestamp(device, context, + KGSL_TIMESTAMP_RETIRED); - kgsl_active_count_put(device); + _do_signal_event(device, event, cur, KGSL_EVENT_CANCELLED); } } +EXPORT_SYMBOL(kgsl_cancel_event); static inline int _mark_next_event(struct kgsl_device *device, struct list_head *head) @@ -278,7 +340,7 @@ static int kgsl_process_context_events(struct kgsl_device *device, unsigned int timestamp = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED); - _process_event_list(device, &context->events, timestamp); + _retire_events(device, &context->events, timestamp); /* * _mark_next event will return 1 as long as the next event @@ -309,7 +371,7 @@ void kgsl_process_events(struct work_struct *work) /* Process expired global events */ timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED); - _process_event_list(device, &device->events, timestamp); + _retire_events(device, &device->events, timestamp); _mark_next_event(device, &device->events); /* Now process all of the pending contexts */ @@ -320,7 +382,7 @@ void kgsl_process_events(struct work_struct *work) * Increment the refcount to make sure that the list_del_init * is called with a valid context's list */ - kgsl_context_get(context); + _kgsl_context_get(context); /* * If kgsl_timestamp_expired_context returns 0 then it no longer * has any pending events and can be removed from the list diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c index 8f285053..48c5feae 100644 --- a/drivers/gpu/msm/kgsl_gpummu.c +++ b/drivers/gpu/msm/kgsl_gpummu.c @@ -598,7 +598,7 @@ kgsl_gpummu_unmap(void *mmu_specific_pt, { unsigned int numpages; unsigned int pte, ptefirst, ptelast, superpte; - unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen); + unsigned int range = memdesc->size; struct kgsl_gpummu_pt *gpummu_pt = mmu_specific_pt; /* All GPU addresses as assigned are page aligned, but some diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 28542af4..ca00d160 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,6 +11,7 @@ * */ #include +#include #include #include #include @@ -31,6 +32,7 @@ #include "adreno.h" #include "kgsl_trace.h" #include "z180.h" +#include "kgsl_cffdump.h" static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = { @@ -40,6 +42,10 @@ static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = { { 0x20, 0, 0 }, /* FSR */ { 0x800, 0, 0 }, /* TLBIALL */ { 0x820, 0, 0 }, /* RESUME */ + { 0x03C, 0, 0 }, /* TLBLKCR */ + { 0x818, 0, 0 }, /* V2PUR */ + { 0x2C, 0, 0 }, /* FSYNR0 */ + { 0x2C, 0, 0 }, /* FSYNR0 */ }; static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = { @@ -48,11 +54,22 @@ static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = { { 0x28, 0x00FFFFFF, 14 }, /* TTBR1 */ { 0x58, 0, 0 }, /* FSR */ { 0x618, 0, 0 }, /* TLBIALL */ - { 0x008, 0, 0 } /* RESUME */ + { 0x008, 0, 0 }, /* RESUME */ + { 0, 0, 0 }, /* TLBLKCR */ + { 0, 0, 0 }, /* V2PUR */ + { 0x68, 0, 0 }, /* FSYNR0 */ + { 0x6C, 0, 0 } /* FSYNR1 */ }; struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars; +/* + * One page allocation for a guard region to protect against over-zealous + * GPU pre-fetch + */ + +static struct page *kgsl_guard_page; + static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out, struct kgsl_iommu_unit **iommu_unit_out) { @@ -100,6 +117,156 @@ static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit, return NULL; } +/* These functions help find the nearest allocated memory entries on either side + * of a faulting address. If we know the nearby allocations memory we can + * get a better determination of what we think should have been located in the + * faulting region + */ + +/* + * A local structure to make it easy to store the interesting bits for the + * memory entries on either side of the faulting address + */ + +struct _mem_entry { + unsigned int gpuaddr; + unsigned int size; + unsigned int flags; + unsigned int priv; + pid_t pid; +}; + +/* + * Find the closest alloated memory block with an smaller GPU address then the + * given address + */ + +static void _prev_entry(struct kgsl_process_private *priv, + unsigned int faultaddr, struct _mem_entry *ret) +{ + struct rb_node *node; + struct kgsl_mem_entry *entry; + + for (node = rb_first(&priv->mem_rb); node; ) { + entry = rb_entry(node, struct kgsl_mem_entry, node); + + if (entry->memdesc.gpuaddr > faultaddr) + break; + + /* + * If this is closer to the faulting address, then copy + * the entry + */ + + if (entry->memdesc.gpuaddr > ret->gpuaddr) { + ret->gpuaddr = entry->memdesc.gpuaddr; + ret->size = entry->memdesc.size; + ret->flags = entry->memdesc.flags; + ret->priv = entry->memdesc.priv; + ret->pid = priv->pid; + } + + node = rb_next(&entry->node); + } +} + +/* + * Find the closest alloated memory block with a greater starting GPU address + * then the given address + */ + +static void _next_entry(struct kgsl_process_private *priv, + unsigned int faultaddr, struct _mem_entry *ret) +{ + struct rb_node *node; + struct kgsl_mem_entry *entry; + + for (node = rb_last(&priv->mem_rb); node; ) { + entry = rb_entry(node, struct kgsl_mem_entry, node); + + if (entry->memdesc.gpuaddr < faultaddr) + break; + + /* + * If this is closer to the faulting address, then copy + * the entry + */ + + if (entry->memdesc.gpuaddr < ret->gpuaddr) { + ret->gpuaddr = entry->memdesc.gpuaddr; + ret->size = entry->memdesc.size; + ret->flags = entry->memdesc.flags; + ret->priv = entry->memdesc.priv; + ret->pid = priv->pid; + } + + node = rb_prev(&entry->node); + } +} + +static void _find_mem_entries(struct kgsl_mmu *mmu, unsigned int faultaddr, + unsigned int ptbase, struct _mem_entry *preventry, + struct _mem_entry *nextentry) +{ + struct kgsl_process_private *private; + int id = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase); + + memset(preventry, 0, sizeof(*preventry)); + memset(nextentry, 0, sizeof(*nextentry)); + + /* Set the maximum possible size as an initial value */ + nextentry->gpuaddr = 0xFFFFFFFF; + + mutex_lock(&kgsl_driver.process_mutex); + + list_for_each_entry(private, &kgsl_driver.process_list, list) { + + if (private->pagetable->name != id) + continue; + + spin_lock(&private->mem_lock); + _prev_entry(private, faultaddr, preventry); + _next_entry(private, faultaddr, nextentry); + spin_unlock(&private->mem_lock); + } + + mutex_unlock(&kgsl_driver.process_mutex); +} + +static void _print_entry(struct kgsl_device *device, struct _mem_entry *entry) +{ + char name[32]; + memset(name, 0, sizeof(name)); + + kgsl_get_memory_usage(name, sizeof(name) - 1, entry->flags); + + KGSL_LOG_DUMP(device, + "[%8.8X - %8.8X] %s (pid = %d) (%s)\n", + entry->gpuaddr, + entry->gpuaddr + entry->size, + entry->priv & KGSL_MEMDESC_GUARD_PAGE ? "(+guard)" : "", + entry->pid, name); +} + +static void _check_if_freed(struct kgsl_iommu_device *iommu_dev, + unsigned long addr, unsigned int pid) +{ + unsigned long gpuaddr = addr; + unsigned long size = 0; + unsigned int flags = 0; + char name[32]; + memset(name, 0, sizeof(name)); + + if (kgsl_memfree_find_entry(pid, &gpuaddr, &size, &flags)) { + kgsl_get_memory_usage(name, sizeof(name) - 1, flags); + KGSL_LOG_DUMP(iommu_dev->kgsldev, + "---- premature free ----\n"); + KGSL_LOG_DUMP(iommu_dev->kgsldev, + "[%8.8lX-%8.8lX] (%s) was already freed by pid %d\n", + gpuaddr, gpuaddr + size, name, pid); + } +} + static int kgsl_iommu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long addr, int flags) { @@ -114,8 +281,11 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, unsigned int no_page_fault_log = 0; unsigned int curr_context_id = 0; unsigned int curr_global_ts = 0; - static struct adreno_context *curr_context; - static struct kgsl_context *context; + struct kgsl_context *context; + unsigned int pid; + unsigned int fsynr0, fsynr1; + int write; + struct _mem_entry prev, next; ret = get_iommu_unit(dev, &mmu, &iommu_unit); if (ret) @@ -135,39 +305,85 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, iommu_dev->ctx_id, FSR); + fsynr0 = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, + iommu_dev->ctx_id, FSYNR0); + fsynr1 = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, + iommu_dev->ctx_id, FSYNR1); + + if (!msm_soc_version_supports_iommu_v1()) + write = ((fsynr1 & (KGSL_IOMMU_FSYNR1_AWRITE_MASK << + KGSL_IOMMU_FSYNR1_AWRITE_SHIFT)) ? 1 : 0); + else + write = ((fsynr0 & (KGSL_IOMMU_V1_FSYNR0_WNR_MASK << + KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT)) ? 1 : 0); if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE) no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr); + pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase); if (!no_page_fault_log) { KGSL_MEM_CRIT(iommu_dev->kgsldev, - "GPU PAGE FAULT: addr = %lX pid = %d\n", - addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase)); - KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n", - iommu_dev->ctx_id, fsr); + "GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid); + KGSL_MEM_CRIT(iommu_dev->kgsldev, + "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n", + iommu_dev->ctx_id, fsr, fsynr0, fsynr1, + write ? "write" : "read"); } + _check_if_freed(iommu_dev, addr, pid); + + KGSL_LOG_DUMP(iommu_dev->kgsldev, "---- nearby memory ----\n"); + + _find_mem_entries(mmu, addr, ptbase, &prev, &next); + + if (prev.gpuaddr) + _print_entry(iommu_dev->kgsldev, &prev); + else + KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n"); + + KGSL_LOG_DUMP(iommu_dev->kgsldev, " <- fault @ %8.8lX\n", addr); + + if (next.gpuaddr != 0xFFFFFFFF) + _print_entry(iommu_dev->kgsldev, &next); + else + KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n"); + mmu->fault = 1; iommu_dev->fault = 1; kgsl_sharedmem_readl(&device->memstore, &curr_context_id, KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context)); - context = idr_find(&device->context_idr, curr_context_id); - if (context != NULL) - curr_context = context->devctxt; + context = kgsl_context_get(device, curr_context_id); - kgsl_sharedmem_readl(&device->memstore, &curr_global_ts, - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, eoptimestamp)); + if (context != NULL && (context->devctxt != NULL)) { + struct adreno_context *drawctxt = context->devctxt; + + ret = kgsl_sharedmem_readl(&device->memstore, &curr_global_ts, + KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, eoptimestamp)); + + if (ret < 0) { + KGSL_CORE_ERR("Invalid curr_global_ts = %d\n", curr_global_ts); + kgsl_context_put(context); + goto done; + } + + /* + * Store pagefault's timestamp in adreno context, + * this information will be used in GFT + */ + + if (drawctxt != NULL) { + drawctxt->pagefault = 1; + drawctxt->pagefault_ts = curr_global_ts; + } + + kgsl_context_put(context); + } - /* - * Store pagefault's timestamp and ib1 addr in context, - * this information is used in GFT - */ - curr_context->pagefault = 1; - curr_context->pagefault_ts = curr_global_ts; trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr, - kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0); + kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), + write ? "write" : "read"); /* * We do not want the h/w to resume fetching data from an iommu unit @@ -224,7 +440,8 @@ static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu) * Return - void */ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, - unsigned int id, unsigned int ts) + unsigned int id, unsigned int ts, + u32 type) { struct kgsl_mmu *mmu = data; struct kgsl_iommu *iommu = mmu->priv; @@ -582,6 +799,46 @@ static int _get_iommu_ctxs(struct kgsl_mmu *mmu, return 0; } +/* + * kgsl_iommu_start_sync_lock - Initialize some variables during MMU start up + * for GPU CPU synchronization + * @mmu - Pointer to mmu device + * + * Return - 0 on success else error code + */ +static int kgsl_iommu_start_sync_lock(struct kgsl_mmu *mmu) +{ + struct kgsl_iommu *iommu = mmu->priv; + uint32_t lock_gpu_addr = 0; + + if (KGSL_DEVICE_3D0 != mmu->device->id || + !msm_soc_version_supports_iommu_v1() || + !kgsl_mmu_is_perprocess() || + iommu->sync_lock_vars) + return 0; + + if (!(mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC)) { + KGSL_DRV_ERR(mmu->device, + "The GPU microcode does not support IOMMUv1 sync opcodes\n"); + return -ENXIO; + } + /* Store Lock variables GPU address */ + lock_gpu_addr = (iommu->sync_lock_desc.gpuaddr + + iommu->sync_lock_offset); + + kgsl_iommu_sync_lock_vars.flag[PROC_APPS] = (lock_gpu_addr + + (offsetof(struct remote_iommu_petersons_spinlock, + flag[PROC_APPS]))); + kgsl_iommu_sync_lock_vars.flag[PROC_GPU] = (lock_gpu_addr + + (offsetof(struct remote_iommu_petersons_spinlock, + flag[PROC_GPU]))); + kgsl_iommu_sync_lock_vars.turn = (lock_gpu_addr + + (offsetof(struct remote_iommu_petersons_spinlock, turn))); + + iommu->sync_lock_vars = &kgsl_iommu_sync_lock_vars; + + return 0; +} /* * kgsl_get_sync_lock - Init Sync Lock between GPU and CPU @@ -591,21 +848,31 @@ static int _get_iommu_ctxs(struct kgsl_mmu *mmu, */ static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu) { - struct kgsl_iommu *iommu = mmu->device->mmu.priv; + struct kgsl_iommu *iommu = mmu->priv; int status = 0; - struct kgsl_pagetable *pagetable = NULL; - uint32_t lock_gpu_addr = 0; uint32_t lock_phy_addr = 0; uint32_t page_offset = 0; - iommu->sync_lock_initialized = 0; + if (KGSL_DEVICE_3D0 != mmu->device->id || + !msm_soc_version_supports_iommu_v1() || + !kgsl_mmu_is_perprocess()) + return status; - if (!(mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC)) { - KGSL_DRV_ERR(mmu->device, - "The GPU microcode does not support IOMMUv1 sync opcodes\n"); - return -ENXIO; + /* + * For 2D devices cpu side sync lock is required. For 3D device, + * since we only have a single 3D core and we always ensure that + * 3D core is idle while writing to IOMMU register using CPU this + * lock is not required + */ + if (KGSL_DEVICE_2D0 == mmu->device->id || + KGSL_DEVICE_2D1 == mmu->device->id) { + return status; } + /* Return if already initialized */ + if (iommu->sync_lock_initialized) + return status; + /* Get the physical address of the Lock variables */ lock_phy_addr = (msm_iommu_lock_initialize() - MSM_SHARED_RAM_BASE + msm_shared_ram_phys); @@ -620,6 +887,7 @@ static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu) page_offset = (lock_phy_addr & (PAGE_SIZE - 1)); lock_phy_addr = (lock_phy_addr & ~(PAGE_SIZE - 1)); iommu->sync_lock_desc.physaddr = (unsigned int)lock_phy_addr; + iommu->sync_lock_offset = page_offset; iommu->sync_lock_desc.size = PAGE_ALIGN(sizeof(kgsl_iommu_sync_lock_vars)); @@ -630,34 +898,6 @@ static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu) if (status) return status; - /* Map Lock variables to GPU pagetable */ - iommu->sync_lock_desc.priv |= KGSL_MEMDESC_GLOBAL; - - pagetable = mmu->priv_bank_table ? mmu->priv_bank_table : - mmu->defaultpagetable; - - status = kgsl_mmu_map(pagetable, &iommu->sync_lock_desc, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); - - if (status) { - kgsl_mmu_unmap(pagetable, &iommu->sync_lock_desc); - iommu->sync_lock_desc.priv &= ~KGSL_MEMDESC_GLOBAL; - return status; - } - - /* Store Lock variables GPU address */ - lock_gpu_addr = (iommu->sync_lock_desc.gpuaddr + page_offset); - - kgsl_iommu_sync_lock_vars.flag[PROC_APPS] = (lock_gpu_addr + - (offsetof(struct remote_iommu_petersons_spinlock, - flag[PROC_APPS]))); - kgsl_iommu_sync_lock_vars.flag[PROC_GPU] = (lock_gpu_addr + - (offsetof(struct remote_iommu_petersons_spinlock, - flag[PROC_GPU]))); - kgsl_iommu_sync_lock_vars.turn = (lock_gpu_addr + - (offsetof(struct remote_iommu_petersons_spinlock, turn))); - - iommu->sync_lock_vars = &kgsl_iommu_sync_lock_vars; /* Flag Sync Lock is Initialized */ iommu->sync_lock_initialized = 1; @@ -699,6 +939,10 @@ inline unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu, *cmds++ = 0x1; *cmds++ = 0x1; + /* WAIT_REG_MEM turns back on protected mode - push it off */ + *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1); + *cmds++ = 0; + *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2); *cmds++ = lock_vars->turn; *cmds++ = 0; @@ -713,11 +957,19 @@ inline unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu, *cmds++ = 0x1; *cmds++ = 0x1; + /* WAIT_REG_MEM turns back on protected mode - push it off */ + *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1); + *cmds++ = 0; + *cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3); *cmds++ = lock_vars->flag[PROC_APPS]; *cmds++ = lock_vars->turn; *cmds++ = 0; + /* TEST_TWO_MEMS turns back on protected mode - push it off */ + *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1); + *cmds++ = 0; + cmds += adreno_add_idle_cmds(adreno_dev, cmds); return cmds - start; @@ -755,6 +1007,10 @@ inline unsigned int kgsl_iommu_sync_unlock(struct kgsl_mmu *mmu, *cmds++ = 0x1; *cmds++ = 0x1; + /* WAIT_REG_MEM turns back on protected mode - push it off */ + *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1); + *cmds++ = 0; + cmds += adreno_add_idle_cmds(adreno_dev, cmds); return cmds - start; @@ -917,6 +1173,76 @@ static void kgsl_iommu_setstate(struct kgsl_mmu *mmu, } } +/* + * kgsl_iommu_setup_regs - map iommu registers into a pagetable + * @mmu: Pointer to mmu structure + * @pt: the pagetable + * + * To do pagetable switches from the GPU command stream, the IOMMU + * registers need to be mapped into the GPU's pagetable. This function + * is used differently on different targets. On 8960, the registers + * are mapped into every pagetable during kgsl_setup_pt(). On + * all other targets, the registers are mapped only into the second + * context bank. + * + * Return - 0 on success else error code + */ +static int kgsl_iommu_setup_regs(struct kgsl_mmu *mmu, + struct kgsl_pagetable *pt) +{ + int status; + int i = 0; + struct kgsl_iommu *iommu = mmu->priv; + + if (!msm_soc_version_supports_iommu_v1()) + return 0; + + for (i = 0; i < iommu->unit_count; i++) { + status = kgsl_mmu_map_global(pt, + &(iommu->iommu_units[i].reg_map)); + if (status) + goto err; + } + + /* Map Lock variables to GPU pagetable */ + if (iommu->sync_lock_initialized) { + status = kgsl_mmu_map_global(pt, + &iommu->sync_lock_desc); + if (status) + goto err; + } + + return 0; +err: + for (i--; i >= 0; i--) + kgsl_mmu_unmap(pt, + &(iommu->iommu_units[i].reg_map)); + + return status; +} + +/* + * kgsl_iommu_cleanup_regs - unmap iommu registers from a pagetable + * @mmu: Pointer to mmu structure + * @pt: the pagetable + * + * Removes mappings created by kgsl_iommu_setup_regs(). + * + * Return - 0 on success else error code + */ +static void kgsl_iommu_cleanup_regs(struct kgsl_mmu *mmu, + struct kgsl_pagetable *pt) +{ + struct kgsl_iommu *iommu = mmu->priv; + int i; + for (i = 0; i < iommu->unit_count; i++) + kgsl_mmu_unmap(pt, &(iommu->iommu_units[i].reg_map)); + + if (iommu->sync_lock_desc.gpuaddr) + kgsl_mmu_unmap(pt, &iommu->sync_lock_desc); +} + + static int kgsl_iommu_init(struct kgsl_mmu *mmu) { /* @@ -942,6 +1268,10 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) if (status) goto done; + status = kgsl_iommu_init_sync_lock(mmu); + if (status) + goto done; + iommu->iommu_reg_list = kgsl_iommuv1_reg; iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1; @@ -959,6 +1289,24 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) KGSL_IOMMU_SETSTATE_NOP_OFFSET, cp_nop_packet(1)); + if (cpu_is_msm8960()) { + /* + * 8960 doesn't have a second context bank, so the IOMMU + * registers must be mapped into every pagetable. + */ + iommu_ops.mmu_setup_pt = kgsl_iommu_setup_regs; + iommu_ops.mmu_cleanup_pt = kgsl_iommu_cleanup_regs; + } + + if (kgsl_guard_page == NULL) { + kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO | + __GFP_HIGHMEM); + if (kgsl_guard_page == NULL) { + status = -ENOMEM; + goto done; + } + } + dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n", __func__); done: @@ -981,9 +1329,6 @@ static int kgsl_iommu_init(struct kgsl_mmu *mmu) static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu) { int status = 0; - int i = 0; - struct kgsl_iommu *iommu = mmu->priv; - struct kgsl_pagetable *pagetable = NULL; /* If chip is not 8960 then we use the 2nd context bank for pagetable * switching on the 3D side for which a separate table is allocated */ @@ -994,6 +1339,9 @@ static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu) status = -ENOMEM; goto err; } + status = kgsl_iommu_setup_regs(mmu, mmu->priv_bank_table); + if (status) + goto err; } mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT); /* Return error if the default pagetable doesn't exist */ @@ -1001,31 +1349,10 @@ static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu) status = -ENOMEM; goto err; } - pagetable = mmu->priv_bank_table ? mmu->priv_bank_table : - mmu->defaultpagetable; - /* Map the IOMMU regsiters to only defaultpagetable */ - if (msm_soc_version_supports_iommu_v1()) { - for (i = 0; i < iommu->unit_count; i++) { - iommu->iommu_units[i].reg_map.priv |= - KGSL_MEMDESC_GLOBAL; - status = kgsl_mmu_map(pagetable, - &(iommu->iommu_units[i].reg_map), - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); - if (status) { - iommu->iommu_units[i].reg_map.priv &= - ~KGSL_MEMDESC_GLOBAL; - goto err; - } - } - } return status; err: - for (i--; i >= 0; i--) { - kgsl_mmu_unmap(pagetable, - &(iommu->iommu_units[i].reg_map)); - iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL; - } if (mmu->priv_bank_table) { + kgsl_iommu_cleanup_regs(mmu, mmu->priv_bank_table); kgsl_mmu_putpagetable(mmu->priv_bank_table); mmu->priv_bank_table = NULL; } @@ -1036,9 +1363,114 @@ static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu) return status; } -static int kgsl_iommu_start(struct kgsl_mmu *mmu) +/* + * kgsl_iommu_lock_rb_in_tlb - Allocates tlb entries and locks the + * virtual to physical address translation of ringbuffer for 3D + * device into tlb. + * @mmu - Pointer to mmu structure + * + * Return - void + */ +static void kgsl_iommu_lock_rb_in_tlb(struct kgsl_mmu *mmu) { struct kgsl_device *device = mmu->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_ringbuffer *rb; + struct kgsl_iommu *iommu = mmu->priv; + unsigned int num_tlb_entries; + unsigned int tlblkcr = 0; + unsigned int v2pxx = 0; + unsigned int vaddr = 0; + int i, j, k, l; + + if (!iommu->sync_lock_initialized) + return; + + rb = &adreno_dev->ringbuffer; + num_tlb_entries = rb->buffer_desc.size / PAGE_SIZE; + + for (i = 0; i < iommu->unit_count; i++) { + struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; + for (j = 0; j < iommu_unit->dev_count; j++) { + tlblkcr = 0; + if (cpu_is_msm8960()) + tlblkcr |= ((num_tlb_entries & + KGSL_IOMMU_TLBLKCR_FLOOR_MASK) << + KGSL_IOMMU_TLBLKCR_FLOOR_SHIFT); + else + tlblkcr |= (((num_tlb_entries * + iommu_unit->dev_count) & + KGSL_IOMMU_TLBLKCR_FLOOR_MASK) << + KGSL_IOMMU_TLBLKCR_FLOOR_SHIFT); + /* Do not invalidate locked entries on tlbiall flush */ + tlblkcr |= ((1 & KGSL_IOMMU_TLBLKCR_TLBIALLCFG_MASK) + << KGSL_IOMMU_TLBLKCR_TLBIALLCFG_SHIFT); + tlblkcr |= ((1 & KGSL_IOMMU_TLBLKCR_TLBIASIDCFG_MASK) + << KGSL_IOMMU_TLBLKCR_TLBIASIDCFG_SHIFT); + tlblkcr |= ((1 & KGSL_IOMMU_TLBLKCR_TLBIVAACFG_MASK) + << KGSL_IOMMU_TLBLKCR_TLBIVAACFG_SHIFT); + /* Enable tlb locking */ + tlblkcr |= ((1 & KGSL_IOMMU_TLBLKCR_LKE_MASK) + << KGSL_IOMMU_TLBLKCR_LKE_SHIFT); + KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, + iommu_unit->dev[j].ctx_id, + TLBLKCR, tlblkcr); + } + for (j = 0; j < iommu_unit->dev_count; j++) { + /* skip locking entries for private bank on 8960 */ + if (cpu_is_msm8960() && KGSL_IOMMU_CONTEXT_PRIV == j) + continue; + /* Lock the ringbuffer virtual address into tlb */ + vaddr = rb->buffer_desc.gpuaddr; + for (k = 0; k < num_tlb_entries; k++) { + v2pxx = 0; + v2pxx |= (((k + j * num_tlb_entries) & + KGSL_IOMMU_V2PXX_INDEX_MASK) + << KGSL_IOMMU_V2PXX_INDEX_SHIFT); + v2pxx |= vaddr & (KGSL_IOMMU_V2PXX_VA_MASK << + KGSL_IOMMU_V2PXX_VA_SHIFT); + + KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, + iommu_unit->dev[j].ctx_id, + V2PUR, v2pxx); + mb(); + vaddr += PAGE_SIZE; + for (l = 0; l < iommu_unit->dev_count; l++) { + tlblkcr = KGSL_IOMMU_GET_CTX_REG(iommu, + iommu_unit, + iommu_unit->dev[l].ctx_id, + TLBLKCR); + mb(); + tlblkcr &= + ~(KGSL_IOMMU_TLBLKCR_VICTIM_MASK + << KGSL_IOMMU_TLBLKCR_VICTIM_SHIFT); + tlblkcr |= (((k + 1 + + (j * num_tlb_entries)) & + KGSL_IOMMU_TLBLKCR_VICTIM_MASK) << + KGSL_IOMMU_TLBLKCR_VICTIM_SHIFT); + KGSL_IOMMU_SET_CTX_REG(iommu, + iommu_unit, + iommu_unit->dev[l].ctx_id, + TLBLKCR, tlblkcr); + } + } + } + for (j = 0; j < iommu_unit->dev_count; j++) { + tlblkcr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, + iommu_unit->dev[j].ctx_id, + TLBLKCR); + mb(); + /* Disable tlb locking */ + tlblkcr &= ~(KGSL_IOMMU_TLBLKCR_LKE_MASK + << KGSL_IOMMU_TLBLKCR_LKE_SHIFT); + KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, + iommu_unit->dev[j].ctx_id, TLBLKCR, tlblkcr); + } + } +} + +static int kgsl_iommu_start(struct kgsl_mmu *mmu) +{ int status; struct kgsl_iommu *iommu = mmu->priv; int i, j; @@ -1050,23 +1482,22 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) status = kgsl_iommu_setup_defaultpagetable(mmu); if (status) return -ENOMEM; - - /* Initialize the sync lock between GPU and CPU */ - if (msm_soc_version_supports_iommu_v1() && - (device->id == KGSL_DEVICE_3D0)) - kgsl_iommu_init_sync_lock(mmu); } + status = kgsl_iommu_start_sync_lock(mmu); + if (status) + return status; + /* We use the GPU MMU to control access to IOMMU registers on 8960 with * a225, hence we still keep the MMU active on 8960 */ - if (cpu_is_msm8960()) { + if (cpu_is_msm8960() && KGSL_DEVICE_3D0 == mmu->device->id) { struct kgsl_mh *mh = &(mmu->device->mh); + BUG_ON(iommu->iommu_units[0].reg_map.gpuaddr != 0 && + mh->mpu_base > iommu->iommu_units[0].reg_map.gpuaddr); kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001); + kgsl_regwrite(mmu->device, MH_MMU_MPU_END, - mh->mpu_base + - iommu->iommu_units[0].reg_map.gpuaddr); - } else { - kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000); + mh->mpu_base + mh->mpu_range); } mmu->hwpagetable = mmu->defaultpagetable; @@ -1091,6 +1522,7 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) * changing pagetables we can use this lsb value of the pagetable w/o * having to read it again */ + msm_iommu_lock(); for (i = 0; i < iommu->unit_count; i++) { struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i]; for (j = 0; j < iommu_unit->dev_count; j++) { @@ -1101,6 +1533,13 @@ static int kgsl_iommu_start(struct kgsl_mmu *mmu) TTBR0)); } } + kgsl_iommu_lock_rb_in_tlb(mmu); + msm_iommu_unlock(); + + /* For complete CFF */ + kgsl_cffdump_setmem(mmu->setstate_memory.gpuaddr + + KGSL_IOMMU_SETSTATE_NOP_OFFSET, + cp_nop_packet(1), sizeof(unsigned int)); kgsl_iommu_disable_clk_on_ts(mmu, 0, false); mmu->flags |= KGSL_FLAGS_STARTED; @@ -1119,32 +1558,33 @@ kgsl_iommu_unmap(void *mmu_specific_pt, unsigned int *tlb_flags) { int ret; - unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen); + unsigned int range = memdesc->size; struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt; /* All GPU addresses as assigned are page aligned, but some functions purturb the gpuaddr with an offset, so apply the mask here to make sure we have the right address */ - unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK; + unsigned int gpuaddr = memdesc->gpuaddr & KGSL_IOMMU_ALIGN_MASK; if (range == 0 || gpuaddr == 0) return 0; + if (kgsl_memdesc_has_guard_page(memdesc)) + range += PAGE_SIZE; + ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range); if (ret) KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed " "with err: %d\n", iommu_pt->domain, gpuaddr, range, ret); -#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE /* * Flushing only required if per process pagetables are used. With * global case, flushing will happen inside iommu_map function */ - if (!ret && msm_soc_version_supports_iommu_v1()) + if (!ret && kgsl_mmu_is_perprocess()) *tlb_flags = UINT_MAX; -#endif return 0; } @@ -1157,23 +1597,35 @@ kgsl_iommu_map(void *mmu_specific_pt, int ret; unsigned int iommu_virt_addr; struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt; - int size = kgsl_sg_size(memdesc->sg, memdesc->sglen); + int size = memdesc->size; BUG_ON(NULL == iommu_pt); - iommu_virt_addr = memdesc->gpuaddr; ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg, - size, (IOMMU_READ | IOMMU_WRITE)); + size, protflags); if (ret) { - KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) " - "failed with err: %d\n", iommu_pt->domain, - iommu_virt_addr, memdesc->sg, size, - (IOMMU_READ | IOMMU_WRITE), ret); + KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %x) err: %d\n", + iommu_pt->domain, iommu_virt_addr, memdesc->sg, size, + protflags, ret); return ret; } - + if (kgsl_memdesc_has_guard_page(memdesc)) { + ret = iommu_map(iommu_pt->domain, iommu_virt_addr + size, + page_to_phys(kgsl_guard_page), PAGE_SIZE, + protflags & ~IOMMU_WRITE); + if (ret) { + KGSL_CORE_ERR("iommu_map(%p, %x, %x, %x) err: %d\n", + iommu_pt->domain, iommu_virt_addr + size, + page_to_phys(kgsl_guard_page), + protflags & ~IOMMU_WRITE, + ret); + /* cleanup the partial mapping */ + iommu_unmap_range(iommu_pt->domain, iommu_virt_addr, + size); + } + } return ret; } @@ -1186,7 +1638,6 @@ static void kgsl_iommu_stop(struct kgsl_mmu *mmu) * * call this with the global lock held */ - if (mmu->flags & KGSL_FLAGS_STARTED) { /* detach iommu attachment */ kgsl_detach_pagetable_iommu_domain(mmu); @@ -1201,10 +1652,12 @@ static void kgsl_iommu_stop(struct kgsl_mmu *mmu) for (j = 0; j < iommu_unit->dev_count; j++) { if (iommu_unit->dev[j].fault) { kgsl_iommu_enable_clk(mmu, j); + msm_iommu_lock(); KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, iommu_unit->dev[j].ctx_id, RESUME, 1); + msm_iommu_unlock(); iommu_unit->dev[j].fault = 0; } } @@ -1222,24 +1675,35 @@ static int kgsl_iommu_close(struct kgsl_mmu *mmu) { struct kgsl_iommu *iommu = mmu->priv; int i; - for (i = 0; i < iommu->unit_count; i++) { - struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ? - mmu->priv_bank_table : mmu->defaultpagetable); - if (iommu->iommu_units[i].reg_map.gpuaddr) - kgsl_mmu_unmap(pagetable, - &(iommu->iommu_units[i].reg_map)); - if (iommu->iommu_units[i].reg_map.hostptr) - iounmap(iommu->iommu_units[i].reg_map.hostptr); - kgsl_sg_free(iommu->iommu_units[i].reg_map.sg, - iommu->iommu_units[i].reg_map.sglen); - } - if (mmu->priv_bank_table) + if (mmu->priv_bank_table != NULL) { + kgsl_iommu_cleanup_regs(mmu, mmu->priv_bank_table); kgsl_mmu_putpagetable(mmu->priv_bank_table); - if (mmu->defaultpagetable) + } + + if (mmu->defaultpagetable != NULL) kgsl_mmu_putpagetable(mmu->defaultpagetable); + + for (i = 0; i < iommu->unit_count; i++) { + struct kgsl_memdesc *reg_map = &iommu->iommu_units[i].reg_map; + + if (reg_map->hostptr) + iounmap(reg_map->hostptr); + kgsl_sg_free(reg_map->sg, reg_map->sglen); + reg_map->priv &= ~KGSL_MEMDESC_GLOBAL; + } + /* clear IOMMU GPU CPU sync structures */ + kgsl_sg_free(iommu->sync_lock_desc.sg, iommu->sync_lock_desc.sglen); + memset(&iommu->sync_lock_desc, 0, sizeof(iommu->sync_lock_desc)); + iommu->sync_lock_vars = NULL; + kfree(iommu); + if (kgsl_guard_page != NULL) { + __free_page(kgsl_guard_page); + kgsl_guard_page = NULL; + } + return 0; } @@ -1382,6 +1846,9 @@ struct kgsl_mmu_ops iommu_ops = { .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr, .mmu_sync_lock = kgsl_iommu_sync_lock, .mmu_sync_unlock = kgsl_iommu_sync_unlock, + /* These callbacks will be set on some chipsets */ + .mmu_setup_pt = NULL, + .mmu_cleanup_pt = NULL, }; struct kgsl_mmu_pt_ops iommu_pt_ops = { diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h index 45077007..f3dd28cb 100644 --- a/drivers/gpu/msm/kgsl_iommu.h +++ b/drivers/gpu/msm/kgsl_iommu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,33 @@ #define KGSL_IOMMU_CTX_OFFSET_V2 0x8000 #define KGSL_IOMMU_CTX_SHIFT 12 +/* TLBLKCR fields */ +#define KGSL_IOMMU_TLBLKCR_LKE_MASK 0x00000001 +#define KGSL_IOMMU_TLBLKCR_LKE_SHIFT 0 +#define KGSL_IOMMU_TLBLKCR_TLBIALLCFG_MASK 0x00000001 +#define KGSL_IOMMU_TLBLKCR_TLBIALLCFG_SHIFT 1 +#define KGSL_IOMMU_TLBLKCR_TLBIASIDCFG_MASK 0x00000001 +#define KGSL_IOMMU_TLBLKCR_TLBIASIDCFG_SHIFT 2 +#define KGSL_IOMMU_TLBLKCR_TLBIVAACFG_MASK 0x00000001 +#define KGSL_IOMMU_TLBLKCR_TLBIVAACFG_SHIFT 3 +#define KGSL_IOMMU_TLBLKCR_FLOOR_MASK 0x000000FF +#define KGSL_IOMMU_TLBLKCR_FLOOR_SHIFT 8 +#define KGSL_IOMMU_TLBLKCR_VICTIM_MASK 0x000000FF +#define KGSL_IOMMU_TLBLKCR_VICTIM_SHIFT 16 + +/* V2PXX fields */ +#define KGSL_IOMMU_V2PXX_INDEX_MASK 0x000000FF +#define KGSL_IOMMU_V2PXX_INDEX_SHIFT 0 +#define KGSL_IOMMU_V2PXX_VA_MASK 0x000FFFFF +#define KGSL_IOMMU_V2PXX_VA_SHIFT 12 + +/* FSYNR1 V0 fields */ +#define KGSL_IOMMU_FSYNR1_AWRITE_MASK 0x00000001 +#define KGSL_IOMMU_FSYNR1_AWRITE_SHIFT 8 +/* FSYNR0 V1 fields */ +#define KGSL_IOMMU_V1_FSYNR0_WNR_MASK 0x00000001 +#define KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT 4 + enum kgsl_iommu_reg_map { KGSL_IOMMU_GLOBAL_BASE = 0, KGSL_IOMMU_CTX_TTBR0, @@ -26,6 +53,10 @@ enum kgsl_iommu_reg_map { KGSL_IOMMU_CTX_FSR, KGSL_IOMMU_CTX_TLBIALL, KGSL_IOMMU_CTX_RESUME, + KGSL_IOMMU_CTX_TLBLKCR, + KGSL_IOMMU_CTX_V2PUR, + KGSL_IOMMU_CTX_FSYNR0, + KGSL_IOMMU_CTX_FSYNR1, KGSL_IOMMU_REG_MAX }; @@ -124,6 +155,8 @@ struct kgsl_iommu_unit { * IOMMU registers * @sync_lock_desc: GPU Memory descriptor for the memory containing the * spinlocks + * @sync_lock_offset: The page offset within a page at which the sync + * variables are located * @sync_lock_initialized: True if the sync_lock feature is enabled */ struct kgsl_iommu { @@ -136,6 +169,7 @@ struct kgsl_iommu { struct kgsl_iommu_register_list *iommu_reg_list; struct remote_iommu_petersons_spinlock *sync_lock_vars; struct kgsl_memdesc sync_lock_desc; + unsigned int sync_lock_offset; bool sync_lock_initialized; }; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index f11511fc..c96a3609 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,9 +27,6 @@ #include "kgsl_sharedmem.h" #include "adreno.h" -#define KGSL_MMU_ALIGN_SHIFT 13 -#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1)) - static enum kgsl_mmutype kgsl_mmu_type; static void pagetable_remove_sysfs_objects(struct kgsl_pagetable *pagetable); @@ -37,17 +34,18 @@ static void pagetable_remove_sysfs_objects(struct kgsl_pagetable *pagetable); static int kgsl_cleanup_pt(struct kgsl_pagetable *pt) { int i; - /* For IOMMU only unmap the global structures to global pt */ - if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) && - (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) && - (KGSL_MMU_GLOBAL_PT != pt->name) && - (KGSL_MMU_PRIV_BANK_TABLE_NAME != pt->name)) - return 0; + struct kgsl_device *device; + for (i = 0; i < KGSL_DEVICE_MAX; i++) { - struct kgsl_device *device = kgsl_driver.devp[i]; + device = kgsl_driver.devp[i]; if (device) device->ftbl->cleanup_pt(device, pt); } + /* Only the 3d device needs mmu specific pt entries */ + device = kgsl_driver.devp[KGSL_DEVICE_3D0]; + if (device->mmu.mmu_ops->mmu_cleanup_pt != NULL) + device->mmu.mmu_ops->mmu_cleanup_pt(&device->mmu, pt); + return 0; } @@ -56,21 +54,25 @@ static int kgsl_setup_pt(struct kgsl_pagetable *pt) { int i = 0; int status = 0; + struct kgsl_device *device; - /* For IOMMU only map the global structures to global pt */ - if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) && - (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) && - (KGSL_MMU_GLOBAL_PT != pt->name) && - (KGSL_MMU_PRIV_BANK_TABLE_NAME != pt->name)) - return 0; for (i = 0; i < KGSL_DEVICE_MAX; i++) { - struct kgsl_device *device = kgsl_driver.devp[i]; + device = kgsl_driver.devp[i]; if (device) { status = device->ftbl->setup_pt(device, pt); if (status) goto error_pt; } } + /* Only the 3d device needs mmu specific pt entries */ + device = kgsl_driver.devp[KGSL_DEVICE_3D0]; + if (device->mmu.mmu_ops->mmu_setup_pt != NULL) { + status = device->mmu.mmu_ops->mmu_setup_pt(&device->mmu, pt); + if (status) { + i = KGSL_DEVICE_MAX - 1; + goto error_pt; + } + } return status; error_pt: while (i >= 0) { @@ -82,16 +84,8 @@ static int kgsl_setup_pt(struct kgsl_pagetable *pt) return status; } -static void kgsl_destroy_pagetable(struct kref *kref) +static void _kgsl_destroy_pagetable(struct kgsl_pagetable *pagetable) { - struct kgsl_pagetable *pagetable = container_of(kref, - struct kgsl_pagetable, refcount); - unsigned long flags; - - spin_lock_irqsave(&kgsl_driver.ptlock, flags); - list_del(&pagetable->list); - spin_unlock_irqrestore(&kgsl_driver.ptlock, flags); - pagetable_remove_sysfs_objects(pagetable); kgsl_cleanup_pt(pagetable); @@ -106,6 +100,29 @@ static void kgsl_destroy_pagetable(struct kref *kref) kfree(pagetable); } +static void kgsl_destroy_pagetable(struct kref *kref) +{ + struct kgsl_pagetable *pagetable = container_of(kref, + struct kgsl_pagetable, refcount); + unsigned long flags; + + spin_lock_irqsave(&kgsl_driver.ptlock, flags); + list_del(&pagetable->list); + spin_unlock_irqrestore(&kgsl_driver.ptlock, flags); + + _kgsl_destroy_pagetable(pagetable); +} + +static void kgsl_destroy_pagetable_locked(struct kref *kref) +{ + struct kgsl_pagetable *pagetable = container_of(kref, + struct kgsl_pagetable, refcount); + + list_del(&pagetable->list); + + _kgsl_destroy_pagetable(pagetable); +} + static inline void kgsl_put_pagetable(struct kgsl_pagetable *pagetable) { if (pagetable) @@ -120,10 +137,12 @@ kgsl_get_pagetable(unsigned long name) spin_lock_irqsave(&kgsl_driver.ptlock, flags); list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { - if (pt->name == name) { - ret = pt; - kref_get(&ret->refcount); - break; + if (kref_get_unless_zero(&pt->refcount)) { + if (pt->name == name) { + ret = pt; + break; + } + kref_put(&pt->refcount, kgsl_destroy_pagetable_locked); } } @@ -134,12 +153,12 @@ kgsl_get_pagetable(unsigned long name) static struct kgsl_pagetable * _get_pt_from_kobj(struct kobject *kobj) { - unsigned long ptname; + unsigned int ptname; if (!kobj) return NULL; - if (sscanf(kobj->name, "%ld", &ptname) != 1) + if (kstrtou32(kobj->name, 0, &ptname)) return NULL; return kgsl_get_pagetable(ptname); @@ -310,22 +329,6 @@ pagetable_add_sysfs_objects(struct kgsl_pagetable *pagetable) return ret; } -unsigned int kgsl_mmu_get_ptsize(void) -{ - /* - * For IOMMU, we could do up to 4G virtual range if we wanted to, but - * it makes more sense to return a smaller range and leave the rest of - * the virtual range for future improvements - */ - - if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type) - return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE; - else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) - return SZ_2G - KGSL_PAGETABLE_BASE; - else - return 0; -} - int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base) { @@ -336,9 +339,14 @@ kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base) return KGSL_MMU_GLOBAL_PT; spin_lock(&kgsl_driver.ptlock); list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { - if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) { - ptid = (int) pt->name; - break; + if (kref_get_unless_zero(&pt->refcount)) { + if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) { + ptid = (int) pt->name; + kref_put(&pt->refcount, + kgsl_destroy_pagetable_locked); + break; + } + kref_put(&pt->refcount, kgsl_destroy_pagetable_locked); } } spin_unlock(&kgsl_driver.ptlock); @@ -358,16 +366,23 @@ kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, unsigned int pt_base, return KGSL_MMU_GLOBAL_PT; spin_lock(&kgsl_driver.ptlock); list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { - if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) { - if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) { - ret = 1; - break; - } else { - pt->fault_addr = (addr & ~(PAGE_SIZE-1)); - ret = 0; - break; + if (kref_get_unless_zero(&pt->refcount)) { + if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) { + if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) { + ret = 1; + kref_put(&pt->refcount, + kgsl_destroy_pagetable_locked); + break; + } else { + pt->fault_addr = + (addr & ~(PAGE_SIZE-1)); + ret = 0; + kref_put(&pt->refcount, + kgsl_destroy_pagetable_locked); + break; + } } - + kref_put(&pt->refcount, kgsl_destroy_pagetable_locked); } } spin_unlock(&kgsl_driver.ptlock); @@ -385,6 +400,10 @@ int kgsl_mmu_init(struct kgsl_device *device) status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE); if (status) return status; + + /* Mark the setstate memory as read only */ + mmu->setstate_memory.flags |= KGSL_MEMFLAGS_GPUREADONLY; + kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0, mmu->setstate_memory.size); @@ -490,10 +509,10 @@ static struct kgsl_pagetable *kgsl_mmu_createpagetableobject( if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) && ((KGSL_MMU_GLOBAL_PT == name) || (KGSL_MMU_PRIV_BANK_TABLE_NAME == name))) { - pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1); + pagetable->kgsl_pool = gen_pool_create(ilog2(SZ_8K), -1); if (pagetable->kgsl_pool == NULL) { KGSL_CORE_ERR("gen_pool_create(%d) failed\n", - KGSL_MMU_ALIGN_SHIFT); + ilog2(SZ_8K)); goto err_alloc; } if (gen_pool_add(pagetable->kgsl_pool, @@ -511,7 +530,7 @@ static struct kgsl_pagetable *kgsl_mmu_createpagetableobject( goto err_kgsl_pool; } - if (gen_pool_add(pagetable->pool, KGSL_PAGETABLE_BASE, + if (gen_pool_add(pagetable->pool, kgsl_mmu_get_base_addr(), ptsize, -1)) { KGSL_CORE_ERR("gen_pool_add failed\n"); goto err_pool; @@ -559,12 +578,9 @@ struct kgsl_pagetable *kgsl_mmu_getpagetable(unsigned long name) if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) return (void *)(-1); -#ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE + if (!kgsl_mmu_is_perprocess()) + name = KGSL_MMU_GLOBAL_PT; -#endif - /* We presently do not support per-process for IOMMU-v2 */ - if (!msm_soc_version_supports_iommu_v1()) - name = KGSL_MMU_GLOBAL_PT; pt = kgsl_get_pagetable(name); @@ -625,23 +641,20 @@ void kgsl_mh_start(struct kgsl_device *device) * kgsl_pwrctrl_irq() is called */ } +EXPORT_SYMBOL(kgsl_mh_start); -static inline struct gen_pool * -_get_pool(struct kgsl_pagetable *pagetable, unsigned int flags) -{ - if (pagetable->kgsl_pool && - (KGSL_MEMDESC_GLOBAL & flags)) - return pagetable->kgsl_pool; - return pagetable->pool; -} - +/** + * kgsl_mmu_get_gpuaddr - Assign a memdesc with a gpuadddr from the gen pool + * @pagetable - pagetable whose pool is to be used + * @memdesc - memdesc to which gpuaddr is assigned + * + * returns - 0 on success else error code + */ int -kgsl_mmu_map(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc, - unsigned int protflags) +kgsl_mmu_get_gpuaddr(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc) { - int ret; - struct gen_pool *pool; + struct gen_pool *pool = NULL; int size; int page_align = ilog2(PAGE_SIZE); @@ -663,31 +676,80 @@ kgsl_mmu_map(struct kgsl_pagetable *pagetable, } } - size = kgsl_sg_size(memdesc->sg, memdesc->sglen); - - /* Allocate from kgsl pool if it exists for global mappings */ - pool = _get_pool(pagetable, memdesc->priv); - - /* Allocate aligned virtual addresses for iommu. This allows - * more efficient pagetable entries if the physical memory - * is also aligned. Don't do this for GPUMMU, because - * the address space is so small. - */ - if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype() && - kgsl_memdesc_get_align(memdesc) > 0) - page_align = kgsl_memdesc_get_align(memdesc); - - memdesc->gpuaddr = gen_pool_alloc_aligned(pool, size, page_align); - if (memdesc->gpuaddr == 0) { - KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n", - size, - (pool == pagetable->kgsl_pool) ? - "kgsl_pool" : "general_pool"); - KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n", - pagetable->name, pagetable->stats.mapped, - pagetable->stats.entries); - return -ENOMEM; + /* Add space for the guard page when allocating the mmu VA. */ + size = memdesc->size; + if (kgsl_memdesc_has_guard_page(memdesc)) + size += PAGE_SIZE; + + pool = pagetable->pool; + + if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) { + /* Allocate aligned virtual addresses for iommu. This allows + * more efficient pagetable entries if the physical memory + * is also aligned. Don't do this for GPUMMU, because + * the address space is so small. + */ + if (kgsl_memdesc_get_align(memdesc) > 0) + page_align = kgsl_memdesc_get_align(memdesc); + if (kgsl_memdesc_is_global(memdesc)) { + /* + * Only the default pagetable has a kgsl_pool, and + * it is responsible for creating the mapping for + * each global buffer. The mapping will be reused + * in all other pagetables and it must already exist + * when we're creating other pagetables which do not + * have a kgsl_pool. + */ + pool = pagetable->kgsl_pool; + if (pool == NULL && memdesc->gpuaddr == 0) { + KGSL_CORE_ERR( + "No address for global mapping into pt %d\n", + pagetable->name); + return -EINVAL; + } + } else if (kgsl_memdesc_use_cpu_map(memdesc)) { + if (memdesc->gpuaddr == 0) + return -EINVAL; + pool = NULL; + } } + if (pool) { + memdesc->gpuaddr = gen_pool_alloc_aligned(pool, size, + page_align); + if (memdesc->gpuaddr == 0) { + KGSL_CORE_ERR("gen_pool_alloc(%d) failed, pool: %s\n", + size, + (pool == pagetable->kgsl_pool) ? + "kgsl_pool" : "general_pool"); + KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n", + pagetable->name, + pagetable->stats.mapped, + pagetable->stats.entries); + return -ENOMEM; + } + } + return 0; +} +EXPORT_SYMBOL(kgsl_mmu_get_gpuaddr); + +int +kgsl_mmu_map(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc) +{ + int ret = 0; + int size; + unsigned int protflags = kgsl_memdesc_protflags(memdesc); + + if (!memdesc->gpuaddr) + return -EINVAL; + /* Only global mappings should be mapped multiple times */ + if (!kgsl_memdesc_is_global(memdesc) && + (KGSL_MEMDESC_MAPPED & memdesc->priv)) + return -EINVAL; + /* Add space for the guard page when allocating the mmu VA. */ + size = memdesc->size; + if (kgsl_memdesc_has_guard_page(memdesc)) + size += PAGE_SIZE; if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype()) spin_lock(&pagetable->lock); @@ -697,7 +759,7 @@ kgsl_mmu_map(struct kgsl_pagetable *pagetable, spin_lock(&pagetable->lock); if (ret) - goto err_free_gpuaddr; + goto done; /* Keep track of the statistics for the sysfs files */ @@ -708,35 +770,81 @@ kgsl_mmu_map(struct kgsl_pagetable *pagetable, pagetable->stats.max_mapped); spin_unlock(&pagetable->lock); + memdesc->priv |= KGSL_MEMDESC_MAPPED; return 0; -err_free_gpuaddr: +done: spin_unlock(&pagetable->lock); - gen_pool_free(pool, memdesc->gpuaddr, size); - memdesc->gpuaddr = 0; return ret; } EXPORT_SYMBOL(kgsl_mmu_map); +/** + * kgsl_mmu_put_gpuaddr - Free a gpuaddress from memory pool + * @pagetable - pagetable whose pool memory is freed from + * @memdesc - memdesc whose gpuaddress is freed + * + * returns - 0 on success else error code + */ int -kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc) +kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc) { struct gen_pool *pool; int size; - unsigned int start_addr = 0; - unsigned int end_addr = 0; if (memdesc->size == 0 || memdesc->gpuaddr == 0) return 0; - if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) { + if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) + goto done; + + /* Add space for the guard page when freeing the mmu VA. */ + size = memdesc->size; + if (kgsl_memdesc_has_guard_page(memdesc)) + size += PAGE_SIZE; + + pool = pagetable->pool; + + if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) { + if (kgsl_memdesc_is_global(memdesc)) + pool = pagetable->kgsl_pool; + else if (kgsl_memdesc_use_cpu_map(memdesc)) + pool = NULL; + } + if (pool) + gen_pool_free(pool, memdesc->gpuaddr, size); + /* + * Don't clear the gpuaddr on global mappings because they + * may be in use by other pagetables + */ +done: + if (!kgsl_memdesc_is_global(memdesc)) memdesc->gpuaddr = 0; + return 0; +} +EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr); + +int +kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc) +{ + int size; + unsigned int start_addr = 0; + unsigned int end_addr = 0; + + if (memdesc->size == 0 || memdesc->gpuaddr == 0 || + !(KGSL_MEMDESC_MAPPED & memdesc->priv)) + return -EINVAL; + + if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) return 0; - } - size = kgsl_sg_size(memdesc->sg, memdesc->sglen); + /* Add space for the guard page when freeing the mmu VA. */ + size = memdesc->size; + if (kgsl_memdesc_has_guard_page(memdesc)) + size += PAGE_SIZE; start_addr = memdesc->gpuaddr; end_addr = (memdesc->gpuaddr + size); @@ -758,22 +866,14 @@ kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, pagetable->stats.mapped -= size; spin_unlock(&pagetable->lock); - - pool = _get_pool(pagetable, memdesc->priv); - gen_pool_free(pool, memdesc->gpuaddr, size); - - /* - * Don't clear the gpuaddr on global mappings because they - * may be in use by other pagetables - */ - if (!(memdesc->priv & KGSL_MEMDESC_GLOBAL)) - memdesc->gpuaddr = 0; + if (!kgsl_memdesc_is_global(memdesc)) + memdesc->priv &= ~KGSL_MEMDESC_MAPPED; return 0; } EXPORT_SYMBOL(kgsl_mmu_unmap); int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc, unsigned int protflags) + struct kgsl_memdesc *memdesc) { int result = -EINVAL; unsigned int gpuaddr = 0; @@ -785,13 +885,15 @@ int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable, /* Not all global mappings are needed for all MMU types */ if (!memdesc->size) return 0; - gpuaddr = memdesc->gpuaddr; memdesc->priv |= KGSL_MEMDESC_GLOBAL; - result = kgsl_mmu_map(pagetable, memdesc, protflags); + result = kgsl_mmu_get_gpuaddr(pagetable, memdesc); if (result) goto error; + result = kgsl_mmu_map(pagetable, memdesc); + if (result) + goto error_put_gpuaddr; /*global mappings must have the same gpu address in all pagetables*/ if (gpuaddr && gpuaddr != memdesc->gpuaddr) { @@ -803,6 +905,8 @@ int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable, return result; error_unmap: kgsl_mmu_unmap(pagetable, memdesc); +error_put_gpuaddr: + kgsl_mmu_put_gpuaddr(pagetable, memdesc); error: return result; } @@ -894,8 +998,13 @@ int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr) { if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) return 1; - return ((gpuaddr >= KGSL_PAGETABLE_BASE) && - (gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize()))); + if (gpuaddr >= kgsl_mmu_get_base_addr() && + gpuaddr < kgsl_mmu_get_base_addr() + kgsl_mmu_get_ptsize()) + return 1; + if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU + && kgsl_mmu_is_perprocess()) + return (gpuaddr > 0 && gpuaddr < TASK_SIZE); + return 0; } EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range); diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 377f3423..f2b476a5 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -13,13 +13,15 @@ #ifndef __KGSL_MMU_H #define __KGSL_MMU_H +#include + /* - * These defines control the split between ttbr1 and ttbr0 pagetables of IOMMU - * and what ranges of memory we map to them + * These defines control the address range for allocations that + * are mapped into all pagetables. */ -#define KGSL_IOMMU_GLOBAL_MEM_BASE 0xC0000000 +#define KGSL_IOMMU_GLOBAL_MEM_BASE 0xf8000000 #define KGSL_IOMMU_GLOBAL_MEM_SIZE SZ_4M -#define KGSL_IOMMU_TTBR1_SPLIT 2 +#define KGSL_IOMMU_ALIGN_MASK (~((1 << PAGE_SHIFT) - 1)) #define KGSL_MMU_ALIGN_SHIFT 13 #define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1)) @@ -155,6 +157,10 @@ struct kgsl_mmu_ops { unsigned int (*mmu_sync_unlock) (struct kgsl_mmu *mmu, unsigned int *cmds); + int (*mmu_setup_pt) (struct kgsl_mmu *mmu, + struct kgsl_pagetable *pt); + void (*mmu_cleanup_pt) (struct kgsl_mmu *mmu, + struct kgsl_pagetable *pt); }; struct kgsl_mmu_pt_ops { @@ -200,12 +206,15 @@ int kgsl_mmu_init(struct kgsl_device *device); int kgsl_mmu_start(struct kgsl_device *device); int kgsl_mmu_close(struct kgsl_device *device); int kgsl_mmu_map(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc, - unsigned int protflags); + struct kgsl_memdesc *memdesc); +int kgsl_mmu_get_gpuaddr(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc); int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc, unsigned int protflags); + struct kgsl_memdesc *memdesc); int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc); +int kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc); unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr); void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id, uint32_t flags); @@ -220,7 +229,6 @@ void *kgsl_mmu_ptpool_init(int entries); int kgsl_mmu_enabled(void); void kgsl_mmu_set_mmutype(char *mmutype); enum kgsl_mmutype kgsl_mmu_get_mmutype(void); -unsigned int kgsl_mmu_get_ptsize(void); int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr); /* @@ -352,4 +360,78 @@ static inline int kgsl_mmu_sync_unlock(struct kgsl_mmu *mmu, return 0; } +/* + * kgsl_mmu_is_perprocess() - Runtime check for per-process + * pagetables. + * + * Returns non-zero if per-process pagetables are enabled, + * 0 if not. + */ +#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE +static inline int kgsl_mmu_is_perprocess(void) +{ + + /* We presently do not support per-process for IOMMU-v2 */ + return (kgsl_mmu_get_mmutype() != KGSL_MMU_TYPE_IOMMU) + || msm_soc_version_supports_iommu_v1(); +} +#else +static inline int kgsl_mmu_is_perprocess(void) +{ + return 0; +} +#endif + +/* + * kgsl_mmu_base_addr() - Get gpu virtual address base. + * + * Returns the start address of the allocatable gpu + * virtual address space. Other mappings that mirror + * the CPU address space are possible outside this range. + */ +static inline unsigned int kgsl_mmu_get_base_addr(void) +{ + if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype() + || !kgsl_mmu_is_perprocess()) + return KGSL_PAGETABLE_BASE; + /* + * This is the start of the kernel address + * space, so allocations from this range will + * never conflict with userpace addresses + */ + return PAGE_OFFSET; +} + +/* + * kgsl_mmu_get_ptsize() - Get gpu pagetable size + * + * Returns the usable size of the gpu allocatable + * address space. + */ +static inline unsigned int kgsl_mmu_get_ptsize(void) +{ + /* + * For IOMMU per-process pagetables, the allocatable range + * and the kernel global range must both be outside + * the userspace address range. There is a 1Mb gap + * between these address ranges to make overrun + * detection easier. + * For the shared pagetable case use 2GB and because + * mirroring the CPU address space is not possible and + * we're better off with extra room. + */ + enum kgsl_mmutype mmu_type = kgsl_mmu_get_mmutype(); + + if (KGSL_MMU_TYPE_GPU == mmu_type) + return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE; + else if (KGSL_MMU_TYPE_IOMMU == mmu_type) { + if (kgsl_mmu_is_perprocess()) + return KGSL_IOMMU_GLOBAL_MEM_BASE + - kgsl_mmu_get_base_addr() - SZ_1M; + else + return SZ_2G; + } + return 0; +} + #endif /* __KGSL_MMU_H */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 3b9b689c..faad5785 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2012,2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,6 +23,7 @@ #include "kgsl_pwrscale.h" #include "kgsl_device.h" #include "kgsl_trace.h" +#include "kgsl_sharedmem.h" #define KGSL_PWRFLAGS_POWER_ON 0 #define KGSL_PWRFLAGS_CLK_ON 1 @@ -178,19 +179,18 @@ static int kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev, { struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; - int ret, level; + int ret; + unsigned int level = 0; if (device == NULL) return 0; pwr = &device->pwrctrl; - ret = sscanf(buf, "%d", &level); - if (ret != 1) - return count; + ret = kgsl_sysfs_store(buf, &level); - if (level < 0) - return count; + if (ret) + return ret; mutex_lock(&device->mutex); @@ -235,20 +235,17 @@ static int kgsl_pwrctrl_max_pwrlevel_store(struct device *dev, { struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; - int ret, level, max_level; + int ret, max_level; + unsigned int level = 0; if (device == NULL) return 0; pwr = &device->pwrctrl; - ret = sscanf(buf, "%d", &level); - if (ret != 1) - return count; - - /* If the use specifies a negative number, then don't change anything */ - if (level < 0) - return count; + ret = kgsl_sysfs_store(buf, &level); + if (ret) + return ret; mutex_lock(&device->mutex); @@ -293,20 +290,17 @@ static int kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, const char *buf, size_t count) { struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; - int ret, level, min_level; + int ret, min_level; + unsigned int level = 0; if (device == NULL) return 0; pwr = &device->pwrctrl; - ret = sscanf(buf, "%d", &level); - if (ret != 1) - return count; - - /* Don't do anything on obviously incorrect values */ - if (level < 0) - return count; + ret = kgsl_sysfs_store(buf, &level); + if (ret) + return ret; mutex_lock(&device->mutex); if (level > pwr->num_pwrlevels - 2) @@ -377,7 +371,7 @@ static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev, { struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; - unsigned long val; + unsigned int val = 0; int ret, level; if (device == NULL) @@ -385,9 +379,9 @@ static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev, pwr = &device->pwrctrl; - ret = sscanf(buf, "%ld", &val); - if (ret != 1) - return count; + ret = kgsl_sysfs_store(buf, &val); + if (ret) + return ret; mutex_lock(&device->mutex); level = _get_nearest_pwrlevel(pwr, val); @@ -429,7 +423,7 @@ static int kgsl_pwrctrl_gpuclk_store(struct device *dev, { struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; - unsigned long val; + unsigned int val = 0; int ret, level; if (device == NULL) @@ -437,9 +431,9 @@ static int kgsl_pwrctrl_gpuclk_store(struct device *dev, pwr = &device->pwrctrl; - ret = sscanf(buf, "%ld", &val); - if (ret != 1) - return count; + ret = kgsl_sysfs_store(buf, &val); + if (ret) + return ret; mutex_lock(&device->mutex); level = _get_nearest_pwrlevel(pwr, val); @@ -467,21 +461,18 @@ static int kgsl_pwrctrl_pwrnap_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - char temp[20]; - unsigned long val; + unsigned int val = 0; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; - int rc; + int ret; if (device == NULL) return 0; pwr = &device->pwrctrl; - snprintf(temp, sizeof(temp), "%.*s", - (int)min(count, sizeof(temp) - 1), buf); - rc = strict_strtoul(temp, 0, &val); - if (rc) - return rc; + ret = kgsl_sysfs_store(buf, &val); + if (ret) + return ret; mutex_lock(&device->mutex); @@ -510,23 +501,20 @@ static int kgsl_pwrctrl_idle_timer_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - char temp[20]; - unsigned long val; + unsigned int val = 0; struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; const long div = 1000/HZ; static unsigned int org_interval_timeout = 1; - int rc; + int ret; if (device == NULL) return 0; pwr = &device->pwrctrl; - snprintf(temp, sizeof(temp), "%.*s", - (int)min(count, sizeof(temp) - 1), buf); - rc = strict_strtoul(temp, 0, &val); - if (rc) - return rc; + ret = kgsl_sysfs_store(buf, &val); + if (ret) + return ret; if (org_interval_timeout == 1) org_interval_timeout = pwr->interval_timeout; @@ -560,7 +548,11 @@ static int kgsl_pwrctrl_gpubusy_show(struct device *dev, { int ret; struct kgsl_device *device = kgsl_device_from_dev(dev); - struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats; + struct kgsl_clk_stats *clkstats; + + if (device == NULL) + return 0; + clkstats = &device->pwrctrl.clk_stats; ret = snprintf(buf, PAGE_SIZE, "%7d %7d\n", clkstats->on_time_old, clkstats->elapsed_old); if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { @@ -576,10 +568,13 @@ static int kgsl_pwrctrl_gputop_show(struct device *dev, { int ret; struct kgsl_device *device = kgsl_device_from_dev(dev); - struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats; + struct kgsl_clk_stats *clkstats; int i = 0; char *ptr = buf; + if (device == NULL) + return 0; + clkstats = &device->pwrctrl.clk_stats; ret = snprintf(buf, PAGE_SIZE, "%7d %7d ", clkstats->on_time_old, clkstats->elapsed_old); for (i = 0, ptr += ret; i < device->pwrctrl.num_pwrlevels; @@ -615,6 +610,16 @@ static int kgsl_pwrctrl_gpu_available_frequencies_show( return num_chars; } +static int kgsl_pwrctrl_reset_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + if (device == NULL) + return 0; + return snprintf(buf, PAGE_SIZE, "%d\n", device->reset_counter); +} + DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store); DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show, kgsl_pwrctrl_max_gpuclk_store); @@ -640,6 +645,9 @@ DEVICE_ATTR(thermal_pwrlevel, 0644, DEVICE_ATTR(num_pwrlevels, 0444, kgsl_pwrctrl_num_pwrlevels_show, NULL); +DEVICE_ATTR(reset_count, 0444, + kgsl_pwrctrl_reset_count_show, + NULL); static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_gpuclk, @@ -653,6 +661,7 @@ static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_min_pwrlevel, &dev_attr_thermal_pwrlevel, &dev_attr_num_pwrlevels, + &dev_attr_reset_count, NULL }; @@ -878,7 +887,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) if (pdata->set_grp_async != NULL) pdata->set_grp_async(); - if (pdata->num_levels > KGSL_MAX_PWRLEVELS) { + if (pdata->num_levels > KGSL_MAX_PWRLEVELS || + pdata->num_levels < 1) { KGSL_PWR_ERR(device, "invalid power level count: %d\n", pdata->num_levels); result = -EINVAL; @@ -998,6 +1008,14 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) pwr->power_flags = 0; } +/** + * kgsl_idle_check() - Work function for GPU interrupts and idle timeouts. + * @device: The device + * + * This function is called for work that is queued by the interrupt + * handler or the idle timer. It attempts to transition to a clocks + * off state if the active_cnt is 0 and the hardware is idle. + */ void kgsl_idle_check(struct work_struct *work) { struct kgsl_device *device = container_of(work, struct kgsl_device, @@ -1007,15 +1025,22 @@ void kgsl_idle_check(struct work_struct *work) return; mutex_lock(&device->mutex); - if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) { - kgsl_pwrscale_idle(device); - if (kgsl_pwrctrl_sleep(device) != 0) { + kgsl_pwrscale_idle(device); + + if (device->state == KGSL_STATE_ACTIVE + || device->state == KGSL_STATE_NAP) { + if (device->active_cnt > 0 || kgsl_pwrctrl_sleep(device) != 0) { + + kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); + mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); - /* If the GPU has been too busy to sleep, make sure * - * that is acurately reflected in the % busy numbers. */ + /* + * If the GPU has been too busy to sleep, make sure + * that is acurately reflected in the % busy numbers. + */ device->pwrctrl.clk_stats.no_nap_cnt++; if (device->pwrctrl.clk_stats.no_nap_cnt > UPDATE_BUSY) { @@ -1030,6 +1055,7 @@ void kgsl_idle_check(struct work_struct *work) mutex_unlock(&device->mutex); } +EXPORT_SYMBOL(kgsl_idle_check); void kgsl_timer(unsigned long data) { @@ -1047,53 +1073,30 @@ void kgsl_timer(unsigned long data) } } -void kgsl_pre_hwaccess(struct kgsl_device *device) +bool kgsl_pwrctrl_isenabled(struct kgsl_device *device) { - BUG_ON(!mutex_is_locked(&device->mutex)); - switch (device->state) { - case KGSL_STATE_ACTIVE: - return; - case KGSL_STATE_NAP: - case KGSL_STATE_SLEEP: - case KGSL_STATE_SLUMBER: - kgsl_pwrctrl_wake(device); - break; - case KGSL_STATE_SUSPEND: - kgsl_check_suspended(device); - break; - case KGSL_STATE_INIT: - case KGSL_STATE_HUNG: - case KGSL_STATE_DUMP_AND_FT: - if (test_bit(KGSL_PWRFLAGS_CLK_ON, - &device->pwrctrl.power_flags)) - break; - else - KGSL_PWR_ERR(device, - "hw access while clocks off from state %d\n", - device->state); - break; - default: - KGSL_PWR_ERR(device, "hw access while in unknown state %d\n", - device->state); - break; - } + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + return (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) != 0); } -EXPORT_SYMBOL(kgsl_pre_hwaccess); -void kgsl_check_suspended(struct kgsl_device *device) +/** + * kgsl_pre_hwaccess - Enforce preconditions for touching registers + * @device: The device + * + * This function ensures that the correct lock is held and that the GPU + * clock is on immediately before a register is read or written. Note + * that this function does not check active_cnt because the registers + * must be accessed during device start and stop, when the active_cnt + * may legitimately be 0. + */ +void kgsl_pre_hwaccess(struct kgsl_device *device) { - if (device->requested_state == KGSL_STATE_SUSPEND || - device->state == KGSL_STATE_SUSPEND) { - mutex_unlock(&device->mutex); - wait_for_completion(&device->hwaccess_gate); - mutex_lock(&device->mutex); - } else if (device->state == KGSL_STATE_DUMP_AND_FT) { - mutex_unlock(&device->mutex); - wait_for_completion(&device->ft_gate); - mutex_lock(&device->mutex); - } else if (device->state == KGSL_STATE_SLUMBER) - kgsl_pwrctrl_wake(device); + /* In order to touch a register you must hold the device mutex...*/ + BUG_ON(!mutex_is_locked(&device->mutex)); + /* and have the clock on! */ + BUG_ON(!kgsl_pwrctrl_isenabled(device)); } +EXPORT_SYMBOL(kgsl_pre_hwaccess); static int _nap(struct kgsl_device *device) @@ -1104,6 +1107,7 @@ _nap(struct kgsl_device *device) kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); return -EBUSY; } + del_timer_sync(&device->hang_timer); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP); kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP); @@ -1173,6 +1177,10 @@ _slumber(struct kgsl_device *device) case KGSL_STATE_NAP: case KGSL_STATE_SLEEP: del_timer_sync(&device->idle_timer); + del_timer_sync(&device->hang_timer); + /* make sure power is on to stop the device*/ + kgsl_pwrctrl_enable(device); + kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); device->ftbl->suspend_context(device); device->ftbl->stop(device); _sleep_accounting(device); @@ -1222,13 +1230,18 @@ EXPORT_SYMBOL(kgsl_pwrctrl_sleep); /******************************************************************/ /* Caller must hold the device mutex. */ -void kgsl_pwrctrl_wake(struct kgsl_device *device) +int kgsl_pwrctrl_wake(struct kgsl_device *device) { - int status; + int status = 0; + unsigned int context_id; + unsigned int state = device->state; + unsigned int ts_processed = 0xdeaddead; + struct kgsl_context *context; + kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE); switch (device->state) { case KGSL_STATE_SLUMBER: - status = device->ftbl->start(device, 0); + status = device->ftbl->start(device); if (status) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); KGSL_DRV_ERR(device, "start failed %d\n", status); @@ -1238,6 +1251,18 @@ void kgsl_pwrctrl_wake(struct kgsl_device *device) case KGSL_STATE_SLEEP: kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); kgsl_pwrscale_wake(device); + kgsl_sharedmem_readl(&device->memstore, + (unsigned int *) &context_id, + KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, + current_context)); + context = kgsl_context_get(device, context_id); + if (context) + ts_processed = kgsl_readtimestamp(device, context, + KGSL_TIMESTAMP_RETIRED); + KGSL_PWR_INFO(device, "Wake from %s state. CTXT: %d RTRD TS: %08X\n", + kgsl_pwrstate_to_str(state), + context ? context->id : -1, ts_processed); + kgsl_context_put(context); /* fall through */ case KGSL_STATE_NAP: /* Turn on the core clocks */ @@ -1248,17 +1273,23 @@ void kgsl_pwrctrl_wake(struct kgsl_device *device) /* Re-enable HW access */ mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); + mod_timer(&device->hang_timer, + (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_HANG_DETECT))); pm_qos_update_request(&device->pm_qos_req_dma, GPU_SWFI_LATENCY); case KGSL_STATE_ACTIVE: kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); break; + case KGSL_STATE_INIT: + break; default: KGSL_PWR_WARN(device, "unhandled state %s\n", kgsl_pwrstate_to_str(device->state)); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); + status = -EINVAL; break; } + return status; } EXPORT_SYMBOL(kgsl_pwrctrl_wake); @@ -1324,3 +1355,122 @@ const char *kgsl_pwrstate_to_str(unsigned int state) } EXPORT_SYMBOL(kgsl_pwrstate_to_str); + +/** + * kgsl_active_count_get() - Increase the device active count + * @device: Pointer to a KGSL device + * + * Increase the active count for the KGSL device and turn on + * clocks if this is the first reference. Code paths that need + * to touch the hardware or wait for the hardware to complete + * an operation must hold an active count reference until they + * are finished. An error code will be returned if waking the + * device fails. The device mutex must be held while *calling + * this function. + */ +int kgsl_active_count_get(struct kgsl_device *device) +{ + int ret = 0; + BUG_ON(!mutex_is_locked(&device->mutex)); + + if (device->active_cnt == 0) { + + if (device->state != KGSL_STATE_DUMP_AND_FT) { + mutex_unlock(&device->mutex); + wait_for_completion(&device->hwaccess_gate); + wait_for_completion(&device->ft_gate); + mutex_lock(&device->mutex); + } + + ret = kgsl_pwrctrl_wake(device); + } + if (ret == 0) + device->active_cnt++; + return ret; +} +EXPORT_SYMBOL(kgsl_active_count_get); + +/** + * kgsl_active_count_get_light() - Increase the device active count + * @device: Pointer to a KGSL device + * + * Increase the active count for the KGSL device WITHOUT + * turning on the clocks. Currently this is only used for creating + * kgsl_events. The device mutex must be held while calling this function. + */ +int kgsl_active_count_get_light(struct kgsl_device *device) +{ + BUG_ON(!mutex_is_locked(&device->mutex)); + + if (device->state != KGSL_STATE_ACTIVE) { + dev_WARN_ONCE(device->dev, 1, "device in unexpected state %s\n", + kgsl_pwrstate_to_str(device->state)); + return -EINVAL; + } + + if (device->active_cnt == 0) { + dev_WARN_ONCE(device->dev, 1, "active count is 0!\n"); + return -EINVAL; + } + + device->active_cnt++; + return 0; +} +EXPORT_SYMBOL(kgsl_active_count_get_light); + +/** + * kgsl_active_count_put() - Decrease the device active count + * @device: Pointer to a KGSL device + * + * Decrease the active count for the KGSL device and turn off + * clocks if there are no remaining references. This function will + * transition the device to NAP if there are no other pending state + * changes. It also completes the suspend gate. The device mutex must + * be held while calling this function. + */ +void kgsl_active_count_put(struct kgsl_device *device) +{ + BUG_ON(!mutex_is_locked(&device->mutex)); + BUG_ON(device->active_cnt == 0); + + kgsl_pwrscale_idle(device); + if (device->active_cnt > 1) { + device->active_cnt--; + return; + } + + INIT_COMPLETION(device->suspend_gate); + + if (device->pwrctrl.nap_allowed == true && + (device->state == KGSL_STATE_ACTIVE && + device->requested_state == KGSL_STATE_NONE)) { + kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP); + if (kgsl_pwrctrl_sleep(device) != 0) + mod_timer(&device->idle_timer, + jiffies + + device->pwrctrl.interval_timeout); + } + device->active_cnt--; + + if (device->active_cnt == 0) + complete(&device->suspend_gate); +} +EXPORT_SYMBOL(kgsl_active_count_put); + +/** + * kgsl_active_count_wait() - Wait for activity to finish. + * @device: Pointer to a KGSL device + * + * Block until all active_cnt users put() their reference. + */ +void kgsl_active_count_wait(struct kgsl_device *device) +{ + BUG_ON(!mutex_is_locked(&device->mutex)); + + if (device->active_cnt != 0) { + mutex_unlock(&device->mutex); + wait_for_completion(&device->suspend_gate); + mutex_lock(&device->mutex); + } +} +EXPORT_SYMBOL(kgsl_active_count_wait); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 8d66505c..532bb4f6 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -93,15 +93,16 @@ void kgsl_pwrctrl_close(struct kgsl_device *device); void kgsl_timer(unsigned long data); void kgsl_idle_check(struct work_struct *work); void kgsl_pre_hwaccess(struct kgsl_device *device); -void kgsl_check_suspended(struct kgsl_device *device); int kgsl_pwrctrl_sleep(struct kgsl_device *device); -void kgsl_pwrctrl_wake(struct kgsl_device *device); +int kgsl_pwrctrl_wake(struct kgsl_device *device); void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, unsigned int level); int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device); void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device); void kgsl_pwrctrl_enable(struct kgsl_device *device); void kgsl_pwrctrl_disable(struct kgsl_device *device); +bool kgsl_pwrctrl_isenabled(struct kgsl_device *device); + static inline unsigned long kgsl_get_clkrate(struct clk *clk) { return (clk != NULL) ? clk_get_rate(clk) : 0; @@ -109,4 +110,10 @@ static inline unsigned long kgsl_get_clkrate(struct clk *clk) void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state); void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); + +int kgsl_active_count_get(struct kgsl_device *device); +int kgsl_active_count_get_light(struct kgsl_device *device); +void kgsl_active_count_put(struct kgsl_device *device); +void kgsl_active_count_wait(struct kgsl_device *device); + #endif /* __KGSL_PWRCTRL_H */ diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 02ada386..afef62e5 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -240,6 +240,7 @@ void kgsl_pwrscale_busy(struct kgsl_device *device) device->pwrscale.policy->busy(device, &device->pwrscale); } +EXPORT_SYMBOL(kgsl_pwrscale_busy); void kgsl_pwrscale_idle(struct kgsl_device *device) { diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c index a6473614..db9054ba 100644 --- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c +++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c @@ -85,20 +85,14 @@ static ssize_t tz_governor_store(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale, const char *buf, size_t count) { - char str[20]; struct tz_priv *priv = pwrscale->priv; struct kgsl_pwrctrl *pwr = &device->pwrctrl; - int ret; - - ret = sscanf(buf, "%20s", str); - if (ret != 1) - return -EINVAL; mutex_lock(&device->mutex); - if (!strncmp(str, "ondemand", 8)) + if (!strncmp(buf, "ondemand", 8)) priv->governor = TZ_GOVERNOR_ONDEMAND; - else if (!strncmp(str, "performance", 11)) + else if (!strncmp(buf, "performance", 11)) priv->governor = TZ_GOVERNOR_PERFORMANCE; if (priv->governor == TZ_GOVERNOR_PERFORMANCE) diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c old mode 100755 new mode 100644 index b8dda845..424269d3 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2012,2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -65,14 +65,6 @@ struct mem_entry_stats { mem_entry_max_show), \ } - -/* - * One page allocation for a guard region to protect against over-zealous - * GPU pre-fetch - */ - -static struct page *kgsl_guard_page; - /** * Given a kobj, find the process structure attached to it */ @@ -81,12 +73,12 @@ static struct kgsl_process_private * _get_priv_from_kobj(struct kobject *kobj) { struct kgsl_process_private *private; - unsigned long name; + unsigned int name; if (!kobj) return NULL; - if (sscanf(kobj->name, "%ld", &name) != 1) + if (kstrtou32(kobj->name, 0, &name)) return NULL; list_for_each_entry(private, &kgsl_driver.process_list, list) { @@ -154,9 +146,7 @@ static struct kobj_type ktype_mem_entry = { static struct mem_entry_stats mem_stats[] = { MEM_ENTRY_STAT(KGSL_MEM_ENTRY_KERNEL, kernel), -#ifdef CONFIG_ANDROID_PMEM MEM_ENTRY_STAT(KGSL_MEM_ENTRY_PMEM, pmem), -#endif #ifdef CONFIG_ASHMEM MEM_ENTRY_STAT(KGSL_MEM_ENTRY_ASHMEM, ashmem), #endif @@ -180,17 +170,19 @@ kgsl_process_uninit_sysfs(struct kgsl_process_private *private) kobject_put(&private->kobj); } -void +int kgsl_process_init_sysfs(struct kgsl_process_private *private) { unsigned char name[16]; - int i, ret; + int i, ret = 0; snprintf(name, sizeof(name), "%d", private->pid); - if (kobject_init_and_add(&private->kobj, &ktype_mem_entry, - kgsl_driver.prockobj, name)) - return; + ret = kobject_init_and_add(&private->kobj, &ktype_mem_entry, + kgsl_driver.prockobj, name); + + if (ret) + return ret; for (i = 0; i < ARRAY_SIZE(mem_stats); i++) { /* We need to check the value of sysfs_create_file, but we @@ -201,6 +193,7 @@ kgsl_process_init_sysfs(struct kgsl_process_private *private) ret = sysfs_create_file(&private->kobj, &mem_stats[i].max_attr.attr); } + return ret; } static int kgsl_drv_memstat_show(struct device *dev, @@ -366,10 +359,6 @@ static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc) struct scatterlist *sg; int sglen = memdesc->sglen; - /* Don't free the guard page if it was used */ - if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE) - sglen--; - kgsl_driver.stats.page_alloc -= memdesc->size; if (memdesc->hostptr) { @@ -407,10 +396,6 @@ static int kgsl_page_alloc_map_kernel(struct kgsl_memdesc *memdesc) int sglen = memdesc->sglen; int i, count = 0; - /* Don't map the guard page if it exists */ - if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE) - sglen--; - /* create a list of pages to call vmap */ pages = vmalloc(npages * sizeof(struct page *)); if (!pages) { @@ -514,21 +499,29 @@ static struct kgsl_memdesc_ops kgsl_coherent_ops = { void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op) { - void *addr = memdesc->hostptr; + /* + * If the buffer is mapped in the kernel operate on that address + * otherwise use the user address + */ + + void *addr = (memdesc->hostptr) ? + memdesc->hostptr : (void *) memdesc->useraddr; + int size = memdesc->size; - switch (op) { - case KGSL_CACHE_OP_FLUSH: - dmac_flush_range(addr, addr + size); - break; - case KGSL_CACHE_OP_CLEAN: - dmac_clean_range(addr, addr + size); - break; - case KGSL_CACHE_OP_INV: - dmac_inv_range(addr, addr + size); - break; + if (addr != NULL) { + switch (op) { + case KGSL_CACHE_OP_FLUSH: + dmac_flush_range(addr, addr + size); + break; + case KGSL_CACHE_OP_CLEAN: + dmac_clean_range(addr, addr + size); + break; + case KGSL_CACHE_OP_INV: + dmac_inv_range(addr, addr + size); + break; + } } - outer_cache_range_op_sg(memdesc->sg, memdesc->sglen, op); } EXPORT_SYMBOL(kgsl_cache_range_op); @@ -536,7 +529,7 @@ EXPORT_SYMBOL(kgsl_cache_range_op); static int _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, - size_t size, unsigned int protflags) + size_t size) { int pcount = 0, order, ret = 0; int j, len, page_size, sglen_alloc, sglen = 0; @@ -550,7 +543,8 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K) ? SZ_64K : PAGE_SIZE; /* update align flags for what we actually use */ - kgsl_memdesc_set_align(memdesc, ilog2(page_size)); + if (page_size != PAGE_SIZE) + kgsl_memdesc_set_align(memdesc, ilog2(page_size)); /* * There needs to be enough room in the sg structure to be able to @@ -559,15 +553,6 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, sglen_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT; - /* - * Add guard page to the end of the allocation when the - * IOMMU is in use. - */ - - if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) - sglen_alloc++; - - memdesc->size = size; memdesc->pagetable = pagetable; memdesc->ops = &kgsl_page_alloc_ops; @@ -581,13 +566,16 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, /* * Allocate space to store the list of pages to send to vmap. - * This is an array of pointers so we can track 1024 pages per page of - * allocation which means we can handle up to a 8MB buffer request with - * two pages; well within the acceptable limits for using kmalloc. + * This is an array of pointers so we can track 1024 pages per page + * of allocation. Since allocations can be as large as the user dares, + * we have to use the kmalloc/vmalloc trick here to make sure we can + * get the memory we need. */ - pages = kmalloc(memdesc->sglen_alloc * sizeof(struct page *), - GFP_KERNEL); + if ((memdesc->sglen_alloc * sizeof(struct page *)) > PAGE_SIZE) + pages = vmalloc(memdesc->sglen_alloc * sizeof(struct page *)); + else + pages = kmalloc(PAGE_SIZE, GFP_KERNEL); if (pages == NULL) { ret = -ENOMEM; @@ -627,6 +615,14 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, continue; } + /* + * Update sglen and memdesc size,as requested allocation + * not served fully. So that they can be correctly freed + * in kgsl_sharedmem_free(). + */ + memdesc->sglen = sglen; + memdesc->size = (size - len); + KGSL_CORE_ERR( "Out of memory: only allocated %dKB of %dKB requested\n", (size - len) >> 10, size >> 10); @@ -642,27 +638,8 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, len -= page_size; } - /* Add the guard page to the end of the sglist */ - - if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) { - /* - * It doesn't matter if we use GFP_ZERO here, this never - * gets mapped, and we only allocate it once in the life - * of the system - */ - - if (kgsl_guard_page == NULL) - kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO | - __GFP_HIGHMEM); - - if (kgsl_guard_page != NULL) { - sg_set_page(&memdesc->sg[sglen++], kgsl_guard_page, - PAGE_SIZE, 0); - memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE; - } - } - memdesc->sglen = sglen; + memdesc->size = size; /* * All memory that goes to the user has to be zeroed out before it gets @@ -703,21 +680,19 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, outer_cache_range_op_sg(memdesc->sg, memdesc->sglen, KGSL_CACHE_OP_FLUSH); - ret = kgsl_mmu_map(pagetable, memdesc, protflags); - - if (ret) - goto done; - - KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc, - kgsl_driver.stats.page_alloc_max); - order = get_order(size); if (order < 16) kgsl_driver.stats.histogram[order]++; done: - kfree(pages); + KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.page_alloc, + kgsl_driver.stats.page_alloc_max); + + if ((memdesc->sglen_alloc * sizeof(struct page *)) > PAGE_SIZE) + vfree(pages); + else + kfree(pages); if (ret) kgsl_sharedmem_free(memdesc); @@ -734,8 +709,7 @@ kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc, size = ALIGN(size, PAGE_SIZE * 2); - ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size); if (!ret) ret = kgsl_page_alloc_map_kernel(memdesc); if (ret) @@ -749,17 +723,7 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size) { - unsigned int protflags; - - if (size == 0) - return -EINVAL; - - protflags = GSL_PT_PAGE_RV; - if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY)) - protflags |= GSL_PT_PAGE_WV; - - return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size, - protflags); + return _kgsl_sharedmem_page_alloc(memdesc, pagetable, PAGE_ALIGN(size)); } EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user); @@ -803,8 +767,10 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) if (memdesc == NULL || memdesc->size == 0) return; - if (memdesc->gpuaddr) + if (memdesc->gpuaddr) { kgsl_mmu_unmap(memdesc->pagetable, memdesc); + kgsl_mmu_put_gpuaddr(memdesc->pagetable, memdesc); + } if (memdesc->ops && memdesc->ops->free) memdesc->ops->free(memdesc); @@ -834,12 +800,6 @@ _kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc, result = memdesc_sg_phys(memdesc, memdesc->physaddr, size); - if (result) - goto err; - - result = kgsl_mmu_map(pagetable, memdesc, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); - if (result) goto err; diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index a895a754..c5bb8cee 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ #include "kgsl_mmu.h" #include #include +#include #include "kgsl_log.h" @@ -64,7 +65,7 @@ int kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc, void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op); -void kgsl_process_init_sysfs(struct kgsl_process_private *private); +int kgsl_process_init_sysfs(struct kgsl_process_private *private); void kgsl_process_uninit_sysfs(struct kgsl_process_private *private); int kgsl_sharedmem_init_sysfs(void); @@ -82,6 +83,18 @@ kgsl_memdesc_get_align(const struct kgsl_memdesc *memdesc) return (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT; } +/* + * kgsl_memdesc_get_cachemode - Get cache mode of a memdesc + * @memdesc: the memdesc + * + * Returns a KGSL_CACHEMODE* value. + */ +static inline int +kgsl_memdesc_get_cachemode(const struct kgsl_memdesc *memdesc) +{ + return (memdesc->flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT; +} + /* * kgsl_memdesc_set_align - Set alignment flags of a memdesc * @memdesc - the memdesc @@ -125,6 +138,9 @@ kgsl_sharedmem_map_vma(struct vm_area_struct *vma, static inline void *kgsl_sg_alloc(unsigned int sglen) { + if ((sglen == 0) || (sglen >= ULONG_MAX / sizeof(struct scatterlist))) + return NULL; + if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE) return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL); else { @@ -162,14 +178,103 @@ memdesc_sg_phys(struct kgsl_memdesc *memdesc, return 0; } +/* + * kgsl_memdesc_is_global - is this a globally mapped buffer? + * @memdesc: the memdesc + * + * Returns nonzero if this is a global mapping, 0 otherwise + */ +static inline int kgsl_memdesc_is_global(const struct kgsl_memdesc *memdesc) +{ + return (memdesc->priv & KGSL_MEMDESC_GLOBAL) != 0; +} + +/* + * kgsl_memdesc_has_guard_page - is the last page a guard page? + * @memdesc - the memdesc + * + * Returns nonzero if there is a guard page, 0 otherwise + */ +static inline int +kgsl_memdesc_has_guard_page(const struct kgsl_memdesc *memdesc) +{ + return (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE) != 0; +} + +/* + * kgsl_memdesc_protflags - get mmu protection flags + * @memdesc - the memdesc + * Returns a mask of GSL_PT_PAGE* or IOMMU* values based + * on the memdesc flags. + */ +static inline unsigned int +kgsl_memdesc_protflags(const struct kgsl_memdesc *memdesc) +{ + unsigned int protflags = 0; + enum kgsl_mmutype mmutype = kgsl_mmu_get_mmutype(); + + if (mmutype == KGSL_MMU_TYPE_GPU) { + protflags = GSL_PT_PAGE_RV; + if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY)) + protflags |= GSL_PT_PAGE_WV; + } else if (mmutype == KGSL_MMU_TYPE_IOMMU) { + protflags = IOMMU_READ; + if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY)) + protflags |= IOMMU_WRITE; + } + return protflags; +} + +/* + * kgsl_memdesc_use_cpu_map - use the same virtual mapping on CPU and GPU? + * @memdesc - the memdesc + */ +static inline int +kgsl_memdesc_use_cpu_map(const struct kgsl_memdesc *memdesc) +{ + return (memdesc->flags & KGSL_MEMFLAGS_USE_CPU_MAP) != 0; +} + +/* + * kgsl_memdesc_mmapsize - get the size of the mmap region + * @memdesc - the memdesc + * + * The entire memdesc must be mapped. Additionally if the + * CPU mapping is going to be mirrored, there must be room + * for the guard page to be mapped so that the address spaces + * match up. + */ +static inline unsigned int +kgsl_memdesc_mmapsize(const struct kgsl_memdesc *memdesc) +{ + unsigned int size = memdesc->size; + if (kgsl_memdesc_use_cpu_map(memdesc) && + kgsl_memdesc_has_guard_page(memdesc)) + size += SZ_4K; + return size; +} + static inline int kgsl_allocate(struct kgsl_memdesc *memdesc, struct kgsl_pagetable *pagetable, size_t size) { + int ret; + memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT); if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE) return kgsl_sharedmem_ebimem(memdesc, pagetable, size); - memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT); - return kgsl_sharedmem_page_alloc(memdesc, pagetable, size); + + ret = kgsl_sharedmem_page_alloc(memdesc, pagetable, size); + if (ret) + return ret; + ret = kgsl_mmu_get_gpuaddr(pagetable, memdesc); + if (ret) { + kgsl_sharedmem_free(memdesc); + return ret; + } + ret = kgsl_mmu_map(pagetable, memdesc); + if (ret) + kgsl_sharedmem_free(memdesc); + return ret; } static inline int @@ -179,6 +284,9 @@ kgsl_allocate_user(struct kgsl_memdesc *memdesc, { int ret; + if (size == 0) + return -EINVAL; + memdesc->flags = flags; if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE) @@ -200,15 +308,4 @@ kgsl_allocate_contiguous(struct kgsl_memdesc *memdesc, size_t size) return ret; } -static inline int kgsl_sg_size(struct scatterlist *sg, int sglen) -{ - int i, size = 0; - struct scatterlist *s; - - for_each_sg(sg, s, sglen, i) { - size += s->length; - } - - return size; -} #endif /* __KGSL_SHAREDMEM_H */ diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index a5aa42f2..7ae65f0f 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -106,7 +106,12 @@ static int snapshot_context_info(int id, void *ptr, void *data) { struct kgsl_snapshot_linux_context *header = _ctxtptr; struct kgsl_context *context = ptr; - struct kgsl_device *device = context->dev_priv->device; + struct kgsl_device *device; + + if (context) + device = context->dev_priv->device; + else + device = (struct kgsl_device *)data; header->id = id; @@ -139,7 +144,12 @@ static int snapshot_os(struct kgsl_device *device, /* Figure out how many active contexts there are - these will * be appended on the end of the structure */ + read_lock(&device->context_lock); idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount); + read_unlock(&device->context_lock); + + /* Increment ctxcount for the global memstore */ + ctxtcount++; size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context); @@ -169,8 +179,9 @@ static int snapshot_os(struct kgsl_device *device, header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]); header->busclk = kgsl_get_clkrate(pwr->ebi1_clk); - /* Future proof for per-context timestamps */ - header->current_context = -1; + /* Save the last active context */ + kgsl_sharedmem_readl(&device->memstore, &header->current_context, + KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context)); /* Get the current PT base */ header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu); @@ -185,9 +196,16 @@ static int snapshot_os(struct kgsl_device *device, header->ctxtcount = ctxtcount; - /* append information for each context */ _ctxtptr = snapshot + sizeof(*header); + + /* append information for the global context */ + snapshot_context_info(KGSL_MEMSTORE_GLOBAL, NULL, device); + + /* append information for each context */ + + read_lock(&device->context_lock); idr_for_each(&device->context_idr, snapshot_context_info, NULL); + read_unlock(&device->context_lock); /* Return the size of the data segment */ return size; @@ -283,7 +301,7 @@ static void kgsl_snapshot_put_object(struct kgsl_device *device, { list_del(&obj->node); - obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN; + obj->entry->memdesc.priv &= ~KGSL_MEMDESC_FROZEN; kgsl_mem_entry_put(obj->entry); kfree(obj); @@ -314,6 +332,7 @@ int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase, return 0; } +EXPORT_SYMBOL(kgsl_snapshot_have_object); /* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen * @device - the device that is being snapshotted @@ -333,6 +352,10 @@ int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase, struct kgsl_mem_entry *entry; struct kgsl_snapshot_object *obj; int offset; + int ret = -EINVAL; + + if (!gpuaddr) + return 0; entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size); @@ -346,7 +369,7 @@ int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase, if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) { KGSL_DRV_ERR(device, "Only internal GPU buffers can be frozen\n"); - return -EINVAL; + goto err_put; } /* @@ -369,36 +392,33 @@ int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase, if (size + offset > entry->memdesc.size) { KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n", gpuaddr); - return -EINVAL; + goto err_put; } /* If the buffer is already on the list, skip it */ list_for_each_entry(obj, &device->snapshot_obj_list, node) { if (obj->gpuaddr == gpuaddr && obj->ptbase == ptbase) { - /* If the size is different, use the new size */ - if (obj->size != size) + /* If the size is different, use the bigger size */ + if (obj->size < size) obj->size = size; - - return 0; + ret = 0; + goto err_put; } } if (kgsl_memdesc_map(&entry->memdesc) == NULL) { KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n", gpuaddr); - return -EINVAL; + goto err_put; } obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (obj == NULL) { KGSL_DRV_ERR(device, "Unable to allocate memory\n"); - return -EINVAL; + goto err_put; } - /* Ref count the mem entry */ - kgsl_mem_entry_get(entry); - obj->type = type; obj->entry = entry; obj->gpuaddr = gpuaddr; @@ -416,12 +436,15 @@ int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase, * 0 so it doesn't get counted twice */ - if (entry->flags & KGSL_MEM_ENTRY_FROZEN) - return 0; + ret = (entry->memdesc.priv & KGSL_MEMDESC_FROZEN) ? 0 + : entry->memdesc.size; - entry->flags |= KGSL_MEM_ENTRY_FROZEN; + entry->memdesc.priv |= KGSL_MEMDESC_FROZEN; - return entry->memdesc.size; + return ret; +err_put: + kgsl_mem_entry_put(entry); + return ret; } EXPORT_SYMBOL(kgsl_snapshot_get_object); @@ -519,6 +542,16 @@ int kgsl_device_snapshot(struct kgsl_device *device, int hang) int remain = device->snapshot_maxsize - sizeof(*header); void *snapshot; struct timespec boot; + int ret = 0; + + /* + * Bail if failed to get active count for GPU, + * try again + */ + if (kgsl_active_count_get(device)) { + KGSL_DRV_ERR(device, "Failed to get GPU active count"); + return -EINVAL; + } /* * The first hang is always the one we are interested in. To @@ -529,19 +562,23 @@ int kgsl_device_snapshot(struct kgsl_device *device, int hang) * of the state and never frozen. */ - if (hang && device->snapshot_frozen == 1) - return 0; + if (hang && device->snapshot_frozen == 1) { + ret = 0; + goto done; + } if (device->snapshot == NULL) { KGSL_DRV_ERR(device, "snapshot: No snapshot memory available\n"); - return -ENOMEM; + ret = -ENOMEM; + goto done; } if (remain < sizeof(*header)) { KGSL_DRV_ERR(device, "snapshot: Not enough memory for the header\n"); - return -ENOMEM; + ret = -ENOMEM; + goto done; } header->magic = SNAPSHOT_MAGIC; @@ -577,7 +614,10 @@ int kgsl_device_snapshot(struct kgsl_device *device, int hang) __pa(device->snapshot), device->snapshot_size); if (hang) sysfs_notify(&device->snapshot_kobj, NULL, "timestamp"); - return 0; + +done: + kgsl_active_count_put(device); + return ret; } EXPORT_SYMBOL(kgsl_device_snapshot); diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h index 327d18a1..4db2815c 100644 --- a/drivers/gpu/msm/kgsl_snapshot.h +++ b/drivers/gpu/msm/kgsl_snapshot.h @@ -52,6 +52,7 @@ struct kgsl_snapshot_section_header { #define KGSL_SNAPSHOT_SECTION_DEBUG 0x0901 #define KGSL_SNAPSHOT_SECTION_DEBUGBUS 0x0A01 #define KGSL_SNAPSHOT_SECTION_GPU_OBJECT 0x0B01 +#define KGSL_SNAPSHOT_SECTION_MEMLIST 0x0E01 #define KGSL_SNAPSHOT_SECTION_END 0xFFFF @@ -103,6 +104,17 @@ struct kgsl_snapshot_rb { int count; /* Number of dwords in the dump */ } __packed; +/* Replay or Memory list section, both sections have same header */ +struct kgsl_snapshot_replay_mem_list { + /* + * Number of IBs to replay for replay section or + * number of memory list entries for mem list section + */ + int num_entries; + /* Pagetable base to which the replay IBs or memory entries belong */ + __u32 ptbase; +} __packed; + /* Indirect buffer sub-section header */ struct kgsl_snapshot_ib { __u32 gpuaddr; /* GPU address of the the IB */ diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index 813305ad..8fa8502d 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -12,9 +12,12 @@ */ #include +#include #include #include +#include + #include "kgsl_sync.h" struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline, @@ -83,9 +86,11 @@ struct kgsl_fence_event_priv { */ static inline void kgsl_fence_event_cb(struct kgsl_device *device, - void *priv, u32 context_id, u32 timestamp) + void *priv, u32 context_id, u32 timestamp, u32 type) { struct kgsl_fence_event_priv *ev = priv; + + /* Signal event time timeline for every event type */ kgsl_sync_timeline_signal(ev->context->timeline, ev->timestamp); kgsl_context_put(ev->context); kfree(ev); @@ -118,16 +123,19 @@ int kgsl_add_fence_event(struct kgsl_device *device, if (len != sizeof(priv)) return -EINVAL; - context = kgsl_find_context(owner, context_id); - if (context == NULL) - return -EINVAL; - event = kzalloc(sizeof(*event), GFP_KERNEL); if (event == NULL) return -ENOMEM; + + context = kgsl_context_get_owner(owner, context_id); + + if (context == NULL) { + kfree(event); + return -EINVAL; + } + event->context = context; event->timestamp = timestamp; - kgsl_context_get(context); pt = kgsl_sync_pt_create(context->timeline, timestamp); if (pt == NULL) { @@ -158,6 +166,10 @@ int kgsl_add_fence_event(struct kgsl_device *device, goto fail_copy_fd; } + /* + * Hold the context ref-count for the event - it will get released in + * the callback + */ ret = kgsl_add_event(device, context_id, timestamp, kgsl_fence_event_cb, event, owner); if (ret) @@ -168,7 +180,6 @@ int kgsl_add_fence_event(struct kgsl_device *device, fail_event: fail_copy_fd: /* clean up sync_fence_install */ - sync_fence_put(fence); put_unused_fd(priv.fence_fd); fail_fd: /* clean up sync_fence_create */ @@ -180,24 +191,81 @@ int kgsl_add_fence_event(struct kgsl_device *device, return ret; } +static unsigned int kgsl_sync_get_timestamp( + struct kgsl_sync_timeline *ktimeline, enum kgsl_timestamp_type type) +{ + unsigned int ret = 0; + + struct kgsl_context *context = kgsl_context_get(ktimeline->device, + ktimeline->context_id); + + if (context) + ret = kgsl_readtimestamp(ktimeline->device, context, type); + + kgsl_context_put(context); + return ret; +} + +static void kgsl_sync_timeline_value_str(struct sync_timeline *sync_timeline, + char *str, int size) +{ + struct kgsl_sync_timeline *ktimeline = + (struct kgsl_sync_timeline *) sync_timeline; + unsigned int timestamp_retired = kgsl_sync_get_timestamp(ktimeline, + KGSL_TIMESTAMP_RETIRED); + snprintf(str, size, "%u retired:%u", ktimeline->last_timestamp, + timestamp_retired); +} + +static void kgsl_sync_pt_value_str(struct sync_pt *sync_pt, + char *str, int size) +{ + struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) sync_pt; + snprintf(str, size, "%u", kpt->timestamp); +} + +static void kgsl_sync_timeline_release_obj(struct sync_timeline *sync_timeline) +{ + /* + * Make sure to free the timeline only after destroy flag is set. + * This is to avoid further accessing to the timeline from KGSL and + * also to catch any unbalanced kref of timeline. + */ + BUG_ON(sync_timeline && (sync_timeline->destroyed != true)); +} static const struct sync_timeline_ops kgsl_sync_timeline_ops = { .driver_name = "kgsl-timeline", .dup = kgsl_sync_pt_dup, .has_signaled = kgsl_sync_pt_has_signaled, .compare = kgsl_sync_pt_compare, + .timeline_value_str = kgsl_sync_timeline_value_str, + .pt_value_str = kgsl_sync_pt_value_str, + .release_obj = kgsl_sync_timeline_release_obj, }; int kgsl_sync_timeline_create(struct kgsl_context *context) { struct kgsl_sync_timeline *ktimeline; + /* Generate a name which includes the thread name, thread id, process + * name, process id, and context id. This makes it possible to + * identify the context of a timeline in the sync dump. */ + char ktimeline_name[sizeof(context->timeline->name)] = {}; + snprintf(ktimeline_name, sizeof(ktimeline_name), + "%s_%.15s(%d)-%.15s(%d)-%d", + context->dev_priv->device->name, + current->group_leader->comm, current->group_leader->pid, + current->comm, current->pid, context->id); + context->timeline = sync_timeline_create(&kgsl_sync_timeline_ops, - (int) sizeof(struct kgsl_sync_timeline), "kgsl-timeline"); + (int) sizeof(struct kgsl_sync_timeline), ktimeline_name); if (context->timeline == NULL) return -EINVAL; ktimeline = (struct kgsl_sync_timeline *) context->timeline; ktimeline->last_timestamp = 0; + ktimeline->device = context->dev_priv->device; + ktimeline->context_id = context->id; return 0; } diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h index 06b3ad0d..63adf06a 100644 --- a/drivers/gpu/msm/kgsl_sync.h +++ b/drivers/gpu/msm/kgsl_sync.h @@ -19,6 +19,8 @@ struct kgsl_sync_timeline { struct sync_timeline timeline; unsigned int last_timestamp; + struct kgsl_device *device; + u32 context_id; }; struct kgsl_sync_pt { diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h index c54445ca..7943be80 100644 --- a/drivers/gpu/msm/kgsl_trace.h +++ b/drivers/gpu/msm/kgsl_trace.h @@ -24,6 +24,8 @@ #include #include "kgsl_device.h" +#include "adreno_drawctxt.h" + struct kgsl_device; struct kgsl_ringbuffer_issueibcmds; struct kgsl_device_waittimestamp; @@ -34,11 +36,16 @@ struct kgsl_device_waittimestamp; TRACE_EVENT(kgsl_issueibcmds, TP_PROTO(struct kgsl_device *device, - struct kgsl_ringbuffer_issueibcmds *cmd, + int drawctxt_id, struct kgsl_ibdesc *ibdesc, - int result), + int numibs, + int timestamp, + int flags, + int result, + unsigned int type), - TP_ARGS(device, cmd, ibdesc, result), + TP_ARGS(device, drawctxt_id, ibdesc, numibs, timestamp, flags, + result, type), TP_STRUCT__entry( __string(device_name, device->name) @@ -48,21 +55,23 @@ TRACE_EVENT(kgsl_issueibcmds, __field(unsigned int, timestamp) __field(unsigned int, flags) __field(int, result) + __field(unsigned int, drawctxt_type) ), TP_fast_assign( __assign_str(device_name, device->name); - __entry->drawctxt_id = cmd->drawctxt_id; + __entry->drawctxt_id = drawctxt_id; __entry->ibdesc_addr = ibdesc[0].gpuaddr; - __entry->numibs = cmd->numibs; - __entry->timestamp = cmd->timestamp; - __entry->flags = cmd->flags; + __entry->numibs = numibs; + __entry->timestamp = timestamp; + __entry->flags = flags; __entry->result = result; + __entry->drawctxt_type = type; ), TP_printk( "d_name=%s ctx=%u ib=0x%u numibs=%u timestamp=0x%x " - "flags=0x%x(%s) result=%d", + "flags=0x%x(%s) result=%d type=%s", __get_str(device_name), __entry->drawctxt_id, __entry->ibdesc_addr, @@ -74,7 +83,9 @@ TRACE_EVENT(kgsl_issueibcmds, { KGSL_CONTEXT_SUBMIT_IB_LIST, "IB_LIST" }, { KGSL_CONTEXT_CTX_SWITCH, "CTX_SWITCH" }) : "None", - __entry->result + __entry->result, + __print_symbolic(__entry->drawctxt_type, + ADRENO_DRAWCTXT_TYPES) ) ); @@ -317,6 +328,8 @@ TRACE_EVENT(kgsl_mem_alloc, __field(unsigned int, size) __field(unsigned int, tgid) __array(char, usage, 16) + __field(unsigned int, id) + __field(unsigned int, flags) ), TP_fast_assign( @@ -325,12 +338,76 @@ TRACE_EVENT(kgsl_mem_alloc, __entry->tgid = mem_entry->priv->pid; kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage), mem_entry->memdesc.flags); + __entry->id = mem_entry->id; + __entry->flags = mem_entry->memdesc.flags; ), TP_printk( - "gpuaddr=0x%08x size=%d tgid=%d usage=%s", + "gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d flags=0x%08x", __entry->gpuaddr, __entry->size, __entry->tgid, - __entry->usage + __entry->usage, __entry->id, __entry->flags + ) +); + +TRACE_EVENT(kgsl_mem_mmap, + + TP_PROTO(struct kgsl_mem_entry *mem_entry), + + TP_ARGS(mem_entry), + + TP_STRUCT__entry( + __field(unsigned long, useraddr) + __field(unsigned int, gpuaddr) + __field(unsigned int, size) + __array(char, usage, 16) + __field(unsigned int, id) + __field(unsigned int, flags) + ), + + TP_fast_assign( + __entry->useraddr = mem_entry->memdesc.useraddr; + __entry->gpuaddr = mem_entry->memdesc.gpuaddr; + __entry->size = mem_entry->memdesc.size; + kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage), + mem_entry->memdesc.flags); + __entry->id = mem_entry->id; + __entry->flags = mem_entry->memdesc.flags; + ), + + TP_printk( + "useraddr=%lx gpuaddr=0x%08x size=%d usage=%s id=%d" + " flags=0x%08x", + __entry->useraddr, __entry->gpuaddr, __entry->size, + __entry->usage, __entry->id, __entry->flags + ) +); + +TRACE_EVENT(kgsl_mem_unmapped_area_collision, + + TP_PROTO(struct kgsl_mem_entry *mem_entry, + unsigned long hint, + unsigned long len, + unsigned long addr), + + TP_ARGS(mem_entry, hint, len, addr), + + TP_STRUCT__entry( + __field(unsigned int, id) + __field(unsigned long, hint) + __field(unsigned long, len) + __field(unsigned long, addr) + ), + + TP_fast_assign( + __entry->id = mem_entry->id; + __entry->hint = hint; + __entry->len = len; + __entry->addr = addr; + ), + + TP_printk( + "id=%d hint=0x%lx len=%ld addr=0x%lx", + __entry->id, __entry->hint, __entry->len, __entry->addr ) ); @@ -347,6 +424,7 @@ TRACE_EVENT(kgsl_mem_map, __field(int, type) __field(unsigned int, tgid) __array(char, usage, 16) + __field(unsigned int, id) ), TP_fast_assign( @@ -357,13 +435,14 @@ TRACE_EVENT(kgsl_mem_map, __entry->tgid = mem_entry->priv->pid; kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage), mem_entry->memdesc.flags); + __entry->id = mem_entry->id; ), TP_printk( - "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage %s", + "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage=%s id=%d", __entry->gpuaddr, __entry->size, __entry->type, __entry->fd, __entry->tgid, - __entry->usage + __entry->usage, __entry->id ) ); @@ -380,6 +459,7 @@ TRACE_EVENT(kgsl_mem_free, __field(int, fd) __field(unsigned int, tgid) __array(char, usage, 16) + __field(unsigned int, id) ), TP_fast_assign( @@ -389,12 +469,13 @@ TRACE_EVENT(kgsl_mem_free, __entry->tgid = mem_entry->priv->pid; kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage), mem_entry->memdesc.flags); + __entry->id = mem_entry->id; ), TP_printk( - "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s", + "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s id=%d", __entry->gpuaddr, __entry->size, __entry->type, - __entry->tgid, __entry->usage + __entry->tgid, __entry->usage, __entry->id ) ); @@ -411,6 +492,7 @@ DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template, __field(unsigned int, size) __field(int, type) __array(char, usage, 16) + __field(unsigned int, id) __field(unsigned int, drawctxt_id) __field(unsigned int, curr_ts) __field(unsigned int, free_ts) @@ -422,6 +504,7 @@ DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template, __entry->size = mem_entry->memdesc.size; kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage), mem_entry->memdesc.flags); + __entry->id = mem_entry->id; __entry->drawctxt_id = id; __entry->type = mem_entry->memtype; __entry->curr_ts = curr_ts; @@ -429,13 +512,14 @@ DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template, ), TP_printk( - "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s ctx=%u" + "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s id=%d ctx=%u" " curr_ts=0x%x free_ts=0x%x", __get_str(device_name), __entry->gpuaddr, __entry->size, __entry->type, __entry->usage, + __entry->id, __entry->drawctxt_id, __entry->curr_ts, __entry->free_ts @@ -553,21 +637,48 @@ TRACE_EVENT(kgsl_register_event, TRACE_EVENT(kgsl_fire_event, TP_PROTO(unsigned int id, unsigned int ts, - unsigned int age), - TP_ARGS(id, ts, age), + unsigned int type, unsigned int age), + TP_ARGS(id, ts, type, age), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, ts) + __field(unsigned int, type) __field(unsigned int, age) ), TP_fast_assign( __entry->id = id; __entry->ts = ts; + __entry->type = type; __entry->age = age; ), TP_printk( - "ctx=%d ts=%d age=%u", - __entry->id, __entry->ts, __entry->age) + "ctx=%d ts=%d type=%d age=%u", + __entry->id, __entry->ts, __entry->type, __entry->age) +); + +TRACE_EVENT(kgsl_regwrite, + + TP_PROTO(struct kgsl_device *device, unsigned int offset, + unsigned int value), + + TP_ARGS(device, offset, value), + + TP_STRUCT__entry( + __string(device_name, device->name) + __field(unsigned int, offset) + __field(unsigned int, value) + ), + + TP_fast_assign( + __assign_str(device_name, device->name); + __entry->offset = offset; + __entry->value = value; + ), + + TP_printk( + "d_name=%s reg=%x value=%x", + __get_str(device_name), __entry->offset, __entry->value + ) ); #endif /* _KGSL_TRACE_H */ diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c index cfa39b2b..95b3abbd 100644 --- a/drivers/gpu/msm/z180.c +++ b/drivers/gpu/msm/z180.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -93,7 +93,8 @@ enum z180_cmdwindow_type { #define Z180_CMDWINDOW_TARGET_SHIFT 0 #define Z180_CMDWINDOW_ADDR_SHIFT 8 -static int z180_start(struct kgsl_device *device, unsigned int init_ram); +static int z180_init(struct kgsl_device *device); +static int z180_start(struct kgsl_device *device); static int z180_stop(struct kgsl_device *device); static int z180_wait(struct kgsl_device *device, struct kgsl_context *context, @@ -123,6 +124,9 @@ static void z180_cmdwindow_write(struct kgsl_device *device, | (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT) \ | (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT)) +/*default log levels is error for everything*/ +#define KGSL_LOG_LEVEL_DEFAULT 3 + static const struct kgsl_functable z180_functable; static struct z180_device device_2d0 = { @@ -148,6 +152,13 @@ static struct z180_device device_2d0 = { }, .iomemname = KGSL_2D0_REG_MEMORY, .ftbl = &z180_functable, + .cmd_log = KGSL_LOG_LEVEL_DEFAULT, + .ctxt_log = KGSL_LOG_LEVEL_DEFAULT, + .drv_log = KGSL_LOG_LEVEL_DEFAULT, + .mem_log = KGSL_LOG_LEVEL_DEFAULT, + .pwr_log = KGSL_LOG_LEVEL_DEFAULT, + .ft_log = KGSL_LOG_LEVEL_DEFAULT, + .pm_dump_enable = 0, }, .cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock), }; @@ -175,6 +186,13 @@ static struct z180_device device_2d1 = { }, .iomemname = KGSL_2D1_REG_MEMORY, .ftbl = &z180_functable, + .cmd_log = KGSL_LOG_LEVEL_DEFAULT, + .ctxt_log = KGSL_LOG_LEVEL_DEFAULT, + .drv_log = KGSL_LOG_LEVEL_DEFAULT, + .mem_log = KGSL_LOG_LEVEL_DEFAULT, + .pwr_log = KGSL_LOG_LEVEL_DEFAULT, + .ft_log = KGSL_LOG_LEVEL_DEFAULT, + .pm_dump_enable = 0, }, .cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock), }; @@ -244,22 +262,26 @@ static int z180_setup_pt(struct kgsl_device *device, int result = 0; struct z180_device *z180_dev = Z180_DEVICE(device); - result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory); if (result) goto error; - result = kgsl_mmu_map_global(pagetable, &device->memstore, - GSL_PT_PAGE_RV | GSL_PT_PAGE_WV); + result = kgsl_mmu_map_global(pagetable, &device->memstore); if (result) goto error_unmap_dummy; result = kgsl_mmu_map_global(pagetable, - &z180_dev->ringbuffer.cmdbufdesc, - GSL_PT_PAGE_RV); + &z180_dev->ringbuffer.cmdbufdesc); if (result) goto error_unmap_memstore; + /* + * Set the mpu end to the last "normal" global memory we use. + * For the IOMMU, this will be used to restrict access to the + * mapped registers. + */ + device->mh.mpu_range = z180_dev->ringbuffer.cmdbufdesc.gpuaddr + + z180_dev->ringbuffer.cmdbufdesc.size; return result; error_unmap_dummy: @@ -315,16 +337,11 @@ static void addcmd(struct z180_ringbuffer *rb, unsigned int timestamp, *p++ = ADDR_VGV3_LAST << 24; } -static void z180_cmdstream_start(struct kgsl_device *device, int init_ram) +static void z180_cmdstream_start(struct kgsl_device *device) { struct z180_device *z180_dev = Z180_DEVICE(device); unsigned int cmd = VGV3_NEXTCMD_JUMP << VGV3_NEXTCMD_NEXTCMD_FSHIFT; - if (init_ram) { - z180_dev->timestamp = 0; - z180_dev->current_timestamp = 0; - } - addmarker(&z180_dev->ringbuffer, 0); z180_cmdwindow_write(device, ADDR_VGV3_MODE, 4); @@ -424,7 +441,7 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, "Cannot make kernel mapping for gpuaddr 0x%x\n", cmd); result = -EINVAL; - goto error; + goto error_put; } KGSL_CMD_INFO(device, "ctxt %d ibaddr 0x%08x sizedwords %d\n", @@ -450,7 +467,7 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, if (result < 0) { KGSL_CMD_ERR(device, "wait_event_interruptible_timeout " "failed: %ld\n", result); - goto error; + goto error_put; } result = 0; @@ -482,7 +499,13 @@ z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv, z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, cmd); z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0); +error_put: + kgsl_mem_entry_put(entry); error: + + kgsl_trace_issueibcmds(device, context->id, ibdesc, numibs, + *timestamp, ctrl, result, 0); + return (int)result; } @@ -491,6 +514,7 @@ static int z180_ringbuffer_init(struct kgsl_device *device) struct z180_device *z180_dev = Z180_DEVICE(device); memset(&z180_dev->ringbuffer, 0, sizeof(struct z180_ringbuffer)); z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT; + z180_dev->ringbuffer.cmdbufdesc.flags = KGSL_MEMFLAGS_GPUREADONLY; return kgsl_allocate_contiguous(&z180_dev->ringbuffer.cmdbufdesc, Z180_RB_SIZE); } @@ -547,7 +571,17 @@ static int __devexit z180_remove(struct platform_device *pdev) return 0; } -static int z180_start(struct kgsl_device *device, unsigned int init_ram) +static int z180_init(struct kgsl_device *device) +{ + struct z180_device *z180_dev = Z180_DEVICE(device); + + z180_dev->timestamp = 0; + z180_dev->current_timestamp = 0; + + return 0; +} + +static int z180_start(struct kgsl_device *device) { int status = 0; @@ -564,11 +598,14 @@ static int z180_start(struct kgsl_device *device, unsigned int init_ram) if (status) goto error_clk_off; - z180_cmdstream_start(device, init_ram); + z180_cmdstream_start(device); mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); device->ftbl->irqctrl(device, 1); + + device->reset_counter++; + return 0; error_clk_off: @@ -806,13 +843,29 @@ static int z180_waittimestamp(struct kgsl_device *device, unsigned int msecs) { int status = -EINVAL; + long timeout = 0; - /* Don't wait forever, set a max (10 sec) value for now */ + /* Don't wait forever, set a max (20 sec) value for now */ if (msecs == -1) - msecs = 10 * MSEC_PER_SEC; + msecs = 20 * MSEC_PER_SEC; mutex_unlock(&device->mutex); - status = z180_wait(device, context, timestamp, msecs); + timeout = wait_io_event_interruptible_timeout( + device->wait_queue, + kgsl_check_timestamp(device, context, timestamp), + msecs_to_jiffies(msecs)); + + if (timeout > 0) + status = 0; + else if (timeout == 0) { + status = -ETIMEDOUT; + mutex_lock(&device->mutex); + kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG); + kgsl_postmortem_dump(device, 0); + mutex_unlock(&device->mutex); + } else + status = timeout; + mutex_lock(&device->mutex); return status; @@ -911,6 +964,7 @@ static const struct kgsl_functable z180_functable = { .idle = z180_idle, .isidle = z180_isidle, .suspend_context = z180_suspend_context, + .init = z180_init, .start = z180_start, .stop = z180_stop, .getproperty = z180_getproperty, diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h index 268aac3e..e247d10a 100644 --- a/drivers/gpu/msm/z180.h +++ b/drivers/gpu/msm/z180.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2012,2014 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,8 +28,8 @@ #define Z180_DEFAULT_PWRSCALE_POLICY NULL -/* Wait a maximum of 10 seconds when trying to idle the core */ -#define Z180_IDLE_TIMEOUT (10 * 1000) +/* Wait a maximum of 20 seconds when trying to idle the core */ +#define Z180_IDLE_TIMEOUT (20 * 1000) struct z180_ringbuffer { unsigned int prevctx; diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c index c1e5f07c..55b8faa3 100644 --- a/drivers/gpu/msm/z180_postmortem.c +++ b/drivers/gpu/msm/z180_postmortem.c @@ -168,6 +168,7 @@ static void z180_dump_ib(struct kgsl_device *device) KGSL_LOG_DUMP(device, "Could not map IB to kernel memory, Ringbuffer Slot: %d\n", rb_slot_num); + kgsl_mem_entry_put(entry); continue; } @@ -190,6 +191,7 @@ static void z180_dump_ib(struct kgsl_device *device) linebuf); } KGSL_LOG_DUMP(device, "IB Dump Finished\n"); + kgsl_mem_entry_put(entry); } } } diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h index c000fa47..0eb21dc8 100644 --- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h +++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h @@ -13,7 +13,7 @@ #ifndef _MPQ_DMX_PLUGIN_COMMON_H #define _MPQ_DMX_PLUGIN_COMMON_H -#include +#include #include "dvbdev.h" #include "dmxdev.h" diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c index 0f44897d..4244ea30 100644 --- a/drivers/media/video/msm/actuators/msm_actuator.c +++ b/drivers/media/video/msm/actuators/msm_actuator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2012, 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 @@ -67,11 +67,9 @@ int32_t msm_actuator_i2c_write(struct msm_actuator_ctrl_t *a_ctrl, struct msm_actuator_reg_params_t *write_arr = a_ctrl->reg_tbl; uint32_t hw_dword = hw_params; uint16_t i2c_byte1 = 0, i2c_byte2 = 0; - uint32_t value = 0; + uint16_t value = 0; uint32_t size = a_ctrl->reg_tbl_size, i = 0; int32_t rc = 0; - unsigned char buf[4]; - int length = 0; CDBG("%s: IN\n", __func__); for (i = 0; i < size; i++) { if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) { @@ -84,7 +82,7 @@ int32_t msm_actuator_i2c_write(struct msm_actuator_ctrl_t *a_ctrl, i2c_byte1 = write_arr[i].reg_addr; i2c_byte2 = value; if (size != (i+1)) { - i2c_byte2 = value & 0xFF; + i2c_byte2 = (i2c_byte2 & 0xFF00) >> 8; CDBG("%s: byte1:0x%x, byte2:0x%x\n", __func__, i2c_byte1, i2c_byte2); rc = msm_camera_i2c_write( @@ -99,33 +97,13 @@ int32_t msm_actuator_i2c_write(struct msm_actuator_ctrl_t *a_ctrl, i++; i2c_byte1 = write_arr[i].reg_addr; - i2c_byte2 = (value & 0xFF00) >> 8; + i2c_byte2 = value & 0xFF; } } else { i2c_byte1 = (value & 0xFF00) >> 8; i2c_byte2 = value & 0xFF; } - } - else if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC_AD5823) { - value = (next_lens_position << - write_arr[i].data_shift) | - ((hw_dword & write_arr[i].hw_mask) << - write_arr[i].hw_shift); - - buf[0] = write_arr[i].reg_addr; - buf[1] = (value & 0xff00)>>8;//MSB - buf[2] = value & 0xff;//LSB - length = 3; - CDBG("%s: position is 0x%x, MSB0x%x, LSB:0x%x\r\n", __func__, value, buf[1], buf[2]); - rc = msm_camera_i2c_txdata(&a_ctrl->i2c_client, buf, length); - if (rc < 0) { - pr_err("%s: i2c write error:%d\n", - __func__, rc); - return rc; - } - break; - } - else { + } else { i2c_byte1 = write_arr[i].reg_addr; i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >> write_arr[i].hw_shift; @@ -215,6 +193,8 @@ int32_t msm_actuator_write_focus( } curr_lens_pos = next_lens_pos; usleep(wait_time); + if(0 == damping_code_step) + break; } if (curr_lens_pos != code_boundary) { @@ -315,6 +295,7 @@ int32_t msm_actuator_move_focus( target_step_pos = dest_step_pos; target_lens_pos = a_ctrl->step_position_table[target_step_pos]; + /*change from Qualcomm. delete some codes*/ rc = a_ctrl->func_tbl-> actuator_write_focus( a_ctrl, @@ -334,6 +315,7 @@ int32_t msm_actuator_move_focus( target_step_pos = step_boundary; target_lens_pos = a_ctrl->step_position_table[target_step_pos]; + /*change from Qualcomm. delete some codes*/ rc = a_ctrl->func_tbl-> actuator_write_focus( a_ctrl, @@ -469,8 +451,7 @@ int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl, } a_ctrl->total_steps = set_info->af_tuning_params.total_steps; a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step; - a_ctrl->total_steps = set_info->af_tuning_params.total_steps; - + //delete this line for it is a duplicated written as the line before if (copy_from_user(&a_ctrl->region_params, (void *)set_info->af_tuning_params.region_params, a_ctrl->region_size * sizeof(struct region_params_t))) diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c index 6550c92c..3c038cc0 100644 --- a/drivers/media/video/msm/gemini/msm_gemini_platform.c +++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -35,9 +34,6 @@ void msm_gemini_platform_p2v(struct file *file, ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL); ion_free(gemini_client, *ionhandle); *ionhandle = NULL; -#elif CONFIG_ANDROID_PMEM - put_pmem_file(file); -#endif } uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p, @@ -53,9 +49,6 @@ uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p, rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL, SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0); -#elif CONFIG_ANDROID_PMEM - unsigned long kvstart; - rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p); #else rc = 0; paddr = 0; diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c index 656630a8..ffa5ee93 100644 --- a/drivers/media/video/msm/msm_camera.c +++ b/drivers/media/video/msm/msm_camera.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -318,15 +317,6 @@ static int msm_pmem_table_add(struct hlist_head *ptype, goto out1; ion_phys(client_for_ion, region->handle, &paddr, (size_t *)&len); -#else - rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file); - if (rc < 0) { - pr_err("%s: get_pmem_file fd %d error %d\n", - __func__, - info->fd, rc); - goto out1; - } - region->file = file; #endif if (!info->len) info->len = len; @@ -363,8 +353,6 @@ static int msm_pmem_table_add(struct hlist_head *ptype, out2: #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_free(client_for_ion, region->handle); -#else - put_pmem_file(region->file); #endif out1: kfree(region); @@ -648,8 +636,6 @@ static int __msm_pmem_table_del(struct msm_sync *sync, hlist_del(node); #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_free(client_for_ion, region->handle); -#else - put_pmem_file(region->file); #endif kfree(region); CDBG("%s: type %d, vaddr 0x%p\n", @@ -672,8 +658,6 @@ static int __msm_pmem_table_del(struct msm_sync *sync, hlist_del(node); #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_free(client_for_ion, region->handle); -#else - put_pmem_file(region->file); #endif kfree(region); CDBG("%s: type %d, vaddr 0x%p\n", @@ -695,8 +679,7 @@ static int __msm_pmem_table_del(struct msm_sync *sync, hlist_del(node); #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_free(client_for_ion, region->handle); -#else - put_pmem_file(region->file); + #endif kfree(region); CDBG("%s: type %d, vaddr 0x%p\n", @@ -3066,8 +3049,7 @@ static int __msm_release(struct msm_sync *sync) hlist_del(hnode); #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_free(client_for_ion, region->handle); -#else - put_pmem_file(region->file); + #endif kfree(region); } @@ -3077,8 +3059,7 @@ static int __msm_release(struct msm_sync *sync) hlist_del(hnode); #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_free(client_for_ion, region->handle); -#else - put_pmem_file(region->file); + #endif kfree(region); } diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c index 3a86fd07..e7245aa7 100644 --- a/drivers/media/video/msm/msm_isp.c +++ b/drivers/media/video/msm/msm_isp.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c index 3beaf702..f4ae3154 100644 --- a/drivers/media/video/msm/msm_mctl.c +++ b/drivers/media/video/msm/msm_mctl.c @@ -25,8 +25,6 @@ #include #include -#include - #include #include "msm.h" diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c index e89c28c1..53c32551 100644 --- a/drivers/media/video/msm/msm_mctl_buf.c +++ b/drivers/media/video/msm/msm_mctl_buf.c @@ -23,8 +23,6 @@ #include #include -#include - #include "msm.h" #include "msm_ispif.h" diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c index 2af95df5..676e623e 100644 --- a/drivers/media/video/msm/msm_mctl_pp.c +++ b/drivers/media/video/msm/msm_mctl_pp.c @@ -25,8 +25,6 @@ #include #include -#include - #include "msm.h" #include "msm_vpe.h" diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c index 938b5cd6..be82d0ea 100644 --- a/drivers/media/video/msm/msm_mem.c +++ b/drivers/media/video/msm/msm_mem.c @@ -26,7 +26,6 @@ #include #include -#include #include "msm.h" @@ -72,26 +71,6 @@ static DEFINE_MUTEX(hlist_mut); -#ifdef CONFIG_ANDROID_PMEM -static int check_pmem_info(struct msm_pmem_info *info, int len) -{ - if (info->offset < len && - info->offset + info->len <= len && - info->planar0_off < len && - info->planar1_off < len) - return 0; - - pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n", - __func__, - info->offset, - info->len, - info->planar0_off, - info->planar1_off, - len); - return -EINVAL; -} -#endif - static int check_overlap(struct hlist_head *ptype, unsigned long paddr, unsigned long len) @@ -137,16 +116,8 @@ static int msm_pmem_table_add(struct hlist_head *ptype, if (IS_ERR_OR_NULL(region->handle)) goto out1; if (ion_map_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL, - SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0) + SZ_4K, 0, &paddr, &len, 0, 0) < 0) goto out2; -#elif CONFIG_ANDROID_PMEM - rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file); - if (rc < 0) { - pr_err("%s: get_pmem_file fd %d error %d\n", - __func__, info->fd, rc); - goto out1; - } - region->file = file; #else paddr = 0; file = NULL; @@ -154,9 +125,6 @@ static int msm_pmem_table_add(struct hlist_head *ptype, #endif if (!info->len) info->len = len; - rc = check_pmem_info(info, len); - if (rc < 0) - goto out3; paddr += info->offset; len = info->len; @@ -186,8 +154,6 @@ static int msm_pmem_table_add(struct hlist_head *ptype, #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION out2: ion_free(client, region->handle); -#elif CONFIG_ANDROID_PMEM - put_pmem_file(region->file); #endif out1: kfree(region); @@ -247,8 +213,7 @@ static int __msm_pmem_table_del(struct hlist_head *ptype, ion_unmap_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL); ion_free(client, region->handle); -#else - put_pmem_file(region->file); + #endif kfree(region); } diff --git a/drivers/media/video/msm/msm_v4l2_video.c b/drivers/media/video/msm/msm_v4l2_video.c index fb46cc1a..c082daf3 100644 --- a/drivers/media/video/msm/msm_v4l2_video.c +++ b/drivers/media/video/msm/msm_v4l2_video.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,7 +22,7 @@ #include #include #include - +#include #include #include #include @@ -104,13 +104,22 @@ static int msm_v4l2_overlay_mapformat(uint32_t pixelformat) mdp_format = MDP_RGB_888; break; case V4L2_PIX_FMT_NV12: - mdp_format = MDP_Y_CRCB_H2V2; + mdp_format = MDP_Y_CBCR_H2V2; break; case V4L2_PIX_FMT_NV21: - mdp_format = MDP_Y_CBCR_H2V2; + mdp_format = MDP_Y_CRCB_H2V2; break; case V4L2_PIX_FMT_YUV420: - mdp_format = MDP_Y_CR_CB_H2V2; + mdp_format = MDP_Y_CB_CR_H2V2; + break; + case V4L2_PIX_FMT_UYVY: + mdp_format = MDP_CBYCRY_H2V1; + break; + case V4L2_PIX_FMT_YUYV: + mdp_format = MDP_YCBYCR_H2V1; + break; + case V4L2_PIX_FMT_YVU420: + mdp_format = MDP_Y_CR_CB_GH2V2; break; default: pr_err("%s:Unrecognized format %u\n", __func__, pixelformat); @@ -140,20 +149,22 @@ msm_v4l2_overlay_fb_update(struct msm_v4l2_overlay_device *vout, src_addr = (unsigned long)v4l2_ram_phys + vout->bufs[buffer->index].offset; src_size = buffer->bytesused; - ret = msm_fb_v4l2_update(vout->par, src_addr, src_size, + ret = msm_fb_v4l2_update(vout->par, false, src_addr, src_size, 0, 0, 0, 0); break; case V4L2_MEMORY_USERPTR: if (copy_from_user(&up_buffer, (void __user *)buffer->m.userptr, sizeof(struct msm_v4l2_overlay_userptr_buffer))) { + pr_err("%s:copy_from_user for userptr failed\n", + __func__); mutex_unlock(&msmfb_lock); return -EINVAL; } - ret = msm_fb_v4l2_update(vout->par, - (unsigned long)up_buffer.base[0], up_buffer.length[0], - (unsigned long)up_buffer.base[1], up_buffer.length[1], - (unsigned long)up_buffer.base[2], up_buffer.length[2]); + ret = msm_fb_v4l2_update(vout->par, true, + (unsigned long)up_buffer.fd[0], up_buffer.offset[0], + (unsigned long)up_buffer.fd[1], up_buffer.offset[1], + (unsigned long)up_buffer.fd[2], up_buffer.offset[2]); break; default: mutex_unlock(&msmfb_lock); @@ -420,6 +431,7 @@ msm_v4l2_overlay_do_ioctl(struct file *file, struct msm_v4l2_overlay_fh *fh = file->private_data; struct msm_v4l2_overlay_device *vout = fh->vout; int ret; + struct v4l2_buffer *buffer = arg; switch (cmd) { case VIDIOC_QUERYCAP: @@ -439,7 +451,14 @@ msm_v4l2_overlay_do_ioctl(struct file *file, case VIDIOC_QBUF: mutex_lock(&vout->update_lock); - ret = msm_v4l2_overlay_vidioc_qbuf(file, fh, arg, false); + if (buffer->memory == V4L2_MEMORY_USERPTR) { + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + ret = msm_v4l2_overlay_vidioc_qbuf(file, fh, arg, true); + } else { + ret = msm_v4l2_overlay_vidioc_qbuf(file, fh, arg, + false); + } mutex_unlock(&vout->update_lock); return ret; @@ -723,6 +742,9 @@ msm_v4l2_overlay_mmap(struct file *filp, struct vm_area_struct * vma) unsigned long off = vma->vm_pgoff << PAGE_SHIFT; u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + v4l2_ram_size); + if (!start) + return -EINVAL; + /* * This is probably unnecessary now - the last PAGE_SHIFT * bits of start should be 0 now, since we are page aligning @@ -730,16 +752,20 @@ msm_v4l2_overlay_mmap(struct file *filp, struct vm_area_struct * vma) */ start &= PAGE_MASK; + if ((vma->vm_end <= vma->vm_start) || + (off >= len) || + ((vma->vm_end - vma->vm_start) > (len - off))) { + pr_err("v4l2 map request, memory requested out of bounds\n"); + return -EINVAL; + } + pr_debug("v4l2 map req for phys(%p,%p) offset %u to virt (%p,%p)\n", (void *)(start+off), (void *)(start+off+(vma->vm_end - vma->vm_start)), (unsigned int)off, (void *)vma->vm_start, (void *)vma->vm_end); - if ((vma->vm_end - vma->vm_start + off) > len) { - pr_err("v4l2 map request, memory requested too big\n"); - return -EINVAL; - } - start += off; + if (start < off) + return -EINVAL; vma->vm_pgoff = start >> PAGE_SHIFT; /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO | VM_RESERVED; @@ -825,7 +851,7 @@ msm_v4l2_overlay_open(struct file *file) | V4L2_FBUF_CAP_LOCAL_ALPHA; vout->fb.flags = V4L2_FBUF_FLAG_LOCAL_ALPHA; vout->fb.base = 0; - memcpy(&vout->fb.fmt, pix, sizeof(struct v4l2_format)); + memcpy(&vout->fb.fmt, pix, sizeof(struct v4l2_pix_format)); vout->bufs = 0; vout->numbufs = 0; diff --git a/drivers/media/video/msm/msm_v4l2_video.h b/drivers/media/video/msm/msm_v4l2_video.h index 0c09a3f8..6de6c80e 100644 --- a/drivers/media/video/msm/msm_v4l2_video.h +++ b/drivers/media/video/msm/msm_v4l2_video.h @@ -52,8 +52,8 @@ struct msm_v4l2_overlay_fh { }; struct msm_v4l2_overlay_userptr_buffer { - uint base[3]; - size_t length[3]; + uint fd[3]; /* ION fd of frame or plane */ + size_t offset[3]; /* offset of frame or plane in multi buffer case */ }; #endif diff --git a/drivers/media/video/msm/msm_vfe7x.c b/drivers/media/video/msm/msm_vfe7x.c index bbf9d1b0..8354671c 100644 --- a/drivers/media/video/msm/msm_vfe7x.c +++ b/drivers/media/video/msm/msm_vfe7x.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/msm/msm_vfe7x27a.c b/drivers/media/video/msm/msm_vfe7x27a.c index 0279c780..dae2b6e7 100644 --- a/drivers/media/video/msm/msm_vfe7x27a.c +++ b/drivers/media/video/msm/msm_vfe7x27a.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c index ef11e4b7..f24df39b 100644 --- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c +++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.c b/drivers/media/video/msm/msm_vfe_stats_buf.c index c21664b3..4eccd8e4 100644 --- a/drivers/media/video/msm/msm_vfe_stats_buf.c +++ b/drivers/media/video/msm/msm_vfe_stats_buf.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include "msm.h" @@ -162,25 +161,6 @@ static int msm_stats_deinit(struct msm_stats_bufq_ctrl *stats_ctrl) return rc; } -#ifdef CONFIG_ANDROID_PMEM -static int msm_stats_check_pmem_info(struct msm_stats_buf_info *info, int len) -{ - if (info->offset < len && - info->offset + info->len <= len && - info->planar0_off < len && info->planar1_off < len) - return 0; - - pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n", - __func__, - info->offset, - info->len, - info->planar0_off, - info->planar1_off, - len); - return -EINVAL; -} -#endif - static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl, struct msm_stats_buf_info *info, struct ion_client *client) { @@ -225,14 +205,7 @@ static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl, pr_err("%s: cannot map address", __func__); goto out2; } -#elif CONFIG_ANDROID_PMEM - rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file); - if (rc < 0) { - pr_err("%s: get_pmem_file fd %d error %d\n", - __func__, info->fd, rc); - goto out1; - } - stats_buf->file = file; + #else paddr = 0; file = NULL; @@ -240,11 +213,6 @@ static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl, #endif if (!info->len) info->len = len; - rc = msm_stats_check_pmem_info(info, len); - if (rc < 0) { - pr_err("%s: msm_stats_check_pmem_info err = %d", __func__, rc); - goto out3; - } paddr += info->offset; len = info->len; stats_buf->paddr = paddr; @@ -255,15 +223,14 @@ static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl, D("%s pmem_stats address is 0x%ld\n", __func__, paddr); stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED; return 0; -out3: + #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL); #endif #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION out2: ion_free(client, stats_buf->handle); -#elif CONFIG_ANDROID_PMEM - put_pmem_file(stats_buf->file); + #endif out1: return rc; @@ -294,8 +261,7 @@ static int msm_stats_buf_unprepare(struct msm_stats_bufq_ctrl *stats_ctrl, ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL); ion_free(client, stats_buf->handle); -#else - put_pmem_file(stats_buf->file); + #endif if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) { /* buf queued need delete from list */ diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c index 887af958..4b60970a 100644 --- a/drivers/media/video/msm/wfd/wfd-ioctl.c +++ b/drivers/media/video/msm/wfd/wfd-ioctl.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/media/video/videobuf-msm-mem.c b/drivers/media/video/videobuf-msm-mem.c index 9e2cc222..28fed735 100644 --- a/drivers/media/video/videobuf-msm-mem.c +++ b/drivers/media/video/videobuf-msm-mem.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -140,55 +139,6 @@ static const struct vm_operations_struct videobuf_vm_ops = { .close = videobuf_vm_close, }; -/** - * videobuf_pmem_contig_user_put() - reset pointer to user space buffer - * @mem: per-buffer private videobuf-contig-pmem data - * - * This function resets the user space pointer - */ -static void videobuf_pmem_contig_user_put(struct videobuf_contig_pmem *mem) -{ - if (mem->phyaddr) { - put_pmem_file(mem->file); - mem->is_userptr = 0; - mem->phyaddr = 0; - mem->size = 0; - } -} - -/** - * videobuf_pmem_contig_user_get() - setup user space memory pointer - * @mem: per-buffer private videobuf-contig-pmem data - * @vb: video buffer to map - * - * This function validates and sets up a pointer to user space memory. - * Only physically contiguous pfn-mapped memory is accepted. - * - * Returns 0 if successful. - */ -static int videobuf_pmem_contig_user_get(struct videobuf_contig_pmem *mem, - struct videobuf_buffer *vb) -{ - unsigned long kvstart; - unsigned long len; - int rc; - - mem->size = PAGE_ALIGN(vb->size); - rc = get_pmem_file(vb->baddr, (unsigned long *)&mem->phyaddr, - &kvstart, &len, &mem->file); - if (rc < 0) { - pr_err("%s: get_pmem_file fd %lu error %d\n", - __func__, vb->baddr, - rc); - return rc; - } - mem->phyaddr += vb->boff; - mem->y_off = 0; - mem->cbcr_off = (vb->size)*2/3; - mem->is_userptr = 1; - return rc; -} - static struct videobuf_buffer *__videobuf_alloc(size_t size) { struct videobuf_contig_pmem *mem; @@ -229,12 +179,6 @@ static int __videobuf_iolock(struct videobuf_queue *q, /* All handling should be done by __videobuf_mmap_mapper() */ break; - case V4L2_MEMORY_USERPTR: - D("%s memory method USERPTR\n", __func__); - - /* handle pointer from user space */ - rc = videobuf_pmem_contig_user_get(mem, vb); - break; case V4L2_MEMORY_OVERLAY: default: pr_err("%s memory method OVERLAY/unknown\n", __func__); @@ -383,7 +327,6 @@ int videobuf_pmem_contig_free(struct videobuf_queue *q, /* handle user space pointer case */ if (buf->baddr) { - videobuf_pmem_contig_user_put(mem); return 0; } else { /* don't support read() method */ diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c index 8114d7a9..d753c42a 100644 --- a/drivers/media/video/videobuf2-msm-mem.c +++ b/drivers/media/video/videobuf2-msm-mem.c @@ -24,10 +24,11 @@ #include #include #include -#include + #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ static unsigned long msm_mem_allocate(struct videobuf2_contig_pmem *mem) goto client_failed; } mem->ion_handle = ion_alloc(mem->client, mem->size, SZ_4K, - (0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID)); + (0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID), 0); if (IS_ERR((void *)mem->ion_handle)) { pr_err("%s Could not allocate\n", __func__); goto alloc_failed; @@ -64,7 +65,7 @@ static unsigned long msm_mem_allocate(struct videobuf2_contig_pmem *mem) rc = ion_map_iommu(mem->client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL, SZ_4K, 0, (unsigned long *)&phyaddr, - (unsigned long *)&len, UNCACHED, 0); + (unsigned long *)&len, 0, 0); if (rc < 0) { pr_err("%s Could not get physical address\n", __func__); goto phys_failed; @@ -176,35 +177,25 @@ int videobuf2_pmem_contig_user_get(struct videobuf2_contig_pmem *mem, uint32_t addr_offset, int path, struct ion_client *client) { - unsigned long len; int rc = 0; -#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION - unsigned long kvstart; +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + unsigned long len; #endif unsigned long paddr = 0; if (mem->phyaddr != 0) return 0; -#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +#if defined(CONFIG_MSM_MULTIMEDIA_USE_ION) mem->ion_handle = ion_import_dma_buf(client, (int)mem->vaddr); if (IS_ERR_OR_NULL(mem->ion_handle)) { pr_err("%s ION import failed\n", __func__); return PTR_ERR(mem->ion_handle); } rc = ion_map_iommu(client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL, - SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0); + SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, 0, 0); if (rc < 0) ion_free(client, mem->ion_handle); -#elif CONFIG_ANDROID_PMEM - rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr, - &kvstart, &len, &mem->file); - if (rc < 0) { - pr_err("%s: get_pmem_file fd %d error %d\n", - __func__, (int)mem->vaddr, rc); - return rc; - } #else paddr = 0; - kvstart = 0; #endif if (offset) mem->offset = *offset; @@ -223,12 +214,10 @@ void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem, struct ion_client *client) { if (mem->is_userptr) { -#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION +#if defined(CONFIG_MSM_MULTIMEDIA_USE_ION) ion_unmap_iommu(client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL); ion_free(client, mem->ion_handle); -#elif CONFIG_ANDROID_PMEM - put_pmem_file(mem->file); #endif } mem->is_userptr = 0; @@ -298,9 +287,9 @@ static int msm_vb2_mem_ops_mmap(void *buf_priv, struct vm_area_struct *vma) vma->vm_flags |= VM_DONTEXPAND; vma->vm_private_data = mem; - D("mmap %p: %08lx-%08lx (%lx) pgoff %08lx\n", - map, vma->vm_start, vma->vm_end, - (long int)mem->bsize, vma->vm_pgoff); + D("mmap: %08lx-%08lx (%lx) pgoff %08lx\n", + vma->vm_start, vma->vm_end, + (long int)mem->size, vma->vm_pgoff); videobuf2_vm_open(vma); return 0; error: diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 5df8afbe..14df87dd 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/devices/msm_nand.c b/drivers/mtd/devices/msm_nand.c index c8c1cdea..40877a8b 100644 --- a/drivers/mtd/devices/msm_nand.c +++ b/drivers/mtd/devices/msm_nand.c @@ -6957,14 +6957,6 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips) mtd->_unpoint = NULL; mtd->_read = msm_nand_read; mtd->_write = msm_nand_write; -<<<<<<< HEAD -======= -#if 0 -//#ifdef CONFIG_HUAWEI_KERNEL - /* add for android panic support*/ - mtd->_panic_write = msm_nand_write_apanic; -#endif ->>>>>>> d7fe698... msm: dma: upstream to CAF Ifaa5efdde8150f932a12d4f9eeccfb36ecb8f88f mtd->_read_oob = msm_nand_read_oob; mtd->_write_oob = msm_nand_write_oob; if (dual_nand_ctlr_present) { diff --git a/drivers/net/ethernet/msm/msm_rmnet.c b/drivers/net/ethernet/msm/msm_rmnet.c index f8f5a55c..87de1778 100644 --- a/drivers/net/ethernet/msm/msm_rmnet.c +++ b/drivers/net/ethernet/msm/msm_rmnet.c @@ -94,6 +94,7 @@ struct rmnet_private struct sk_buff *skb; spinlock_t lock; struct tasklet_struct tsklt; + struct tasklet_struct rx_tasklet; u32 operation_mode; /* IOCTL specified mode (protocol, QoS header) */ struct platform_driver pdrv; struct completion complete; @@ -257,7 +258,6 @@ static __be16 rmnet_ip_type_trans(struct sk_buff *skb, struct net_device *dev) } static void smd_net_data_handler(unsigned long arg); -static DECLARE_TASKLET(smd_net_data_tasklet, smd_net_data_handler, 0); /* Called in soft-irq context */ static void smd_net_data_handler(unsigned long arg) @@ -280,8 +280,8 @@ static void smd_net_data_handler(unsigned long arg) pr_err("[%s] rmnet_recv() cannot allocate skb\n", dev->name); /* out of memory, reschedule a later attempt */ - smd_net_data_tasklet.data = (unsigned long)dev; - tasklet_schedule(&smd_net_data_tasklet); + p->rx_tasklet.data = (unsigned long)dev; + tasklet_schedule(&p->rx_tasklet); break; } else { skb->dev = dev; @@ -449,8 +449,8 @@ static void smd_net_notify(void *_dev, unsigned event) if (smd_read_avail(p->ch) && (smd_read_avail(p->ch) >= smd_cur_packet_size(p->ch))) { - smd_net_data_tasklet.data = (unsigned long) _dev; - tasklet_schedule(&smd_net_data_tasklet); + p->rx_tasklet.data = (unsigned long) _dev; + tasklet_schedule(&p->rx_tasklet); } break; @@ -501,16 +501,10 @@ static int __rmnet_open(struct net_device *dev) static int __rmnet_close(struct net_device *dev) { struct rmnet_private *p = netdev_priv(dev); - int rc; - unsigned long flags; - if (p->ch) { - rc = smd_close(p->ch); - spin_lock_irqsave(&p->lock, flags); - p->ch = 0; - spin_unlock_irqrestore(&p->lock, flags); - return rc; - } else + if (p->ch) + return 0; + else return -EBADF; } @@ -529,12 +523,9 @@ static int rmnet_open(struct net_device *dev) static int rmnet_stop(struct net_device *dev) { - struct rmnet_private *p = netdev_priv(dev); - DBG0("[%s] rmnet_stop()\n", dev->name); netif_stop_queue(dev); - tasklet_kill(&p->tsklt); /* TODO: unload modem safely, currently, this causes unnecessary unloads */ @@ -797,6 +788,8 @@ static int __init rmnet_init(void) spin_lock_init(&p->lock); tasklet_init(&p->tsklt, _rmnet_resume_flow, (unsigned long)dev); + tasklet_init(&p->rx_tasklet, smd_net_data_handler, + (unsigned long)dev); wake_lock_init(&p->wake_lock, WAKE_LOCK_SUSPEND, ch_name[n]); #ifdef CONFIG_MSM_RMNET_DEBUG p->timeout_us = timeout_us; diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 09602241..07354883 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,6 +1,6 @@ menuconfig ATH_COMMON tristate "Atheros Wireless Cards" - depends on CFG80211 && (!UML || BROKEN) + depends on CFG80211 ---help--- This will enable the support for the Atheros wireless drivers. ath5k, ath9k, ath9k_htc and ar9170 drivers share some common code, this option diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index d716b748..f4eb545b 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -1,14 +1,17 @@ +NOSTDINC_FLAGS := -I$(srctree)/include/compat/ \ + -include $(srctree)/include/compat/linux/compat-2.6.h \ + $(CFLAGS) + obj-$(CONFIG_ATH5K) += ath5k/ +obj-$(CONFIG_ATH6KL) += ath6kl/ obj-$(CONFIG_ATH9K_HW) += ath9k/ obj-$(CONFIG_CARL9170) += carl9170/ -obj-$(CONFIG_ATH6KL) += ath6kl/ -obj-$(CONFIG_ATH_COMMON) += ath.o +# obj-$(CONFIG_ATH_COMMON) += ath.o ath-objs := main.o \ regd.o \ hw.o \ key.o -ath-$(CONFIG_ATH_DEBUG) += debug.o -ccflags-y += -D__CHECK_ENDIAN__ +ath-$(CONFIG_ATH_DEBUG) += debug.o \ No newline at end of file diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h old mode 100644 new mode 100755 diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index aec33cc2..e5be7e70 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "ath5k.h" #include "debug.h" @@ -120,7 +119,7 @@ static int ath_ahb_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "no IRQ resource found\n"); ret = -ENXIO; - goto err_iounmap; + goto err_out; } irq = res->start; @@ -129,7 +128,7 @@ static int ath_ahb_probe(struct platform_device *pdev) if (hw == NULL) { dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); ret = -ENOMEM; - goto err_iounmap; + goto err_out; } ah = hw->priv; @@ -141,23 +140,23 @@ static int ath_ahb_probe(struct platform_device *pdev) if (bcfg->devid >= AR5K_SREV_AR2315_R6) { /* Enable WMAC AHB arbitration */ - reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN; - iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); /* Enable global WMAC swapping */ - reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP); + reg = __raw_readl((void __iomem *) AR5K_AR2315_BYTESWAP); reg |= AR5K_AR2315_BYTESWAP_WMAC; - iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP); + __raw_writel(reg, (void __iomem *) AR5K_AR2315_BYTESWAP); } else { /* Enable WMAC DMA access (assuming 5312 or 231x*/ /* TODO: check other platforms */ - reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE); + reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE); if (to_platform_device(ah->dev)->id == 0) reg |= AR5K_AR5312_ENABLE_WLAN0; else reg |= AR5K_AR5312_ENABLE_WLAN1; - iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE); + __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); /* * On a dual-band AR5312, the multiband radio is only @@ -167,9 +166,7 @@ static int ath_ahb_probe(struct platform_device *pdev) if (to_platform_device(ah->dev)->id == 0 && (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) == (BD_WLAN1 | BD_WLAN0)) - ah->ah_capabilities.cap_needs_2GHz_ovr = true; - else - ah->ah_capabilities.cap_needs_2GHz_ovr = false; + __set_bit(ATH_STAT_2G_DISABLED, ah->status); } ret = ath5k_init_ah(ah, &ath_ahb_bus_ops); @@ -186,8 +183,6 @@ static int ath_ahb_probe(struct platform_device *pdev) err_free_hw: ieee80211_free_hw(hw); platform_set_drvdata(pdev, NULL); - err_iounmap: - iounmap(mem); err_out: return ret; } @@ -206,21 +201,20 @@ static int ath_ahb_remove(struct platform_device *pdev) if (bcfg->devid >= AR5K_SREV_AR2315_R6) { /* Disable WMAC AHB arbitration */ - reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN; - iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); } else { /*Stop DMA access */ - reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE); + reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE); if (to_platform_device(ah->dev)->id == 0) reg &= ~AR5K_AR5312_ENABLE_WLAN0; else reg &= ~AR5K_AR5312_ENABLE_WLAN1; - iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE); + __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); } ath5k_deinit_ah(ah); - iounmap(ah->iobase); platform_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index 35e93704..bea90e6b 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -27,21 +27,15 @@ * or reducing sensitivity as necessary. * * The parameters are: - * * - "noise immunity" - * * - "spur immunity" - * * - "firstep level" - * * - "OFDM weak signal detection" - * * - "CCK weak signal detection" * * Basically we look at the amount of ODFM and CCK timing errors we get and then * raise or lower immunity accordingly by setting one or more of these * parameters. - * * Newer chipsets have PHY error counters in hardware which will generate a MIB * interrupt when they overflow. Older hardware has too enable PHY error frames * by setting a RX flag and then count every single PHY error. When a specified @@ -51,13 +45,11 @@ */ -/***********************\ -* ANI parameter control * -\***********************/ +/*** ANI parameter control ***/ /** * ath5k_ani_set_noise_immunity_level() - Set noise immunity level - * @ah: The &struct ath5k_hw + * * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL */ void @@ -99,11 +91,12 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); } + /** * ath5k_ani_set_spur_immunity_level() - Set spur immunity level - * @ah: The &struct ath5k_hw + * * @level: level between 0 and @max_spur_level (the maximum level is dependent - * on the chip revision). + * on the chip revision). */ void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) @@ -124,9 +117,10 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); } + /** * ath5k_ani_set_firstep_level() - Set "firstep" level - * @ah: The &struct ath5k_hw + * * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL */ void @@ -146,9 +140,11 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); } + /** - * ath5k_ani_set_ofdm_weak_signal_detection() - Set OFDM weak signal detection - * @ah: The &struct ath5k_hw + * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal + * detection + * * @on: turn on or off */ void @@ -186,9 +182,10 @@ ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) on ? "on" : "off"); } + /** - * ath5k_ani_set_cck_weak_signal_detection() - Set CCK weak signal detection - * @ah: The &struct ath5k_hw + * ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection + * * @on: turn on or off */ void @@ -203,16 +200,13 @@ ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) } -/***************\ -* ANI algorithm * -\***************/ +/*** ANI algorithm ***/ /** * ath5k_ani_raise_immunity() - Increase noise immunity - * @ah: The &struct ath5k_hw - * @as: The &struct ath5k_ani_state + * * @ofdm_trigger: If this is true we are called because of too many OFDM errors, - * the algorithm will tune more parameters then. + * the algorithm will tune more parameters then. * * Try to raise noise immunity (=decrease sensitivity) in several steps * depending on the average RSSI of the beacons we received. @@ -257,7 +251,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, "beacon RSSI high"); /* only OFDM: beacon RSSI is high, we can disable ODFM weak * signal detection */ - if (ofdm_trigger && as->ofdm_weak_sig) { + if (ofdm_trigger && as->ofdm_weak_sig == true) { ath5k_ani_set_ofdm_weak_signal_detection(ah, false); ath5k_ani_set_spur_immunity_level(ah, 0); return; @@ -272,7 +266,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, * but can raise firstep level */ ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "beacon RSSI mid"); - if (ofdm_trigger && !as->ofdm_weak_sig) + if (ofdm_trigger && as->ofdm_weak_sig == false) ath5k_ani_set_ofdm_weak_signal_detection(ah, true); if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); @@ -282,7 +276,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, * detect and zero firstep level to maximize CCK sensitivity */ ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "beacon RSSI low, 2GHz"); - if (ofdm_trigger && as->ofdm_weak_sig) + if (ofdm_trigger && as->ofdm_weak_sig == true) ath5k_ani_set_ofdm_weak_signal_detection(ah, false); if (as->firstep_level > 0) ath5k_ani_set_firstep_level(ah, 0); @@ -296,10 +290,9 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, */ } + /** * ath5k_ani_lower_immunity() - Decrease noise immunity - * @ah: The &struct ath5k_hw - * @as: The &struct ath5k_ani_state * * Try to lower noise immunity (=increase sensitivity) in several steps * depending on the average RSSI of the beacons we received. @@ -326,7 +319,7 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) { /* beacon RSSI is mid-range: turn on ODFM weak signal * detection and next, lower firstep level */ - if (!as->ofdm_weak_sig) { + if (as->ofdm_weak_sig == false) { ath5k_ani_set_ofdm_weak_signal_detection(ah, true); return; @@ -359,10 +352,9 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) } } + /** * ath5k_hw_ani_get_listen_time() - Update counters and return listening time - * @ah: The &struct ath5k_hw - * @as: The &struct ath5k_ani_state * * Return an approximation of the time spent "listening" in milliseconds (ms) * since the last call of this function. @@ -387,10 +379,9 @@ ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) return listen; } + /** * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters - * @ah: The &struct ath5k_hw - * @as: The &struct ath5k_ani_state * * Clear the PHY error counters as soon as possible, since this might be called * from a MIB interrupt and we want to make sure we don't get interrupted again. @@ -438,14 +429,14 @@ ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, return 1; } + /** * ath5k_ani_period_restart() - Restart ANI period - * @as: The &struct ath5k_ani_state * * Just reset counters, so they are clear for the next "ani period". */ static void -ath5k_ani_period_restart(struct ath5k_ani_state *as) +ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as) { /* keep last values for debugging */ as->last_ofdm_errors = as->ofdm_errors; @@ -457,9 +448,9 @@ ath5k_ani_period_restart(struct ath5k_ani_state *as) as->listen_time = 0; } + /** * ath5k_ani_calibration() - The main ANI calibration function - * @ah: The &struct ath5k_hw * * We count OFDM and CCK errors relative to the time where we did not send or * receive ("listen" time) and raise or lower immunity accordingly. @@ -501,7 +492,7 @@ ath5k_ani_calibration(struct ath5k_hw *ah) /* too many PHY errors - we have to raise immunity */ bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false; ath5k_ani_raise_immunity(ah, as, ofdm_flag); - ath5k_ani_period_restart(as); + ath5k_ani_period_restart(ah, as); } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) { /* If more than 5 (TODO: why 5?) periods have passed and we got @@ -513,18 +504,15 @@ ath5k_ani_calibration(struct ath5k_hw *ah) if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low) ath5k_ani_lower_immunity(ah, as); - ath5k_ani_period_restart(as); + ath5k_ani_period_restart(ah, as); } } -/*******************\ -* Interrupt handler * -\*******************/ +/*** INTERRUPT HANDLER ***/ /** * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters - * @ah: The &struct ath5k_hw * * Just read & reset the registers quickly, so they don't generate more * interrupts, save the counters and schedule the tasklet to decide whether @@ -561,11 +549,9 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah) tasklet_schedule(&ah->ani_tasklet); } + /** - * ath5k_ani_phy_error_report - Used by older HW to report PHY errors - * - * @ah: The &struct ath5k_hw - * @phyerr: One of enum ath5k_phy_error_code + * ath5k_ani_phy_error_report() - Used by older HW to report PHY errors * * This is used by hardware without PHY error counters to report PHY errors * on a frame-by-frame basis, instead of the interrupt. @@ -588,13 +574,10 @@ ath5k_ani_phy_error_report(struct ath5k_hw *ah, } -/****************\ -* Initialization * -\****************/ +/*** INIT ***/ /** * ath5k_enable_phy_err_counters() - Enable PHY error counters - * @ah: The &struct ath5k_hw * * Enable PHY error counters for OFDM and CCK timing errors. */ @@ -613,9 +596,9 @@ ath5k_enable_phy_err_counters(struct ath5k_hw *ah) ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); } + /** * ath5k_disable_phy_err_counters() - Disable PHY error counters - * @ah: The &struct ath5k_hw * * Disable PHY error counters for OFDM and CCK timing errors. */ @@ -632,10 +615,10 @@ ath5k_disable_phy_err_counters(struct ath5k_hw *ah) ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); } + /** * ath5k_ani_init() - Initialize ANI - * @ah: The &struct ath5k_hw - * @mode: One of enum ath5k_ani_mode + * @mode: Which mode to use (auto, manual high, manual low, off) * * Initialize ANI according to mode. */ @@ -712,18 +695,10 @@ ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) } -/**************\ -* Debug output * -\**************/ +/*** DEBUG ***/ #ifdef CONFIG_ATH5K_DEBUG -/** - * ath5k_ani_print_counters() - Print ANI counters - * @ah: The &struct ath5k_hw - * - * Used for debugging ANI - */ void ath5k_ani_print_counters(struct ath5k_hw *ah) { diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index 21aa3554..7358b6c8 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -40,13 +40,13 @@ enum ath5k_phy_error_code; * enum ath5k_ani_mode - mode for ANI / noise sensitivity * * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI - * algorithm after it has been on auto mode. - * @ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, - * maximizing sensitivity. ANI will not run. - * @ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, - * minimizing sensitivity. ANI will not run. - * @ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the - * amount of OFDM and CCK frame errors (default). + * algorithm after it has been on auto mode. + * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, + * maximizing sensitivity. ANI will not run. + * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, + * minimizing sensitivity. ANI will not run. + * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the + * amount of OFDM and CCK frame errors (default). */ enum ath5k_ani_mode { ATH5K_ANI_MODE_OFF = 0, @@ -58,22 +58,8 @@ enum ath5k_ani_mode { /** * struct ath5k_ani_state - ANI state and associated counters - * @ani_mode: One of enum ath5k_ani_mode - * @noise_imm_level: Noise immunity level - * @spur_level: Spur immunity level - * @firstep_level: FIRstep level - * @ofdm_weak_sig: OFDM weak signal detection state (on/off) - * @cck_weak_sig: CCK weak signal detection state (on/off) - * @max_spur_level: Max spur immunity level (chip specific) - * @listen_time: Listen time - * @ofdm_errors: OFDM timing error count - * @cck_errors: CCK timing error count - * @last_cc: The &struct ath_cycle_counters (for stats) - * @last_listen: Listen time from previous run (for stats) - * @last_ofdm_errors: OFDM timing error count from previous run (for tats) - * @last_cck_errors: CCK timing error count from previous run (for stats) - * @sum_ofdm_errors: Sum of OFDM timing errors (for stats) - * @sum_cck_errors: Sum of all CCK timing errors (for stats) + * + * @max_spur_level: the maximum spur level is chip dependent */ struct ath5k_ani_state { enum ath5k_ani_mode ani_mode; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 8d434b8f..fecbcd9a 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -187,9 +187,10 @@ #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false -#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 60000 /* 60 sec */ -#define ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT 10000 /* 10 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */ #define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */ + #define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */ #define AR5K_INIT_CARR_SENSE_EN 1 @@ -261,34 +262,16 @@ #define AR5K_AGC_SETTLING_TURBO 37 +/* GENERIC CHIPSET DEFINITIONS */ -/*****************************\ -* GENERIC CHIPSET DEFINITIONS * -\*****************************/ - -/** - * enum ath5k_version - MAC Chips - * @AR5K_AR5210: AR5210 (Crete) - * @AR5K_AR5211: AR5211 (Oahu/Maui) - * @AR5K_AR5212: AR5212 (Venice) and newer - */ +/* MAC Chips */ enum ath5k_version { AR5K_AR5210 = 0, AR5K_AR5211 = 1, AR5K_AR5212 = 2, }; -/** - * enum ath5k_radio - PHY Chips - * @AR5K_RF5110: RF5110 (Fez) - * @AR5K_RF5111: RF5111 (Sombrero) - * @AR5K_RF5112: RF2112/5112(A) (Derby/Derby2) - * @AR5K_RF2413: RF2413/2414 (Griffin/Griffin-Lite) - * @AR5K_RF5413: RF5413/5414/5424 (Eagle/Condor) - * @AR5K_RF2316: RF2315/2316 (Cobra SoC) - * @AR5K_RF2317: RF2317 (Spider SoC) - * @AR5K_RF2425: RF2425/2417 (Swan/Nalla) - */ +/* PHY Chips */ enum ath5k_radio { AR5K_RF5110 = 0, AR5K_RF5111 = 1, @@ -320,11 +303,11 @@ enum ath5k_radio { #define AR5K_SREV_AR5213A 0x59 /* Hainan */ #define AR5K_SREV_AR2413 0x78 /* Griffin lite */ #define AR5K_SREV_AR2414 0x70 /* Griffin */ -#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */ -#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */ +#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */ +#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */ #define AR5K_SREV_AR5424 0x90 /* Condor */ -#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */ -#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */ +#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */ +#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */ #define AR5K_SREV_AR5413 0xa4 /* Eagle lite */ #define AR5K_SREV_AR5414 0xa0 /* Eagle */ #define AR5K_SREV_AR2415 0xb0 /* Talon */ @@ -361,40 +344,32 @@ enum ath5k_radio { /* TODO add support to mac80211 for vendor-specific rates and modes */ -/** - * DOC: Atheros XR - * +/* * Some of this information is based on Documentation from: * * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG * - * Atheros' eXtended Range - range enhancing extension is a modulation scheme - * that is supposed to double the link distance between an Atheros XR-enabled - * client device with an Atheros XR-enabled access point. This is achieved - * by increasing the receiver sensitivity up to, -105dBm, which is about 20dB - * above what the 802.11 specifications demand. In addition, new (proprietary) - * data rates are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. + * Modulation for Atheros' eXtended Range - range enhancing extension that is + * supposed to double the distance an Atheros client device can keep a + * connection with an Atheros access point. This is achieved by increasing + * the receiver sensitivity up to, -105dBm, which is about 20dB above what + * the 802.11 specifications demand. In addition, new (proprietary) data rates + * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. * * Please note that can you either use XR or TURBO but you cannot use both, * they are exclusive. * - * Also note that we do not plan to support XR mode at least for now. You can - * get a mode similar to XR by using 5MHz bwmode. */ - - -/** - * DOC: Atheros SuperAG - * - * In addition to XR we have another modulation scheme called TURBO mode - * that is supposed to provide a throughput transmission speed up to 40Mbit/s - * -60Mbit/s at a 108Mbit/s signaling rate achieved through the bonding of two - * 54Mbit/s 802.11g channels. To use this feature both ends must support it. +#define MODULATION_XR 0x00000200 +/* + * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a + * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s + * signaling rate achieved through the bonding of two 54Mbit/s 802.11g + * channels. To use this feature your Access Point must also support it. * There is also a distinction between "static" and "dynamic" turbo modes: * * - Static: is the dumb version: devices set to this mode stick to it until * the mode is turned off. - * * - Dynamic: is the intelligent version, the network decides itself if it * is ok to use turbo. As soon as traffic is detected on adjacent channels * (which would get used in turbo mode), or when a non-turbo station joins @@ -408,39 +383,24 @@ enum ath5k_radio { * * http://www.pcworld.com/article/id,113428-page,1/article.html * - * The channel bonding seems to be driver specific though. - * - * In addition to TURBO modes we also have the following features for even - * greater speed-up: + * The channel bonding seems to be driver specific though. In addition to + * deciding what channels will be used, these "Turbo" modes are accomplished + * by also enabling the following features: * * - Bursting: allows multiple frames to be sent at once, rather than pausing * after each frame. Bursting is a standards-compliant feature that can be * used with any Access Point. - * * - Fast frames: increases the amount of information that can be sent per * frame, also resulting in a reduction of transmission overhead. It is a * proprietary feature that needs to be supported by the Access Point. - * * - Compression: data frames are compressed in real time using a Lempel Ziv * algorithm. This is done transparently. Once this feature is enabled, * compression and decompression takes place inside the chipset, without * putting additional load on the host CPU. * - * As with XR we also don't plan to support SuperAG features for now. You can - * get a mode similar to TURBO by using 40MHz bwmode. */ +#define MODULATION_TURBO 0x00000080 - -/** - * enum ath5k_driver_mode - PHY operation mode - * @AR5K_MODE_11A: 802.11a - * @AR5K_MODE_11B: 802.11b - * @AR5K_MODE_11G: 801.11g - * @AR5K_MODE_MAX: Used for boundary checks - * - * Do not change the order here, we use these as - * array indices and it also maps EEPROM structures. - */ enum ath5k_driver_mode { AR5K_MODE_11A = 0, AR5K_MODE_11B = 1, @@ -448,64 +408,30 @@ enum ath5k_driver_mode { AR5K_MODE_MAX = 3 }; -/** - * enum ath5k_ant_mode - Antenna operation mode - * @AR5K_ANTMODE_DEFAULT: Default antenna setup - * @AR5K_ANTMODE_FIXED_A: Only antenna A is present - * @AR5K_ANTMODE_FIXED_B: Only antenna B is present - * @AR5K_ANTMODE_SINGLE_AP: STA locked on a single ap - * @AR5K_ANTMODE_SECTOR_AP: AP with tx antenna set on tx desc - * @AR5K_ANTMODE_SECTOR_STA: STA with tx antenna set on tx desc - * @AR5K_ANTMODE_DEBUG: Debug mode -A -> Rx, B-> Tx- - * @AR5K_ANTMODE_MAX: Used for boundary checks - * - * For more infos on antenna control check out phy.c - */ enum ath5k_ant_mode { - AR5K_ANTMODE_DEFAULT = 0, - AR5K_ANTMODE_FIXED_A = 1, - AR5K_ANTMODE_FIXED_B = 2, - AR5K_ANTMODE_SINGLE_AP = 3, - AR5K_ANTMODE_SECTOR_AP = 4, - AR5K_ANTMODE_SECTOR_STA = 5, - AR5K_ANTMODE_DEBUG = 6, + AR5K_ANTMODE_DEFAULT = 0, /* default antenna setup */ + AR5K_ANTMODE_FIXED_A = 1, /* only antenna A is present */ + AR5K_ANTMODE_FIXED_B = 2, /* only antenna B is present */ + AR5K_ANTMODE_SINGLE_AP = 3, /* sta locked on a single ap */ + AR5K_ANTMODE_SECTOR_AP = 4, /* AP with tx antenna set on tx desc */ + AR5K_ANTMODE_SECTOR_STA = 5, /* STA with tx antenna set on tx desc */ + AR5K_ANTMODE_DEBUG = 6, /* Debug mode -A -> Rx, B-> Tx- */ AR5K_ANTMODE_MAX, }; -/** - * enum ath5k_bw_mode - Bandwidth operation mode - * @AR5K_BWMODE_DEFAULT: 20MHz, default operation - * @AR5K_BWMODE_5MHZ: Quarter rate - * @AR5K_BWMODE_10MHZ: Half rate - * @AR5K_BWMODE_40MHZ: Turbo - */ enum ath5k_bw_mode { - AR5K_BWMODE_DEFAULT = 0, - AR5K_BWMODE_5MHZ = 1, - AR5K_BWMODE_10MHZ = 2, - AR5K_BWMODE_40MHZ = 3 + AR5K_BWMODE_DEFAULT = 0, /* 20MHz, default operation */ + AR5K_BWMODE_5MHZ = 1, /* Quarter rate */ + AR5K_BWMODE_10MHZ = 2, /* Half rate */ + AR5K_BWMODE_40MHZ = 3 /* Turbo */ }; - - /****************\ TX DEFINITIONS \****************/ -/** - * struct ath5k_tx_status - TX Status descriptor - * @ts_seqnum: Sequence number - * @ts_tstamp: Timestamp - * @ts_status: Status code - * @ts_final_idx: Final transmission series index - * @ts_final_retry: Final retry count - * @ts_rssi: RSSI for received ACK - * @ts_shortretry: Short retry count - * @ts_virtcol: Virtual collision count - * @ts_antenna: Antenna used - * - * TX status descriptor gets filled by the hw - * on each transmission attempt. +/* + * TX Status descriptor */ struct ath5k_tx_status { u16 ts_seqnum; @@ -528,6 +454,7 @@ struct ath5k_tx_status { * enum ath5k_tx_queue - Queue types used to classify tx queues. * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue * @AR5K_TX_QUEUE_DATA: A normal data queue + * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue * @AR5K_TX_QUEUE_BEACON: The beacon queue * @AR5K_TX_QUEUE_CAB: The after-beacon queue * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue @@ -535,6 +462,7 @@ struct ath5k_tx_status { enum ath5k_tx_queue { AR5K_TX_QUEUE_INACTIVE = 0, AR5K_TX_QUEUE_DATA, + AR5K_TX_QUEUE_XR_DATA, AR5K_TX_QUEUE_BEACON, AR5K_TX_QUEUE_CAB, AR5K_TX_QUEUE_UAPSD, @@ -543,46 +471,36 @@ enum ath5k_tx_queue { #define AR5K_NUM_TX_QUEUES 10 #define AR5K_NUM_TX_QUEUES_NOQCU 2 -/** - * enum ath5k_tx_queue_subtype - Queue sub-types to classify normal data queues - * @AR5K_WME_AC_BK: Background traffic - * @AR5K_WME_AC_BE: Best-effort (normal) traffic - * @AR5K_WME_AC_VI: Video traffic - * @AR5K_WME_AC_VO: Voice traffic - * +/* + * Queue syb-types to classify normal data queues. * These are the 4 Access Categories as defined in * WME spec. 0 is the lowest priority and 4 is the * highest. Normal data that hasn't been classified * goes to the Best Effort AC. */ enum ath5k_tx_queue_subtype { - AR5K_WME_AC_BK = 0, - AR5K_WME_AC_BE, - AR5K_WME_AC_VI, - AR5K_WME_AC_VO, + AR5K_WME_AC_BK = 0, /*Background traffic*/ + AR5K_WME_AC_BE, /*Best-effort (normal) traffic*/ + AR5K_WME_AC_VI, /*Video traffic*/ + AR5K_WME_AC_VO, /*Voice traffic*/ }; -/** - * enum ath5k_tx_queue_id - Queue ID numbers as returned by the hw functions - * @AR5K_TX_QUEUE_ID_NOQCU_DATA: Data queue on AR5210 (no QCU available) - * @AR5K_TX_QUEUE_ID_NOQCU_BEACON: Beacon queue on AR5210 (no QCU available) - * @AR5K_TX_QUEUE_ID_DATA_MIN: Data queue min index - * @AR5K_TX_QUEUE_ID_DATA_MAX: Data queue max index - * @AR5K_TX_QUEUE_ID_CAB: Content after beacon queue - * @AR5K_TX_QUEUE_ID_BEACON: Beacon queue - * @AR5K_TX_QUEUE_ID_UAPSD: Urgent Automatic Power Save Delivery, - * - * Each number represents a hw queue. If hw does not support hw queues - * (eg 5210) all data goes in one queue. +/* + * Queue ID numbers as returned by the hw functions, each number + * represents a hw queue. If hw does not support hw queues + * (eg 5210) all data goes in one queue. These match + * d80211 definitions (net80211/MadWiFi don't use them). */ enum ath5k_tx_queue_id { AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, - AR5K_TX_QUEUE_ID_DATA_MIN = 0, - AR5K_TX_QUEUE_ID_DATA_MAX = 3, - AR5K_TX_QUEUE_ID_UAPSD = 7, - AR5K_TX_QUEUE_ID_CAB = 8, - AR5K_TX_QUEUE_ID_BEACON = 9, + AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/ + AR5K_TX_QUEUE_ID_DATA_MAX = 3, /*IEEE80211_TX_QUEUE_DATA3*/ + AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/ + AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/ + AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/ + AR5K_TX_QUEUE_ID_UAPSD = 8, + AR5K_TX_QUEUE_ID_XR_DATA = 9, }; /* @@ -603,70 +521,46 @@ enum ath5k_tx_queue_id { #define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ #define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ -/** - * struct ath5k_txq - Transmit queue state - * @qnum: Hardware q number - * @link: Link ptr in last TX desc - * @q: Transmit queue (&struct list_head) - * @lock: Lock on q and link - * @setup: Is the queue configured - * @txq_len:Number of queued buffers - * @txq_max: Max allowed num of queued buffers - * @txq_poll_mark: Used to check if queue got stuck - * @txq_stuck: Queue stuck counter - * - * One of these exists for each hardware transmit queue. - * Packets sent to us from above are assigned to queues based - * on their priority. Not all devices support a complete set - * of hardware transmit queues. For those devices the array - * sc_ac2q will map multiple priorities to fewer hardware queues - * (typically all to one hardware queue). +/* + * Data transmit queue state. One of these exists for each + * hardware transmit queue. Packets sent to us from above + * are assigned to queues based on their priority. Not all + * devices support a complete set of hardware transmit queues. + * For those devices the array sc_ac2q will map multiple + * priorities to fewer hardware queues (typically all to one + * hardware queue). */ struct ath5k_txq { - unsigned int qnum; - u32 *link; - struct list_head q; - spinlock_t lock; + unsigned int qnum; /* hardware q number */ + u32 *link; /* link ptr in last TX desc */ + struct list_head q; /* transmit queue */ + spinlock_t lock; /* lock on q and link */ bool setup; - int txq_len; - int txq_max; + int txq_len; /* number of queued buffers */ + int txq_max; /* max allowed num of queued buffers */ bool txq_poll_mark; - unsigned int txq_stuck; + unsigned int txq_stuck; /* informational counter */ }; -/** - * struct ath5k_txq_info - A struct to hold TX queue's parameters - * @tqi_type: One of enum ath5k_tx_queue - * @tqi_subtype: One of enum ath5k_tx_queue_subtype - * @tqi_flags: TX queue flags (see above) - * @tqi_aifs: Arbitrated Inter-frame Space - * @tqi_cw_min: Minimum Contention Window - * @tqi_cw_max: Maximum Contention Window - * @tqi_cbr_period: Constant bit rate period - * @tqi_ready_time: Time queue waits after an event when RDYTIME is enabled +/* + * A struct to hold tx queue's parameters */ struct ath5k_txq_info { enum ath5k_tx_queue tqi_type; enum ath5k_tx_queue_subtype tqi_subtype; - u16 tqi_flags; - u8 tqi_aifs; - u16 tqi_cw_min; - u16 tqi_cw_max; - u32 tqi_cbr_period; + u16 tqi_flags; /* Tx queue flags (see above) */ + u8 tqi_aifs; /* Arbitrated Interframe Space */ + u16 tqi_cw_min; /* Minimum Contention Window */ + u16 tqi_cw_max; /* Maximum Contention Window */ + u32 tqi_cbr_period; /* Constant bit rate period */ u32 tqi_cbr_overflow_limit; u32 tqi_burst_time; - u32 tqi_ready_time; + u32 tqi_ready_time; /* Time queue waits after an event */ }; -/** - * enum ath5k_pkt_type - Transmit packet types - * @AR5K_PKT_TYPE_NORMAL: Normal data - * @AR5K_PKT_TYPE_ATIM: ATIM - * @AR5K_PKT_TYPE_PSPOLL: PS-Poll - * @AR5K_PKT_TYPE_BEACON: Beacon - * @AR5K_PKT_TYPE_PROBE_RESP: Probe response - * @AR5K_PKT_TYPE_PIFS: PIFS - * Used on tx control descriptor +/* + * Transmit packet types. + * used on tx control descriptor */ enum ath5k_pkt_type { AR5K_PKT_TYPE_NORMAL = 0, @@ -689,23 +583,27 @@ enum ath5k_pkt_type { (ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v) \ ) +/* + * DMA size definitions (2^(n+2)) + */ +enum ath5k_dmasize { + AR5K_DMASIZE_4B = 0, + AR5K_DMASIZE_8B, + AR5K_DMASIZE_16B, + AR5K_DMASIZE_32B, + AR5K_DMASIZE_64B, + AR5K_DMASIZE_128B, + AR5K_DMASIZE_256B, + AR5K_DMASIZE_512B +}; /****************\ RX DEFINITIONS \****************/ -/** - * struct ath5k_rx_status - RX Status descriptor - * @rs_datalen: Data length - * @rs_tstamp: Timestamp - * @rs_status: Status code - * @rs_phyerr: PHY error mask - * @rs_rssi: RSSI in 0.5dbm units - * @rs_keyix: Index to the key used for decrypting - * @rs_rate: Rate used to decode the frame - * @rs_antenna: Antenna used to receive the frame - * @rs_more: Indicates this is a frame fragment (Fast frames) +/* + * RX Status descriptor */ struct ath5k_rx_status { u16 rs_datalen; @@ -747,18 +645,10 @@ struct ath5k_rx_status { #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) - /*******************************\ GAIN OPTIMIZATION DEFINITIONS \*******************************/ -/** - * enum ath5k_rfgain - RF Gain optimization engine state - * @AR5K_RFGAIN_INACTIVE: Engine disabled - * @AR5K_RFGAIN_ACTIVE: Probe active - * @AR5K_RFGAIN_READ_REQUESTED: Probe requested - * @AR5K_RFGAIN_NEED_CHANGE: Gain_F needs change - */ enum ath5k_rfgain { AR5K_RFGAIN_INACTIVE = 0, AR5K_RFGAIN_ACTIVE, @@ -766,16 +656,6 @@ enum ath5k_rfgain { AR5K_RFGAIN_NEED_CHANGE, }; -/** - * struct ath5k_gain - RF Gain optimization engine state data - * @g_step_idx: Current step index - * @g_current: Current gain - * @g_target: Target gain - * @g_low: Low gain boundary - * @g_high: High gain boundary - * @g_f_corr: Gain_F correction - * @g_state: One of enum ath5k_rfgain - */ struct ath5k_gain { u8 g_step_idx; u8 g_current; @@ -786,8 +666,6 @@ struct ath5k_gain { u8 g_state; }; - - /********************\ COMMON DEFINITIONS \********************/ @@ -796,14 +674,9 @@ struct ath5k_gain { #define AR5K_SLOT_TIME_20 880 #define AR5K_SLOT_TIME_MAX 0xffff -/** - * struct ath5k_athchan_2ghz - 2GHz to 5GHZ map for RF5111 - * @a2_flags: Channel flags (internal) - * @a2_athchan: HW channel number (internal) - * - * This structure is used to map 2GHz channels to - * 5GHz Atheros channels on 2111 frequency converter - * that comes together with RF5111 +/* + * The following structure is used to map 2GHz channels to + * 5GHz Atheros channels. * TODO: Clean up */ struct ath5k_athchan_2ghz { @@ -811,80 +684,36 @@ struct ath5k_athchan_2ghz { u16 a2_athchan; }; -/** - * enum ath5k_dmasize - DMA size definitions (2^(n+2)) - * @AR5K_DMASIZE_4B: 4Bytes - * @AR5K_DMASIZE_8B: 8Bytes - * @AR5K_DMASIZE_16B: 16Bytes - * @AR5K_DMASIZE_32B: 32Bytes - * @AR5K_DMASIZE_64B: 64Bytes (Default) - * @AR5K_DMASIZE_128B: 128Bytes - * @AR5K_DMASIZE_256B: 256Bytes - * @AR5K_DMASIZE_512B: 512Bytes - * - * These are used to set DMA burst size on hw - * - * Note: Some platforms can't handle more than 4Bytes - * be careful on embedded boards. - */ -enum ath5k_dmasize { - AR5K_DMASIZE_4B = 0, - AR5K_DMASIZE_8B, - AR5K_DMASIZE_16B, - AR5K_DMASIZE_32B, - AR5K_DMASIZE_64B, - AR5K_DMASIZE_128B, - AR5K_DMASIZE_256B, - AR5K_DMASIZE_512B -}; - - /******************\ RATE DEFINITIONS \******************/ /** - * DOC: Rate codes - * * Seems the ar5xxx hardware supports up to 32 rates, indexed by 1-32. * * The rate code is used to get the RX rate or set the TX rate on the * hardware descriptors. It is also used for internal modulation control * and settings. * - * This is the hardware rate map we are aware of (html unfriendly): + * This is the hardware rate map we are aware of: + * + * rate_code 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 + * rate_kbps 3000 1000 ? ? ? 2000 500 48000 + * + * rate_code 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 + * rate_kbps 24000 12000 6000 54000 36000 18000 9000 ? * - * Rate code Rate (Kbps) - * --------- ----------- - * 0x01 3000 (XR) - * 0x02 1000 (XR) - * 0x03 250 (XR) - * 0x04 - 05 -Reserved- - * 0x06 2000 (XR) - * 0x07 500 (XR) - * 0x08 48000 (OFDM) - * 0x09 24000 (OFDM) - * 0x0A 12000 (OFDM) - * 0x0B 6000 (OFDM) - * 0x0C 54000 (OFDM) - * 0x0D 36000 (OFDM) - * 0x0E 18000 (OFDM) - * 0x0F 9000 (OFDM) - * 0x10 - 17 -Reserved- - * 0x18 11000L (CCK) - * 0x19 5500L (CCK) - * 0x1A 2000L (CCK) - * 0x1B 1000L (CCK) - * 0x1C 11000S (CCK) - * 0x1D 5500S (CCK) - * 0x1E 2000S (CCK) - * 0x1F -Reserved- + * rate_code 17 18 19 20 21 22 23 24 + * rate_kbps ? ? ? ? ? ? ? 11000 * - * "S" indicates CCK rates with short preamble and "L" with long preamble. + * rate_code 25 26 27 28 29 30 31 32 + * rate_kbps 5500 2000 1000 11000S 5500S 2000S ? ? + * + * "S" indicates CCK rates with short preamble. * * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the - * lowest 4 bits, so they are the same as above with a 0xF mask. + * lowest 4 bits, so they are the same as below with a 0xF mask. * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M). * We handle this in ath5k_setup_bands(). */ @@ -904,9 +733,13 @@ enum ath5k_dmasize { #define ATH5K_RATE_CODE_36M 0x0D #define ATH5K_RATE_CODE_48M 0x08 #define ATH5K_RATE_CODE_54M 0x0C +/* XR */ +#define ATH5K_RATE_CODE_XR_500K 0x07 +#define ATH5K_RATE_CODE_XR_1M 0x02 +#define ATH5K_RATE_CODE_XR_2M 0x06 +#define ATH5K_RATE_CODE_XR_3M 0x01 -/* Adding this flag to rate_code on B rates - * enables short preamble */ +/* adding this flag to rate_code enables short preamble */ #define AR5K_SET_SHORT_PREAMBLE 0x04 /* @@ -914,7 +747,7 @@ enum ath5k_dmasize { */ #define AR5K_KEYCACHE_SIZE 8 -extern bool ath5k_modparam_nohwcrypt; +extern int ath5k_modparam_nohwcrypt; /***********************\ HW RELATED DEFINITIONS @@ -936,65 +769,49 @@ extern bool ath5k_modparam_nohwcrypt; /** * enum ath5k_int - Hardware interrupt masks helpers - * @AR5K_INT_RXOK: Frame successfully received - * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor - * @AR5K_INT_RXERR: Frame reception failed - * @AR5K_INT_RXNOFRM: No frame received within a specified time period - * @AR5K_INT_RXEOL: Reached "End Of List", means we need more RX descriptors - * @AR5K_INT_RXORN: Indicates we got RX FIFO overrun. Note that Rx overrun is - * not always fatal, on some chips we can continue operation - * without resetting the card, that's why %AR5K_INT_FATAL is not - * common for all chips. - * @AR5K_INT_RX_ALL: Mask to identify all RX related interrupts - * - * @AR5K_INT_TXOK: Frame transmission success - * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor - * @AR5K_INT_TXERR: Frame transmission failure - * @AR5K_INT_TXEOL: Received End Of List for VEOL (Virtual End Of List). The - * Queue Control Unit (QCU) signals an EOL interrupt only if a - * descriptor's LinkPtr is NULL. For more details, refer to: - * "http://www.freepatentsonline.com/20030225739.html" - * @AR5K_INT_TXNOFRM: No frame was transmitted within a specified time period - * @AR5K_INT_TXURN: Indicates we got TX FIFO underrun. In such case we should - * increase the TX trigger threshold. - * @AR5K_INT_TX_ALL: Mask to identify all TX related interrupts * + * @AR5K_INT_RX: mask to identify received frame interrupts, of type + * AR5K_ISR_RXOK or AR5K_ISR_RXERR + * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?) + * @AR5K_INT_RXNOFRM: No frame received (?) + * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The + * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's + * LinkPtr is NULL. For more details, refer to: + * http://www.freepatentsonline.com/20030225739.html + * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors). + * Note that Rx overrun is not always fatal, on some chips we can continue + * operation without resetting the card, that's why int_fatal is not + * common for all chips. + * @AR5K_INT_TX: mask to identify received frame interrupts, of type + * AR5K_ISR_TXOK or AR5K_ISR_TXERR + * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?) + * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold + * We currently do increments on interrupt by + * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 * @AR5K_INT_MIB: Indicates the either Management Information Base counters or - * one of the PHY error counters reached the maximum value and - * should be read and cleared. - * @AR5K_INT_SWI: Software triggered interrupt. + * one of the PHY error counters reached the maximum value and should be + * read and cleared. * @AR5K_INT_RXPHY: RX PHY Error * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a - * beacon that must be handled in software. The alternative is if - * you have VEOL support, in that case you let the hardware deal - * with things. - * @AR5K_INT_BRSSI: Beacon received with an RSSI value below our threshold + * beacon that must be handled in software. The alternative is if you + * have VEOL support, in that case you let the hardware deal with things. * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing - * beacons from the AP have associated with, we should probably - * try to reassociate. When in IBSS mode this might mean we have - * not received any beacons from any local stations. Note that - * every station in an IBSS schedules to send beacons at the - * Target Beacon Transmission Time (TBTT) with a random backoff. - * @AR5K_INT_BNR: Beacon queue got triggered (DMA beacon alert) while empty. - * @AR5K_INT_TIM: Beacon with local station's TIM bit set - * @AR5K_INT_DTIM: Beacon with DTIM bit and zero DTIM count received - * @AR5K_INT_DTIM_SYNC: DTIM sync lost - * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill switches connected to - * our GPIO pins. - * @AR5K_INT_BCN_TIMEOUT: Beacon timeout, we waited after TBTT but got noting - * @AR5K_INT_CAB_TIMEOUT: We waited for CAB traffic after the beacon but got - * nothing or an incomplete CAB frame sequence. - * @AR5K_INT_QCBRORN: A queue got it's CBR counter expired - * @AR5K_INT_QCBRURN: A queue got triggered wile empty - * @AR5K_INT_QTRIG: A queue got triggered - * - * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by bus/DMA - * errors. Indicates we need to reset the card. + * beacons from the AP have associated with, we should probably try to + * reassociate. When in IBSS mode this might mean we have not received + * any beacons from any local stations. Note that every station in an + * IBSS schedules to send beacons at the Target Beacon Transmission Time + * (TBTT) with a random backoff. + * @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? + * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now + * until properly handled + * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA + * errors. These types of errors we can enable seem to be of type + * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. * @AR5K_INT_GLOBAL: Used to clear and set the IER - * @AR5K_INT_NOCARD: Signals the card has been removed - * @AR5K_INT_COMMON: Common interrupts shared among MACs with the same - * bit value + * @AR5K_INT_NOCARD: signals the card has been removed + * @AR5K_INT_COMMON: common interrupts shared among MACs with the same + * bit value * * These are mapped to take advantage of some common bits * between the MACs, to be able to set intr properties @@ -1030,15 +847,15 @@ enum ath5k_int { AR5K_INT_GPIO = 0x01000000, AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ - AR5K_INT_QCBRORN = 0x08000000, /* Non common */ - AR5K_INT_QCBRURN = 0x10000000, /* Non common */ - AR5K_INT_QTRIG = 0x20000000, /* Non common */ + AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ + AR5K_INT_QCBRORN = 0x10000000, /* Non common */ + AR5K_INT_QCBRURN = 0x20000000, /* Non common */ + AR5K_INT_QTRIG = 0x40000000, /* Non common */ AR5K_INT_GLOBAL = 0x80000000, AR5K_INT_TX_ALL = AR5K_INT_TXOK | AR5K_INT_TXDESC | AR5K_INT_TXERR - | AR5K_INT_TXNOFRM | AR5K_INT_TXEOL | AR5K_INT_TXURN, @@ -1074,32 +891,15 @@ enum ath5k_int { AR5K_INT_NOCARD = 0xffffffff }; -/** - * enum ath5k_calibration_mask - Mask which calibration is active at the moment - * @AR5K_CALIBRATION_FULL: Full calibration (AGC + SHORT) - * @AR5K_CALIBRATION_SHORT: Short calibration (NF + I/Q) - * @AR5K_CALIBRATION_NF: Noise Floor calibration - * @AR5K_CALIBRATION_ANI: Adaptive Noise Immunity - */ +/* mask which calibration is active at the moment */ enum ath5k_calibration_mask { AR5K_CALIBRATION_FULL = 0x01, AR5K_CALIBRATION_SHORT = 0x02, - AR5K_CALIBRATION_NF = 0x04, - AR5K_CALIBRATION_ANI = 0x08, + AR5K_CALIBRATION_ANI = 0x04, }; -/** - * enum ath5k_power_mode - Power management modes - * @AR5K_PM_UNDEFINED: Undefined - * @AR5K_PM_AUTO: Allow card to sleep if possible - * @AR5K_PM_AWAKE: Force card to wake up - * @AR5K_PM_FULL_SLEEP: Force card to full sleep (DANGEROUS) - * @AR5K_PM_NETWORK_SLEEP: Allow to sleep for a specified duration - * - * Currently only PM_AWAKE is used, FULL_SLEEP and NETWORK_SLEEP/AUTO - * are also known to have problems on some cards. This is not a big - * problem though because we can have almost the same effect as - * FULL_SLEEP by putting card on warm reset (it's almost powered down). +/* + * Power management */ enum ath5k_power_mode { AR5K_PM_UNDEFINED = 0, @@ -1157,8 +957,6 @@ struct ath5k_capabilities { } cap_queues; bool cap_has_phyerr_counters; - bool cap_has_mrr_support; - bool cap_needs_2GHz_ovr; }; /* size of noise floor history (keep it a power of two) */ @@ -1274,11 +1072,13 @@ struct ath5k_hw { dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - DECLARE_BITMAP(status, 4); + DECLARE_BITMAP(status, 6); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ -#define ATH_STAT_PROMISC 1 -#define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */ -#define ATH_STAT_STARTED 3 /* opened & irqs enabled */ +#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ +#define ATH_STAT_PROMISC 2 +#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ +#define ATH_STAT_STARTED 4 /* opened & irqs enabled */ +#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ struct ieee80211_channel *curchan; /* current h/w channel */ @@ -1297,7 +1097,6 @@ struct ath5k_hw { led_on; /* pin setting for LED on */ struct work_struct reset_work; /* deferred chip reset */ - struct work_struct calib_work; /* deferred phy calibration */ struct list_head rxbuf; /* receive buffer */ spinlock_t rxbuflock; @@ -1314,13 +1113,14 @@ struct ath5k_hw { struct ath5k_rfkill rf_kill; + struct tasklet_struct calib; /* calibration tasklet */ + spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct list_head bcbuf; /* beacon buffer */ struct ieee80211_vif *bslot[ATH_BCBUF]; u16 num_ap_vifs; u16 num_adhoc_vifs; - u16 num_mesh_vifs; unsigned int bhalq, /* SW q for outgoing beacons */ bmisscount, /* missed beacon transmits */ bintval, /* beacon interval in TU */ @@ -1344,7 +1144,7 @@ struct ath5k_hw { enum ath5k_int ah_imr; struct ieee80211_channel *ah_current_channel; - bool ah_iq_cal_needed; + bool ah_calibration; bool ah_single_chip; enum ath5k_version ah_version; @@ -1387,13 +1187,7 @@ struct ath5k_hw { u32 ah_txq_imr_cbrurn; u32 ah_txq_imr_qtrig; u32 ah_txq_imr_nofrm; - - u32 ah_txq_isr_txok_all; - u32 ah_txq_isr_txurn; - u32 ah_txq_isr_qcborn; - u32 ah_txq_isr_qcburn; - u32 ah_txq_isr_qtrig; - + u32 ah_txq_isr; u32 *ah_rf_banks; size_t ah_rf_banks_size; size_t ah_rf_regs_count; @@ -1434,8 +1228,8 @@ struct ath5k_hw { /* Calibration timestamp */ unsigned long ah_cal_next_full; - unsigned long ah_cal_next_short; unsigned long ah_cal_next_ani; + unsigned long ah_cal_next_nf; /* Calibration mask */ u8 ah_cal_mask; @@ -1544,11 +1338,11 @@ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64); void ath5k_hw_reset_tsf(struct ath5k_hw *ah); -void ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, - u32 interval); +void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval); /* Init function */ -void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode); +void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, + u8 mode); /* Queue Control Unit, DFS Control Unit Functions */ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, @@ -1657,12 +1451,12 @@ static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg) static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) { - return ioread32(ath5k_ahb_reg(ah, reg)); + return __raw_readl(ath5k_ahb_reg(ah, reg)); } static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) { - iowrite32(val, ath5k_ahb_reg(ah, reg)); + __raw_writel(val, ath5k_ahb_reg(ah, reg)); } #else diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index d7114c75..91627dd2 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -27,7 +27,8 @@ #include "debug.h" /** - * ath5k_hw_post() - Power On Self Test helper function + * ath5k_hw_post - Power On Self Test helper function + * * @ah: The &struct ath5k_hw */ static int ath5k_hw_post(struct ath5k_hw *ah) @@ -91,7 +92,8 @@ static int ath5k_hw_post(struct ath5k_hw *ah) } /** - * ath5k_hw_init() - Check if hw is supported and init the needed structs + * ath5k_hw_init - Check if hw is supported and init the needed structs + * * @ah: The &struct ath5k_hw associated with the device * * Check if the device is supported, perform a POST and initialize the needed @@ -296,7 +298,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) /* Reset SERDES to load new settings */ ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); - usleep_range(1000, 1500); + mdelay(1); } /* Get misc capabilities */ @@ -306,6 +308,11 @@ int ath5k_hw_init(struct ath5k_hw *ah) goto err; } + if (test_bit(ATH_STAT_2G_DISABLED, ah->status)) { + __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode); + __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode); + } + /* Crypto settings */ common->keymax = (ah->ah_version == AR5K_AR5210 ? AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); @@ -342,7 +349,8 @@ int ath5k_hw_init(struct ath5k_hw *ah) } /** - * ath5k_hw_deinit() - Free the &struct ath5k_hw + * ath5k_hw_deinit - Free the ath5k_hw struct + * * @ah: The &struct ath5k_hw */ void ath5k_hw_deinit(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c old mode 100644 new mode 100755 index c7d1437c..362ed14d --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -68,23 +68,18 @@ #define CREATE_TRACE_POINTS #include "trace.h" -bool ath5k_modparam_nohwcrypt; +int ath5k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -static bool modparam_all_channels; +static int modparam_all_channels; module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); -static bool modparam_fastchanswitch; +static int modparam_fastchanswitch; module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); -static bool ath5k_modparam_no_hw_rfkill_switch; -module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch, - bool, S_IRUGO); -MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state"); - /* Module info */ MODULE_AUTHOR("Jiri Slaby"); @@ -188,6 +183,7 @@ static const struct ieee80211_rate ath5k_rates[] = { { .bitrate = 540, .hw_value = ATH5K_RATE_CODE_54M, .flags = 0 }, + /* XR missing */ }; static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) @@ -725,25 +721,22 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, if (ret) goto err_unmap; - /* Set up MRR descriptor */ - if (ah->ah_capabilities.cap_has_mrr_support) { - memset(mrr_rate, 0, sizeof(mrr_rate)); - memset(mrr_tries, 0, sizeof(mrr_tries)); - for (i = 0; i < 3; i++) { - rate = ieee80211_get_alt_retry_rate(ah->hw, info, i); - if (!rate) - break; - - mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.rates[i + 1].count; - } + memset(mrr_rate, 0, sizeof(mrr_rate)); + memset(mrr_tries, 0, sizeof(mrr_tries)); + for (i = 0; i < 3; i++) { + rate = ieee80211_get_alt_retry_rate(ah->hw, info, i); + if (!rate) + break; - ath5k_hw_setup_mrr_tx_desc(ah, ds, - mrr_rate[0], mrr_tries[0], - mrr_rate[1], mrr_tries[1], - mrr_rate[2], mrr_tries[2]); + mrr_rate[i] = rate->hw_value; + mrr_tries[i] = info->control.rates[i + 1].count; } + ath5k_hw_setup_mrr_tx_desc(ah, ds, + mrr_rate[0], mrr_tries[0], + mrr_rate[1], mrr_tries[1], + mrr_rate[2], mrr_tries[2]); + ds->ds_link = 0; ds->ds_data = bf->skbaddr; @@ -1696,7 +1689,7 @@ ath5k_tasklet_tx(unsigned long data) struct ath5k_hw *ah = (void *)data; for (i = 0; i < AR5K_NUM_TX_QUEUES; i++) - if (ah->txqs[i].setup && (ah->ah_txq_isr_txok_all & BIT(i))) + if (ah->txqs[i].setup && (ah->ah_txq_isr & BIT(i))) ath5k_tx_processq(ah, &ah->txqs[i]); ah->tx_pending = false; @@ -1867,8 +1860,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) ah->bmisscount = 0; } - if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + - ah->num_mesh_vifs > 1) || + if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) || ah->opmode == NL80211_IFTYPE_MESH_POINT) { u64 tsf = ath5k_hw_get_tsf64(ah); u32 tsftu = TSF_TO_TU(tsf); @@ -1953,8 +1945,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf) u64 hw_tsf; intval = ah->bintval & AR5K_BEACON_PERIOD; - if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs - + ah->num_mesh_vifs > 1) { + if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) { intval /= ATH_BCBUF; /* staggered multi-bss beacons */ if (intval < 15) ATH5K_WARN(ah, "intval %u is too low, min 15\n", @@ -2014,7 +2005,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf) ah->nexttbtt = nexttbtt; intval |= AR5K_BEACON_ENA; - ath5k_hw_init_beacon_timers(ah, nexttbtt, intval); + ath5k_hw_init_beacon(ah, nexttbtt, intval); /* * debugging output last in order to preserve the time critical aspect @@ -2121,29 +2112,16 @@ static void ath5k_intr_calibration_poll(struct ath5k_hw *ah) { if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && - !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && - !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) { - - /* Run ANI only when calibration is not active */ - + !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { + /* run ANI only when full calibration is not active */ ah->ah_cal_next_ani = jiffies + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); tasklet_schedule(&ah->ani_tasklet); - } else if (time_is_before_eq_jiffies(ah->ah_cal_next_short) && - !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && - !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) { - - /* Run calibration only when another calibration - * is not running. - * - * Note: This is for both full/short calibration, - * if it's time for a full one, ath5k_calibrate_work will deal - * with it. */ - - ah->ah_cal_next_short = jiffies + - msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); - ieee80211_queue_work(ah->hw, &ah->calib_work); + } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { + ah->ah_cal_next_full = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); + tasklet_schedule(&ah->calib); } /* we could use SWI to generate enough interrupts to meet our * calibration interval requirements, if necessary: @@ -2171,110 +2149,69 @@ ath5k_intr(int irq, void *dev_id) enum ath5k_int status; unsigned int counter = 1000; - - /* - * If hw is not ready (or detached) and we get an - * interrupt, or if we have no interrupts pending - * (that means it's not for us) skip it. - * - * NOTE: Group 0/1 PCI interface registers are not - * supported on WiSOCs, so we can't check for pending - * interrupts (ISR belongs to another register group - * so we are ok). - */ if (unlikely(test_bit(ATH_STAT_INVALID, ah->status) || - ((ath5k_get_bus_type(ah) != ATH_AHB) && - !ath5k_hw_is_intr_pending(ah)))) + ((ath5k_get_bus_type(ah) != ATH_AHB) && + !ath5k_hw_is_intr_pending(ah)))) return IRQ_NONE; - /** Main loop **/ do { - ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ - + ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ ATH5K_DBG(ah, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", status, ah->imask); - - /* - * Fatal hw error -> Log and reset - * - * Fatal errors are unrecoverable so we have to - * reset the card. These errors include bus and - * dma errors. - */ if (unlikely(status & AR5K_INT_FATAL)) { - + /* + * Fatal errors are unrecoverable. + * Typically these are caused by DMA errors. + */ ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "fatal int, resetting\n"); ieee80211_queue_work(ah->hw, &ah->reset_work); - - /* - * RX Overrun -> Count and reset if needed - * - * Receive buffers are full. Either the bus is busy or - * the CPU is not fast enough to process all received - * frames. - */ } else if (unlikely(status & AR5K_INT_RXORN)) { - /* + * Receive buffers are full. Either the bus is busy or + * the CPU is not fast enough to process all received + * frames. * Older chipsets need a reset to come out of this * condition, but we treat it as RX for newer chips. - * We don't know exactly which versions need a reset + * We don't know exactly which versions need a reset - * this guess is copied from the HAL. */ ah->stats.rxorn_intr++; - if (ah->ah_mac_srev < AR5K_SREV_AR5212) { ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "rx overrun, resetting\n"); ieee80211_queue_work(ah->hw, &ah->reset_work); } else ath5k_schedule_rx(ah); - } else { - - /* Software Beacon Alert -> Schedule beacon tasklet */ if (status & AR5K_INT_SWBA) tasklet_hi_schedule(&ah->beacontq); - /* - * No more RX descriptors -> Just count - * - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work at - * least on older hardware revs. - */ - if (status & AR5K_INT_RXEOL) + if (status & AR5K_INT_RXEOL) { + /* + * NB: the hardware should re-read the link when + * RXE bit is written, but it doesn't work at + * least on older hardware revs. + */ ah->stats.rxeol_intr++; - - - /* TX Underrun -> Bump tx trigger level */ - if (status & AR5K_INT_TXURN) + } + if (status & AR5K_INT_TXURN) { + /* bump tx trigger level */ ath5k_hw_update_tx_triglevel(ah, true); - - /* RX -> Schedule rx tasklet */ + } if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) ath5k_schedule_rx(ah); - - /* TX -> Schedule tx tasklet */ - if (status & (AR5K_INT_TXOK - | AR5K_INT_TXDESC - | AR5K_INT_TXERR - | AR5K_INT_TXEOL)) + if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC + | AR5K_INT_TXERR | AR5K_INT_TXEOL)) ath5k_schedule_tx(ah); - - /* Missed beacon -> TODO - if (status & AR5K_INT_BMISS) - */ - - /* MIB event -> Update counters and notify ANI */ + if (status & AR5K_INT_BMISS) { + /* TODO */ + } if (status & AR5K_INT_MIB) { ah->stats.mib_intr++; ath5k_hw_update_mib_counters(ah); ath5k_ani_mib_intr(ah); } - - /* GPIO -> Notify RFKill layer */ if (status & AR5K_INT_GPIO) tasklet_schedule(&ah->rf_kill.toggleq); @@ -2285,19 +2222,12 @@ ath5k_intr(int irq, void *dev_id) } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); - /* - * Until we handle rx/tx interrupts mask them on IMR - * - * NOTE: ah->(rx/tx)_pending are set when scheduling the tasklets - * and unset after we 've handled the interrupts. - */ if (ah->rx_pending || ah->tx_pending) ath5k_set_current_imask(ah); if (unlikely(!counter)) ATH5K_WARN(ah, "too many interrupts, giving up for now\n"); - /* Fire up calibration poll */ ath5k_intr_calibration_poll(ah); return IRQ_HANDLED; @@ -2308,48 +2238,41 @@ ath5k_intr(int irq, void *dev_id) * for temperature/environment changes. */ static void -ath5k_calibrate_work(struct work_struct *work) +ath5k_tasklet_calibrate(unsigned long data) { - struct ath5k_hw *ah = container_of(work, struct ath5k_hw, - calib_work); - - /* Should we run a full calibration ? */ - if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { - - ah->ah_cal_next_full = jiffies + - msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); - ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; - - ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, - "running full calibration\n"); - - if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { - /* - * Rfgain is out of bounds, reset the chip - * to load new gain values. - */ - ATH5K_DBG(ah, ATH5K_DEBUG_RESET, - "got new rfgain, resetting\n"); - ieee80211_queue_work(ah->hw, &ah->reset_work); - } - } else - ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT; + struct ath5k_hw *ah = (void *)data; + /* Only full calibration for now */ + ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ieee80211_frequency_to_channel(ah->curchan->center_freq), ah->curchan->hw_value); + if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { + /* + * Rfgain is out of bounds, reset the chip + * to load new gain values. + */ + ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "calibration, resetting\n"); + ieee80211_queue_work(ah->hw, &ah->reset_work); + } if (ath5k_hw_phy_calibrate(ah, ah->curchan)) ATH5K_ERR(ah, "calibration of channel %u failed\n", ieee80211_frequency_to_channel( ah->curchan->center_freq)); - /* Clear calibration flags */ - if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) - ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; - else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT) - ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT; + /* Noise floor calibration interrupts rx/tx path while I/Q calibration + * doesn't. + * TODO: We should stop TX here, so that it doesn't interfere. + * Note that stopping the queues is not enough to stop TX! */ + if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) { + ah->ah_cal_next_nf = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF); + ath5k_hw_update_noise_floor(ah); + } + + ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; } @@ -2434,9 +2357,6 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - /* SW support for IBSS_RSN is provided by mac80211 */ - hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - /* both antennas can be configured as RX or TX */ hw->wiphy->available_antennas_tx = 0x3; hw->wiphy->available_antennas_rx = 0x3; @@ -2487,8 +2407,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) if (ret) goto err_irq; - /* Set up multi-rate retry capabilities */ - if (ah->ah_capabilities.cap_has_mrr_support) { + /* set up multi-rate retry capabilities */ + if (ah->ah_version == AR5K_AR5212) { hw->max_rates = 4; hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT, AR5K_INIT_RETRY_LONG); @@ -2624,22 +2544,15 @@ int ath5k_start(struct ieee80211_hw *hw) * and then setup of the interrupt mask. */ ah->curchan = ah->hw->conf.channel; - ah->imask = AR5K_INT_RXOK - | AR5K_INT_RXERR - | AR5K_INT_RXEOL - | AR5K_INT_RXORN - | AR5K_INT_TXDESC - | AR5K_INT_TXEOL - | AR5K_INT_FATAL - | AR5K_INT_GLOBAL - | AR5K_INT_MIB; + ah->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | + AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; ret = ath5k_reset(ah, NULL, false); if (ret) goto done; - if (!ath5k_modparam_no_hw_rfkill_switch) - ath5k_rfkill_hw_start(ah); + ath5k_rfkill_hw_start(ah); /* * Reset the key cache since some parts do not reset the @@ -2672,6 +2585,7 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah) ah->tx_pending = false; tasklet_kill(&ah->rxtq); tasklet_kill(&ah->txtq); + tasklet_kill(&ah->calib); tasklet_kill(&ah->beacontq); tasklet_kill(&ah->ani_tasklet); } @@ -2723,8 +2637,7 @@ void ath5k_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&ah->tx_complete_work); - if (!ath5k_modparam_no_hw_rfkill_switch) - ath5k_rfkill_hw_stop(ah); + ath5k_rfkill_hw_stop(ah); } /* @@ -2776,24 +2689,9 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, ath5k_ani_init(ah, ani_mode); - /* - * Set calibration intervals - * - * Note: We don't need to run calibration imediately - * since some initial calibration is done on reset - * even for fast channel switching. Also on scanning - * this will get set again and again and it won't get - * executed unless we connect somewhere and spend some - * time on the channel (that's what calibration needs - * anyway to be accurate). - */ - ah->ah_cal_next_full = jiffies + - msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); - ah->ah_cal_next_ani = jiffies + - msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); - ah->ah_cal_next_short = jiffies + - msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); - + ah->ah_cal_next_full = jiffies + msecs_to_jiffies(100); + ah->ah_cal_next_ani = jiffies; + ah->ah_cal_next_nf = jiffies; ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8); /* clear survey data and cycle counters */ @@ -2846,6 +2744,20 @@ ath5k_init(struct ieee80211_hw *hw) int ret; + /* + * Check if the MAC has multi-rate retry support. + * We do this by trying to setup a fake extended + * descriptor. MACs that don't have support will + * return false w/o doing anything. MACs that do + * support it will return true w/o doing anything. + */ + ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); + + if (ret < 0) + goto err; + if (ret > 0) + __set_bit(ATH_STAT_MRRETRY, ah->status); + /* * Collect the channel list. The 802.11 layer * is responsible for filtering this list based @@ -2929,11 +2841,11 @@ ath5k_init(struct ieee80211_hw *hw) tasklet_init(&ah->rxtq, ath5k_tasklet_rx, (unsigned long)ah); tasklet_init(&ah->txtq, ath5k_tasklet_tx, (unsigned long)ah); + tasklet_init(&ah->calib, ath5k_tasklet_calibrate, (unsigned long)ah); tasklet_init(&ah->beacontq, ath5k_tasklet_beacon, (unsigned long)ah); tasklet_init(&ah->ani_tasklet, ath5k_tasklet_ani, (unsigned long)ah); INIT_WORK(&ah->reset_work, ath5k_reset_work); - INIT_WORK(&ah->calib_work, ath5k_calibrate_work); INIT_DELAYED_WORK(&ah->tx_complete_work, ath5k_tx_complete_poll_work); ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index 994169ad..810fba96 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -85,19 +85,12 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) caps->cap_range.range_2ghz_min = 2412; caps->cap_range.range_2ghz_max = 2732; - /* Override 2GHz modes on SoCs that need it - * NOTE: cap_needs_2GHz_ovr gets set from - * ath_ahb_probe */ - if (!caps->cap_needs_2GHz_ovr) { - if (AR5K_EEPROM_HDR_11B(ee_header)) - __set_bit(AR5K_MODE_11B, - caps->cap_mode); - - if (AR5K_EEPROM_HDR_11G(ee_header) && - ah->ah_version != AR5K_AR5211) - __set_bit(AR5K_MODE_11G, - caps->cap_mode); - } + if (AR5K_EEPROM_HDR_11B(ee_header)) + __set_bit(AR5K_MODE_11B, caps->cap_mode); + + if (AR5K_EEPROM_HDR_11G(ee_header) && + ah->ah_version != AR5K_AR5211) + __set_bit(AR5K_MODE_11G, caps->cap_mode); } } @@ -110,18 +103,12 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) else caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; - /* Newer hardware has PHY error counters */ + /* newer hardware has PHY error counters */ if (ah->ah_mac_srev >= AR5K_SREV_AR5213A) caps->cap_has_phyerr_counters = true; else caps->cap_has_phyerr_counters = false; - /* MACs since AR5212 have MRR support */ - if (ah->ah_version == AR5K_AR5212) - caps->cap_has_mrr_support = true; - else - caps->cap_has_mrr_support = false; - return 0; } diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index e5e8f45d..8c5ce8b0 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -71,6 +71,13 @@ static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); +static int ath5k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + + /* debugfs: registers */ struct reg { @@ -258,7 +265,7 @@ static ssize_t write_file_beacon(struct file *file, static const struct file_operations fops_beacon = { .read = read_file_beacon, .write = write_file_beacon, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -278,7 +285,7 @@ static ssize_t write_file_reset(struct file *file, static const struct file_operations fops_reset = { .write = write_file_reset, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, .llseek = noop_llseek, }; @@ -358,7 +365,7 @@ static ssize_t write_file_debug(struct file *file, static const struct file_operations fops_debug = { .read = read_file_debug, .write = write_file_debug, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -470,7 +477,7 @@ static ssize_t write_file_antenna(struct file *file, static const struct file_operations fops_antenna = { .read = read_file_antenna, .write = write_file_antenna, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -525,7 +532,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, static const struct file_operations fops_misc = { .read = read_file_misc, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, }; @@ -640,7 +647,7 @@ static ssize_t write_file_frameerrors(struct file *file, static const struct file_operations fops_frameerrors = { .read = read_file_frameerrors, .write = write_file_frameerrors, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -803,7 +810,7 @@ static ssize_t write_file_ani(struct file *file, static const struct file_operations fops_ani = { .read = read_file_ani, .write = write_file_ani, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -874,7 +881,7 @@ static ssize_t write_file_queue(struct file *file, static const struct file_operations fops_queue = { .read = read_file_queue, .write = write_file_queue, - .open = simple_open, + .open = ath5k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index f8bfa3ac..7e88dda8 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -26,61 +26,20 @@ #include "debug.h" -/** - * DOC: Hardware descriptor functions - * - * Here we handle the processing of the low-level hw descriptors - * that hw reads and writes via DMA for each TX and RX attempt (that means - * we can also have descriptors for failed TX/RX tries). We have two kind of - * descriptors for RX and TX, control descriptors tell the hw how to send or - * receive a packet where to read/write it from/to etc and status descriptors - * that contain information about how the packet was sent or received (errors - * included). - * - * Descriptor format is not exactly the same for each MAC chip version so we - * have function pointers on &struct ath5k_hw we initialize at runtime based on - * the chip used. - */ - - /************************\ * TX Control descriptors * \************************/ -/** - * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @pkt_len: Frame length in bytes - * @hdr_len: Header length in bytes (only used on AR5210) - * @padsize: Any padding we've added to the frame length - * @type: One of enum ath5k_pkt_type - * @tx_power: Tx power in 0.5dB steps - * @tx_rate0: HW idx for transmission rate - * @tx_tries0: Max number of retransmissions - * @key_index: Index on key table to use for encryption - * @antenna_mode: Which antenna to use (0 for auto) - * @flags: One of AR5K_TXDESC_* flags (desc.h) - * @rtscts_rate: HW idx for RTS/CTS transmission rate - * @rtscts_duration: What to put on duration field on the header of RTS/CTS - * - * Internal function to initialize a 2-Word TX control descriptor - * found on AR5210 and AR5211 MACs chips. - * - * Returns 0 on success or -EINVAL on false input +/* + * Initialize the 2-word tx control descriptor on 5210/5211 */ static int -ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, - struct ath5k_desc *desc, - unsigned int pkt_len, unsigned int hdr_len, - int padsize, - enum ath5k_pkt_type type, - unsigned int tx_power, - unsigned int tx_rate0, unsigned int tx_tries0, - unsigned int key_index, - unsigned int antenna_mode, - unsigned int flags, - unsigned int rtscts_rate, unsigned int rtscts_duration) +ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int pkt_len, unsigned int hdr_len, int padsize, + enum ath5k_pkt_type type, + unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, + unsigned int key_index, unsigned int antenna_mode, unsigned int flags, + unsigned int rtscts_rate, unsigned int rtscts_duration) { u32 frame_type; struct ath5k_hw_2w_tx_ctl *tx_ctl; @@ -213,40 +172,17 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @pkt_len: Frame length in bytes - * @hdr_len: Header length in bytes (only used on AR5210) - * @padsize: Any padding we've added to the frame length - * @type: One of enum ath5k_pkt_type - * @tx_power: Tx power in 0.5dB steps - * @tx_rate0: HW idx for transmission rate - * @tx_tries0: Max number of retransmissions - * @key_index: Index on key table to use for encryption - * @antenna_mode: Which antenna to use (0 for auto) - * @flags: One of AR5K_TXDESC_* flags (desc.h) - * @rtscts_rate: HW idx for RTS/CTS transmission rate - * @rtscts_duration: What to put on duration field on the header of RTS/CTS - * - * Internal function to initialize a 4-Word TX control descriptor - * found on AR5212 and later MACs chips. - * - * Returns 0 on success or -EINVAL on false input +/* + * Initialize the 4-word tx control descriptor on 5212 */ -static int -ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, - struct ath5k_desc *desc, - unsigned int pkt_len, unsigned int hdr_len, - int padsize, - enum ath5k_pkt_type type, - unsigned int tx_power, - unsigned int tx_rate0, unsigned int tx_tries0, - unsigned int key_index, - unsigned int antenna_mode, - unsigned int flags, - unsigned int rtscts_rate, unsigned int rtscts_duration) +static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, + struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, + int padsize, + enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, + unsigned int tx_tries0, unsigned int key_index, + unsigned int antenna_mode, unsigned int flags, + unsigned int rtscts_rate, + unsigned int rtscts_duration) { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; @@ -356,29 +292,13 @@ ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_setup_mrr_tx_desc() - Initialize an MRR tx control descriptor - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @tx_rate1: HW idx for rate used on transmission series 1 - * @tx_tries1: Max number of retransmissions for transmission series 1 - * @tx_rate2: HW idx for rate used on transmission series 2 - * @tx_tries2: Max number of retransmissions for transmission series 2 - * @tx_rate3: HW idx for rate used on transmission series 3 - * @tx_tries3: Max number of retransmissions for transmission series 3 - * - * Multi rate retry (MRR) tx control descriptors are available only on AR5212 - * MACs, they are part of the normal 4-word tx control descriptor (see above) - * but we handle them through a separate function for better abstraction. - * - * Returns 0 on success or -EINVAL on invalid input +/* + * Initialize a 4-word multi rate retry tx control descriptor on 5212 */ int -ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, - struct ath5k_desc *desc, - u_int tx_rate1, u_int tx_tries1, - u_int tx_rate2, u_int tx_tries2, - u_int tx_rate3, u_int tx_tries3) +ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, + u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) { struct ath5k_hw_4w_tx_ctl *tx_ctl; @@ -430,16 +350,11 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, * TX Status descriptors * \***********************/ -/** - * ath5k_hw_proc_2word_tx_status() - Process a tx status descriptor on 5210/1 - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @ts: The &struct ath5k_tx_status +/* + * Process the tx status descriptor on 5210/5211 */ -static int -ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, - struct ath5k_tx_status *ts) +static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_tx_status *ts) { struct ath5k_hw_2w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; @@ -484,16 +399,11 @@ ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_proc_4word_tx_status() - Process a tx status descriptor on 5212 - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @ts: The &struct ath5k_tx_status +/* + * Process a tx status descriptor on 5212 */ -static int -ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, - struct ath5k_tx_status *ts) +static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_tx_status *ts) { struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; @@ -550,17 +460,11 @@ ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, * RX Descriptors * \****************/ -/** - * ath5k_hw_setup_rx_desc() - Initialize an rx control descriptor - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @size: RX buffer length in bytes - * @flags: One of AR5K_RXDESC_* flags +/* + * Initialize an rx control descriptor */ -int -ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, - struct ath5k_desc *desc, - u32 size, unsigned int flags) +int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags) { struct ath5k_hw_rx_ctl *rx_ctl; @@ -587,22 +491,11 @@ ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_proc_5210_rx_status() - Process the rx status descriptor on 5210/1 - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @rs: The &struct ath5k_rx_status - * - * Internal function used to process an RX status descriptor - * on AR5210/5211 MAC. - * - * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e - * frame yet. +/* + * Process the rx status descriptor on 5210/5211 */ -static int -ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, - struct ath5k_rx_status *rs) +static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; @@ -681,22 +574,12 @@ ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_proc_5212_rx_status() - Process the rx status descriptor on 5212 - * @ah: The &struct ath5k_hw - * @desc: The &struct ath5k_desc - * @rs: The &struct ath5k_rx_status - * - * Internal function used to process an RX status descriptor - * on AR5212 and later MAC. - * - * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e - * frame yet. +/* + * Process the rx status descriptor on 5212 */ -static int -ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, - struct ath5k_rx_status *rs) +static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, + struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; u32 rxstat0, rxstat1; @@ -763,16 +646,10 @@ ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, * Attach * \********/ -/** - * ath5k_hw_init_desc_functions() - Init function pointers inside ah - * @ah: The &struct ath5k_hw - * - * Maps the internal descriptor functions to the function pointers on ah, used - * from above. This is used as an abstraction layer to handle the various chips - * the same way. +/* + * Init function pointers inside ath5k_hw struct */ -int -ath5k_hw_init_desc_functions(struct ath5k_hw *ah) +int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) { if (ah->ah_version == AR5K_AR5212) { ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h index 8d6c01a4..cfd529b5 100644 --- a/drivers/net/wireless/ath/ath5k/desc.h +++ b/drivers/net/wireless/ath/ath5k/desc.h @@ -20,30 +20,25 @@ * RX/TX descriptor structures */ -/** - * struct ath5k_hw_rx_ctl - Common hardware RX control descriptor - * @rx_control_0: RX control word 0 - * @rx_control_1: RX control word 1 +/* + * Common hardware RX control descriptor */ struct ath5k_hw_rx_ctl { - u32 rx_control_0; - u32 rx_control_1; + u32 rx_control_0; /* RX control word 0 */ + u32 rx_control_1; /* RX control word 1 */ } __packed __aligned(4); /* RX control word 1 fields/flags */ #define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */ #define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 /* RX interrupt request */ -/** - * struct ath5k_hw_rx_status - Common hardware RX status descriptor - * @rx_status_0: RX status word 0 - * @rx_status_1: RX status word 1 - * +/* + * Common hardware RX status descriptor * 5210, 5211 and 5212 differ only in the fields and flags defined below */ struct ath5k_hw_rx_status { - u32 rx_status_0; - u32 rx_status_1; + u32 rx_status_0; /* RX status word 0 */ + u32 rx_status_1; /* RX status word 1 */ } __packed __aligned(4); /* 5210/5211 */ @@ -103,36 +98,17 @@ struct ath5k_hw_rx_status { /** * enum ath5k_phy_error_code - PHY Error codes - * @AR5K_RX_PHY_ERROR_UNDERRUN: Transmit underrun, [5210] No error - * @AR5K_RX_PHY_ERROR_TIMING: Timing error - * @AR5K_RX_PHY_ERROR_PARITY: Illegal parity - * @AR5K_RX_PHY_ERROR_RATE: Illegal rate - * @AR5K_RX_PHY_ERROR_LENGTH: Illegal length - * @AR5K_RX_PHY_ERROR_RADAR: Radar detect, [5210] 64 QAM rate - * @AR5K_RX_PHY_ERROR_SERVICE: Illegal service - * @AR5K_RX_PHY_ERROR_TOR: Transmit override receive - * @AR5K_RX_PHY_ERROR_OFDM_TIMING: OFDM Timing error [5212+] - * @AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY: OFDM Signal parity error [5212+] - * @AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL: OFDM Illegal rate [5212+] - * @AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL: OFDM Illegal length [5212+] - * @AR5K_RX_PHY_ERROR_OFDM_POWER_DROP: OFDM Power drop [5212+] - * @AR5K_RX_PHY_ERROR_OFDM_SERVICE: OFDM Service (?) [5212+] - * @AR5K_RX_PHY_ERROR_OFDM_RESTART: OFDM Restart (?) [5212+] - * @AR5K_RX_PHY_ERROR_CCK_TIMING: CCK Timing error [5212+] - * @AR5K_RX_PHY_ERROR_CCK_HEADER_CRC: Header CRC error [5212+] - * @AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL: Illegal rate [5212+] - * @AR5K_RX_PHY_ERROR_CCK_SERVICE: CCK Service (?) [5212+] - * @AR5K_RX_PHY_ERROR_CCK_RESTART: CCK Restart (?) [5212+] */ enum ath5k_phy_error_code { - AR5K_RX_PHY_ERROR_UNDERRUN = 0, - AR5K_RX_PHY_ERROR_TIMING = 1, - AR5K_RX_PHY_ERROR_PARITY = 2, - AR5K_RX_PHY_ERROR_RATE = 3, - AR5K_RX_PHY_ERROR_LENGTH = 4, - AR5K_RX_PHY_ERROR_RADAR = 5, - AR5K_RX_PHY_ERROR_SERVICE = 6, - AR5K_RX_PHY_ERROR_TOR = 7, + AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun, [5210] No error */ + AR5K_RX_PHY_ERROR_TIMING = 1, /* Timing error */ + AR5K_RX_PHY_ERROR_PARITY = 2, /* Illegal parity */ + AR5K_RX_PHY_ERROR_RATE = 3, /* Illegal rate */ + AR5K_RX_PHY_ERROR_LENGTH = 4, /* Illegal length */ + AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect, [5210] 64 QAM rate */ + AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */ + AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */ + /* these are specific to the 5212 */ AR5K_RX_PHY_ERROR_OFDM_TIMING = 17, AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY = 18, AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL = 19, @@ -147,14 +123,12 @@ enum ath5k_phy_error_code { AR5K_RX_PHY_ERROR_CCK_RESTART = 31, }; -/** - * struct ath5k_hw_2w_tx_ctl - 5210/5211 hardware 2-word TX control descriptor - * @tx_control_0: TX control word 0 - * @tx_control_1: TX control word 1 +/* + * 5210/5211 hardware 2-word TX control descriptor */ struct ath5k_hw_2w_tx_ctl { - u32 tx_control_0; - u32 tx_control_1; + u32 tx_control_0; /* TX control word 0 */ + u32 tx_control_1; /* TX control word 1 */ } __packed __aligned(4); /* TX control word 0 fields/flags */ @@ -203,18 +177,14 @@ struct ath5k_hw_2w_tx_ctl { #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 4 #define AR5K_AR5211_TX_DESC_FRAME_TYPE_PRESP 4 -/** - * struct ath5k_hw_4w_tx_ctl - 5212 hardware 4-word TX control descriptor - * @tx_control_0: TX control word 0 - * @tx_control_1: TX control word 1 - * @tx_control_2: TX control word 2 - * @tx_control_3: TX control word 3 +/* + * 5212 hardware 4-word TX control descriptor */ struct ath5k_hw_4w_tx_ctl { - u32 tx_control_0; - u32 tx_control_1; - u32 tx_control_2; - u32 tx_control_3; + u32 tx_control_0; /* TX control word 0 */ + u32 tx_control_1; /* TX control word 1 */ + u32 tx_control_2; /* TX control word 2 */ + u32 tx_control_3; /* TX control word 3 */ } __packed __aligned(4); /* TX control word 0 fields/flags */ @@ -268,14 +238,12 @@ struct ath5k_hw_4w_tx_ctl { #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 /* RTS or CTS rate */ #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 -/** - * struct ath5k_hw_tx_status - Common TX status descriptor - * @tx_status_0: TX status word 0 - * @tx_status_1: TX status word 1 +/* + * Common TX status descriptor */ struct ath5k_hw_tx_status { - u32 tx_status_0; - u32 tx_status_1; + u32 tx_status_0; /* TX status word 0 */ + u32 tx_status_1; /* TX status word 1 */ } __packed __aligned(4); /* TX status word 0 fields/flags */ @@ -308,47 +276,37 @@ struct ath5k_hw_tx_status { #define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212 0x00800000 /* [5212] compression status */ #define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212 0x01000000 /* [5212] transmit antenna */ -/** - * struct ath5k_hw_5210_tx_desc - 5210/5211 hardware TX descriptor - * @tx_ctl: The &struct ath5k_hw_2w_tx_ctl - * @tx_stat: The &struct ath5k_hw_tx_status +/* + * 5210/5211 hardware TX descriptor */ struct ath5k_hw_5210_tx_desc { struct ath5k_hw_2w_tx_ctl tx_ctl; struct ath5k_hw_tx_status tx_stat; } __packed __aligned(4); -/** - * struct ath5k_hw_5212_tx_desc - 5212 hardware TX descriptor - * @tx_ctl: The &struct ath5k_hw_4w_tx_ctl - * @tx_stat: The &struct ath5k_hw_tx_status +/* + * 5212 hardware TX descriptor */ struct ath5k_hw_5212_tx_desc { struct ath5k_hw_4w_tx_ctl tx_ctl; struct ath5k_hw_tx_status tx_stat; } __packed __aligned(4); -/** - * struct ath5k_hw_all_rx_desc - Common hardware RX descriptor - * @rx_ctl: The &struct ath5k_hw_rx_ctl - * @rx_stat: The &struct ath5k_hw_rx_status +/* + * Common hardware RX descriptor */ struct ath5k_hw_all_rx_desc { struct ath5k_hw_rx_ctl rx_ctl; struct ath5k_hw_rx_status rx_stat; } __packed __aligned(4); -/** - * struct ath5k_desc - Atheros hardware DMA descriptor - * @ds_link: Physical address of the next descriptor - * @ds_data: Physical address of data buffer (skb) - * @ud: Union containing hw_5xxx_tx_desc structs and hw_all_rx_desc - * +/* + * Atheros hardware DMA descriptor * This is read and written to by the hardware */ struct ath5k_desc { - u32 ds_link; - u32 ds_data; + u32 ds_link; /* physical address of the next descriptor */ + u32 ds_data; /* physical address of data buffer (skb) */ union { struct ath5k_hw_5210_tx_desc ds_tx5210; diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 5cc9aa81..2481f9c7 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -20,13 +20,16 @@ * DMA and interrupt masking functions * \*************************************/ -/** - * DOC: DMA and interrupt masking functions +/* + * dma.c - DMA and interrupt masking functions * * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and * handle queue setup for 5210 chipset (rest are handled on qcu.c). * Also we setup interrupt mask register (IMR) and read the various interrupt * status registers (ISR). + * + * TODO: Handle SISR on 5211+ and introduce a function to return the queue + * number that resulted the interrupt. */ #include "ath5k.h" @@ -39,22 +42,22 @@ \*********/ /** - * ath5k_hw_start_rx_dma() - Start DMA receive + * ath5k_hw_start_rx_dma - Start DMA receive + * * @ah: The &struct ath5k_hw */ -void -ath5k_hw_start_rx_dma(struct ath5k_hw *ah) +void ath5k_hw_start_rx_dma(struct ath5k_hw *ah) { ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); ath5k_hw_reg_read(ah, AR5K_CR); } /** - * ath5k_hw_stop_rx_dma() - Stop DMA receive + * ath5k_hw_stop_rx_dma - Stop DMA receive + * * @ah: The &struct ath5k_hw */ -static int -ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) +static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) { unsigned int i; @@ -76,24 +79,24 @@ ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) } /** - * ath5k_hw_get_rxdp() - Get RX Descriptor's address + * ath5k_hw_get_rxdp - Get RX Descriptor's address + * * @ah: The &struct ath5k_hw */ -u32 -ath5k_hw_get_rxdp(struct ath5k_hw *ah) +u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) { return ath5k_hw_reg_read(ah, AR5K_RXDP); } /** - * ath5k_hw_set_rxdp() - Set RX Descriptor's address + * ath5k_hw_set_rxdp - Set RX Descriptor's address + * * @ah: The &struct ath5k_hw * @phys_addr: RX descriptor address * * Returns -EIO if rx is active */ -int -ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) +int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) { if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) { ATH5K_DBG(ah, ATH5K_DEBUG_DMA, @@ -111,7 +114,8 @@ ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) \**********/ /** - * ath5k_hw_start_tx_dma() - Start DMA transmit for a specific queue + * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue + * * @ah: The &struct ath5k_hw * @queue: The hw queue number * @@ -124,8 +128,7 @@ ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) * NOTE: Must be called after setting up tx control descriptor for that * queue (see below). */ -int -ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) +int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) { u32 tx_queue; @@ -174,16 +177,17 @@ ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) } /** - * ath5k_hw_stop_tx_dma() - Stop DMA transmit on a specific queue + * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue + * * @ah: The &struct ath5k_hw * @queue: The hw queue number * * Stop DMA transmit on a specific hw queue and drain queue so we don't * have any pending frames. Returns -EBUSY if we still have pending frames, * -EINVAL if queue number is out of range or inactive. + * */ -static int -ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) +static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) { unsigned int i = 40; u32 tx_queue, pending; @@ -316,14 +320,14 @@ ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) } /** - * ath5k_hw_stop_beacon_queue() - Stop beacon queue - * @ah: The &struct ath5k_hw - * @queue: The queue number + * ath5k_hw_stop_beacon_queue - Stop beacon queue + * + * @ah The &struct ath5k_hw + * @queue The queue number * * Returns -EIO if queue didn't stop */ -int -ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) +int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) { int ret; ret = ath5k_hw_stop_tx_dma(ah, queue); @@ -336,7 +340,8 @@ ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) } /** - * ath5k_hw_get_txdp() - Get TX Descriptor's address for a specific queue + * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue + * * @ah: The &struct ath5k_hw * @queue: The hw queue number * @@ -347,8 +352,7 @@ ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) * * XXX: Is TXDP read and clear ? */ -u32 -ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) +u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) { u16 tx_reg; @@ -378,10 +382,10 @@ ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) } /** - * ath5k_hw_set_txdp() - Set TX Descriptor's address for a specific queue + * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue + * * @ah: The &struct ath5k_hw * @queue: The hw queue number - * @phys_addr: The physical address * * Set TX descriptor's address for a specific queue. For 5210 we ignore * the queue number and we use tx queue type since we only have 2 queues @@ -390,8 +394,7 @@ ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still * active. */ -int -ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) +int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) { u16 tx_reg; @@ -432,7 +435,8 @@ ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) } /** - * ath5k_hw_update_tx_triglevel() - Update tx trigger level + * ath5k_hw_update_tx_triglevel - Update tx trigger level + * * @ah: The &struct ath5k_hw * @increase: Flag to force increase of trigger level * @@ -440,15 +444,15 @@ ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) * buffer (aka FIFO threshold) that is used to indicate when PCU flushes * the buffer and transmits its data. Lowering this results sending small * frames more quickly but can lead to tx underruns, raising it a lot can - * result other problems. Right now we start with the lowest possible - * (64Bytes) and if we get tx underrun we increase it using the increase - * flag. Returns -EIO if we have reached maximum/minimum. + * result other problems (i think bmiss is related). Right now we start with + * the lowest possible (64Bytes) and if we get tx underrun we increase it using + * the increase flag. Returns -EIO if we have reached maximum/minimum. * * XXX: Link this with tx DMA size ? - * XXX2: Use it to save interrupts ? + * XXX: Use it to save interrupts ? + * TODO: Needs testing, i think it's related to bmiss... */ -int -ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) +int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) { u32 trigger_level, imr; int ret = -EIO; @@ -494,20 +498,21 @@ ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) \*******************/ /** - * ath5k_hw_is_intr_pending() - Check if we have pending interrupts + * ath5k_hw_is_intr_pending - Check if we have pending interrupts + * * @ah: The &struct ath5k_hw * * Check if we have pending interrupts to process. Returns 1 if we * have pending interrupts and 0 if we haven't. */ -bool -ath5k_hw_is_intr_pending(struct ath5k_hw *ah) +bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) { return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0; } /** - * ath5k_hw_get_isr() - Get interrupt status + * ath5k_hw_get_isr - Get interrupt status + * * @ah: The @struct ath5k_hw * @interrupt_mask: Driver's interrupt mask used to filter out * interrupts in sw. @@ -518,162 +523,62 @@ ath5k_hw_is_intr_pending(struct ath5k_hw *ah) * being mapped on some standard non hw-specific positions * (check out &ath5k_int). * - * NOTE: We do write-to-clear, so the active PISR/SISR bits at the time this - * function gets called are cleared on return. + * NOTE: We use read-and-clear register, so after this function is called ISR + * is zeroed. */ -int -ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) +int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) { - u32 data = 0; + u32 data; /* - * Read interrupt status from Primary Interrupt - * Register. - * - * Note: PISR/SISR Not available on 5210 + * Read interrupt status from the Interrupt Status register + * on 5210 */ if (ah->ah_version == AR5K_AR5210) { - u32 isr = 0; - isr = ath5k_hw_reg_read(ah, AR5K_ISR); - if (unlikely(isr == AR5K_INT_NOCARD)) { - *interrupt_mask = isr; + data = ath5k_hw_reg_read(ah, AR5K_ISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; return -ENODEV; } - - /* - * Filter out the non-common bits from the interrupt - * status. - */ - *interrupt_mask = (isr & AR5K_INT_COMMON) & ah->ah_imr; - - /* Hanlde INT_FATAL */ - if (unlikely(isr & (AR5K_ISR_SSERR | AR5K_ISR_MCABT - | AR5K_ISR_DPERR))) - *interrupt_mask |= AR5K_INT_FATAL; - - /* - * XXX: BMISS interrupts may occur after association. - * I found this on 5210 code but it needs testing. If this is - * true we should disable them before assoc and re-enable them - * after a successful assoc + some jiffies. - interrupt_mask &= ~AR5K_INT_BMISS; - */ - - data = isr; } else { - u32 pisr = 0; - u32 pisr_clear = 0; - u32 sisr0 = 0; - u32 sisr1 = 0; - u32 sisr2 = 0; - u32 sisr3 = 0; - u32 sisr4 = 0; - - /* Read PISR and SISRs... */ - pisr = ath5k_hw_reg_read(ah, AR5K_PISR); - if (unlikely(pisr == AR5K_INT_NOCARD)) { - *interrupt_mask = pisr; - return -ENODEV; - } - - sisr0 = ath5k_hw_reg_read(ah, AR5K_SISR0); - sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1); - sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2); - sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3); - sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4); - /* - * PISR holds the logical OR of interrupt bits - * from SISR registers: - * - * TXOK and TXDESC -> Logical OR of TXOK and TXDESC - * per-queue bits on SISR0 - * - * TXERR and TXEOL -> Logical OR of TXERR and TXEOL - * per-queue bits on SISR1 - * - * TXURN -> Logical OR of TXURN per-queue bits on SISR2 + * Read interrupt status from Interrupt + * Status Register shadow copy (Read And Clear) * - * HIUERR -> Logical OR of MCABT, SSERR and DPER bits on SISR2 - * - * BCNMISC -> Logical OR of TIM, CAB_END, DTIM_SYNC - * BCN_TIMEOUT, CAB_TIMEOUT and DTIM - * (and TSFOOR ?) bits on SISR2 - * - * QCBRORN and QCBRURN -> Logical OR of QCBRORN and - * QCBRURN per-queue bits on SISR3 - * QTRIG -> Logical OR of QTRIG per-queue bits on SISR4 - * - * If we clean these bits on PISR we 'll also clear all - * related bits from SISRs, e.g. if we write the TXOK bit on - * PISR we 'll clean all TXOK bits from SISR0 so if a new TXOK - * interrupt got fired for another queue while we were reading - * the interrupt registers and we write back the TXOK bit on - * PISR we 'll lose it. So make sure that we don't write back - * on PISR any bits that come from SISRs. Clearing them from - * SISRs will also clear PISR so no need to worry here. - */ - - pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS; - - /* - * Write to clear them... - * Note: This means that each bit we write back - * to the registers will get cleared, leaving the - * rest unaffected. So this won't affect new interrupts - * we didn't catch while reading/processing, we 'll get - * them next time get_isr gets called. - */ - ath5k_hw_reg_write(ah, sisr0, AR5K_SISR0); - ath5k_hw_reg_write(ah, sisr1, AR5K_SISR1); - ath5k_hw_reg_write(ah, sisr2, AR5K_SISR2); - ath5k_hw_reg_write(ah, sisr3, AR5K_SISR3); - ath5k_hw_reg_write(ah, sisr4, AR5K_SISR4); - ath5k_hw_reg_write(ah, pisr_clear, AR5K_PISR); - /* Flush previous write */ - ath5k_hw_reg_read(ah, AR5K_PISR); - - /* - * Filter out the non-common bits from the interrupt - * status. + * Note: PISR/SISR Not available on 5210 */ - *interrupt_mask = (pisr & AR5K_INT_COMMON) & ah->ah_imr; - - - /* We treat TXOK,TXDESC, TXERR and TXEOL - * the same way (schedule the tx tasklet) - * so we track them all together per queue */ - if (pisr & AR5K_ISR_TXOK) - ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0, - AR5K_SISR0_QCU_TXOK); + data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } + } - if (pisr & AR5K_ISR_TXDESC) - ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0, - AR5K_SISR0_QCU_TXDESC); + /* + * Get abstract interrupt mask (driver-compatible) + */ + *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; - if (pisr & AR5K_ISR_TXERR) - ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1, - AR5K_SISR1_QCU_TXERR); + if (ah->ah_version != AR5K_AR5210) { + u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); - if (pisr & AR5K_ISR_TXEOL) - ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1, - AR5K_SISR1_QCU_TXEOL); + /*HIU = Host Interface Unit (PCI etc)*/ + if (unlikely(data & (AR5K_ISR_HIUERR))) + *interrupt_mask |= AR5K_INT_FATAL; - /* Currently this is not much usefull since we treat - * all queues the same way if we get a TXURN (update - * tx trigger level) but we might need it later on*/ - if (pisr & AR5K_ISR_TXURN) - ah->ah_txq_isr_txurn |= AR5K_REG_MS(sisr2, - AR5K_SISR2_QCU_TXURN); + /*Beacon Not Ready*/ + if (unlikely(data & (AR5K_ISR_BNR))) + *interrupt_mask |= AR5K_INT_BNR; - /* Misc Beacon related interrupts */ + if (unlikely(sisr2 & (AR5K_SISR2_SSERR | + AR5K_SISR2_DPERR | + AR5K_SISR2_MCABT))) + *interrupt_mask |= AR5K_INT_FATAL; - /* For AR5211 */ - if (pisr & AR5K_ISR_TIM) + if (data & AR5K_ISR_TIM) *interrupt_mask |= AR5K_INT_TIM; - /* For AR5212+ */ - if (pisr & AR5K_ISR_BCNMISC) { + if (data & AR5K_ISR_BCNMISC) { if (sisr2 & AR5K_SISR2_TIM) *interrupt_mask |= AR5K_INT_TIM; if (sisr2 & AR5K_SISR2_DTIM) @@ -686,39 +591,63 @@ ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; } - /* Below interrupts are unlikely to happen */ - - /* HIU = Host Interface Unit (PCI etc) - * Can be one of MCABT, SSERR, DPERR from SISR2 */ - if (unlikely(pisr & (AR5K_ISR_HIUERR))) - *interrupt_mask |= AR5K_INT_FATAL; - - /*Beacon Not Ready*/ - if (unlikely(pisr & (AR5K_ISR_BNR))) - *interrupt_mask |= AR5K_INT_BNR; - - /* A queue got CBR overrun */ - if (unlikely(pisr & (AR5K_ISR_QCBRORN))) { + if (data & AR5K_ISR_RXDOPPLER) + *interrupt_mask |= AR5K_INT_RX_DOPPLER; + if (data & AR5K_ISR_QCBRORN) { *interrupt_mask |= AR5K_INT_QCBRORN; - ah->ah_txq_isr_qcborn |= AR5K_REG_MS(sisr3, - AR5K_SISR3_QCBRORN); + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRORN); } - - /* A queue got CBR underrun */ - if (unlikely(pisr & (AR5K_ISR_QCBRURN))) { + if (data & AR5K_ISR_QCBRURN) { *interrupt_mask |= AR5K_INT_QCBRURN; - ah->ah_txq_isr_qcburn |= AR5K_REG_MS(sisr3, - AR5K_SISR3_QCBRURN); + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRURN); } - - /* A queue got triggered */ - if (unlikely(pisr & (AR5K_ISR_QTRIG))) { + if (data & AR5K_ISR_QTRIG) { *interrupt_mask |= AR5K_INT_QTRIG; - ah->ah_txq_isr_qtrig |= AR5K_REG_MS(sisr4, - AR5K_SISR4_QTRIG); + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), + AR5K_SISR4_QTRIG); } - data = pisr; + if (data & AR5K_ISR_TXOK) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXOK); + + if (data & AR5K_ISR_TXDESC) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXDESC); + + if (data & AR5K_ISR_TXERR) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXERR); + + if (data & AR5K_ISR_TXEOL) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXEOL); + + if (data & AR5K_ISR_TXURN) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR2), + AR5K_SISR2_QCU_TXURN); + } else { + if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT + | AR5K_ISR_HIUERR | AR5K_ISR_DPERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /* + * XXX: BMISS interrupts may occur after association. + * I found this on 5210 code but it needs testing. If this is + * true we should disable them before assoc and re-enable them + * after a successful assoc + some jiffies. + interrupt_mask &= ~AR5K_INT_BMISS; + */ } /* @@ -732,7 +661,8 @@ ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) } /** - * ath5k_hw_set_imr() - Set interrupt mask + * ath5k_hw_set_imr - Set interrupt mask + * * @ah: The &struct ath5k_hw * @new_mask: The new interrupt mask to be set * @@ -740,8 +670,7 @@ ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) * ath5k_int bits to hw-specific bits to remove abstraction and writing * Interrupt Mask Register. */ -enum ath5k_int -ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) +enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) { enum ath5k_int old_mask, int_mask; @@ -768,14 +697,16 @@ ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) & AR5K_SIMR2_QCU_TXURN; - /* Fatal interrupt abstraction for 5211+ */ if (new_mask & AR5K_INT_FATAL) { int_mask |= AR5K_IMR_HIUERR; simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); } - /* Misc beacon related interrupts */ + /*Beacon Not Ready*/ + if (new_mask & AR5K_INT_BNR) + int_mask |= AR5K_INT_BNR; + if (new_mask & AR5K_INT_TIM) int_mask |= AR5K_IMR_TIM; @@ -790,9 +721,8 @@ ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) if (new_mask & AR5K_INT_CAB_TIMEOUT) simr2 |= AR5K_SISR2_CAB_TIMEOUT; - /*Beacon Not Ready*/ - if (new_mask & AR5K_INT_BNR) - int_mask |= AR5K_INT_BNR; + if (new_mask & AR5K_INT_RX_DOPPLER) + int_mask |= AR5K_IMR_RXDOPPLER; /* Note: Per queue interrupt masks * are set via ath5k_hw_reset_tx_queue() (qcu.c) */ @@ -800,12 +730,10 @@ ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); } else { - /* Fatal interrupt abstraction for 5210 */ if (new_mask & AR5K_INT_FATAL) int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); - /* Only common interrupts left for 5210 (no SIMRs) */ ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); } @@ -832,7 +760,8 @@ ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) \********************/ /** - * ath5k_hw_dma_init() - Initialize DMA unit + * ath5k_hw_dma_init - Initialize DMA unit + * * @ah: The &struct ath5k_hw * * Set DMA size and pre-enable interrupts @@ -841,8 +770,7 @@ ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) * * XXX: Save/restore RXDP/TXDP registers ? */ -void -ath5k_hw_dma_init(struct ath5k_hw *ah) +void ath5k_hw_dma_init(struct ath5k_hw *ah) { /* * Set Rx/Tx DMA Configuration @@ -871,7 +799,8 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) } /** - * ath5k_hw_dma_stop() - stop DMA unit + * ath5k_hw_dma_stop - stop DMA unit + * * @ah: The &struct ath5k_hw * * Stop tx/rx DMA and interrupts. Returns @@ -881,8 +810,7 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) * stuck frames on tx queues, only a reset * can fix that. */ -int -ath5k_hw_dma_stop(struct ath5k_hw *ah) +int ath5k_hw_dma_stop(struct ath5k_hw *ah) { int i, qmax, err; err = 0; diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c index 73d3dd8a..85929781 100644 --- a/drivers/net/wireless/ath/ath5k/gpio.c +++ b/drivers/net/wireless/ath/ath5k/gpio.c @@ -24,33 +24,10 @@ #include "reg.h" #include "debug.h" - -/** - * DOC: GPIO/LED functions - * - * Here we control the 6 bidirectional GPIO pins provided by the hw. - * We can set a GPIO pin to be an input or an output pin on GPIO control - * register and then read or set its status from GPIO data input/output - * registers. - * - * We also control the two LED pins provided by the hw, LED_0 is our - * "power" LED and LED_1 is our "network activity" LED but many scenarios - * are available from hw. Vendors might also provide LEDs connected to the - * GPIO pins, we handle them through the LED subsystem on led.c - */ - - -/** - * ath5k_hw_set_ledstate() - Set led state - * @ah: The &struct ath5k_hw - * @state: One of AR5K_LED_* - * - * Used to set the LED blinking state. This only - * works for the LED connected to the LED_0, LED_1 pins, - * not the GPIO based. +/* + * Set led state */ -void -ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) +void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) { u32 led; /*5210 has different led mode handling*/ @@ -97,13 +74,10 @@ ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); } -/** - * ath5k_hw_set_gpio_input() - Set GPIO inputs - * @ah: The &struct ath5k_hw - * @gpio: GPIO pin to set as input +/* + * Set GPIO inputs */ -int -ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) +int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return -EINVAL; @@ -115,13 +89,10 @@ ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) return 0; } -/** - * ath5k_hw_set_gpio_output() - Set GPIO outputs - * @ah: The &struct ath5k_hw - * @gpio: The GPIO pin to set as output +/* + * Set GPIO outputs */ -int -ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) +int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return -EINVAL; @@ -133,13 +104,10 @@ ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) return 0; } -/** - * ath5k_hw_get_gpio() - Get GPIO state - * @ah: The &struct ath5k_hw - * @gpio: The GPIO pin to read +/* + * Get GPIO state */ -u32 -ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) +u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return 0xffffffff; @@ -149,14 +117,10 @@ ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) 0x1; } -/** - * ath5k_hw_set_gpio() - Set GPIO state - * @ah: The &struct ath5k_hw - * @gpio: The GPIO pin to set - * @val: Value to set (boolean) +/* + * Set GPIO state */ -int -ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) +int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) { u32 data; @@ -174,19 +138,10 @@ ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) return 0; } -/** - * ath5k_hw_set_gpio_intr() - Initialize the GPIO interrupt (RFKill switch) - * @ah: The &struct ath5k_hw - * @gpio: The GPIO pin to use - * @interrupt_level: True to generate interrupt on active pin (high) - * - * This function is used to set up the GPIO interrupt for the hw RFKill switch. - * That switch is connected to a GPIO pin and it's number is stored on EEPROM. - * It can either open or close the circuit to indicate that we should disable - * RF/Wireless to save power (we also get that from EEPROM). +/* + * Initialize the GPIO interrupt (RFKill switch) */ -void -ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, +void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level) { u32 data; diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index a1ea78e0..1ffecc0f 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -23,27 +23,24 @@ #include "reg.h" #include "debug.h" -/** - * struct ath5k_ini - Mode-independent initial register writes - * @ini_register: Register address - * @ini_value: Default value - * @ini_mode: 0 to write 1 to read (and clear) +/* + * Mode-independent initial register writes */ + struct ath5k_ini { u16 ini_register; u32 ini_value; enum { AR5K_INI_WRITE = 0, /* Default */ - AR5K_INI_READ = 1, + AR5K_INI_READ = 1, /* Cleared on read */ } ini_mode; }; -/** - * struct ath5k_ini_mode - Mode specific initial register values - * @mode_register: Register address - * @mode_value: Set of values for each enum ath5k_driver_mode +/* + * Mode specific initial register values */ + struct ath5k_ini_mode { u16 mode_register; u32 mode_value[3]; @@ -389,10 +386,11 @@ static const struct ath5k_ini ar5211_ini[] = { /* Initial mode-specific settings for AR5211 * 5211 supports OFDM-only g (draft g) but we - * need to test it ! */ + * need to test it ! + */ static const struct ath5k_ini_mode ar5211_ini_mode[] = { { AR5K_TXCFG, - /* A B G */ + /* A/XR B G */ { 0x00000015, 0x0000001d, 0x00000015 } }, { AR5K_QUEUE_DFS_LOCAL_IFS(0), { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } }, @@ -462,7 +460,7 @@ static const struct ath5k_ini_mode ar5211_ini_mode[] = { { 0x00000010, 0x00000010, 0x00000010 } }, }; -/* Initial register settings for AR5212 and newer chips */ +/* Initial register settings for AR5212 */ static const struct ath5k_ini ar5212_ini_common_start[] = { { AR5K_RXDP, 0x00000000 }, { AR5K_RXCFG, 0x00000005 }, @@ -726,8 +724,7 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { { 0x00000000, 0x00000000, 0x00000108 } }, }; -/* Initial mode-specific settings for AR5212 + RF5111 - * (Written after ar5212_ini) */ +/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */ static const struct ath5k_ini_mode rf5111_ini_mode_end[] = { { AR5K_TXCFG, /* A/XR B G */ @@ -760,7 +757,6 @@ static const struct ath5k_ini_mode rf5111_ini_mode_end[] = { { 0x1883800a, 0x1873800a, 0x1883800a } }, }; -/* Common for all modes */ static const struct ath5k_ini rf5111_ini_common_end[] = { { AR5K_DCU_FP, 0x00000000 }, { AR5K_PHY_AGC, 0x00000000 }, @@ -778,9 +774,7 @@ static const struct ath5k_ini rf5111_ini_common_end[] = { { 0xa23c, 0x13c889af }, }; - -/* Initial mode-specific settings for AR5212 + RF5112 - * (Written after ar5212_ini) */ +/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */ static const struct ath5k_ini_mode rf5112_ini_mode_end[] = { { AR5K_TXCFG, /* A/XR B G */ @@ -831,9 +825,7 @@ static const struct ath5k_ini rf5112_ini_common_end[] = { { 0xa23c, 0x13c889af }, }; - -/* Initial mode-specific settings for RF5413/5414 - * (Written after ar5212_ini) */ +/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */ static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { { AR5K_TXCFG, /* A/XR B G */ @@ -971,8 +963,7 @@ static const struct ath5k_ini rf5413_ini_common_end[] = { { 0xa384, 0xf3307ff0 }, }; -/* Initial mode-specific settings for RF2413/2414 - * (Written after ar5212_ini) */ +/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */ /* XXX: a mode ? */ static const struct ath5k_ini_mode rf2413_ini_mode_end[] = { { AR5K_TXCFG, @@ -1094,8 +1085,7 @@ static const struct ath5k_ini rf2413_ini_common_end[] = { { 0xa384, 0xf3307ff0 }, }; -/* Initial mode-specific settings for RF2425 - * (Written after ar5212_ini) */ +/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */ /* XXX: a mode ? */ static const struct ath5k_ini_mode rf2425_ini_mode_end[] = { { AR5K_TXCFG, @@ -1367,15 +1357,10 @@ static const struct ath5k_ini rf5112_ini_bbgain[] = { }; -/** - * ath5k_hw_ini_registers() - Write initial register dump common for all modes - * @ah: The &struct ath5k_hw - * @size: Dump size - * @ini_regs: The array of &struct ath5k_ini - * @skip_pcu: Skip PCU registers +/* + * Write initial register dump */ -static void -ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, +static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, const struct ath5k_ini *ini_regs, bool skip_pcu) { unsigned int i; @@ -1403,15 +1388,7 @@ ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, } } -/** - * ath5k_hw_ini_mode_registers() - Write initial mode-specific register dump - * @ah: The &struct ath5k_hw - * @size: Dump size - * @ini_mode: The array of &struct ath5k_ini_mode - * @mode: One of enum ath5k_driver_mode - */ -static void -ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, +static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, unsigned int size, const struct ath5k_ini_mode *ini_mode, u8 mode) { @@ -1425,17 +1402,7 @@ ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, } -/** - * ath5k_hw_write_initvals() - Write initial chip-specific register dump - * @ah: The &struct ath5k_hw - * @mode: One of enum ath5k_driver_mode - * @skip_pcu: Skip PCU registers - * - * Write initial chip-specific register dump, to get the chipset on a - * clean and ready-to-work state after warm reset. - */ -int -ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu) +int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu) { /* * Write initial register settings diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c old mode 100644 new mode 100755 index 5d1be4da..82a4065a --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -134,8 +134,6 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ah->num_ap_vifs++; else if (avf->opmode == NL80211_IFTYPE_ADHOC) ah->num_adhoc_vifs++; - else if (avf->opmode == NL80211_IFTYPE_MESH_POINT) - ah->num_mesh_vifs++; } /* Any MAC address is fine, all others are included through the @@ -177,8 +175,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw, ah->num_ap_vifs--; else if (avf->opmode == NL80211_IFTYPE_ADHOC) ah->num_adhoc_vifs--; - else if (avf->opmode == NL80211_IFTYPE_MESH_POINT) - ah->num_mesh_vifs--; ath5k_update_bssid_mask_and_opmode(ah, NULL); mutex_unlock(&ah->lock); @@ -316,20 +312,42 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) struct netdev_hw_addr_list *mc_list) +#else + int mc_count, struct dev_addr_list *ha) +#endif { u32 mfilt[2], val; u8 pos; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) struct netdev_hw_addr *ha; +#else + int i; +#endif mfilt[0] = 0; mfilt[1] = 1; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) netdev_hw_addr_list_for_each(ha, mc_list) { +#else + for (i = 0; i < mc_count; i++) { + if (!ha) + break; +#endif /* calculate XOR of eight 6-bit values */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) val = get_unaligned_le32(ha->addr + 0); +#else + val = get_unaligned_le32(ha->dmi_addr + 0); +#endif pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) val = get_unaligned_le32(ha->addr + 3); +#else + val = get_unaligned_le32(ha->dmi_addr + 3); +#endif pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; pos &= 0x3f; mfilt[pos / 32] |= (1 << (pos % 32)); @@ -338,6 +356,9 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw, * need to inform below not to reset the mcast */ /* ath5k_hw_set_mcast_filterindex(ah, * ha->addr[5]); */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) + ha = ha->next; +#endif } return ((u64)(mfilt[1]) << 32) | mfilt[0]; @@ -487,14 +508,6 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (ath5k_modparam_nohwcrypt) return -EOPNOTSUPP; - if (vif->type == NL80211_IFTYPE_ADHOC && - (key->cipher == WLAN_CIPHER_SUITE_TKIP || - key->cipher == WLAN_CIPHER_SUITE_CCMP) && - !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { - /* don't program group keys when using IBSS_RSN */ - return -EOPNOTSUPP; - } - switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 849fa060..f90980f0 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -98,7 +98,7 @@ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) 0xffff); return true; } - usleep_range(15, 20); + udelay(15); } return false; @@ -323,6 +323,9 @@ static int ath5k_pci_resume(struct device *dev) return 0; } +compat_pci_suspend(ath5k_pci_suspend) +compat_pci_resume(ath5k_pci_resume) + static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); #define ATH5K_PM_OPS (&ath5k_pm_ops) #else @@ -334,7 +337,12 @@ static struct pci_driver ath5k_pci_driver = { .id_table = ath5k_pci_id_table, .probe = ath5k_pci_probe, .remove = __devexit_p(ath5k_pci_remove), +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) .driver.pm = ATH5K_PM_OPS, +#elif defined(CONFIG_PM_SLEEP) + .suspend = ath5k_pci_suspend_compat, + .resume = ath5k_pci_resume_compat, +#endif }; /* diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index cebfd6fd..a7eafa3e 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -30,47 +30,11 @@ #include "reg.h" #include "debug.h" -/** - * DOC: Protocol Control Unit (PCU) functions - * - * Protocol control unit is responsible to maintain various protocol - * properties before a frame is send and after a frame is received to/from - * baseband. To be more specific, PCU handles: - * - * - Buffering of RX and TX frames (after QCU/DCUs) - * - * - Encrypting and decrypting (using the built-in engine) - * - * - Generating ACKs, RTS/CTS frames - * - * - Maintaining TSF - * - * - FCS - * - * - Updating beacon data (with TSF etc) - * - * - Generating virtual CCA - * - * - RX/Multicast filtering - * - * - BSSID filtering - * - * - Various statistics - * - * -Different operating modes: AP, STA, IBSS - * - * Note: Most of these functions can be tweaked/bypassed so you can do - * them on sw above for debugging or research. For more infos check out PCU - * registers on reg.h. - */ - -/** - * DOC: ACK rates - * +/* * AR5212+ can use higher rates for ack transmission * based on current tx rate instead of the base rate. * It does this to better utilize channel usage. - * There is a mapping between G rates (that cover both + * This is a mapping between G rates (that cover both * CCK and OFDM) and ack rates that we use when setting * rate -> duration table. This mapping is hw-based so * don't change anything. @@ -99,18 +63,17 @@ static const unsigned int ack_rates_high[] = \*******************/ /** - * ath5k_hw_get_frame_duration() - Get tx time of a frame + * ath5k_hw_get_frame_duration - Get tx time of a frame + * * @ah: The &struct ath5k_hw * @len: Frame's length in bytes * @rate: The @struct ieee80211_rate - * @shortpre: Indicate short preample * * Calculate tx duration of a frame given it's rate and length * It extends ieee80211_generic_frame_duration for non standard * bwmodes. */ -int -ath5k_hw_get_frame_duration(struct ath5k_hw *ah, +int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, int len, struct ieee80211_rate *rate, bool shortpre) { int sifs, preamble, plcp_bits, sym_time; @@ -166,11 +129,11 @@ ath5k_hw_get_frame_duration(struct ath5k_hw *ah, } /** - * ath5k_hw_get_default_slottime() - Get the default slot time for current mode + * ath5k_hw_get_default_slottime - Get the default slot time for current mode + * * @ah: The &struct ath5k_hw */ -unsigned int -ath5k_hw_get_default_slottime(struct ath5k_hw *ah) +unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; unsigned int slot_time; @@ -197,11 +160,11 @@ ath5k_hw_get_default_slottime(struct ath5k_hw *ah) } /** - * ath5k_hw_get_default_sifs() - Get the default SIFS for current mode + * ath5k_hw_get_default_sifs - Get the default SIFS for current mode + * * @ah: The &struct ath5k_hw */ -unsigned int -ath5k_hw_get_default_sifs(struct ath5k_hw *ah) +unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; unsigned int sifs; @@ -228,17 +191,17 @@ ath5k_hw_get_default_sifs(struct ath5k_hw *ah) } /** - * ath5k_hw_update_mib_counters() - Update MIB counters (mac layer statistics) + * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics) + * * @ah: The &struct ath5k_hw * * Reads MIB counters from PCU and updates sw statistics. Is called after a * MIB interrupt, because one of these counters might have reached their maximum * and triggered the MIB interrupt, to let us read and clear the counter. * - * NOTE: Is called in interrupt context! + * Is called in interrupt context! */ -void -ath5k_hw_update_mib_counters(struct ath5k_hw *ah) +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) { struct ath5k_statistics *stats = &ah->stats; @@ -256,8 +219,10 @@ ath5k_hw_update_mib_counters(struct ath5k_hw *ah) \******************/ /** - * ath5k_hw_write_rate_duration() - Fill rate code to duration table - * @ah: The &struct ath5k_hw + * ath5k_hw_write_rate_duration - fill rate code to duration table + * + * @ah: the &struct ath5k_hw + * @mode: one of enum ath5k_driver_mode * * Write the rate code to duration table upon hw reset. This is a helper for * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on @@ -271,8 +236,7 @@ ath5k_hw_update_mib_counters(struct ath5k_hw *ah) * that include all OFDM and CCK rates. * */ -static inline void -ath5k_hw_write_rate_duration(struct ath5k_hw *ah) +static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah) { struct ieee80211_rate *rate; unsigned int i; @@ -316,12 +280,12 @@ ath5k_hw_write_rate_duration(struct ath5k_hw *ah) } /** - * ath5k_hw_set_ack_timeout() - Set ACK timeout on PCU + * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU + * * @ah: The &struct ath5k_hw * @timeout: Timeout in usec */ -static int -ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) +static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) { if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) <= timeout) @@ -334,12 +298,12 @@ ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) } /** - * ath5k_hw_set_cts_timeout() - Set CTS timeout on PCU + * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU + * * @ah: The &struct ath5k_hw * @timeout: Timeout in usec */ -static int -ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) +static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) { if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) <= timeout) @@ -357,14 +321,14 @@ ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) \*******************/ /** - * ath5k_hw_set_lladdr() - Set station id + * ath5k_hw_set_lladdr - Set station id + * * @ah: The &struct ath5k_hw - * @mac: The card's mac address (array of octets) + * @mac: The card's mac address * * Set station id on hw using the provided mac address */ -int -ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) +int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { struct ath_common *common = ath5k_hw_common(ah); u32 low_id, high_id; @@ -385,14 +349,14 @@ ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) } /** - * ath5k_hw_set_bssid() - Set current BSSID on hw + * ath5k_hw_set_bssid - Set current BSSID on hw + * * @ah: The &struct ath5k_hw * * Sets the current BSSID and BSSID mask we have from the * common struct into the hardware */ -void -ath5k_hw_set_bssid(struct ath5k_hw *ah) +void ath5k_hw_set_bssid(struct ath5k_hw *ah) { struct ath_common *common = ath5k_hw_common(ah); u16 tim_offset = 0; @@ -425,23 +389,7 @@ ath5k_hw_set_bssid(struct ath5k_hw *ah) ath5k_hw_enable_pspoll(ah, NULL, 0); } -/** - * ath5k_hw_set_bssid_mask() - Filter out bssids we listen - * @ah: The &struct ath5k_hw - * @mask: The BSSID mask to set (array of octets) - * - * BSSID masking is a method used by AR5212 and newer hardware to inform PCU - * which bits of the interface's MAC address should be looked at when trying - * to decide which packets to ACK. In station mode and AP mode with a single - * BSS every bit matters since we lock to only one BSS. In AP mode with - * multiple BSSes (virtual interfaces) not every bit matters because hw must - * accept frames for all BSSes and so we tweak some bits of our mac address - * in order to have multiple BSSes. - * - * For more information check out ../hw.c of the common ath module. - */ -void -ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) +void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) { struct ath_common *common = ath5k_hw_common(ah); @@ -452,21 +400,18 @@ ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) ath_hw_setbssidmask(common); } -/** - * ath5k_hw_set_mcast_filter() - Set multicast filter - * @ah: The &struct ath5k_hw - * @filter0: Lower 32bits of muticast filter - * @filter1: Higher 16bits of multicast filter +/* + * Set multicast filter */ -void -ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) +void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) { ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); } /** - * ath5k_hw_get_rx_filter() - Get current rx filter + * ath5k_hw_get_rx_filter - Get current rx filter + * * @ah: The &struct ath5k_hw * * Returns the RX filter by reading rx filter and @@ -475,8 +420,7 @@ ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) * and pass to the driver. For a list of frame types * check out reg.h. */ -u32 -ath5k_hw_get_rx_filter(struct ath5k_hw *ah) +u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) { u32 data, filter = 0; @@ -496,7 +440,8 @@ ath5k_hw_get_rx_filter(struct ath5k_hw *ah) } /** - * ath5k_hw_set_rx_filter() - Set rx filter + * ath5k_hw_set_rx_filter - Set rx filter + * * @ah: The &struct ath5k_hw * @filter: RX filter mask (see reg.h) * @@ -504,8 +449,7 @@ ath5k_hw_get_rx_filter(struct ath5k_hw *ah) * register on 5212 and newer chips so that we have proper PHY * error reporting. */ -void -ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) +void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) { u32 data = 0; @@ -549,13 +493,13 @@ ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) #define ATH5K_MAX_TSF_READ 10 /** - * ath5k_hw_get_tsf64() - Get the full 64bit TSF + * ath5k_hw_get_tsf64 - Get the full 64bit TSF + * * @ah: The &struct ath5k_hw * * Returns the current TSF */ -u64 -ath5k_hw_get_tsf64(struct ath5k_hw *ah) +u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { u32 tsf_lower, tsf_upper1, tsf_upper2; int i; @@ -592,30 +536,28 @@ ath5k_hw_get_tsf64(struct ath5k_hw *ah) return ((u64)tsf_upper1 << 32) | tsf_lower; } -#undef ATH5K_MAX_TSF_READ - /** - * ath5k_hw_set_tsf64() - Set a new 64bit TSF + * ath5k_hw_set_tsf64 - Set a new 64bit TSF + * * @ah: The &struct ath5k_hw * @tsf64: The new 64bit TSF * * Sets the new TSF */ -void -ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) +void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) { ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32); ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32); } /** - * ath5k_hw_reset_tsf() - Force a TSF reset + * ath5k_hw_reset_tsf - Force a TSF reset + * * @ah: The &struct ath5k_hw * * Forces a TSF reset on PCU */ -void -ath5k_hw_reset_tsf(struct ath5k_hw *ah) +void ath5k_hw_reset_tsf(struct ath5k_hw *ah) { u32 val; @@ -631,17 +573,10 @@ ath5k_hw_reset_tsf(struct ath5k_hw *ah) ath5k_hw_reg_write(ah, val, AR5K_BEACON); } -/** - * ath5k_hw_init_beacon_timers() - Initialize beacon timers - * @ah: The &struct ath5k_hw - * @next_beacon: Next TBTT - * @interval: Current beacon interval - * - * This function is used to initialize beacon timers based on current - * operation mode and settings. +/* + * Initialize beacon timers */ -void -ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval) +void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) { u32 timer1, timer2, timer3; @@ -720,7 +655,8 @@ ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval) } /** - * ath5k_check_timer_win() - Check if timer B is timer A + window + * ath5k_check_timer_win - Check if timer B is timer A + window + * * @a: timer a (before b) * @b: timer b (after a) * @window: difference between a and b @@ -750,11 +686,12 @@ ath5k_check_timer_win(int a, int b, int window, int intval) } /** - * ath5k_hw_check_beacon_timers() - Check if the beacon timers are correct + * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct + * * @ah: The &struct ath5k_hw * @intval: beacon interval * - * This is a workaround for IBSS mode + * This is a workaround for IBSS mode: * * The need for this function arises from the fact that we have 4 separate * HW timer registers (TIMER0 - TIMER3), which are closely related to the @@ -809,14 +746,14 @@ ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval) } /** - * ath5k_hw_set_coverage_class() - Set IEEE 802.11 coverage class + * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class + * * @ah: The &struct ath5k_hw * @coverage_class: IEEE 802.11 coverage class number * * Sets IFS intervals and ACK/CTS timeouts for given coverage class. */ -void -ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) +void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) { /* As defined by IEEE 802.11-2007 17.3.8.6 */ int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; @@ -835,7 +772,8 @@ ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) \***************************/ /** - * ath5k_hw_start_rx_pcu() - Start RX engine + * ath5k_hw_start_rx_pcu - Start RX engine + * * @ah: The &struct ath5k_hw * * Starts RX engine on PCU so that hw can process RXed frames @@ -843,33 +781,32 @@ ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) * * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma */ -void -ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) +void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) { AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); } /** - * at5k_hw_stop_rx_pcu() - Stop RX engine + * at5k_hw_stop_rx_pcu - Stop RX engine + * * @ah: The &struct ath5k_hw * * Stops RX engine on PCU */ -void -ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) +void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) { AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); } /** - * ath5k_hw_set_opmode() - Set PCU operating mode + * ath5k_hw_set_opmode - Set PCU operating mode + * * @ah: The &struct ath5k_hw - * @op_mode: One of enum nl80211_iftype + * @op_mode: &enum nl80211_iftype operating mode * * Configure PCU for the various operating modes (AP/STA etc) */ -int -ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) +int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) { struct ath_common *common = ath5k_hw_common(ah); u32 pcu_reg, beacon_reg, low_id, high_id; @@ -936,17 +873,8 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) return 0; } -/** - * ath5k_hw_pcu_init() - Initialize PCU - * @ah: The &struct ath5k_hw - * @op_mode: One of enum nl80211_iftype - * @mode: One of enum ath5k_driver_mode - * - * This function is used to initialize PCU by setting current - * operation mode and various other settings. - */ -void -ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode) +void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, + u8 mode) { /* Set bssid and bssid mask */ ath5k_hw_set_bssid(ah); diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 3a284548..01cb72de 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1,4 +1,6 @@ /* + * PHY functions + * * Copyright (c) 2004-2007 Reyk Floeter * Copyright (c) 2006-2009 Nick Kossifidis * Copyright (c) 2007-2008 Jiri Slaby @@ -18,10 +20,6 @@ * */ -/***********************\ -* PHY related functions * -\***********************/ - #include #include #include @@ -33,53 +31,14 @@ #include "../regd.h" -/** - * DOC: PHY related functions - * - * Here we handle the low-level functions related to baseband - * and analog frontend (RF) parts. This is by far the most complex - * part of the hw code so make sure you know what you are doing. - * - * Here is a list of what this is all about: - * - * - Channel setting/switching - * - * - Automatic Gain Control (AGC) calibration - * - * - Noise Floor calibration - * - * - I/Q imbalance calibration (QAM correction) - * - * - Calibration due to thermal changes (gain_F) - * - * - Spur noise mitigation - * - * - RF/PHY initialization for the various operating modes and bwmodes - * - * - Antenna control - * - * - TX power control per channel/rate/packet type - * - * Also have in mind we never got documentation for most of these - * functions, what we have comes mostly from Atheros's code, reverse - * engineering and patent docs/presentations etc. - */ - - /******************\ * Helper functions * \******************/ -/** - * ath5k_hw_radio_revision() - Get the PHY Chip revision - * @ah: The &struct ath5k_hw - * @band: One of enum ieee80211_band - * - * Returns the revision number of a 2GHz, 5GHz or single chip - * radio. +/* + * Get the PHY Chip revision */ -u16 -ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) +u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) { unsigned int i; u32 srev; @@ -99,7 +58,7 @@ ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) return 0; } - usleep_range(2000, 2500); + mdelay(2); /* ...wait until PHY is ready and read the selected radio revision */ ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34)); @@ -122,16 +81,10 @@ ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) return ret; } -/** - * ath5k_channel_ok() - Check if a channel is supported by the hw - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * Note: We don't do any regulatory domain checks here, it's just - * a sanity check. +/* + * Check if a channel is supported */ -bool -ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) +bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u16 freq = channel->center_freq; @@ -148,13 +101,7 @@ ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) return false; } -/** - * ath5k_hw_chan_has_spur_noise() - Check if channel is sensitive to spur noise - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - */ -bool -ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, +bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u8 refclk_freq; @@ -175,20 +122,11 @@ ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, return false; } -/** - * ath5k_hw_rfb_op() - Perform an operation on the given RF Buffer - * @ah: The &struct ath5k_hw - * @rf_regs: The struct ath5k_rf_reg - * @val: New value - * @reg_id: RF register ID - * @set: Indicate we need to swap data - * - * This is an internal function used to modify RF Banks before - * writing them to AR5K_RF_BUFFER. Check out rfbuffer.h for more - * infos. +/* + * Used to modify RF Banks before writing them to AR5K_RF_BUFFER */ -static unsigned int -ath5k_hw_rfb_op(struct ath5k_hw *ah, const struct ath5k_rf_reg *rf_regs, +static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, + const struct ath5k_rf_reg *rf_regs, u32 val, u8 reg_id, bool set) { const struct ath5k_rf_reg *rfreg = NULL; @@ -266,7 +204,8 @@ ath5k_hw_rfb_op(struct ath5k_hw *ah, const struct ath5k_rf_reg *rf_regs, } /** - * ath5k_hw_write_ofdm_timings() - set OFDM timings on AR5212 + * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 + * * @ah: the &struct ath5k_hw * @channel: the currently set channel upon reset * @@ -277,11 +216,10 @@ ath5k_hw_rfb_op(struct ath5k_hw *ah, const struct ath5k_rf_reg *rf_regs, * mantissa and provide these values on hw. * * For more infos i think this patent is related - * "http://www.freepatentsonline.com/7184495.html" + * http://www.freepatentsonline.com/7184495.html */ -static inline int -ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, - struct ieee80211_channel *channel) +static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, + struct ieee80211_channel *channel) { /* Get exponent and mantissa and set it */ u32 coef_scaled, coef_exp, coef_man, @@ -340,10 +278,6 @@ ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_phy_disable() - Disable PHY - * @ah: The &struct ath5k_hw - */ int ath5k_hw_phy_disable(struct ath5k_hw *ah) { /*Just a try M.F.*/ @@ -352,13 +286,10 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah) return 0; } -/** - * ath5k_hw_wait_for_synth() - Wait for synth to settle - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel +/* + * Wait for synth to settle */ -static void -ath5k_hw_wait_for_synth(struct ath5k_hw *ah, +static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, struct ieee80211_channel *channel) { /* @@ -377,9 +308,9 @@ ath5k_hw_wait_for_synth(struct ath5k_hw *ah, delay = delay << 2; /* XXX: /2 on turbo ? Let's be safe * for now */ - usleep_range(100 + delay, 100 + (2 * delay)); + udelay(100 + delay); } else { - usleep_range(1000, 1500); + mdelay(1); } } @@ -388,9 +319,7 @@ ath5k_hw_wait_for_synth(struct ath5k_hw *ah, * RF Gain optimization * \**********************/ -/** - * DOC: RF Gain optimization - * +/* * This code is used to optimize RF gain on different environments * (temperature mostly) based on feedback from a power detector. * @@ -399,22 +328,22 @@ ath5k_hw_wait_for_synth(struct ath5k_hw *ah, * no gain optimization ladder-. * * For more infos check out this patent doc - * "http://www.freepatentsonline.com/7400691.html" + * http://www.freepatentsonline.com/7400691.html * * This paper describes power drops as seen on the receiver due to * probe packets - * "http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues - * %20of%20Power%20Control.pdf" + * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues + * %20of%20Power%20Control.pdf * * And this is the MadWiFi bug entry related to the above - * "http://madwifi-project.org/ticket/1659" + * http://madwifi-project.org/ticket/1659 * with various measurements and diagrams + * + * TODO: Deal with power drops due to probes by setting an appropriate + * tx power on the probe packets ! Make this part of the calibration process. */ -/** - * ath5k_hw_rfgain_opt_init() - Initialize ah_gain during attach - * @ah: The &struct ath5k_hw - */ +/* Initialize ah_gain during attach */ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) { /* Initialize the gain optimization values */ @@ -438,21 +367,17 @@ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) return 0; } -/** - * ath5k_hw_request_rfgain_probe() - Request a PAPD probe packet - * @ah: The &struct ath5k_hw - * - * Schedules a gain probe check on the next transmitted packet. +/* Schedule a gain probe check on the next transmitted packet. * That means our next packet is going to be sent with lower * tx power and a Peak to Average Power Detector (PAPD) will try * to measure the gain. * - * TODO: Force a tx packet (bypassing PCU arbitrator etc) + * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) * just after we enable the probe so that we don't mess with - * standard traffic. + * standard traffic ? Maybe it's time to use sw interrupts and + * a probe tasklet !!! */ -static void -ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) +static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) { /* Skip if gain calibration is inactive or @@ -470,15 +395,9 @@ ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) } -/** - * ath5k_hw_rf_gainf_corr() - Calculate Gain_F measurement correction - * @ah: The &struct ath5k_hw - * - * Calculate Gain_F measurement correction - * based on the current step for RF5112 rev. 2 - */ -static u32 -ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) +/* Calculate gain_F measurement correction + * based on the current step for RF5112 rev. 2 */ +static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) { u32 mix, step; u32 *rf; @@ -531,19 +450,11 @@ ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) return ah->ah_gain.g_f_corr; } -/** - * ath5k_hw_rf_check_gainf_readback() - Validate Gain_F feedback from detector - * @ah: The &struct ath5k_hw - * - * Check if current gain_F measurement is in the range of our +/* Check if current gain_F measurement is in the range of our * power detector windows. If we get a measurement outside range * we know it's not accurate (detectors can't measure anything outside - * their detection window) so we must ignore it. - * - * Returns true if readback was O.K. or false on failure - */ -static bool -ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) + * their detection window) so we must ignore it */ +static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) { const struct ath5k_rf_reg *rf_regs; u32 step, mix_ovr, level[4]; @@ -595,15 +506,9 @@ ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) ah->ah_gain.g_current <= level[3]); } -/** - * ath5k_hw_rf_gainf_adjust() - Perform Gain_F adjustment - * @ah: The &struct ath5k_hw - * - * Choose the right target gain based on current gain - * and RF gain optimization ladder - */ -static s8 -ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) +/* Perform gain_F adjustment by choosing the right set + * of parameters from RF gain optimization ladder */ +static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) { const struct ath5k_gain_opt *go; const struct ath5k_gain_opt_step *g_step; @@ -667,18 +572,13 @@ ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) return ret; } -/** - * ath5k_hw_gainf_calibrate() - Do a gain_F calibration - * @ah: The &struct ath5k_hw - * - * Main callback for thermal RF gain calibration engine +/* Main callback for thermal RF gain calibration engine * Check for a new gain reading and schedule an adjustment * if needed. * - * Returns one of enum ath5k_rfgain codes - */ -enum ath5k_rfgain -ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) + * TODO: Use sw interrupt to schedule reset if gain_F needs + * adjustment */ +enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) { u32 data, type; struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; @@ -738,18 +638,10 @@ ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) return ah->ah_gain.g_state; } -/** - * ath5k_hw_rfgain_init() - Write initial RF gain settings to hw - * @ah: The &struct ath5k_hw - * @band: One of enum ieee80211_band - * - * Write initial RF gain table to set the RF sensitivity. - * - * NOTE: This one works on all RF chips and has nothing to do - * with Gain_F calibration - */ -static int -ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band) +/* Write initial RF gain table to set the RF sensitivity + * this one works on all RF chips and has nothing to do + * with gain_F calibration */ +static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band) { const struct ath5k_ini_rfgain *ath5k_rfg; unsigned int i, size, index; @@ -796,23 +688,16 @@ ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band) } + /********************\ * RF Registers setup * \********************/ -/** - * ath5k_hw_rfregs_init() - Initialize RF register settings - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * @mode: One of enum ath5k_driver_mode - * - * Setup RF registers by writing RF buffer on hw. For - * more infos on this, check out rfbuffer.h +/* + * Setup RF registers by writing RF buffer on hw */ -static int -ath5k_hw_rfregs_init(struct ath5k_hw *ah, - struct ieee80211_channel *channel, - unsigned int mode) +static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, + struct ieee80211_channel *channel, unsigned int mode) { const struct ath5k_rf_reg *rf_regs; const struct ath5k_ini_rfbuffer *ini_rfb; @@ -1170,18 +1055,19 @@ ath5k_hw_rfregs_init(struct ath5k_hw *ah, PHY/RF channel functions \**************************/ -/** - * ath5k_hw_rf5110_chan2athchan() - Convert channel freq on RF5110 - * @channel: The &struct ieee80211_channel - * - * Map channel frequency to IEEE channel number and convert it - * to an internal channel value used by the RF5110 chipset. +/* + * Conversion needed for RF5110 */ -static u32 -ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) +static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) { u32 athchan; + /* + * Convert IEEE channel/MHz to an internal channel value used + * by the AR5210 chipset. This has not been verified with + * newer chipsets like the AR5212A who have a completely + * different RF/PHY part. + */ athchan = (ath5k_hw_bitswap( (ieee80211_frequency_to_channel( channel->center_freq) - 24) / 2, 5) @@ -1189,13 +1075,10 @@ ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) return athchan; } -/** - * ath5k_hw_rf5110_channel() - Set channel frequency on RF5110 - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel +/* + * Set channel on RF5110 */ -static int -ath5k_hw_rf5110_channel(struct ath5k_hw *ah, +static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 data; @@ -1206,23 +1089,15 @@ ath5k_hw_rf5110_channel(struct ath5k_hw *ah, data = ath5k_hw_rf5110_chan2athchan(channel); ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); - usleep_range(1000, 1500); + mdelay(1); return 0; } -/** - * ath5k_hw_rf5111_chan2athchan() - Handle 2GHz channels on RF5111/2111 - * @ieee: IEEE channel number - * @athchan: The &struct ath5k_athchan_2ghz - * - * In order to enable the RF2111 frequency converter on RF5111/2111 setups - * we need to add some offsets and extra flags to the data values we pass - * on to the PHY. So for every 2GHz channel this function gets called - * to do the conversion. +/* + * Conversion needed for 5111 */ -static int -ath5k_hw_rf5111_chan2athchan(unsigned int ieee, +static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, struct ath5k_athchan_2ghz *athchan) { int channel; @@ -1248,13 +1123,10 @@ ath5k_hw_rf5111_chan2athchan(unsigned int ieee, return 0; } -/** - * ath5k_hw_rf5111_channel() - Set channel frequency on RF5111/2111 - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel +/* + * Set channel on 5111 */ -static int -ath5k_hw_rf5111_channel(struct ath5k_hw *ah, +static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct ath5k_athchan_2ghz ath5k_channel_2ghz; @@ -1299,20 +1171,10 @@ ath5k_hw_rf5111_channel(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_rf5112_channel() - Set channel frequency on 5112 and newer - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * On RF5112/2112 and newer we don't need to do any conversion. - * We pass the frequency value after a few modifications to the - * chip directly. - * - * NOTE: Make sure channel frequency given is within our range or else - * we might damage the chip ! Use ath5k_channel_ok before calling this one. +/* + * Set channel on 5112 and newer */ -static int -ath5k_hw_rf5112_channel(struct ath5k_hw *ah, +static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 data, data0, data1, data2; @@ -1321,37 +1183,17 @@ ath5k_hw_rf5112_channel(struct ath5k_hw *ah, data = data0 = data1 = data2 = 0; c = channel->center_freq; - /* My guess based on code: - * 2GHz RF has 2 synth modes, one with a Local Oscillator - * at 2224Hz and one with a LO at 2192Hz. IF is 1520Hz - * (3040/2). data0 is used to set the PLL divider and data1 - * selects synth mode. */ if (c < 4800) { - /* Channel 14 and all frequencies with 2Hz spacing - * below/above (non-standard channels) */ if (!((c - 2224) % 5)) { - /* Same as (c - 2224) / 5 */ data0 = ((2 * (c - 704)) - 3040) / 10; data1 = 1; - /* Channel 1 and all frequencies with 5Hz spacing - * below/above (standard channels without channel 14) */ } else if (!((c - 2192) % 5)) { - /* Same as (c - 2192) / 5 */ data0 = ((2 * (c - 672)) - 3040) / 10; data1 = 0; } else return -EINVAL; data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); - /* This is more complex, we have a single synthesizer with - * 4 reference clock settings (?) based on frequency spacing - * and set using data2. LO is at 4800Hz and data0 is again used - * to set some divider. - * - * NOTE: There is an old atheros presentation at Stanford - * that mentions a method called dual direct conversion - * with 1GHz sliding IF for RF5110. Maybe that's what we - * have here, or an updated version. */ } else if ((c % 5) != 2 || c > 5435) { if (!(c % 20) && c >= 5120) { data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); @@ -1377,16 +1219,10 @@ ath5k_hw_rf5112_channel(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_rf2425_channel() - Set channel frequency on RF2425 - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * AR2425/2417 have a different 2GHz RF so code changes - * a little bit from RF5112. +/* + * Set the channel on the RF2425 */ -static int -ath5k_hw_rf2425_channel(struct ath5k_hw *ah, +static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 data, data0, data2; @@ -1422,16 +1258,10 @@ ath5k_hw_rf2425_channel(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_channel() - Set a channel on the radio chip - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * This is the main function called to set a channel on the - * radio chip based on the radio chip version. +/* + * Set a channel on the radio chip */ -static int -ath5k_hw_channel(struct ath5k_hw *ah, +static int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) { int ret; @@ -1483,46 +1313,11 @@ ath5k_hw_channel(struct ath5k_hw *ah, return 0; } - /*****************\ PHY calibration \*****************/ -/** - * DOC: PHY Calibration routines - * - * Noise floor calibration: When we tell the hardware to - * perform a noise floor calibration by setting the - * AR5K_PHY_AGCCTL_NF bit on AR5K_PHY_AGCCTL, it will periodically - * sample-and-hold the minimum noise level seen at the antennas. - * This value is then stored in a ring buffer of recently measured - * noise floor values so we have a moving window of the last few - * samples. The median of the values in the history is then loaded - * into the hardware for its own use for RSSI and CCA measurements. - * This type of calibration doesn't interfere with traffic. - * - * AGC calibration: When we tell the hardware to perform - * an AGC (Automatic Gain Control) calibration by setting the - * AR5K_PHY_AGCCTL_CAL, hw disconnects the antennas and does - * a calibration on the DC offsets of ADCs. During this period - * rx/tx gets disabled so we have to deal with it on the driver - * part. - * - * I/Q calibration: When we tell the hardware to perform - * an I/Q calibration, it tries to correct I/Q imbalance and - * fix QAM constellation by sampling data from rxed frames. - * It doesn't interfere with traffic. - * - * For more infos on AGC and I/Q calibration check out patent doc - * #03/094463. - */ - -/** - * ath5k_hw_read_measured_noise_floor() - Read measured NF from hw - * @ah: The &struct ath5k_hw - */ -static s32 -ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) +static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) { s32 val; @@ -1530,12 +1325,7 @@ ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) return sign_extend32(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 8); } -/** - * ath5k_hw_init_nfcal_hist() - Initialize NF calibration history buffer - * @ah: The &struct ath5k_hw - */ -void -ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) +void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) { int i; @@ -1544,11 +1334,6 @@ ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE; } -/** - * ath5k_hw_update_nfcal_hist() - Update NF calibration history buffer - * @ah: The &struct ath5k_hw - * @noise_floor: The NF we got from hw - */ static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor) { struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist; @@ -1556,12 +1341,7 @@ static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor) hist->nfval[hist->index] = noise_floor; } -/** - * ath5k_hw_get_median_noise_floor() - Get median NF from history buffer - * @ah: The &struct ath5k_hw - */ -static s16 -ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) +static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) { s16 sort[ATH5K_NF_CAL_HIST_MAX]; s16 tmp; @@ -1584,16 +1364,18 @@ ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) return sort[(ATH5K_NF_CAL_HIST_MAX - 1) / 2]; } -/** - * ath5k_hw_update_noise_floor() - Update NF on hardware - * @ah: The &struct ath5k_hw +/* + * When we tell the hardware to perform a noise floor calibration + * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically + * sample-and-hold the minimum noise level seen at the antennas. + * This value is then stored in a ring buffer of recently measured + * noise floor values so we have a moving window of the last few + * samples. * - * This is the main function we call to perform a NF calibration, - * it reads NF from hardware, calculates the median and updates - * NF on hw. + * The median of the values in the history is then loaded into the + * hardware for its own use for RSSI and CCA measurements. */ -void -ath5k_hw_update_noise_floor(struct ath5k_hw *ah) +void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 val; @@ -1608,8 +1390,6 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah) return; } - ah->ah_cal_mask |= AR5K_CALIBRATION_NF; - ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); /* completed NF calibration, test threshold */ @@ -1654,29 +1434,20 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah) ah->ah_noise_floor = nf; - ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF; - ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "noise floor calibrated: %d\n", nf); } -/** - * ath5k_hw_rf5110_calibrate() - Perform a PHY calibration on RF5110 - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * Do a complete PHY calibration (AGC + NF + I/Q) on RF5110 +/* + * Perform a PHY calibration on RF5110 + * -Fix BPSK/QAM Constellation (I/Q correction) */ -static int -ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, +static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 phy_sig, phy_agc, phy_sat, beacon; int ret; - if (!(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) - return 0; - /* * Disable beacons and RX/TX queues, wait */ @@ -1685,7 +1456,7 @@ ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - usleep_range(2000, 2500); + mdelay(2); /* * Set the channel (with AGC turned off) @@ -1698,7 +1469,7 @@ ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Activate PHY and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - usleep_range(1000, 1500); + mdelay(1); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); @@ -1735,7 +1506,7 @@ ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); - usleep_range(1000, 1500); + mdelay(1); /* * Enable calibration and wait until completion @@ -1766,9 +1537,8 @@ ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, return 0; } -/** - * ath5k_hw_rf511x_iq_calibrate() - Perform I/Q calibration on RF5111 and newer - * @ah: The &struct ath5k_hw +/* + * Perform I/Q calibration on RF5111/5112 and newer chips */ static int ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) @@ -1777,19 +1547,12 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; int i; - /* Skip if I/Q calibration is not needed or if it's still running */ - if (!ah->ah_iq_cal_needed) - return -EINVAL; - else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) { - ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, - "I/Q calibration still running"); - return -EBUSY; - } + if (!ah->ah_calibration || + ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) + return 0; /* Calibration has finished, get the results and re-run */ - - /* Work around for empty results which can apparently happen on 5212: - * Read registers up to 10 times until we get both i_pr and q_pwr */ + /* work around empty results which can apparently happen on 5212 */ for (i = 0; i <= 10; i++) { iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); @@ -1807,13 +1570,9 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) else q_coffd = q_pwr >> 7; - /* In case i_coffd became zero, cancel calibration - * not only it's too small, it'll also result a divide - * by zero later on. */ + /* protect against divide by 0 and loss of sign bits */ if (i_coffd == 0 || q_coffd < 2) - return -ECANCELED; - - /* Protect against loss of sign bits */ + return 0; i_coff = (-iq_corr) / i_coffd; i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ @@ -1842,17 +1601,10 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) return 0; } -/** - * ath5k_hw_phy_calibrate() - Perform a PHY calibration - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * The main function we call from above to perform - * a short or full PHY calibration based on RF chip - * and current channel +/* + * Perform a PHY calibration */ -int -ath5k_hw_phy_calibrate(struct ath5k_hw *ah, +int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel) { int ret; @@ -1861,28 +1613,11 @@ ath5k_hw_phy_calibrate(struct ath5k_hw *ah, return ath5k_hw_rf5110_calibrate(ah, channel); ret = ath5k_hw_rf511x_iq_calibrate(ah); - if (ret) { - ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE, - "No I/Q correction performed (%uMHz)\n", - channel->center_freq); - /* Happens all the time if there is not much - * traffic, consider it normal behaviour. */ - ret = 0; - } - - /* On full calibration request a PAPD probe for - * gainf calibration if needed */ - if ((ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && - (ah->ah_radio == AR5K_RF5111 || - ah->ah_radio == AR5K_RF5112) && - channel->hw_value != AR5K_MODE_11B) + if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) && + (channel->hw_value != AR5K_MODE_11B)) ath5k_hw_request_rfgain_probe(ah); - /* Update noise floor */ - if (!(ah->ah_cal_mask & AR5K_CALIBRATION_NF)) - ath5k_hw_update_noise_floor(ah); - return ret; } @@ -1891,16 +1626,6 @@ ath5k_hw_phy_calibrate(struct ath5k_hw *ah, * Spur mitigation functions * \***************************/ -/** - * ath5k_hw_set_spur_mitigation_filter() - Configure SPUR filter - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * This function gets called during PHY initialization to - * configure the spur filter for the given channel. Spur is noise - * generated due to "reflection" effects, for more information on this - * method check out patent US7643810 - */ static void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, struct ieee80211_channel *channel) @@ -2140,73 +1865,15 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, * Antenna control * \*****************/ -/** - * DOC: Antenna control - * - * Hw supports up to 14 antennas ! I haven't found any card that implements - * that. The maximum number of antennas I've seen is up to 4 (2 for 2GHz and 2 - * for 5GHz). Antenna 1 (MAIN) should be omnidirectional, 2 (AUX) - * omnidirectional or sectorial and antennas 3-14 sectorial (or directional). - * - * We can have a single antenna for RX and multiple antennas for TX. - * RX antenna is our "default" antenna (usually antenna 1) set on - * DEFAULT_ANTENNA register and TX antenna is set on each TX control descriptor - * (0 for automatic selection, 1 - 14 antenna number). - * - * We can let hw do all the work doing fast antenna diversity for both - * tx and rx or we can do things manually. Here are the options we have - * (all are bits of STA_ID1 register): - * - * AR5K_STA_ID1_DEFAULT_ANTENNA -> When 0 is set as the TX antenna on TX - * control descriptor, use the default antenna to transmit or else use the last - * antenna on which we received an ACK. - * - * AR5K_STA_ID1_DESC_ANTENNA -> Update default antenna after each TX frame to - * the antenna on which we got the ACK for that frame. - * - * AR5K_STA_ID1_RTS_DEF_ANTENNA -> Use default antenna for RTS or else use the - * one on the TX descriptor. - * - * AR5K_STA_ID1_SELFGEN_DEF_ANT -> Use default antenna for self generated frames - * (ACKs etc), or else use current antenna (the one we just used for TX). - * - * Using the above we support the following scenarios: - * - * AR5K_ANTMODE_DEFAULT -> Hw handles antenna diversity etc automatically - * - * AR5K_ANTMODE_FIXED_A -> Only antenna A (MAIN) is present - * - * AR5K_ANTMODE_FIXED_B -> Only antenna B (AUX) is present - * - * AR5K_ANTMODE_SINGLE_AP -> Sta locked on a single ap - * - * AR5K_ANTMODE_SECTOR_AP -> AP with tx antenna set on tx desc - * - * AR5K_ANTMODE_SECTOR_STA -> STA with tx antenna set on tx desc - * - * AR5K_ANTMODE_DEBUG Debug mode -A -> Rx, B-> Tx- - * - * Also note that when setting antenna to F on tx descriptor card inverts - * current tx antenna. - */ - -/** - * ath5k_hw_set_def_antenna() - Set default rx antenna on AR5211/5212 and newer - * @ah: The &struct ath5k_hw - * @ant: Antenna number - */ -static void +static void /*TODO:Boundary check*/ ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) { if (ah->ah_version != AR5K_AR5210) ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA); } -/** - * ath5k_hw_set_fast_div() - Enable/disable fast rx antenna diversity - * @ah: The &struct ath5k_hw - * @ee_mode: One of enum ath5k_driver_mode - * @enable: True to enable, false to disable +/* + * Enable/disable fast rx antenna diversity */ static void ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) @@ -2246,14 +1913,6 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) } } -/** - * ath5k_hw_set_antenna_switch() - Set up antenna switch table - * @ah: The &struct ath5k_hw - * @ee_mode: One of enum ath5k_driver_mode - * - * Switch table comes from EEPROM and includes information on controlling - * the 2 antenna RX attenuators - */ void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode) { @@ -2285,10 +1944,8 @@ ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode) AR5K_PHY_ANT_SWITCH_TABLE_1); } -/** - * ath5k_hw_set_antenna_mode() - Set antenna operating mode - * @ah: The &struct ath5k_hw - * @ant_mode: One of enum ath5k_ant_mode +/* + * Set antenna operating mode */ void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) @@ -2411,13 +2068,8 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) * Helper functions */ -/** - * ath5k_get_interpolated_value() - Get interpolated Y val between two points - * @target: X value of the middle point - * @x_left: X value of the left point - * @x_right: X value of the right point - * @y_left: Y value of the left point - * @y_right: Y value of the right point +/* + * Do linear interpolation between two given (x, y) points */ static s16 ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, @@ -2444,18 +2096,13 @@ ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, return result; } -/** - * ath5k_get_linear_pcdac_min() - Find vertical boundary (min pwr) for the - * linear PCDAC curve - * @stepL: Left array with y values (pcdac steps) - * @stepR: Right array with y values (pcdac steps) - * @pwrL: Left array with x values (power steps) - * @pwrR: Right array with x values (power steps) +/* + * Find vertical boundary (min pwr) for the linear PCDAC curve. * * Since we have the top of the curve and we draw the line below * until we reach 1 (1 pcdac step) we need to know which point - * (x value) that is so that we don't go below x axis and have negative - * pcdac values when creating the curve, or fill the table with zeros. + * (x value) that is so that we don't go below y axis and have negative + * pcdac values when creating the curve, or fill the table with zeroes. */ static s16 ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, @@ -2501,16 +2148,7 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, return max(min_pwrL, min_pwrR); } -/** - * ath5k_create_power_curve() - Create a Power to PDADC or PCDAC curve - * @pmin: Minimum power value (xmin) - * @pmax: Maximum power value (xmax) - * @pwr: Array of power steps (x values) - * @vpd: Array of matching PCDAC/PDADC steps (y values) - * @num_points: Number of provided points - * @vpd_table: Array to fill with the full PCDAC/PDADC values (y values) - * @type: One of enum ath5k_powertable_type (eeprom.h) - * +/* * Interpolate (pwr,vpd) points to create a Power to PDADC or a * Power to PCDAC curve. * @@ -2568,14 +2206,7 @@ ath5k_create_power_curve(s16 pmin, s16 pmax, } } -/** - * ath5k_get_chan_pcal_surrounding_piers() - Get surrounding calibration piers - * for a given channel. - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * @pcinfo_l: The &struct ath5k_chan_pcal_info to put the left cal. pier - * @pcinfo_r: The &struct ath5k_chan_pcal_info to put the right cal. pier - * +/* * Get the surrounding per-channel power calibration piers * for a given frequency so that we can interpolate between * them and come up with an appropriate dataset for our current @@ -2658,17 +2289,11 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, *pcinfo_r = &pcinfo[idx_r]; } -/** - * ath5k_get_rate_pcal_data() - Get the interpolated per-rate power - * calibration data - * @ah: The &struct ath5k_hw *ah, - * @channel: The &struct ieee80211_channel - * @rates: The &struct ath5k_rate_pcal_info to fill - * +/* * Get the surrounding per-rate power calibration data * for a given frequency and interpolate between power * values to set max target power supported by hw for - * each rate on this frequency. + * each rate. */ static void ath5k_get_rate_pcal_data(struct ath5k_hw *ah, @@ -2756,11 +2381,7 @@ ath5k_get_rate_pcal_data(struct ath5k_hw *ah, rpinfo[idx_r].target_power_54); } -/** - * ath5k_get_max_ctl_power() - Get max edge power for a given frequency - * @ah: the &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * +/* * Get the max edge power for this channel if * we have such data from EEPROM's Conformance Test * Limits (CTL), and limit max power if needed. @@ -2840,39 +2461,8 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, * Power to PCDAC table functions */ -/** - * DOC: Power to PCDAC table functions - * - * For RF5111 we have an XPD -eXternal Power Detector- curve - * for each calibrated channel. Each curve has 0,5dB Power steps - * on x axis and PCDAC steps (offsets) on y axis and looks like an - * exponential function. To recreate the curve we read 11 points - * from eeprom (eeprom.c) and interpolate here. - * - * For RF5112 we have 4 XPD -eXternal Power Detector- curves - * for each calibrated channel on 0, -6, -12 and -18dBm but we only - * use the higher (3) and the lower (0) curves. Each curve again has 0.5dB - * power steps on x axis and PCDAC steps on y axis and looks like a - * linear function. To recreate the curve and pass the power values - * on hw, we get 4 points for xpd 0 (lower gain -> max power) - * and 3 points for xpd 3 (higher gain -> lower power) from eeprom (eeprom.c) - * and interpolate here. - * - * For a given channel we get the calibrated points (piers) for it or - * -if we don't have calibration data for this specific channel- from the - * available surrounding channels we have calibration data for, after we do a - * linear interpolation between them. Then since we have our calibrated points - * for this channel, we do again a linear interpolation between them to get the - * whole curve. - * - * We finally write the Y values of the curve(s) (the PCDAC values) on hw - */ - -/** - * ath5k_fill_pwr_to_pcdac_table() - Fill Power to PCDAC table on RF5111 - * @ah: The &struct ath5k_hw - * @table_min: Minimum power (x min) - * @table_max: Maximum power (x max) +/* + * Fill Power to PCDAC table on RF5111 * * No further processing is needed for RF5111, the only thing we have to * do is fill the values below and above calibration range since eeprom data @@ -2913,14 +2503,10 @@ ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, } -/** - * ath5k_combine_linear_pcdac_curves() - Combine available PCDAC Curves - * @ah: The &struct ath5k_hw - * @table_min: Minimum power (x min) - * @table_max: Maximum power (x max) - * @pdcurves: Number of pd curves +/* + * Combine available XPD Curves and fill Linear Power to PCDAC table + * on RF5112 * - * Combine available XPD Curves and fill Linear Power to PCDAC table on RF5112 * RFX112 can have up to 2 curves (one for low txpower range and one for * higher txpower range). We need to put them both on pcdac_out and place * them in the correct location. In case we only have one curve available @@ -3022,10 +2608,7 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, } } -/** - * ath5k_write_pcdac_table() - Write the PCDAC values on hw - * @ah: The &struct ath5k_hw - */ +/* Write PCDAC values on hw */ static void ath5k_write_pcdac_table(struct ath5k_hw *ah) { @@ -3048,32 +2631,9 @@ ath5k_write_pcdac_table(struct ath5k_hw *ah) * Power to PDADC table functions */ -/** - * DOC: Power to PDADC table functions - * - * For RF2413 and later we have a Power to PDADC table (Power Detector) - * instead of a PCDAC (Power Control) and 4 pd gain curves for each - * calibrated channel. Each curve has power on x axis in 0.5 db steps and - * PDADC steps on y axis and looks like an exponential function like the - * RF5111 curve. - * - * To recreate the curves we read the points from eeprom (eeprom.c) - * and interpolate here. Note that in most cases only 2 (higher and lower) - * curves are used (like RF5112) but vendors have the opportunity to include - * all 4 curves on eeprom. The final curve (higher power) has an extra - * point for better accuracy like RF5112. - * - * The process is similar to what we do above for RF5111/5112 - */ - -/** - * ath5k_combine_pwr_to_pdadc_curves() - Combine the various PDADC curves - * @ah: The &struct ath5k_hw - * @pwr_min: Minimum power (x min) - * @pwr_max: Maximum power (x max) - * @pdcurves: Number of available curves +/* + * Set the gain boundaries and create final Power to PDADC table * - * Combine the various pd curves and create the final Power to PDADC table * We can have up to 4 pd curves, we need to do a similar process * as we do for RF5112. This time we don't have an edge_flag but we * set the gain boundaries on a separate register. @@ -3197,11 +2757,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, } -/** - * ath5k_write_pwr_to_pdadc_table() - Write the PDADC values on hw - * @ah: The &struct ath5k_hw - * @ee_mode: One of enum ath5k_driver_mode - */ +/* Write PDADC values on hw */ static void ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) { @@ -3258,13 +2814,7 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) * Common code for PCDAC/PDADC tables */ -/** - * ath5k_setup_channel_powertable() - Set up power table for this channel - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * @ee_mode: One of enum ath5k_driver_mode - * @type: One of enum ath5k_powertable_type (eeprom.h) - * +/* * This is the main function that uses all of the above * to set PCDAC/PDADC table on hw for the current channel. * This table is used for tx power calibration on the baseband, @@ -3462,12 +3012,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah, return 0; } -/** - * ath5k_write_channel_powertable() - Set power table for current channel on hw - * @ah: The &struct ath5k_hw - * @ee_mode: One of enum ath5k_driver_mode - * @type: One of enum ath5k_powertable_type (eeprom.h) - */ +/* Write power table for current channel to hw */ static void ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type) { @@ -3477,36 +3022,28 @@ ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type) ath5k_write_pcdac_table(ah); } - -/** - * DOC: Per-rate tx power setting +/* + * Per-rate tx power setting * - * This is the code that sets the desired tx power limit (below + * This is the code that sets the desired tx power (below * maximum) on hw for each rate (we also have TPC that sets - * power per packet type). We do that by providing an index on the - * PCDAC/PDADC table we set up above, for each rate. + * power per packet). We do that by providing an index on the + * PCDAC/PDADC table we set up. + */ + +/* + * Set rate power table * * For now we only limit txpower based on maximum tx power - * supported by hw (what's inside rate_info) + conformance test - * limits. We need to limit this even more, based on regulatory domain - * etc to be safe. Normally this is done from above so we don't care - * here, all we care is that the tx power we set will be O.K. - * for the hw (e.g. won't create noise on PA etc). + * supported by hw (what's inside rate_info). We need to limit + * this even more, based on regulatory domain etc. * - * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps - - * x values) and is indexed as follows: + * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps) + * and is indexed as follows: * rates[0] - rates[7] -> OFDM rates * rates[8] - rates[14] -> CCK rates * rates[15] -> XR rates (they all have the same power) */ - -/** - * ath5k_setup_rate_powertable() - Set up rate power table for a given tx power - * @ah: The &struct ath5k_hw - * @max_pwr: The maximum tx power requested in 0.5dB steps - * @rate_info: The &struct ath5k_rate_pcal_info to fill - * @ee_mode: One of enum ath5k_driver_mode - */ static void ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, struct ath5k_rate_pcal_info *rate_info, @@ -3577,14 +3114,8 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, } -/** - * ath5k_hw_txpower() - Set transmission power limit for a given channel - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * @txpower: Requested tx power in 0.5dB steps - * - * Combines all of the above to set the requested tx power limit - * on hw. +/* + * Set transmission power */ static int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, @@ -3702,16 +3233,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, return 0; } -/** - * ath5k_hw_set_txpower_limit() - Set txpower limit for the current channel - * @ah: The &struct ath5k_hw - * @txpower: The requested tx power limit in 0.5dB steps - * - * This function provides access to ath5k_hw_txpower to the driver in - * case user or an application changes it while PHY is running. - */ -int -ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) +int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) { ATH5K_DBG(ah, ATH5K_DEBUG_TXPOWER, "changing txpower to %d\n", txpower); @@ -3719,26 +3241,11 @@ ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) return ath5k_hw_txpower(ah, ah->ah_current_channel, txpower); } - /*************\ Init function \*************/ -/** - * ath5k_hw_phy_init() - Initialize PHY - * @ah: The &struct ath5k_hw - * @channel: The @struct ieee80211_channel - * @mode: One of enum ath5k_driver_mode - * @fast: Try a fast channel switch instead - * - * This is the main function used during reset to initialize PHY - * or do a fast channel change if possible. - * - * NOTE: Do not call this one from the driver, it assumes PHY is in a - * warm reset state ! - */ -int -ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, +int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 mode, bool fast) { struct ieee80211_channel *curr_channel; @@ -3848,7 +3355,7 @@ ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, if (ret) return ret; - usleep_range(1000, 1500); + mdelay(1); /* * Write RF buffer @@ -3869,10 +3376,10 @@ ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, } } else if (ah->ah_version == AR5K_AR5210) { - usleep_range(1000, 1500); + mdelay(1); /* Disable phy and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); - usleep_range(1000, 1500); + mdelay(1); } /* Set channel on PHY */ @@ -3898,7 +3405,7 @@ ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, for (i = 0; i <= 20; i++) { if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) break; - usleep_range(200, 250); + udelay(200); } ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1); @@ -3926,9 +3433,9 @@ ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, /* At the same time start I/Q calibration for QAM constellation * -no need for CCK- */ - ah->ah_iq_cal_needed = false; + ah->ah_calibration = false; if (!(mode == AR5K_MODE_11B)) { - ah->ah_iq_cal_needed = true; + ah->ah_calibration = true; AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 30b50f93..ff3d348a 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -17,48 +17,23 @@ */ /********************************************\ -Queue Control Unit, DCF Control Unit Functions +Queue Control Unit, DFS Control Unit Functions \********************************************/ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include - -/** - * DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions - * - * Here we setup parameters for the 12 available TX queues. Note that - * on the various registers we can usually only map the first 10 of them so - * basically we have 10 queues to play with. Each queue has a matching - * QCU that controls when the queue will get triggered and multiple QCUs - * can be mapped to a single DCU that controls the various DFS parameters - * for the various queues. In our setup we have a 1:1 mapping between QCUs - * and DCUs allowing us to have different DFS settings for each queue. - * - * When a frame goes into a TX queue, QCU decides when it'll trigger a - * transmission based on various criteria (such as how many data we have inside - * it's buffer or -if it's a beacon queue- if it's time to fire up the queue - * based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler - * (arbitrator) decides the priority of each QCU based on it's configuration - * (e.g. beacons are always transmitted when they leave DCU bypassing all other - * frames from other queues waiting to be transmitted). After a frame leaves - * the DCU it goes to PCU for further processing and then to PHY for - * the actual transmission. - */ /******************\ * Helper functions * \******************/ -/** - * ath5k_hw_num_tx_pending() - Get number of pending frames for a given queue - * @ah: The &struct ath5k_hw - * @queue: One of enum ath5k_tx_queue_id +/* + * Get number of pending frames + * for a specific queue [5211+] */ -u32 -ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) +u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { u32 pending; AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); @@ -83,13 +58,10 @@ ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) return pending; } -/** - * ath5k_hw_release_tx_queue() - Set a transmit queue inactive - * @ah: The &struct ath5k_hw - * @queue: One of enum ath5k_tx_queue_id +/* + * Set a transmit queue inactive */ -void -ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) +void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) { if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) return; @@ -100,56 +72,34 @@ ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); } -/** - * ath5k_cw_validate() - Make sure the given cw is valid - * @cw_req: The contention window value to check - * +/* * Make sure cw is a power of 2 minus 1 and smaller than 1024 */ -static u16 -ath5k_cw_validate(u16 cw_req) +static u16 ath5k_cw_validate(u16 cw_req) { + u32 cw = 1; cw_req = min(cw_req, (u16)1023); - /* Check if cw_req + 1 a power of 2 */ - if (is_power_of_2(cw_req + 1)) - return cw_req; + while (cw < cw_req) + cw = (cw << 1) | 1; - /* Check if cw_req is a power of 2 */ - if (is_power_of_2(cw_req)) - return cw_req - 1; - - /* If none of the above is correct - * find the closest power of 2 */ - cw_req = (u16) roundup_pow_of_two(cw_req) - 1; - - return cw_req; + return cw; } -/** - * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue - * @ah: The &struct ath5k_hw - * @queue: One of enum ath5k_tx_queue_id - * @queue_info: The &struct ath5k_txq_info to fill +/* + * Get properties for a transmit queue */ -int -ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, +int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info) { memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); return 0; } -/** - * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue - * @ah: The &struct ath5k_hw - * @queue: One of enum ath5k_tx_queue_id - * @qinfo: The &struct ath5k_txq_info to use - * - * Returns 0 on success or -EIO if queue is inactive +/* + * Set properties for a transmit queue */ -int -ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, +int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *qinfo) { struct ath5k_txq_info *qi; @@ -189,16 +139,10 @@ ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, return 0; } -/** - * ath5k_hw_setup_tx_queue() - Initialize a transmit queue - * @ah: The &struct ath5k_hw - * @queue_type: One of enum ath5k_tx_queue - * @queue_info: The &struct ath5k_txq_info to use - * - * Returns 0 on success, -EINVAL on invalid arguments +/* + * Initialize a transmit queue */ -int -ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, +int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info) { unsigned int queue; @@ -223,13 +167,7 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, } else { switch (queue_type) { case AR5K_TX_QUEUE_DATA: - for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; - ah->ah_txq[queue].tqi_type != - AR5K_TX_QUEUE_INACTIVE; queue++) { - - if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) - return -EINVAL; - } + queue = queue_info->tqi_subtype; break; case AR5K_TX_QUEUE_UAPSD: queue = AR5K_TX_QUEUE_ID_UAPSD; @@ -273,16 +211,10 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, * Single QCU/DCU initialization * \*******************************/ -/** - * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU - * @ah: The &struct ath5k_hw - * @queue: One of enum ath5k_tx_queue_id - * - * This function is used when initializing a queue, to set - * retry limits based on ah->ah_retry_* and the chipset used. +/* + * Set tx retry limits on DCU */ -void -ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, +void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, unsigned int queue) { /* Single data queue on AR5210 */ @@ -317,15 +249,15 @@ ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, } /** - * ath5k_hw_reset_tx_queue() - Initialize a single hw queue - * @ah: The &struct ath5k_hw - * @queue: One of enum ath5k_tx_queue_id + * ath5k_hw_reset_tx_queue - Initialize a single hw queue + * + * @ah The &struct ath5k_hw + * @queue The hw queue number * - * Set DCF properties for the given transmit queue on DCU + * Set DFS properties for the given transmit queue on DCU * and configures all queue-specific parameters. */ -int -ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) +int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) { struct ath5k_txq_info *tq = &ah->ah_txq[queue]; @@ -553,9 +485,10 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) \**************************/ /** - * ath5k_hw_set_ifs_intervals() - Set global inter-frame spaces on DCU - * @ah: The &struct ath5k_hw - * @slot_time: Slot time in us + * ath5k_hw_set_ifs_intervals - Set global inter-frame spaces on DCU + * + * @ah The &struct ath5k_hw + * @slot_time Slot time in us * * Sets the global IFS intervals on DCU (also works on AR5210) for * the given slot time and the current bwmode. @@ -658,15 +591,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) } -/** - * ath5k_hw_init_queues() - Initialize tx queues - * @ah: The &struct ath5k_hw - * - * Initializes all tx queues based on information on - * ah->ah_txq* set by the driver - */ -int -ath5k_hw_init_queues(struct ath5k_hw *ah) +int ath5k_hw_init_queues(struct ath5k_hw *ah) { int i, ret; diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 0ea1608b..f5c10000 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -280,10 +280,6 @@ * 5211/5212 we have one primary and 4 secondary registers. * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. * Most of these bits are common for all chipsets. - * - * NOTE: On 5211+ TXOK, TXDESC, TXERR, TXEOL and TXURN contain - * the logical OR from per-queue interrupt bits found on SISR registers - * (see below). */ #define AR5K_ISR 0x001c /* Register Address [5210] */ #define AR5K_PISR 0x0080 /* Register Address [5211+] */ @@ -296,10 +292,7 @@ #define AR5K_ISR_TXOK 0x00000040 /* Frame successfully transmitted */ #define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ #define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ -#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmitted (transmit timeout) - * NOTE: We don't have per-queue info for this - * one, but we can enable it per-queue through - * TXNOFRM_QCU field on TXNOFRM register */ +#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmitted (transmit timeout) */ #define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ #define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ #define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ @@ -309,29 +302,21 @@ #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ #define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ -#define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] - * 'or' of MCABT, SSERR, DPERR from SISR2 */ +#define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ #define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ -#define AR5K_ISR_DPERR 0x00400000 /* Bus parity error [5210] */ +#define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ #define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ #define AR5K_ISR_TIM 0x00800000 /* [5211+] */ -#define AR5K_ISR_BCNMISC 0x00800000 /* Misc beacon related interrupt - * 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, - * CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ +#define AR5K_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, + CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ #define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */ #define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */ #define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */ #define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ -#define AR5K_ISR_BITS_FROM_SISRS (AR5K_ISR_TXOK | AR5K_ISR_TXDESC |\ - AR5K_ISR_TXERR | AR5K_ISR_TXEOL |\ - AR5K_ISR_TXURN | AR5K_ISR_HIUERR |\ - AR5K_ISR_BCNMISC | AR5K_ISR_QCBRORN |\ - AR5K_ISR_QCBRURN | AR5K_ISR_QTRIG) - /* * Secondary status registers [5211+] (0 - 4) * @@ -362,7 +347,7 @@ #define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ #define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ -#define AR5K_SISR2_TSFOOR 0x80000000 /* TSF Out of range */ +#define AR5K_SISR2_TSFOOR 0x80000000 /* TSF OOR (?) */ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 200f165c..2abac257 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -19,9 +19,9 @@ * */ -/****************************\ - Reset function and helpers -\****************************/ +/*****************************\ + Reset functions and helpers +\*****************************/ #include @@ -33,36 +33,14 @@ #include "debug.h" -/** - * DOC: Reset function and helpers - * - * Here we implement the main reset routine, used to bring the card - * to a working state and ready to receive. We also handle routines - * that don't fit on other places such as clock, sleep and power control - */ - - /******************\ * Helper functions * \******************/ -/** - * ath5k_hw_register_timeout() - Poll a register for a flag/field change - * @ah: The &struct ath5k_hw - * @reg: The register to read - * @flag: The flag/field to check on the register - * @val: The field value we expect (if we check a field) - * @is_set: Instead of checking if the flag got cleared, check if it got set - * - * Some registers contain flags that indicate that an operation is - * running. We use this function to poll these registers and check - * if these flags get cleared. We also use it to poll a register - * field (containing multiple flags) until it gets a specific value. - * - * Returns -EAGAIN if we exceeded AR5K_TUNE_REGISTER_TIMEOUT * 15us or 0 +/* + * Check if a register write has been completed */ -int -ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, +int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set) { int i; @@ -86,48 +64,35 @@ ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, \*************************/ /** - * ath5k_hw_htoclock() - Translate usec to hw clock units + * ath5k_hw_htoclock - Translate usec to hw clock units + * * @ah: The &struct ath5k_hw * @usec: value in microseconds - * - * Translate usecs to hw clock units based on the current - * hw clock rate. - * - * Returns number of clock units */ -unsigned int -ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) +unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) { struct ath_common *common = ath5k_hw_common(ah); return usec * common->clockrate; } /** - * ath5k_hw_clocktoh() - Translate hw clock units to usec - * @ah: The &struct ath5k_hw + * ath5k_hw_clocktoh - Translate hw clock units to usec * @clock: value in hw clock units - * - * Translate hw clock units to usecs based on the current - * hw clock rate. - * - * Returns number of usecs */ -unsigned int -ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) +unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) { struct ath_common *common = ath5k_hw_common(ah); return clock / common->clockrate; } /** - * ath5k_hw_init_core_clock() - Initialize core clock - * @ah: The &struct ath5k_hw + * ath5k_hw_init_core_clock - Initialize core clock + * + * @ah The &struct ath5k_hw * - * Initialize core clock parameters (usec, usec32, latencies etc), - * based on current bwmode and chipset properties. + * Initialize core clock parameters (usec, usec32, latencies etc). */ -static void -ath5k_hw_init_core_clock(struct ath5k_hw *ah) +static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; struct ath_common *common = ath5k_hw_common(ah); @@ -262,21 +227,16 @@ ath5k_hw_init_core_clock(struct ath5k_hw *ah) } } -/** - * ath5k_hw_set_sleep_clock() - Setup sleep clock operation - * @ah: The &struct ath5k_hw - * @enable: Enable sleep clock operation (false to disable) - * +/* * If there is an external 32KHz crystal available, use it * as ref. clock instead of 32/40MHz clock and baseband clocks * to save power during sleep or restore normal 32/40MHz * operation. * - * NOTE: When operating on 32KHz certain PHY registers (27 - 31, - * 123 - 127) require delay on access. + * XXX: When operating on 32KHz certain PHY registers (27 - 31, + * 123 - 127) require delay on access. */ -static void -ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) +static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 scal, spending, sclock; @@ -380,19 +340,10 @@ ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) * Reset/Sleep control * \*********************/ -/** - * ath5k_hw_nic_reset() - Reset the various chipset units - * @ah: The &struct ath5k_hw - * @val: Mask to indicate what units to reset - * - * To reset the various chipset units we need to write - * the mask to AR5K_RESET_CTL and poll the register until - * all flags are cleared. - * - * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout) +/* + * Reset chipset */ -static int -ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) +static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) { int ret; u32 mask = val ? val : ~0U; @@ -406,7 +357,7 @@ ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); /* Wait at least 128 PCI clocks */ - usleep_range(15, 20); + udelay(15); if (ah->ah_version == AR5K_AR5210) { val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA @@ -431,17 +382,12 @@ ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) return ret; } -/** - * ath5k_hw_wisoc_reset() - Reset AHB chipset - * @ah: The &struct ath5k_hw - * @flags: Mask to indicate what units to reset - * - * Same as ath5k_hw_nic_reset but for AHB based devices - * - * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout) +/* + * Reset AHB chipset + * AR5K_RESET_CTL_PCU flag resets WMAC + * AR5K_RESET_CTL_BASEBAND flag resets WBB */ -static int -ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) +static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) { u32 mask = flags ? flags : ~0U; u32 __iomem *reg; @@ -473,14 +419,14 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) } /* Put BB/MAC into reset */ - regval = ioread32(reg); - iowrite32(regval | val, reg); - regval = ioread32(reg); - usleep_range(100, 150); + regval = __raw_readl(reg); + __raw_writel(regval | val, reg); + regval = __raw_readl(reg); + udelay(100); /* Bring BB/MAC out of reset */ - iowrite32(regval & ~val, reg); - regval = ioread32(reg); + __raw_writel(regval & ~val, reg); + regval = __raw_readl(reg); /* * Reset configuration register (for hw byte-swap). Note that this @@ -493,23 +439,11 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) return 0; } -/** - * ath5k_hw_set_power_mode() - Set power mode - * @ah: The &struct ath5k_hw - * @mode: One of enum ath5k_power_mode - * @set_chip: Set to true to write sleep control register - * @sleep_duration: How much time the device is allowed to sleep - * when sleep logic is enabled (in 128 microsecond increments). - * - * This function is used to configure sleep policy and allowed - * sleep modes. For more information check out the sleep control - * register on reg.h and STA_ID1. - * - * Returns 0 on success, -EIO if chip didn't wake up or -EINVAL if an invalid - * mode is requested. + +/* + * Sleep control */ -static int -ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode, +static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration) { unsigned int i; @@ -559,7 +493,7 @@ ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode, ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, AR5K_SLEEP_CTL); - usleep_range(15, 20); + udelay(15); for (i = 200; i > 0; i--) { /* Check if the chip did wake up */ @@ -568,7 +502,7 @@ ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode, break; /* Wait a bit and retry */ - usleep_range(50, 75); + udelay(50); ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, AR5K_SLEEP_CTL); } @@ -589,20 +523,17 @@ ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode, return 0; } -/** - * ath5k_hw_on_hold() - Put device on hold - * @ah: The &struct ath5k_hw +/* + * Put device on hold * - * Put MAC and Baseband on warm reset and keep that state - * (don't clean sleep control register). After this MAC - * and Baseband are disabled and a full reset is needed - * to come back. This way we save as much power as possible + * Put MAC and Baseband on warm reset and + * keep that state (don't clean sleep control + * register). After this MAC and Baseband are + * disabled and a full reset is needed to come + * back. This way we save as much power as possible * without putting the card on full sleep. - * - * Returns 0 on success or -EIO on error */ -int -ath5k_hw_on_hold(struct ath5k_hw *ah) +int ath5k_hw_on_hold(struct ath5k_hw *ah) { struct pci_dev *pdev = ah->pdev; u32 bus_flags; @@ -612,7 +543,7 @@ ath5k_hw_on_hold(struct ath5k_hw *ah) return 0; /* Make sure device is awake */ - ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n"); return ret; @@ -632,7 +563,7 @@ ath5k_hw_on_hold(struct ath5k_hw *ah) ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); - usleep_range(2000, 2500); + mdelay(2); } else { ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND | bus_flags); @@ -644,7 +575,7 @@ ath5k_hw_on_hold(struct ath5k_hw *ah) } /* ...wakeup again!*/ - ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to put device on hold\n"); return ret; @@ -653,18 +584,11 @@ ath5k_hw_on_hold(struct ath5k_hw *ah) return ret; } -/** - * ath5k_hw_nic_wakeup() - Force card out of sleep - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * +/* * Bring up MAC + PHY Chips and program PLL - * NOTE: Channel is NULL for the initial wakeup. - * - * Returns 0 on success, -EIO on hw failure or -EINVAL for false channel infos + * Channel is NULL for the initial wakeup. */ -int -ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) +int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct pci_dev *pdev = ah->pdev; u32 turbo, mode, clock, bus_flags; @@ -676,7 +600,7 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) { /* Wakeup the device */ - ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n"); return ret; @@ -697,7 +621,7 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); - usleep_range(2000, 2500); + mdelay(2); } else { if (ath5k_get_bus_type(ah) == ATH_AHB) ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU | @@ -713,7 +637,7 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) } /* ...wakeup again!...*/ - ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0); + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); if (ret) { ATH5K_ERR(ah, "failed to resume the MAC Chip\n"); return ret; @@ -815,7 +739,7 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) /* ...update PLL if needed */ if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) { ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); - usleep_range(300, 350); + udelay(300); } /* ...set the PHY operating mode */ @@ -831,19 +755,8 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) * Post-initvals register modifications * \**************************************/ -/** - * ath5k_hw_tweak_initval_settings() - Tweak initial settings - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * Some settings are not handled on initvals, e.g. bwmode - * settings, some phy settings, workarounds etc that in general - * don't fit anywhere else or are too small to introduce a separate - * function for each one. So we have this function to handle - * them all during reset and complete card's initialization. - */ -static void -ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, +/* TODO: Half/Quarter rate */ +static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, struct ieee80211_channel *channel) { if (ah->ah_version == AR5K_AR5212 && @@ -962,16 +875,7 @@ ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, } } -/** - * ath5k_hw_commit_eeprom_settings() - Commit settings from EEPROM - * @ah: The &struct ath5k_hw - * @channel: The &struct ieee80211_channel - * - * Use settings stored on EEPROM to properly initialize the card - * based on various infos and per-mode calibration data. - */ -static void -ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, +static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; @@ -1125,23 +1029,7 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, * Main reset function * \*********************/ -/** - * ath5k_hw_reset() - The main reset function - * @ah: The &struct ath5k_hw - * @op_mode: One of enum nl80211_iftype - * @channel: The &struct ieee80211_channel - * @fast: Enable fast channel switching - * @skip_pcu: Skip pcu initialization - * - * This is the function we call each time we want to (re)initialize the - * card and pass new settings to hw. We also call it when hw runs into - * trouble to make it come back to a working state. - * - * Returns 0 on success, -EINVAL on false op_mode or channel infos, or -EIO - * on failure. - */ -int -ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, +int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool fast, bool skip_pcu) { u32 s_seq[10], s_led[3], tsf_up, tsf_lo; @@ -1159,7 +1047,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ if (fast && (ah->ah_radio != AR5K_RF2413) && (ah->ah_radio != AR5K_RF5413)) - fast = false; + fast = 0; /* Disable sleep clock operation * to avoid register access delay on certain @@ -1185,7 +1073,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ret && fast) { ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "DMA didn't stop, falling back to normal reset\n"); - fast = false; + fast = 0; /* Non fatal, just continue with * normal reset */ ret = 0; @@ -1354,7 +1242,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* * Initialize PCU */ - ath5k_hw_pcu_init(ah, op_mode); + ath5k_hw_pcu_init(ah, op_mode, mode); /* * Initialize PHY diff --git a/drivers/net/wireless/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h index aed34d99..5d11c23b 100644 --- a/drivers/net/wireless/ath/ath5k/rfbuffer.h +++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h @@ -18,9 +18,7 @@ */ -/** - * DOC: RF Buffer registers - * +/* * There are some special registers on the RF chip * that control various operation settings related mostly to * the analog parts (channel, gain adjustment etc). @@ -46,63 +44,40 @@ */ -/** - * struct ath5k_ini_rfbuffer - Initial RF Buffer settings - * @rfb_bank: RF Bank number - * @rfb_ctrl_register: RF Buffer control register - * @rfb_mode_data: RF Buffer data for each mode - * +/* * Struct to hold default mode specific RF - * register values (RF Banks) for each chip. + * register values (RF Banks) */ struct ath5k_ini_rfbuffer { - u8 rfb_bank; - u16 rfb_ctrl_register; - u32 rfb_mode_data[3]; + u8 rfb_bank; /* RF Bank number */ + u16 rfb_ctrl_register; /* RF Buffer control register */ + u32 rfb_mode_data[3]; /* RF Buffer data for each mode */ }; -/** - * struct ath5k_rfb_field - An RF Buffer field (register/value) - * @len: Field length - * @pos: Offset on the raw packet - * @col: Used for shifting - * +/* * Struct to hold RF Buffer field * infos used to access certain RF * analog registers */ struct ath5k_rfb_field { - u8 len; - u16 pos; - u8 col; + u8 len; /* Field length */ + u16 pos; /* Offset on the raw packet */ + u8 col; /* Column -used for shifting */ }; -/** - * struct ath5k_rf_reg - RF analog register definition - * @bank: RF Buffer Bank number - * @index: Register's index on ath5k_rf_regx_idx - * @field: The &struct ath5k_rfb_field - * - * We use this struct to define the set of RF registers - * on each chip that we want to tweak. Some RF registers - * are common between different chip versions so this saves - * us space and complexity because we can refer to an rf - * register by it's index no matter what chip we work with - * as long as it has that register. +/* + * RF analog register definition */ struct ath5k_rf_reg { - u8 bank; - u8 index; - struct ath5k_rfb_field field; + u8 bank; /* RF Buffer Bank number */ + u8 index; /* Register's index on rf_regs_idx */ + struct ath5k_rfb_field field; /* RF Buffer field for this register */ }; -/** - * enum ath5k_rf_regs_idx - Map RF registers to indexes - * +/* Map RF registers to indexes * We do this to handle common bits and make our * life easier by using an index for each register - * instead of a full rfb_field - */ + * instead of a full rfb_field */ enum ath5k_rf_regs_idx { /* BANK 2 */ AR5K_RF_TURBO = 0, diff --git a/drivers/net/wireless/ath/ath5k/rfgain.h b/drivers/net/wireless/ath/ath5k/rfgain.h index 4d21df0e..ebfae052 100644 --- a/drivers/net/wireless/ath/ath5k/rfgain.h +++ b/drivers/net/wireless/ath/ath5k/rfgain.h @@ -18,17 +18,13 @@ * */ -/** - * struct ath5k_ini_rfgain - RF Gain table - * @rfg_register: RF Gain register address - * @rfg_value: Register value for 5 and 2GHz - * +/* * Mode-specific RF Gain table (64bytes) for RF5111/5112 * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial * RF Gain values are included in AR5K_AR5210_INI) */ struct ath5k_ini_rfgain { - u16 rfg_register; + u16 rfg_register; /* RF Gain register address */ u32 rfg_value[2]; /* [freq (see below)] */ }; @@ -459,31 +455,18 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = { #define AR5K_GAIN_CHECK_ADJUST(_g) \ ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) -/** - * struct ath5k_gain_opt_step - An RF gain optimization step - * @gos_param: Set of parameters - * @gos_gain: Gain - */ struct ath5k_gain_opt_step { s8 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; s8 gos_gain; }; -/** - * struct ath5k_gain_opt - RF Gain optimization ladder - * @go_default: The default step - * @go_steps_count: How many optimization steps - * @go_step: Array of &struct ath5k_gain_opt_step - */ struct ath5k_gain_opt { u8 go_default; u8 go_steps_count; const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; }; - /* - * RF5111 * Parameters on gos_param: * 1) Tx clip PHY register * 2) PWD 90 RF register @@ -507,7 +490,6 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = { }; /* - * RF5112 * Parameters on gos_param: * 1) Mixgain ovr RF register * 2) PWD 138 RF register diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h index 00f01581..39f002ed 100644 --- a/drivers/net/wireless/ath/ath5k/trace.h +++ b/drivers/net/wireless/ath/ath5k/trace.h @@ -3,8 +3,7 @@ #include - -#if !defined(CONFIG_ATH5K_TRACER) || defined(__CHECKER__) +#ifndef CONFIG_ATH5K_TRACER #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ static inline void trace_ ## name(proto) {} @@ -94,7 +93,7 @@ TRACE_EVENT(ath5k_tx_complete, #endif /* __TRACE_ATH5K_H */ -#if defined(CONFIG_ATH5K_TRACER) && !defined(__CHECKER__) +#ifdef CONFIG_ATH5K_TRACER #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH ../../drivers/net/wireless/ath/ath5k diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index d755a5e7..c930b5a8 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -13,6 +13,12 @@ config ATH6KL_SDIO Please note that AR6002 and AR6001 are not supported by this driver. +config WIFI_MAC_FROM_NV + tristate "Atheros ath6kl softmac" + depends on ATH6KL + ---help--- + Softmac. + config ATH6KL_USB tristate "Atheros ath6kl USB support" depends on ATH6KL @@ -30,3 +36,11 @@ config ATH6KL_DEBUG depends on ATH6KL ---help--- Enables debug support + +config ATH6KL_REGDOMAIN + bool "Atheros ath6kl regdomain support" + depends on ATH6KL + ---help--- + Enabling this makes it possible to change the regdomain in + the firmware. This can be only enabled if regulatory requirements + are taken into account. diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 85746c3e..bab4f310 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -22,21 +22,44 @@ # Author(s): ="Atheros" #------------------------------------------------------------------------------ -obj-$(CONFIG_ATH6KL) += ath6kl_core.o -ath6kl_core-y += debug.o -ath6kl_core-y += hif.o -ath6kl_core-y += htc.o -ath6kl_core-y += bmi.o -ath6kl_core-y += cfg80211.o -ath6kl_core-y += init.o -ath6kl_core-y += main.o -ath6kl_core-y += txrx.o -ath6kl_core-y += wmi.o -ath6kl_core-y += core.o -ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o - -obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o +obj-$(CONFIG_ATH6KL_SDIO) := ath6kl_sdio.o +ath6kl_sdio-y += debug.o +ath6kl_sdio-y += debugfs_pri.o +ath6kl_sdio-y += hif.o +ath6kl_sdio-y += htc.o +ath6kl_sdio-y += bmi.o +ath6kl_sdio-y += cfg80211.o +ath6kl_sdio-y += cfg80211_btcoex.o +ath6kl_sdio-y += pm.o +ath6kl_sdio-y += init.o +ath6kl_sdio-y += main.o +ath6kl_sdio-y += txrx.o +ath6kl_sdio-y += wmi.o +ath6kl_sdio-y += wmi_btcoex.o ath6kl_sdio-y += sdio.o +ath6kl_sdio-y += platform.o +ath6kl_sdio-y += softmac.o +ath6kl_sdio-y += regd.o +ath6kl_sdio-y += wmiconfig.o +ath6kl_sdio-y += recovery.o +ath6kl_sdio-$(CONFIG_NL80211_TESTMODE) += testmode.o obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o +ath6kl_usb-y += debug.o +ath6kl_usb-y += hif.o +ath6kl_usb-y += htc.o +ath6kl_usb-y += bmi.o +ath6kl_usb-y += cfg80211.o +ath6kl_usb-y += cfg80211_btcoex.o +ath6kl_usb-y += pm.o +ath6kl_usb-y += init.o +ath6kl_usb-y += main.o +ath6kl_usb-y += txrx.o +ath6kl_usb-y += wmi.o +ath6kl_usb-y += wmi_btcoex.o ath6kl_usb-y += usb.o +ath6kl_usb-y += wmiconfig.o +ath6kl_usb-$(CONFIG_NL80211_TESTMODE) += testmode.o + +ccflags-y += -D__CHECK_ENDIAN__ +ccflags-y += -DSS_3RD_INTF diff --git a/drivers/net/wireless/ath/ath6kl/ath.h b/drivers/net/wireless/ath/ath6kl/ath.h new file mode 100644 index 00000000..4596c33a --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/ath.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef ATH_H +#define ATH_H + +#include +#include +#include +#include + +/* + * The key cache is used for h/w cipher state and also for + * tracking station state such as the current tx antenna. + * We also setup a mapping table between key cache slot indices + * and station state to short-circuit node lookups on rx. + * Different parts have different size key caches. We handle + * up to ATH_KEYMAX entries (could dynamically allocate state). + */ +#define ATH_KEYMAX 128 /* max key cache size we handle */ + +static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +struct ath_ani { + bool caldone; + unsigned int longcal_timer; + unsigned int shortcal_timer; + unsigned int resetcal_timer; + unsigned int checkani_timer; + struct timer_list timer; +}; + +struct ath_cycle_counters { + u32 cycles; + u32 rx_busy; + u32 rx_frame; + u32 tx_frame; +}; + +enum ath_device_state { + ATH_HW_UNAVAILABLE, + ATH_HW_INITIALIZED, +}; + +enum ath_bus_type { + ATH_PCI, + ATH_AHB, + ATH_USB, +}; + +struct reg_dmn_pair_mapping { + u16 regDmnEnum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +struct ath_regulatory { + char alpha2[2]; + u16 country_code; + u16 max_power_level; + u16 current_rd; + int16_t power_limit; + struct reg_dmn_pair_mapping *regpair; +}; + +enum ath_crypt_caps { + ATH_CRYPT_CAP_CIPHER_AESCCM = BIT(0), + ATH_CRYPT_CAP_MIC_COMBINED = BIT(1), +}; + +struct ath_keyval { + u8 kv_type; + u8 kv_pad; + u16 kv_len; + u8 kv_val[16]; /* TK */ + u8 kv_mic[8]; /* Michael MIC key */ + u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware + * supports both MIC keys in the same key cache entry; + * in that case, kv_mic is the RX key) */ +}; + +enum ath_cipher { + ATH_CIPHER_WEP = 0, + ATH_CIPHER_AES_OCB = 1, + ATH_CIPHER_AES_CCM = 2, + ATH_CIPHER_CKIP = 3, + ATH_CIPHER_TKIP = 4, + ATH_CIPHER_CLR = 5, + ATH_CIPHER_MIC = 127 +}; + +/** + * struct ath_ops - Register read/write operations + * + * @read: Register read + * @multi_read: Multiple register read + * @write: Register write + * @enable_write_buffer: Enable multiple register writes + * @write_flush: flush buffered register writes and disable buffering + */ +struct ath_ops { + unsigned int (*read)(void *, u32 reg_offset); + void (*multi_read)(void *, u32 *addr, u32 *val, u16 count); + void (*write)(void *, u32 val, u32 reg_offset); + void (*enable_write_buffer)(void *); + void (*write_flush) (void *); + u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); +}; + +struct ath_common; +struct ath_bus_ops; + +struct ath_common { + void *ah; + void *priv; + struct ieee80211_hw *hw; + int debug_mask; + enum ath_device_state state; + + struct ath_ani ani; + + u16 cachelsz; + u16 curaid; + u8 macaddr[ETH_ALEN]; + u8 curbssid[ETH_ALEN]; + u8 bssidmask[ETH_ALEN]; + + u32 rx_bufsize; + + u32 keymax; + DECLARE_BITMAP(keymap, ATH_KEYMAX); + DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); + enum ath_crypt_caps crypt_caps; + + unsigned int clockrate; + + spinlock_t cc_lock; + struct ath_cycle_counters cc_ani; + struct ath_cycle_counters cc_survey; + + struct ath_regulatory regulatory; + const struct ath_ops *ops; + const struct ath_bus_ops *bus_ops; + + bool btcoex_enabled; + bool disable_ani; +}; + +struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, + u32 len, + gfp_t gfp_mask); + +void ath_hw_setbssidmask(struct ath_common *common); +void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key); +int ath_key_config(struct ath_common *common, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); +bool ath_hw_keyreset(struct ath_common *common, u16 entry); +void ath_hw_cycle_counters_update(struct ath_common *common); +int32_t ath_hw_get_listen_time(struct ath_common *common); + +extern __printf(2, 3) void ath_printk(const char *level, const char *fmt, ...); + +#define _ath_printk(level, common, fmt, ...) \ +do { \ + __always_unused struct ath_common *unused = common; \ + ath_printk(level, fmt, ##__VA_ARGS__); \ +} while (0) + +#define ath_emerg(common, fmt, ...) \ + _ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__) +#define ath_alert(common, fmt, ...) \ + _ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__) +#define ath_crit(common, fmt, ...) \ + _ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__) +#define ath_err(common, fmt, ...) \ + _ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__) +#define ath_warn(common, fmt, ...) \ + _ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__) +#define ath_notice(common, fmt, ...) \ + _ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__) +#define ath_info(common, fmt, ...) \ + _ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__) + +/** + * enum ath_debug_level - atheros wireless debug level + * + * @ATH_DBG_RESET: reset processing + * @ATH_DBG_QUEUE: hardware queue management + * @ATH_DBG_EEPROM: eeprom processing + * @ATH_DBG_CALIBRATE: periodic calibration + * @ATH_DBG_INTERRUPT: interrupt processing + * @ATH_DBG_REGULATORY: regulatory processing + * @ATH_DBG_ANI: adaptive noise immunitive processing + * @ATH_DBG_XMIT: basic xmit operation + * @ATH_DBG_BEACON: beacon handling + * @ATH_DBG_CONFIG: configuration of the hardware + * @ATH_DBG_FATAL: fatal errors, this is the default, DBG_DEFAULT + * @ATH_DBG_PS: power save processing + * @ATH_DBG_HWTIMER: hardware timer handling + * @ATH_DBG_BTCOEX: bluetooth coexistance + * @ATH_DBG_BSTUCK: stuck beacons + * @ATH_DBG_ANY: enable all debugging + * + * The debug level is used to control the amount and type of debugging output + * we want to see. Each driver has its own method for enabling debugging and + * modifying debug level states -- but this is typically done through a + * module parameter 'debug' along with a respective 'debug' debugfs file + * entry. + */ +enum ATH_DEBUG { + ATH_DBG_RESET = 0x00000001, + ATH_DBG_QUEUE = 0x00000002, + ATH_DBG_EEPROM = 0x00000004, + ATH_DBG_CALIBRATE = 0x00000008, + ATH_DBG_INTERRUPT = 0x00000010, + ATH_DBG_REGULATORY = 0x00000020, + ATH_DBG_ANI = 0x00000040, + ATH_DBG_XMIT = 0x00000080, + ATH_DBG_BEACON = 0x00000100, + ATH_DBG_CONFIG = 0x00000200, + ATH_DBG_FATAL = 0x00000400, + ATH_DBG_PS = 0x00000800, + ATH_DBG_HWTIMER = 0x00001000, + ATH_DBG_BTCOEX = 0x00002000, + ATH_DBG_WMI = 0x00004000, + ATH_DBG_BSTUCK = 0x00008000, + ATH_DBG_MCI = 0x00010000, + ATH_DBG_ANY = 0xffffffff +}; + +#define ATH_DBG_DEFAULT (ATH_DBG_FATAL) + +#ifdef CONFIG_ATH_DEBUG + +#define ath_dbg(common, dbg_mask, fmt, ...) \ +do { \ + if ((common)->debug_mask & dbg_mask) \ + _ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \ +} while (0) + +#define ATH_DBG_WARN(foo, arg...) WARN(foo, arg) +#define ATH_DBG_WARN_ON_ONCE(foo) WARN_ON_ONCE(foo) + +#else + +static inline __attribute__ ((format (printf, 3, 4))) +void ath_dbg(struct ath_common *common, enum ATH_DEBUG dbg_mask, + const char *fmt, ...) +{ +} +#define ATH_DBG_WARN(foo, arg...) do {} while (0) +#define ATH_DBG_WARN_ON_ONCE(foo) ({ \ + int __ret_warn_once = !!(foo); \ + unlikely(__ret_warn_once); \ +}) + +#endif /* CONFIG_ATH_DEBUG */ + +/** Returns string describing opmode, or NULL if unknown mode. */ +#ifdef CONFIG_ATH_DEBUG +const char *ath_opmode_to_string(enum nl80211_iftype opmode); +#else +static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode) +{ + return "UNKNOWN"; +} +#endif + +#endif /* ATH_H */ diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index 334dbd83..05d1d894 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c @@ -106,7 +106,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, } ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", - targ_info->version, targ_info->type); + targ_info->version, targ_info->type); return 0; } @@ -193,7 +193,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header); ath6kl_dbg(ATH6KL_DBG_BMI, - "bmi write memory: addr: 0x%x, len: %d\n", addr, len); + "bmi write memory: addr: 0x%x, len: %d\n", addr, len); len_remain = len; while (len_remain) { @@ -435,7 +435,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); offset += sizeof(tx_len); memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], - tx_len); + tx_len); offset += tx_len; ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h index 18fdd69e..114f7b26 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.h +++ b/drivers/net/wireless/ath/ath6kl/bmi.h @@ -223,29 +223,6 @@ struct ath6kl_bmi_target_info { __le32 type; /* target type */ } __packed; -#define ath6kl_bmi_write_hi32(ar, item, val) \ - ({ \ - u32 addr; \ - __le32 v; \ - \ - addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ - v = cpu_to_le32(val); \ - ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v)); \ - }) - -#define ath6kl_bmi_read_hi32(ar, item, val) \ - ({ \ - u32 addr, *check_type = val; \ - __le32 tmp; \ - int ret; \ - \ - (void) (check_type == val); \ - addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ - ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ - *val = le32_to_cpu(tmp); \ - ret; \ - }) - int ath6kl_bmi_init(struct ath6kl *ar); void ath6kl_bmi_cleanup(struct ath6kl *ar); void ath6kl_bmi_reset(struct ath6kl *ar); diff --git a/drivers/net/wireless/ath/ath6kl/btc.h b/drivers/net/wireless/ath/ath6kl/btc.h new file mode 100644 index 00000000..71075a8e --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/btc.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef BTC_H +#define BTC_H +#include + +#define EVENT_ID_LEN 2 + +void cfg80211_send_genevent_to_app(struct net_device *dev, + u16 event_id, + u8 *datap, int len) +{ + char *buf; + u16 size; + union iwreq_data wrqu; + + size = len + EVENT_ID_LEN; + + if (size > IW_GENERIC_IE_MAX) + return; + + buf = kmalloc(size, GFP_ATOMIC); + if (buf == NULL) + return; + + memset(buf, 0, size); + memcpy(buf, &event_id, EVENT_ID_LEN); + memcpy(buf + EVENT_ID_LEN, datap, len); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = size; + wireless_send_event(dev, IWEVGENIE, &wrqu, buf); + kfree(buf); +} + +void cfg80211_send_event_to_app(struct net_device *dev, + u16 event_id, + u8 *datap, int len) +{ + char *buf; + u16 size; + union iwreq_data wrqu; + + size = len + EVENT_ID_LEN; + + if (size > IW_CUSTOM_MAX) + return; + + buf = kmalloc(size, GFP_ATOMIC); + if (buf == NULL) + return; + + memset(buf, 0, size); + memcpy(buf, &event_id, EVENT_ID_LEN); + memcpy(buf + EVENT_ID_LEN, datap, len); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = size; + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); + kfree(buf); +} +#endif diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 00d38952..aaa62fb2 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -17,13 +17,18 @@ #include #include -#include #include "core.h" #include "cfg80211.h" #include "debug.h" #include "hif-ops.h" #include "testmode.h" +#include "cfg80211_btcoex.h" +#include "pm.h" + +static unsigned int ath6kl_p2p = 1; + +module_param(ath6kl_p2p, uint, 0644); #define RATETAB_ENT(_rate, _rateid, _flags) { \ .bitrate = (_rate), \ @@ -49,6 +54,13 @@ .max_power = 30, \ } +#define DEFAULT_BG_SCAN_PERIOD 60 + +struct ath6kl_cfg80211_match_probe_ssid { + struct cfg80211_ssid ssid; + u8 flag; +}; + static struct ieee80211_rate ath6kl_rates[] = { RATETAB_ENT(10, 0x1, 0), RATETAB_ENT(20, 0x2, 0), @@ -69,7 +81,8 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 -#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ +#define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20 +#define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_20 | \ IEEE80211_HT_CAP_SGI_40) @@ -126,26 +139,28 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, - .ht_cap.cap = ath6kl_g_htcap, + .ht_cap.cap = ath6kl_a_htcap, .ht_cap.ht_supported = true, }; #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ +#define SSCAN_WAKELOCK_IN_SECOND 35 + /* returns true if scheduled scan was stopped */ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif) { struct ath6kl *ar = vif->ar; - if (ar->state != ATH6KL_STATE_SCHED_SCAN) + if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags)) return false; del_timer_sync(&vif->sched_scan_timer); - ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_AWAKE); + if (ar->state == ATH6KL_STATE_RECOVERY) + return true; - ar->state = ATH6KL_STATE_ON; + ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false); return true; } @@ -203,7 +218,7 @@ static int ath6kl_set_auth_type(struct ath6kl_vif *vif, break; default: - ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type); + ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type); return -ENOTSUPP; } @@ -272,7 +287,7 @@ static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt) } } -static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif) +bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif) { struct ath6kl *ar = vif->ar; @@ -390,7 +405,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, return false; if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && - ar->num_vif)) + ar->num_vif)) return false; if (type == NL80211_IFTYPE_STATION || @@ -416,12 +431,6 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, return false; } -static bool ath6kl_is_tx_pending(struct ath6kl *ar) -{ - return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; -} - - static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { @@ -466,8 +475,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * sleep until the command queue drains */ wait_event_interruptible_timeout(ar->event_wq, - ath6kl_is_tx_pending(ar), - WMI_TIMEOUT); + ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, + WMI_TIMEOUT); if (signal_pending(current)) { ath6kl_err("cmd queue drain timeout\n"); up(&ar->sem); @@ -562,7 +571,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (!ar->usr_bss_filter) { clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, - ALL_BSS_FILTER, 0) != 0) { + ALL_BSS_FILTER, 0) != 0) { ath6kl_err("couldn't set bss filtering\n"); up(&ar->sem); return -EIO; @@ -571,6 +580,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->nw_type = vif->next_mode; + /* enable enhanced bmiss detection if applicable */ + ath6kl_cfg80211_sta_bmiss_enhance(vif, true); + if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) nw_subtype = SUBTYPE_P2PCLIENT; @@ -586,8 +598,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->reconnect_flag = 0; if (vif->nw_type == INFRA_NETWORK) { - interval = max_t(u16, vif->listen_intvl_t, - ATH6KL_MAX_WOW_LISTEN_INTL); + interval = max(vif->listen_intvl_t, + (u16) ATH6KL_MAX_WOW_LISTEN_INTL); status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, interval, 0); @@ -607,6 +619,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->req_bssid, vif->ch_hint, ar->connect_ctrl_flags, nw_subtype); + /* disable background scan if period is 0 */ + if (sme->bg_scan_period == 0) + sme->bg_scan_period = 0xffff; + + /* configure default value if not specified */ + if (sme->bg_scan_period == -1) + sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; + + ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, + sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); + up(&ar->sem); if (status == -EINVAL) { @@ -620,8 +643,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && - ((vif->auth_mode == WPA_PSK_AUTH) || - (vif->auth_mode == WPA2_PSK_AUTH))) { + ((vif->auth_mode == WPA_PSK_AUTH) + || (vif->auth_mode == WPA2_PSK_AUTH))) { mod_timer(&vif->disconnect_timer, jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); } @@ -836,34 +859,110 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, } } + clear_bit(CONNECT_PEND, &vif->flags); + + if (vif->sme_state == SME_CONNECTING) { + cfg80211_connect_result(vif->ndev, + bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } else if (vif->sme_state == SME_CONNECTED) { + cfg80211_disconnected(vif->ndev, proto_reason, + NULL, 0, GFP_KERNEL); + } + + vif->sme_state = SME_DISCONNECTED; + /* * Send a disconnect command to target when a disconnect event is * received with reason code other than 3 (DISCONNECT_CMD - disconnect * request from host) to make the firmware stop trying to connect even * after giving disconnect event. There will be one more disconnect * event for this disconnect command with reason code DISCONNECT_CMD - * which will be notified to cfg80211. + * which won't be notified to cfg80211. */ - - if (reason != DISCONNECT_CMD) { + if (reason != DISCONNECT_CMD) ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); - return; +} + +static int ath6kl_set_probed_ssids(struct ath6kl *ar, + struct ath6kl_vif *vif, + struct cfg80211_ssid *ssids, int n_ssids, + struct cfg80211_match_set *match_set, + int n_match_ssid) +{ + u8 i, j, index_to_add, ssid_found = false; + struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS]; + + memset(ssid_list, 0, sizeof(ssid_list)); + + if (n_ssids > MAX_PROBED_SSIDS || + n_match_ssid > MAX_PROBED_SSIDS) + return -EINVAL; + + for (i = 0; i < n_ssids; i++) { + memcpy(ssid_list[i].ssid.ssid, + ssids[i].ssid, + ssids[i].ssid_len); + ssid_list[i].ssid.ssid_len = ssids[i].ssid_len; + + if (ssids[i].ssid_len) + ssid_list[i].flag = SPECIFIC_SSID_FLAG; + else + ssid_list[i].flag = ANY_SSID_FLAG; + + if (n_match_ssid == 0) + ssid_list[i].flag |= MATCH_SSID_FLAG; } - clear_bit(CONNECT_PEND, &vif->flags); + index_to_add = i; - if (vif->sme_state == SME_CONNECTING) { - cfg80211_connect_result(vif->ndev, - bssid, NULL, 0, - NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - } else if (vif->sme_state == SME_CONNECTED) { - cfg80211_disconnected(vif->ndev, reason, - NULL, 0, GFP_KERNEL); + for (i = 0; i < n_match_ssid; i++) { + ssid_found = false; + + for (j = 0; j < n_ssids; j++) { + if ((match_set[i].ssid.ssid_len == + ssid_list[j].ssid.ssid_len) && + (!memcmp(ssid_list[j].ssid.ssid, + match_set[i].ssid.ssid, + match_set[i].ssid.ssid_len))) { + ssid_list[j].flag |= MATCH_SSID_FLAG; + ssid_found = true; + break; + } + } + + if (ssid_found) + continue; + + if (index_to_add >= MAX_PROBED_SSIDS) + continue; + + ssid_list[index_to_add].ssid.ssid_len = + match_set[i].ssid.ssid_len; + memcpy(ssid_list[index_to_add].ssid.ssid, + match_set[i].ssid.ssid, + match_set[i].ssid.ssid_len); + ssid_list[index_to_add].flag |= MATCH_SSID_FLAG; + index_to_add++; } - vif->sme_state = SME_DISCONNECTED; + for (i = 0; i < index_to_add; i++) { + ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, + ssid_list[i].flag, + ssid_list[i].ssid.ssid_len, + ssid_list[i].ssid.ssid); + + } + + /* Make sure no old entries are left behind */ + for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) { + ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, + DISABLE_SSID_FLAG, 0, NULL); + } + + return 0; } static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, @@ -883,28 +982,18 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (!ar->usr_bss_filter) { clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); - ret = ath6kl_wmi_bssfilter_cmd( - ar->wmi, vif->fw_vif_idx, - (test_bit(CONNECTED, &vif->flags) ? - ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0); + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + ALL_BSS_FILTER, 0); if (ret) { ath6kl_err("couldn't set bss filtering\n"); return ret; } } - if (request->n_ssids && request->ssids[0].ssid_len) { - u8 i; - - if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1)) - request->n_ssids = MAX_PROBED_SSID_INDEX - 1; - - for (i = 0; i < request->n_ssids; i++) - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i + 1, SPECIFIC_SSID_FLAG, - request->ssids[i].ssid_len, - request->ssids[i].ssid); - } + ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, + request->n_ssids, NULL, 0); + if (ret < 0) + return ret; /* this also clears IE in fw if it's not set */ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, @@ -941,32 +1030,20 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (test_bit(CONNECTED, &vif->flags)) force_fg_scan = 1; - if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, - ar->fw_capabilities)) { - /* - * If capable of doing P2P mgmt operations using - * station interface, send additional information like - * supported rates to advertise and xmit rates for - * probe requests - */ - ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, - WMI_LONG_SCAN, force_fg_scan, - false, 0, - ATH6KL_FG_SCAN_INTERVAL, - n_channels, channels, - request->no_cck, - request->rates); - } else { - ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, - WMI_LONG_SCAN, force_fg_scan, - false, 0, - ATH6KL_FG_SCAN_INTERVAL, - n_channels, channels); + vif->scan_req = request; + + ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, + WMI_LONG_SCAN, force_fg_scan, + false, 0, + ATH6KL_FG_SCAN_INTERVAL, + n_channels, channels, + request->no_cck, + request->rates); + + if (ret) { + ath6kl_err("failed to start scan: %d\n", ret); + vif->scan_req = NULL; } - if (ret) - ath6kl_err("wmi_startscan_cmd failed\n"); - else - vif->scan_req = request; kfree(channels); @@ -1000,6 +1077,20 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted) vif->scan_req = NULL; } +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, + enum wmi_phy_mode mode) +{ + enum nl80211_channel_type type; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "channel switch notify nw_type %d freq %d mode %d\n", + vif->nw_type, freq, mode); + + type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; + + cfg80211_ch_switch_notify(vif->ndev, freq, type); +} + static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr, @@ -1008,7 +1099,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, struct ath6kl *ar = ath6kl_priv(ndev); struct ath6kl_vif *vif = netdev_priv(ndev); struct ath6kl_key *key = NULL; - int seq_len; + int seq_len = 0; u8 key_usage; u8 key_type; @@ -1074,9 +1165,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, return -ENOTSUPP; } - if (((vif->auth_mode == WPA_PSK_AUTH) || - (vif->auth_mode == WPA2_PSK_AUTH)) && - (key_usage & GROUP_USAGE)) + if (((vif->auth_mode == WPA_PSK_AUTH) + || (vif->auth_mode == WPA2_PSK_AUTH)) + && (key_usage & GROUP_USAGE)) del_timer(&vif->disconnect_timer); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, @@ -1291,6 +1382,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl_vif *vif; + u8 ath6kl_dbm; int dbm = MBM_TO_DBM(mbm); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, @@ -1307,7 +1399,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, case NL80211_TX_POWER_AUTOMATIC: return 0; case NL80211_TX_POWER_LIMITED: - ar->tx_pwr = dbm; + ar->tx_pwr = ath6kl_dbm = dbm; break; default: ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", @@ -1315,7 +1407,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, return -EOPNOTSUPP; } - ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm); + ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm); return 0; } @@ -1376,7 +1468,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, } if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx, - mode.pwr_mode) != 0) { + mode.pwr_mode) != 0) { ath6kl_err("wmi_powermode_cmd failed\n"); return -EIO; } @@ -1413,6 +1505,15 @@ static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, return ndev; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) +struct net_device *ath6kl_cfg80211_add_p2p0_iface(struct ath6kl *ar) +{ + return ath6kl_cfg80211_add_iface(ar->wiphy, "p2p0", + NL80211_IFTYPE_P2P_CLIENT, + NULL, NULL); +} +#endif + static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, struct net_device *ndev) { @@ -1425,7 +1526,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); - ath6kl_cfg80211_vif_cleanup(vif); + ath6kl_deinit_if_data(vif); return 0; } @@ -1436,9 +1537,41 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, struct vif_params *params) { struct ath6kl_vif *vif = netdev_priv(ndev); + int i; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); + /* + * Don't bring up p2p on an interface which is not initialized + * for p2p operation where fw does not have capability to switch + * dynamically between non-p2p and p2p type interface. + */ + if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + vif->ar->fw_capabilities) && + (type == NL80211_IFTYPE_P2P_CLIENT || + type == NL80211_IFTYPE_P2P_GO)) { + if (vif->ar->vif_max == 1) { + if (vif->fw_vif_idx != 0) + return -EINVAL; + else + goto set_iface_type; + } + + for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) { + if (i == vif->fw_vif_idx) + break; + } + + if (i == vif->ar->vif_max) { + ath6kl_err("Invalid interface to bring up P2P\n"); + return -EINVAL; + } + } + + /* need to clean up enhanced bmiss detection fw state */ + ath6kl_cfg80211_sta_bmiss_enhance(vif, false); + +set_iface_type: switch (type) { case NL80211_IFTYPE_STATION: vif->next_mode = INFRA_NETWORK; @@ -1887,8 +2020,10 @@ static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif) static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) { struct net_device *ndev = vif->ndev; - static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; - static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 }; + static const u8 discvr_lmnr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; + static const u8 discvr_lmnr_mask[] = { 0xff, 0xff, 0xff, 0xf8 }; + static const u8 discvr_ssdp_pattern[] = { 0xef, 0xff, 0xff, 0xfa }; + static const u8 discvr_ssdp_mask[] = { 0xff, 0xff, 0xff, 0xff }; u8 discvr_offset = 38; u8 mac_mask[ETH_ALEN]; int ret; @@ -1912,11 +2047,18 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) { ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, WOW_LIST_ID, - sizeof(discvr_pattern), discvr_offset, - discvr_pattern, discvr_mask); + sizeof(discvr_lmnr_pattern), discvr_offset, + discvr_lmnr_pattern, discvr_lmnr_mask); + if (ret) { + ath6kl_err("failed to add WOW mDNS/LMNR pattern\n"); + return ret; + } + ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, + vif->fw_vif_idx, WOW_LIST_ID, + sizeof(discvr_ssdp_pattern), discvr_offset, + discvr_ssdp_pattern, discvr_ssdp_mask); if (ret) { - ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR " - "pattern\n"); + ath6kl_err("failed to add WOW SSDP pattern\n"); return ret; } } @@ -1924,29 +2066,72 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) return 0; } -static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +static int is_hsleep_mode_procsed(struct ath6kl_vif *vif) +{ + return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); +} + +static bool is_ctrl_ep_empty(struct ath6kl *ar) +{ + return !ar->tx_pending[ar->ctrl_ep]; +} + +static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif) { - struct in_device *in_dev; - struct in_ifaddr *ifa; - struct ath6kl_vif *vif; int ret, left; - u32 filter = 0; - u16 i, bmiss_time; - u8 index = 0; - __be32 ips[MAX_IP_ADDRS]; - vif = ath6kl_vif_first(ar); - if (!vif) - return -EIO; + clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_ASLEEP); + if (ret) + return ret; - if (!test_bit(CONNECTED, &vif->flags)) - return -ENOTCONN; + left = wait_event_interruptible_timeout(ar->event_wq, + is_hsleep_mode_procsed(vif), + WMI_TIMEOUT); + if (left == 0) { + ath6kl_warn("timeout, didn't get host sleep cmd processed event\n"); + ret = -ETIMEDOUT; + } else if (left < 0) { + ath6kl_warn("error while waiting for host sleep cmd processed event %d\n", + left); + ret = left; + } - if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) - return -EINVAL; + if (ar->tx_pending[ar->ctrl_ep]) { + left = wait_event_interruptible_timeout(ar->event_wq, + is_ctrl_ep_empty(ar), + WMI_TIMEOUT); + if (left == 0) { + ath6kl_warn("clear wmi ctrl data timeout\n"); + ret = -ETIMEDOUT; + } else if (left < 0) { + ath6kl_warn("clear wmi ctrl data failed: %d\n", left); + ret = left; + } + } + + return ret; +} + +static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif, + struct cfg80211_wowlan *wow, u32 *filter) +{ + struct ath6kl *ar = vif->ar; + struct in_device *in_dev; + struct in_ifaddr *ifa; + int ret; + u16 i, bmiss_time; + __be32 ips[MAX_IP_ADDRS]; + u8 index = 0; + + if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) { + ret = ath6kl_wmi_mcast_filter_cmd(ar->wmi, + vif->fw_vif_idx, false); + if (ret) + return ret; + } /* Clear existing WOW patterns */ for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) @@ -1959,7 +2144,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) * the user. */ if (wow) - ret = ath6kl_wow_usr(ar, vif, wow, &filter); + ret = ath6kl_wow_usr(ar, vif, wow, filter); else if (vif->nw_type == AP_NETWORK) ret = ath6kl_wow_ap(ar, vif); else @@ -1994,12 +2179,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) return ret; } - ar->state = ATH6KL_STATE_SUSPENDING; - /* Setup own IP addr for ARP agent. */ in_dev = __in_dev_get_rtnl(vif->ndev); if (!in_dev) - goto skip_arp; + return 0; ifa = in_dev->ifa_list; memset(&ips, 0, sizeof(ips)); @@ -2022,68 +2205,71 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) return ret; } -skip_arp: - ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_WOW_MODE_ENABLE, - filter, - WOW_HOST_REQ_DELAY); - if (ret) - return ret; + return ret; +} - clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); +static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +{ + struct ath6kl_vif *first_vif, *vif; + int ret = 0; + u32 filter = 0; + bool connected = false, sscan = false; - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_ASLEEP); - if (ret) - return ret; + /* enter / leave wow suspend on first vif always */ + first_vif = ath6kl_vif_first(ar); + if (WARN_ON(unlikely(!first_vif)) || + !ath6kl_cfg80211_ready(first_vif)) + return -EIO; - left = wait_event_interruptible_timeout(ar->event_wq, - test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags), - WMI_TIMEOUT); - if (left == 0) { - ath6kl_warn("timeout, didn't get host sleep cmd " - "processed event\n"); - ret = -ETIMEDOUT; - } else if (left < 0) { - ath6kl_warn("error while waiting for host sleep cmd " - "processed event %d\n", left); - ret = left; - } + if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) + return -EINVAL; - if (ar->tx_pending[ar->ctrl_ep]) { - left = wait_event_interruptible_timeout(ar->event_wq, - ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT); - if (left == 0) { - ath6kl_warn("clear wmi ctrl data timeout\n"); - ret = -ETIMEDOUT; - } else if (left < 0) { - ath6kl_warn("clear wmi ctrl data failed: %d\n", left); - ret = left; + /* install filters for each connected vif */ + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (!test_bit(CONNECTED, &vif->flags) || + !ath6kl_cfg80211_ready(vif)) { + /* if a sscan is going on, do not clear + WOW_FILTER_SSID later */ + if (test_bit(SCHED_SCANNING, &vif->flags)) { + filter |= WOW_FILTER_SSID; + sscan = true; + } + continue; } - } - return ret; -} + connected = true; -static int ath6kl_wow_resume(struct ath6kl *ar) -{ - struct ath6kl_vif *vif; - int ret; + spin_unlock_bh(&ar->list_lock); + ret = ath6kl_wow_suspend_vif(vif, wow, &filter); + spin_lock_bh(&ar->list_lock); + if (ret) + break; + } + spin_unlock_bh(&ar->list_lock); - vif = ath6kl_vif_first(ar); - if (!vif) - return -EIO; + /* to enable pno, goes into wow while sscan */ + if (!connected && !sscan) + return -ENOTCONN; + else if (ret) + return ret; - ar->state = ATH6KL_STATE_RESUMING; + ar->state = ATH6KL_STATE_SUSPENDING; - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_AWAKE); - if (ret) { - ath6kl_warn("Failed to configure host sleep mode for " - "wow resume: %d\n", ret); - ar->state = ATH6KL_STATE_WOW; + ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx, + ATH6KL_WOW_MODE_ENABLE, + filter, + WOW_HOST_REQ_DELAY); + if (ret) return ret; - } + + return ath6kl_cfg80211_host_sleep(ar, first_vif); +} + +static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif) +{ + struct ath6kl *ar = vif->ar; + int ret; if (vif->nw_type != AP_NETWORK) { ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, @@ -2101,23 +2287,166 @@ static int ath6kl_wow_resume(struct ath6kl *ar) if (ret) return ret; } - - ar->state = ATH6KL_STATE_ON; + if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) { + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, + vif->fw_vif_idx, true); + if (ret) + return ret; + } netif_wake_queue(vif->ndev); return 0; } -int ath6kl_cfg80211_suspend(struct ath6kl *ar, - enum ath6kl_cfg_suspend_mode mode, - struct cfg80211_wowlan *wow) +static int ath6kl_wow_resume(struct ath6kl *ar) { - enum ath6kl_state prev_state; + struct ath6kl_vif *vif, *vif_p; int ret; + bool sscan = false; - switch (mode) { - case ATH6KL_CFG_SUSPEND_WOW: + vif = ath6kl_vif_first(ar); + if (WARN_ON(unlikely(!vif)) || + !ath6kl_cfg80211_ready(vif)) + return -EIO; + +#ifdef CONFIG_HAS_WAKELOCK + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif_p, &ar->vif_list, list) { + if (test_bit(SCHED_SCANNING, &vif_p->flags)) { + sscan = true; + break; + } + } + spin_unlock_bh(&ar->list_lock); + + if (sscan) { + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan %ds(%d jiffies) wake lock\n", + SSCAN_WAKELOCK_IN_SECOND, SSCAN_WAKELOCK_IN_SECOND*HZ); + wake_lock_timeout(&ar->wake_lock, + SSCAN_WAKELOCK_IN_SECOND * HZ); + } else { + wake_lock_timeout(&ar->wake_lock, 5); + } +#endif + + ar->state = ATH6KL_STATE_RESUMING; + + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_AWAKE); + if (ret) { + ath6kl_warn("Failed to configure host sleep mode for " + "wow resume: %d\n", ret); + goto cleanup; + } + + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (!test_bit(CONNECTED, &vif->flags) || + !ath6kl_cfg80211_ready(vif)) + continue; + spin_unlock_bh(&ar->list_lock); + ret = ath6kl_wow_resume_vif(vif); + spin_lock_bh(&ar->list_lock); + if (ret) + break; + } + spin_unlock_bh(&ar->list_lock); + + if (ret) + goto cleanup; + + ar->state = ATH6KL_STATE_ON; + return 0; + +cleanup: + ar->state = ATH6KL_STATE_WOW; + return ret; +} + +static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + if (!test_bit(WMI_READY, &ar->flag)) { + ath6kl_err("deepsleep failed as wmi is not ready\n"); + return -EIO; + } + + ath6kl_cfg80211_stop_all(ar); + + /* Save the current power mode before enabling power save */ + ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; + + ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); + if (ret) + return ret; + + /* Disable WOW mode */ + ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_WOW_MODE_DISABLE, + 0, 0); + if (ret) + return ret; + + /* Flush all non control pkts in TX path */ + ath6kl_tx_data_cleanup(ar); + + ret = ath6kl_cfg80211_host_sleep(ar, vif); + if (ret) + return ret; + + return 0; +} + +static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + + if (!vif) + return -EIO; + + if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { + ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, + ar->wmi->saved_pwr_mode); + if (ret) + return ret; + } + + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_AWAKE); + if (ret) + return ret; + + ar->state = ATH6KL_STATE_ON; + + /* Reset scan parameter to default values */ + ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, + 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); + if (ret) + return ret; + + return 0; +} + +int ath6kl_cfg80211_suspend(struct ath6kl *ar, + enum ath6kl_cfg_suspend_mode mode, + struct cfg80211_wowlan *wow) +{ + struct ath6kl_vif *vif; + enum ath6kl_state prev_state; + int ret; + + switch (mode) { + case ATH6KL_CFG_SUSPEND_WOW: ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n"); @@ -2125,7 +2454,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, ath6kl_tx_data_cleanup(ar); prev_state = ar->state; - ret = ath6kl_wow_suspend(ar, wow); if (ret) { ar->state = prev_state; @@ -2137,15 +2465,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, case ATH6KL_CFG_SUSPEND_DEEPSLEEP: - ath6kl_cfg80211_stop_all(ar); + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n"); - /* save the current power mode before enabling power save */ - ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; - - ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); + ret = ath6kl_cfg80211_deepsleep_suspend(ar); if (ret) { - ath6kl_warn("wmi powermode command failed during suspend: %d\n", - ret); + ath6kl_err("deepsleep suspend failed: %d\n", ret); + return ret; } ar->state = ATH6KL_STATE_DEEPSLEEP; @@ -2174,20 +2499,15 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, break; - case ATH6KL_CFG_SUSPEND_SCHED_SCAN: - /* - * Nothing needed for schedule scan, firmware is already in - * wow mode and sleeping most of the time. - */ - break; - default: break; } + list_for_each_entry(vif, &ar->vif_list, list) + ath6kl_cfg80211_scan_complete_event(vif, true); + return 0; } -EXPORT_SYMBOL(ath6kl_cfg80211_suspend); int ath6kl_cfg80211_resume(struct ath6kl *ar) { @@ -2206,17 +2526,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) break; case ATH6KL_STATE_DEEPSLEEP: - if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { - ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, - ar->wmi->saved_pwr_mode); - if (ret) { - ath6kl_warn("wmi powermode command failed during resume: %d\n", - ret); - } - } - - ar->state = ATH6KL_STATE_ON; + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n"); + ret = ath6kl_cfg80211_deepsleep_resume(ar); + if (ret) { + ath6kl_warn("deep sleep resume failed: %d\n", ret); + return ret; + } break; case ATH6KL_STATE_CUTPOWER: @@ -2229,18 +2545,14 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) } break; - case ATH6KL_STATE_SCHED_SCAN: - break; - default: break; } return 0; } -EXPORT_SYMBOL(ath6kl_cfg80211_resume); -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) /* hif layer decides what suspend mode to use */ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy, @@ -2248,14 +2560,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy, { struct ath6kl *ar = wiphy_priv(wiphy); + ath6kl_recovery_suspend(ar); + return ath6kl_hif_suspend(ar, wow); } static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) { struct ath6kl *ar = wiphy_priv(wiphy); + int err; + + err = ath6kl_hif_resume(ar); + if (err) + return err; - return ath6kl_hif_resume(ar); + ath6kl_recovery_resume(ar); + + return 0; } /* @@ -2274,22 +2595,47 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) * * ath6kl_check_wow_status() is called from ath6kl_rx(). */ -void ath6kl_check_wow_status(struct ath6kl *ar) +void ath6kl_check_wow_status(struct ath6kl *ar, struct sk_buff *skb, + bool is_event_pkt) { if (ar->state == ATH6KL_STATE_SUSPENDING) return; if (ar->state == ATH6KL_STATE_WOW) ath6kl_cfg80211_resume(ar); + else + ath6kl_config_suspend_wake_lock(ar, skb, is_event_pkt); } #else -void ath6kl_check_wow_status(struct ath6kl *ar) +void ath6kl_check_wow_status(struct ath6kl *ar, struct sk_buff *skb, + bool is_event_pkt) { } #endif +static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band, + bool ht_enable) +{ + struct ath6kl_htcap *htcap = &vif->htcap[band]; + + if (htcap->ht_enable == ht_enable) + return 0; + + if (ht_enable) { + /* Set default ht capabilities */ + htcap->ht_enable = true; + htcap->cap_info = (band == IEEE80211_BAND_2GHZ) ? + ath6kl_g_htcap : ath6kl_a_htcap; + htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; + } else /* Disable ht */ + memset(htcap, 0, sizeof(*htcap)); + + return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx, + band, htcap); +} + static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) @@ -2313,6 +2659,8 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", __func__, chan->center_freq, chan->hw_value); vif->next_chan = chan->center_freq; + vif->next_ch_type = channel_type; + vif->next_ch_band = chan->band; return 0; } @@ -2360,11 +2708,31 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif, return ret; } -static int ath6kl_set_ies(struct ath6kl_vif *vif, - struct cfg80211_beacon_data *info) +static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info, bool add) { - struct ath6kl *ar = vif->ar; + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + struct ieee80211_mgmt *mgmt; + enum wmi_phy_mode phy_mode; + bool hidden = false; + u8 *ies; + int ies_len; + struct wmi_connect_cmd p; int res; + int i, ret; + u8 *rsn_ie; + int rsn_ie_len; + u16 cnt; + u16 rsn_capb; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + if (vif->next_mode != AP_NETWORK) + return -EOPNOTSUPP; /* this also clears IE in fw if it's not set */ res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, @@ -2388,31 +2756,8 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, if (res) return res; - return 0; -} - -static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ap_settings *info) -{ - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); - struct ieee80211_mgmt *mgmt; - bool hidden = false; - u8 *ies; - int ies_len; - struct wmi_connect_cmd p; - int res; - int i, ret; - - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); - - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; - - if (vif->next_mode != AP_NETWORK) - return -EOPNOTSUPP; - - res = ath6kl_set_ies(vif, &info->beacon); + if (!add) + return 0; ar->ap_mode_bkey.valid = false; @@ -2421,13 +2766,13 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, * info->dtim_period */ - if (info->beacon.head == NULL) + if (info->head == NULL) return -EINVAL; - mgmt = (struct ieee80211_mgmt *) info->beacon.head; + mgmt = (struct ieee80211_mgmt *) info->head; ies = mgmt->u.beacon.variable; - if (ies > info->beacon.head + info->beacon.head_len) + if (ies > info->head + info->head_len) return -EINVAL; - ies_len = info->beacon.head + info->beacon.head_len - ies; + ies_len = info->head + info->head_len - ies; if (info->ssid == NULL) return -EINVAL; @@ -2515,8 +2860,61 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, p.ssid_len = vif->ssid_len; memcpy(p.ssid, vif->ssid, vif->ssid_len); p.dot11_auth_mode = vif->dot11_auth_mode; + + if (info->auto_channel_select) { + ar->want_ch_switch |= 1 << vif->fw_vif_idx; + vif->next_chan = info->auto_channel_select - 1; + } + p.ch = cpu_to_le16(vif->next_chan); + /* + * Get the PTKSA replay counter in the RSN IE. Supplicant + * will use the RSN IE in M3 message and firmware has to + * advertise the same in beacon/probe response. Send + * the complete RSN IE capability field to firmware + */ + if ((p.auth_mode & (WPA2_AUTH | WPA2_PSK_AUTH)) && (info->tail) && + test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities)) { + rsn_capb = 0; + rsn_ie = (u8 *)cfg80211_find_ie(WLAN_EID_RSN, info->tail, + info->tail_len); + if (rsn_ie) { + rsn_ie_len = *(rsn_ie + 1); + rsn_ie += 2; /* skip element id and length */ + do { + /* skip version, group cipher */ + if (rsn_ie_len < 6) + break; + rsn_ie += 6; + rsn_ie_len -= 6; + /* skip pairwise cipher suite */ + if (rsn_ie_len < 2) + break; + cnt = *((u16 *)rsn_ie); + rsn_ie += (2 + cnt * 4); + rsn_ie_len -= (2 + cnt * 4); + /* skip akm suite */ + if (rsn_ie_len < 2) + break; + cnt = *((u16 *)rsn_ie); + rsn_ie += (2 + cnt * 4); + rsn_ie_len -= (2 + cnt * 4); + if (rsn_ie_len < 2) + break; + rsn_capb = *((u16 *)rsn_ie); + } while (0); + rsn_capb = cpu_to_le16(rsn_capb); + res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, + WLAN_EID_RSN, WMI_RSN_IE_CAPB, + (const u8 *)&rsn_capb, sizeof(rsn_capb)); + vif->rsn_capab = rsn_capb; + if (res < 0) + return res; + } + } + /* Enable uAPSD support by default */ res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true); if (res < 0) @@ -2532,6 +2930,39 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, p.nw_subtype = SUBTYPE_NONE; } + if (ath6kl_set_htcap(vif, vif->next_ch_band, + vif->next_ch_type != NL80211_CHAN_NO_HT)) + return -EIO; + + if (test_bit(ATH6KL_FW_CAPABILITY_MAC_ACL, ar->fw_capabilities)) { + res = ath6kl_wmi_set_acl_policy(ar->wmi, vif->fw_vif_idx, + info->acl_mac); + if (res < 0) + return res; + } + + if (!info->sta_cap_req) + goto ap_commit; + + switch (info->sta_cap_req) { + case NL80211_STA_CAP_REQ_11BONLY: + phy_mode = WMI_11B_MODE; + break; + case NL80211_STA_CAP_REQ_11GONLY: + phy_mode = WMI_11GONLY_MODE; + break; + default: + ath6kl_err("STA capability requirement %d is not supported in AP mode\n", + info->sta_cap_req); + return -ENOTSUPP; + } + + res = ath6kl_wmi_set_ch_params(ar->wmi, vif->fw_vif_idx, phy_mode); + if (res) + return res; + +ap_commit: + memcpy(&vif->profile, &p, sizeof(p)); res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); if (res < 0) return res; @@ -2539,21 +2970,43 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, return 0; } -static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_beacon_data *beacon) +void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable) { - struct ath6kl_vif *vif = netdev_priv(dev); + int err; - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; + if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, + vif->ar->fw_capabilities)) + return; - if (vif->next_mode != AP_NETWORK) - return -EOPNOTSUPP; + if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag))) + return; - return ath6kl_set_ies(vif, beacon); + if (vif->nw_type != INFRA_NETWORK) + return; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n", + enable ? "enable" : "disable"); + + err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi, + vif->fw_vif_idx, enable); + if (err) + ath6kl_err("failed to %s enhanced bmiss detection: %d\n", + enable ? "enable" : "disable", err); } -static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + return ath6kl_ap_beacon(wiphy, dev, info, true); +} + +static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + return ath6kl_ap_beacon(wiphy, dev, info, false); +} + +static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -2566,6 +3019,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); clear_bit(CONNECTED, &vif->flags); + /* Restore ht setting in firmware */ + if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true)) + return -EIO; + + if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true)) + return -EIO; + return 0; } @@ -2612,7 +3072,10 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy, struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); u32 id; - +#ifdef CONFIG_HAS_WAKELOCK + ath6kl_p2p_release_wakelock(ar); + ath6kl_p2p_acquire_wakelock(ar , duration + 100); +#endif /* TODO: if already pending or ongoing remain-on-channel, * return -EBUSY */ id = ++vif->last_roc_id; @@ -2747,6 +3210,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, return false; } +/* Check if SSID length is greater than DIRECT- */ +static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + mgmt = (const struct ieee80211_mgmt *) buf; + + /* variable[1] contains the SSID tag length */ + if (buf + len >= &mgmt->u.probe_resp.variable[1] && + (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) { + return true; + } + + return false; +} + static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, @@ -2761,11 +3239,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; - if (buf + len >= mgmt->u.probe_resp.variable && - vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && - ieee80211_is_probe_resp(mgmt->frame_control)) { + if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && + ieee80211_is_probe_resp(mgmt->frame_control) && + ath6kl_is_p2p_go_ssid(buf, len)) { /* - * Send Probe Response frame in AP mode using a separate WMI + * Send Probe Response frame in GO mode using a separate WMI * command to allow the target to fill in the generic IEs. */ *cookie = 0; /* TX status not supported */ @@ -2824,8 +3302,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; - int ret; - u8 i; + int ret, rssi_thold; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -2833,10 +3310,42 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; - for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i, DISABLE_SSID_FLAG, - 0, NULL); + ath6kl_cfg80211_scan_complete_event(vif, true); + + ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, + request->n_ssids, + request->match_sets, + request->n_match_sets); + if (ret < 0) + return ret; + + if (!request->n_match_sets) { + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + ALL_BSS_FILTER, 0); + if (ret < 0) + return ret; + } else { + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + MATCHED_SSID_FILTER, 0); + if (ret < 0) + return ret; + } + + if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + ar->fw_capabilities)) { + if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) + rssi_thold = 0; + else if (request->rssi_thold < -127) + rssi_thold = -127; + else + rssi_thold = request->rssi_thold; + + ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, + rssi_thold); + if (ret) { + ath6kl_err("failed to set RSSI threshold for scan\n"); + return ret; + } } /* fw uses seconds, also make sure that it's >0 */ @@ -2844,25 +3353,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, interval, interval, - 10, 0, 0, 0, 3, 0, 0, 0); - - if (request->n_ssids && request->ssids[0].ssid_len) { - for (i = 0; i < request->n_ssids; i++) { - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i, SPECIFIC_SSID_FLAG, - request->ssids[i].ssid_len, - request->ssids[i].ssid); - } - } - - ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_WOW_MODE_ENABLE, - WOW_FILTER_SSID, - WOW_HOST_REQ_DELAY); - if (ret) { - ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret); - return ret; - } + vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); /* this also clears IE in fw if it's not set */ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, @@ -2874,17 +3365,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, return ret; } - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_ASLEEP); - if (ret) { - ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n", - ret); + ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true); + if (ret) return ret; - } - ar->state = ATH6KL_STATE_SCHED_SCAN; + set_bit(SCHED_SCANNING, &vif->flags); - return ret; + return 0; } static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, @@ -2901,6 +3388,77 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, return 0; } +static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr, + const struct cfg80211_bitrate_mask *mask) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + + return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx, + mask); +} + +static int ath6kl_set_mac_acl(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_acl_params *acl_info) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + int i, err; + static const u8 zero_mac[ETH_ALEN] = { 0 }; + + /* Reset the acl list */ + err = ath6kl_wmi_set_acl_list(ar->wmi, vif->fw_vif_idx, 0, zero_mac, + acl_info->acl_policy, true); + if (err) + return err; + + for (i = 0; i < acl_info->n_acl_entries; i++) { + err = ath6kl_wmi_set_acl_list(ar->wmi, vif->fw_vif_idx, i, + acl_info->mac_addrs[i].addr, + acl_info->acl_policy, false); + if (err) + return err; + } + + /* + * Notify fw of the state that the host is done with setting + * the acl list. This is done with a special configuration + * where the index of the mac address is passed as 0xff and + * the mac address is zero mac. Firmware would carry out + * certain operations based on the newly set acl list after + * this notification. + */ + err = ath6kl_wmi_set_acl_list(ar->wmi, vif->fw_vif_idx, + MAC_ACL_INDEX_EOL, zero_mac, + acl_info->acl_policy, false); + + return err; +} + +static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy, + struct net_device *dev, + u32 rate, u32 pkts, u32 intvl) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + + if (vif->nw_type != INFRA_NETWORK || + !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities)) + return -EOPNOTSUPP; + + if (vif->sme_state != SME_CONNECTED) + return -ENOTCONN; + + /* save this since the firmware won't report the interval */ + vif->txe_intvl = intvl; + + return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx, + rate, pkts, intvl); +} + static const struct ieee80211_txrx_stypes ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_STATION] = { @@ -2951,22 +3509,26 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .del_pmksa = ath6kl_del_pmksa, .flush_pmksa = ath6kl_flush_pmksa, CFG80211_TESTMODE_CMD(ath6kl_tm_cmd) -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) .suspend = __ath6kl_cfg80211_suspend, .resume = __ath6kl_cfg80211_resume, #endif .set_channel = ath6kl_set_channel, - .start_ap = ath6kl_start_ap, - .change_beacon = ath6kl_change_beacon, - .stop_ap = ath6kl_stop_ap, + .add_beacon = ath6kl_add_beacon, + .set_beacon = ath6kl_set_beacon, + .del_beacon = ath6kl_del_beacon, .del_station = ath6kl_del_station, .change_station = ath6kl_change_station, .remain_on_channel = ath6kl_remain_on_channel, .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, .mgmt_tx = ath6kl_mgmt_tx, .mgmt_frame_register = ath6kl_mgmt_frame_register, + .notify_btcoex = ath6kl_notify_btcoex, .sched_scan_start = ath6kl_cfg80211_sscan_start, .sched_scan_stop = ath6kl_cfg80211_sscan_stop, + .set_bitrate_mask = ath6kl_cfg80211_set_bitrate, + .set_mac_acl = ath6kl_set_mac_acl, + .set_cqm_txe_config = ath6kl_cfg80211_set_txe_config, }; void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) @@ -2987,16 +3549,22 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) break; } - if (test_bit(CONNECTED, &vif->flags) || - test_bit(CONNECT_PEND, &vif->flags)) + if (vif->ar->state != ATH6KL_STATE_RECOVERY && + (test_bit(CONNECTED, &vif->flags) || + test_bit(CONNECT_PEND, &vif->flags))) ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx); vif->sme_state = SME_DISCONNECTED; clear_bit(CONNECTED, &vif->flags); clear_bit(CONNECT_PEND, &vif->flags); + /* Stop netdev queues, needed during recovery */ + netif_stop_queue(vif->ndev); + netif_carrier_off(vif->ndev); + /* disable scanning */ - if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, + if (vif->ar->state != ATH6KL_STATE_RECOVERY && + ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0) ath6kl_warn("failed to disable scan during stop\n"); @@ -3008,7 +3576,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) struct ath6kl_vif *vif; vif = ath6kl_vif_first(ar); - if (!vif) { + if (!vif && ar->state != ATH6KL_STATE_RECOVERY) { /* save the current power mode before enabling power save */ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; @@ -3027,7 +3595,200 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) ath6kl_cfg80211_stop(vif); } -static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) +#ifdef CONFIG_ATH6KL_REGDOMAIN +static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ath6kl *ar = wiphy_priv(wiphy); + u32 rates[IEEE80211_NUM_BANDS]; + int ret, i; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "cfg reg_notify %c%c%s%s initiator %d\n", + request->alpha2[0], request->alpha2[1], + request->intersect ? " intersect" : "", + request->processed ? " processed" : "", + request->initiator); + + ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); + if (ret) { + ath6kl_err("failed to set regdomain: %d\n", ret); + return ret; + } + + /* + * Firmware will apply the regdomain change only after a scan is + * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been + * changed. + */ + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + if (wiphy->bands[i]) + rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; + + + ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false, + false, 0, ATH6KL_FG_SCAN_INTERVAL, + 0, NULL, false, rates); + if (ret) { + ath6kl_err("failed to start scan for a regdomain change: %d\n", + ret); + return ret; + } + + return 0; +} +#endif + +struct ath6kl *ath6kl_core_alloc(struct device *dev) +{ + struct ath6kl *ar; + struct wiphy *wiphy; + u8 ctr; + + /* create a new wiphy for use with cfg80211 */ + wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); + + if (!wiphy) { + ath6kl_err("couldn't allocate wiphy device\n"); + return NULL; + } + + ar = wiphy_priv(wiphy); + ar->p2p = !!ath6kl_p2p; + ar->wiphy = wiphy; + ar->dev = dev; + + ar->vif_max = 1; + + ar->max_norm_iface = 1; + + spin_lock_init(&ar->lock); + spin_lock_init(&ar->mcastpsq_lock); + spin_lock_init(&ar->list_lock); + + init_waitqueue_head(&ar->event_wq); + sema_init(&ar->sem, 1); + + INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); + INIT_LIST_HEAD(&ar->vif_list); + + clear_bit(WMI_ENABLED, &ar->flag); + clear_bit(SKIP_SCAN, &ar->flag); + clear_bit(DESTROY_IN_PROGRESS, &ar->flag); + + ar->tx_pwr = 0; + ar->intra_bss = 1; + ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; + + ar->state = ATH6KL_STATE_OFF; + + memset((u8 *)ar->sta_list, 0, + AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); + + /* Init the PS queues */ + for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { + spin_lock_init(&ar->sta_list[ctr].psq_lock); + skb_queue_head_init(&ar->sta_list[ctr].psq); + skb_queue_head_init(&ar->sta_list[ctr].apsdq); + ar->sta_list[ctr].mgmt_psq_len = 0; + INIT_LIST_HEAD(&ar->sta_list[ctr].mgmt_psq); + ar->sta_list[ctr].aggr_conn = + kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); + if (!ar->sta_list[ctr].aggr_conn) { + ath6kl_err("Failed to allocate memory for sta aggregation information\n"); + ath6kl_core_cleanup(ar); + return NULL; + } + } + + skb_queue_head_init(&ar->mcastpsq); + + memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); + + return ar; +} + +int ath6kl_register_ieee80211_hw(struct ath6kl *ar) +{ + struct wiphy *wiphy = ar->wiphy; + int ret; + + wiphy->mgmt_stypes = ath6kl_mgmt_stypes; + + wiphy->max_remain_on_channel_duration = 5000; + + /* set device pointer for wiphy */ + set_wiphy_dev(wiphy, ar->dev); + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + if (ar->p2p) { + wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); + } + +#ifdef CONFIG_ATH6KL_REGDOMAIN + /* FIXME: add firmware capability */ + wiphy->reg_notifier = ath6kl_cfg80211_reg_notify; +#endif + + /* max num of ssids that can be probed during scanning */ + wiphy->max_scan_ssids = MAX_PROBED_SSIDS; + + /* max num of ssids that can be matched after scan */ + if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, + ar->fw_capabilities)) + wiphy->max_match_sets = MAX_PROBED_SSIDS; + + wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ + if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) { + ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; + ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; + ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; + ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff; + } else { + ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; + ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; + } + + wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; + wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + wiphy->cipher_suites = cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE; + wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; + wiphy->wowlan.pattern_min_len = 1; + wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; + + wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS; + + ath6kl_setup_android_resource(ar); + + if (test_bit(ATH6KL_FW_CAPABILITY_MAC_ACL, ar->fw_capabilities)) { + ar->wiphy->features |= NL80211_FEATURE_MAC_ACL; + ar->wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRS; + } + + ret = wiphy_register(wiphy); + if (ret < 0) { + ath6kl_err("couldn't register wiphy device\n"); + return ret; + } + + return 0; +} + +static int ath6kl_init_if_data(struct ath6kl_vif *vif) { vif->aggr_cntxt = aggr_init(vif); if (!vif->aggr_cntxt) { @@ -3048,7 +3809,7 @@ static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) return 0; } -void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) +void ath6kl_deinit_if_data(struct ath6kl_vif *vif) { struct ath6kl *ar = vif->ar; struct ath6kl_mc_filter *mc_filter, *tmp; @@ -3090,21 +3851,29 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->wdev.netdev = ndev; vif->wdev.iftype = type; vif->fw_vif_idx = fw_vif_idx; - vif->nw_type = nw_type; - vif->next_mode = nw_type; + vif->nw_type = vif->next_mode = nw_type; + vif->scan_ctrl_flag = 0; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; + vif->bg_scan_period = 0; + vif->htcap[IEEE80211_BAND_2GHZ].ht_enable = true; + vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); - if (fw_vif_idx != 0) + if (fw_vif_idx != 0) { ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) | 0x2; + if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + ar->fw_capabilities)) + ndev->dev_addr[4] ^= 0x80; + } init_netdev(ndev); ath6kl_init_control_info(vif); - if (ath6kl_cfg80211_vif_init(vif)) + /* TODO: Pass interface specific pointer instead of ar */ + if (ath6kl_init_if_data(vif)) goto err; if (register_netdevice(ndev)) @@ -3131,107 +3900,15 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, return NULL; } -int ath6kl_cfg80211_init(struct ath6kl *ar) -{ - struct wiphy *wiphy = ar->wiphy; - int ret; - - wiphy->mgmt_stypes = ath6kl_mgmt_stypes; - - wiphy->max_remain_on_channel_duration = 5000; - - /* set device pointer for wiphy */ - set_wiphy_dev(wiphy, ar->dev); - - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP); - if (ar->p2p) { - wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_CLIENT); - } - - /* max num of ssids that can be probed during scanning */ - wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; - wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ - wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; - wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - - wiphy->cipher_suites = cipher_suites; - wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - - wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | - WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_GTK_REKEY_FAILURE | - WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | - WIPHY_WOWLAN_EAP_IDENTITY_REQ | - WIPHY_WOWLAN_4WAY_HANDSHAKE; - wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; - wiphy->wowlan.pattern_min_len = 1; - wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; - - wiphy->max_sched_scan_ssids = 10; - - ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | - WIPHY_FLAG_HAVE_AP_SME | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - - if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) - ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; - - ar->wiphy->probe_resp_offload = - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; - - ret = wiphy_register(wiphy); - if (ret < 0) { - ath6kl_err("couldn't register wiphy device\n"); - return ret; - } - - ar->wiphy_registered = true; - - return 0; -} - -void ath6kl_cfg80211_cleanup(struct ath6kl *ar) -{ - wiphy_unregister(ar->wiphy); - - ar->wiphy_registered = false; -} - -struct ath6kl *ath6kl_cfg80211_create(void) -{ - struct ath6kl *ar; - struct wiphy *wiphy; - - /* create a new wiphy for use with cfg80211 */ - wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); - - if (!wiphy) { - ath6kl_err("couldn't allocate wiphy device\n"); - return NULL; - } - - ar = wiphy_priv(wiphy); - ar->wiphy = wiphy; - - return ar; -} - -/* Note: ar variable must not be accessed after calling this! */ -void ath6kl_cfg80211_destroy(struct ath6kl *ar) +void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar) { int i; + ath6kl_cleanup_android_resource(ar); + for (i = 0; i < AP_MAX_NUM_STA; i++) kfree(ar->sta_list[i].aggr_conn); + wiphy_unregister(ar->wiphy); wiphy_free(ar->wiphy); } - diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index c5def436..dce4756d 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -22,12 +22,16 @@ enum ath6kl_cfg_suspend_mode { ATH6KL_CFG_SUSPEND_DEEPSLEEP, ATH6KL_CFG_SUSPEND_CUTPOWER, ATH6KL_CFG_SUSPEND_WOW, - ATH6KL_CFG_SUSPEND_SCHED_SCAN, }; struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type); +int ath6kl_register_ieee80211_hw(struct ath6kl *ar); +struct ath6kl *ath6kl_core_alloc(struct device *dev); +void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar); +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, + enum wmi_phy_mode mode); void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, @@ -50,15 +54,15 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, int ath6kl_cfg80211_resume(struct ath6kl *ar); -void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif); - void ath6kl_cfg80211_stop(struct ath6kl_vif *vif); void ath6kl_cfg80211_stop_all(struct ath6kl *ar); +bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif); -int ath6kl_cfg80211_init(struct ath6kl *ar); -void ath6kl_cfg80211_cleanup(struct ath6kl *ar); +/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */ +void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable); -struct ath6kl *ath6kl_cfg80211_create(void); -void ath6kl_cfg80211_destroy(struct ath6kl *ar); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) +struct net_device *ath6kl_cfg80211_add_p2p0_iface(struct ath6kl *ar); +#endif #endif /* ATH6KL_CFG80211_H */ diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.c b/drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.c new file mode 100644 index 00000000..2d0b02e4 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include +#include + +#ifdef CONFIG_HAS_WAKELOCK +#include +#endif + +#include "core.h" +#include "cfg80211.h" +#include "debug.h" +#include "hif-ops.h" +#include "testmode.h" +#include "cfg80211_btcoex.h" + +bool ath6kl_btcoex_cfg80211_ready(struct ath6kl_vif *vif) +{ + struct ath6kl *ar = vif->ar; + + if (!test_bit(WMI_READY, &ar->flag)) { + ath6kl_err("wmi is not ready\n"); + return false; + } + + if (!test_bit(WLAN_ENABLED, &vif->flags)) { + ath6kl_err("wlan disabled\n"); + return false; + } + + return true; +} + +int ath6kl_notify_btcoex(struct wiphy *wiphy, u8 *buf, + int len) +{ + struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); + struct ath6kl_vif *vif; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "BT coex wmi command:%p\n", buf); + + if (!ath6kl_btcoex_cfg80211_ready(vif)) + return -EIO; + + return ath6kl_wmi_send_btcoex_cmd(ar->wmi, buf, + len); +} diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.h b/drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.h new file mode 100644 index 00000000..365d6e37 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/cfg80211_btcoex.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +int ath6kl_notify_btcoex(struct wiphy *wiphy, u8 *buf, + int len); diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index a60e78c0..f78c59c8 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h @@ -77,8 +77,12 @@ enum crypto_type { struct htc_endpoint_credit_dist; struct ath6kl; +struct ath6kl_htcap; enum htc_credit_dist_reason; struct ath6kl_htc_credit_info; +struct ath6kl *ath6kl_core_alloc(struct device *sdev); +int ath6kl_core_init(struct ath6kl *ar); +void ath6kl_core_cleanup(struct ath6kl *ar); struct sk_buff *ath6kl_buf_alloc(int size); #endif /* COMMON_H */ diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c deleted file mode 100644 index 45e641f3..00000000 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2004-2011 Atheros Communications Inc. - * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, 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. - */ - -#include "core.h" - -#include -#include -#include - -#include "debug.h" -#include "hif-ops.h" -#include "cfg80211.h" - -unsigned int debug_mask; -static unsigned int suspend_mode; -static unsigned int wow_mode; -static unsigned int uart_debug; -static unsigned int ath6kl_p2p; -static unsigned int testmode; - -module_param(debug_mask, uint, 0644); -module_param(suspend_mode, uint, 0644); -module_param(wow_mode, uint, 0644); -module_param(uart_debug, uint, 0644); -module_param(ath6kl_p2p, uint, 0644); -module_param(testmode, uint, 0644); - -int ath6kl_core_init(struct ath6kl *ar) -{ - struct ath6kl_bmi_target_info targ_info; - struct net_device *ndev; - int ret = 0, i; - - ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); - if (!ar->ath6kl_wq) - return -ENOMEM; - - ret = ath6kl_bmi_init(ar); - if (ret) - goto err_wq; - - /* - * Turn on power to get hardware (target) version and leave power - * on delibrately as we will boot the hardware anyway within few - * seconds. - */ - ret = ath6kl_hif_power_on(ar); - if (ret) - goto err_bmi_cleanup; - - ret = ath6kl_bmi_get_target_info(ar, &targ_info); - if (ret) - goto err_power_off; - - ar->version.target_ver = le32_to_cpu(targ_info.version); - ar->target_type = le32_to_cpu(targ_info.type); - ar->wiphy->hw_version = le32_to_cpu(targ_info.version); - - ret = ath6kl_init_hw_params(ar); - if (ret) - goto err_power_off; - - ar->htc_target = ath6kl_htc_create(ar); - - if (!ar->htc_target) { - ret = -ENOMEM; - goto err_power_off; - } - - ar->testmode = testmode; - - ret = ath6kl_init_fetch_firmwares(ar); - if (ret) - goto err_htc_cleanup; - - /* FIXME: we should free all firmwares in the error cases below */ - - /* Indicate that WMI is enabled (although not ready yet) */ - set_bit(WMI_ENABLED, &ar->flag); - ar->wmi = ath6kl_wmi_init(ar); - if (!ar->wmi) { - ath6kl_err("failed to initialize wmi\n"); - ret = -EIO; - goto err_htc_cleanup; - } - - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); - - /* setup access class priority mappings */ - ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ - ar->ac_stream_pri_map[WMM_AC_BE] = 1; - ar->ac_stream_pri_map[WMM_AC_VI] = 2; - ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ - - /* allocate some buffers that handle larger AMSDU frames */ - ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); - - ath6kl_cookie_init(ar); - - ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | - ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; - - if (suspend_mode && - suspend_mode >= WLAN_POWER_STATE_CUT_PWR && - suspend_mode <= WLAN_POWER_STATE_WOW) - ar->suspend_mode = suspend_mode; - else - ar->suspend_mode = 0; - - if (suspend_mode == WLAN_POWER_STATE_WOW && - (wow_mode == WLAN_POWER_STATE_CUT_PWR || - wow_mode == WLAN_POWER_STATE_DEEP_SLEEP)) - ar->wow_suspend_mode = wow_mode; - else - ar->wow_suspend_mode = 0; - - if (uart_debug) - ar->conf_flags |= ATH6KL_CONF_UART_DEBUG; - - set_bit(FIRST_BOOT, &ar->flag); - - ath6kl_debug_init(ar); - - ret = ath6kl_init_hw_start(ar); - if (ret) { - ath6kl_err("Failed to start hardware: %d\n", ret); - goto err_rxbuf_cleanup; - } - - /* give our connected endpoints some buffers */ - ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); - ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); - - ret = ath6kl_cfg80211_init(ar); - if (ret) - goto err_rxbuf_cleanup; - - ret = ath6kl_debug_init_fs(ar); - if (ret) { - wiphy_unregister(ar->wiphy); - goto err_rxbuf_cleanup; - } - - for (i = 0; i < ar->vif_max; i++) - ar->avail_idx_map |= BIT(i); - - rtnl_lock(); - - /* Add an initial station interface */ - ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, - INFRA_NETWORK); - - rtnl_unlock(); - - if (!ndev) { - ath6kl_err("Failed to instantiate a network device\n"); - ret = -ENOMEM; - wiphy_unregister(ar->wiphy); - goto err_rxbuf_cleanup; - } - - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", - __func__, ndev->name, ndev, ar); - - return ret; - -err_rxbuf_cleanup: - ath6kl_debug_cleanup(ar); - ath6kl_htc_flush_rx_buf(ar->htc_target); - ath6kl_cleanup_amsdu_rxbufs(ar); - ath6kl_wmi_shutdown(ar->wmi); - clear_bit(WMI_ENABLED, &ar->flag); - ar->wmi = NULL; -err_htc_cleanup: - ath6kl_htc_cleanup(ar->htc_target); -err_power_off: - ath6kl_hif_power_off(ar); -err_bmi_cleanup: - ath6kl_bmi_cleanup(ar); -err_wq: - destroy_workqueue(ar->ath6kl_wq); - - return ret; -} -EXPORT_SYMBOL(ath6kl_core_init); - -struct ath6kl *ath6kl_core_create(struct device *dev) -{ - struct ath6kl *ar; - u8 ctr; - - ar = ath6kl_cfg80211_create(); - if (!ar) - return NULL; - - ar->p2p = !!ath6kl_p2p; - ar->dev = dev; - - ar->vif_max = 1; - - ar->max_norm_iface = 1; - - spin_lock_init(&ar->lock); - spin_lock_init(&ar->mcastpsq_lock); - spin_lock_init(&ar->list_lock); - - init_waitqueue_head(&ar->event_wq); - sema_init(&ar->sem, 1); - - INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); - INIT_LIST_HEAD(&ar->vif_list); - - clear_bit(WMI_ENABLED, &ar->flag); - clear_bit(SKIP_SCAN, &ar->flag); - clear_bit(DESTROY_IN_PROGRESS, &ar->flag); - - ar->tx_pwr = 0; - ar->intra_bss = 1; - ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; - - ar->state = ATH6KL_STATE_OFF; - - memset((u8 *)ar->sta_list, 0, - AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); - - /* Init the PS queues */ - for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { - spin_lock_init(&ar->sta_list[ctr].psq_lock); - skb_queue_head_init(&ar->sta_list[ctr].psq); - skb_queue_head_init(&ar->sta_list[ctr].apsdq); - ar->sta_list[ctr].mgmt_psq_len = 0; - INIT_LIST_HEAD(&ar->sta_list[ctr].mgmt_psq); - ar->sta_list[ctr].aggr_conn = - kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); - if (!ar->sta_list[ctr].aggr_conn) { - ath6kl_err("Failed to allocate memory for sta aggregation information\n"); - ath6kl_core_destroy(ar); - return NULL; - } - } - - skb_queue_head_init(&ar->mcastpsq); - - memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); - - return ar; -} -EXPORT_SYMBOL(ath6kl_core_create); - -void ath6kl_core_cleanup(struct ath6kl *ar) -{ - ath6kl_hif_power_off(ar); - - destroy_workqueue(ar->ath6kl_wq); - - if (ar->htc_target) - ath6kl_htc_cleanup(ar->htc_target); - - ath6kl_cookie_cleanup(ar); - - ath6kl_cleanup_amsdu_rxbufs(ar); - - ath6kl_bmi_cleanup(ar); - - ath6kl_debug_cleanup(ar); - - kfree(ar->fw_board); - kfree(ar->fw_otp); - kfree(ar->fw); - kfree(ar->fw_patch); - kfree(ar->fw_testscript); - - ath6kl_cfg80211_cleanup(ar); -} -EXPORT_SYMBOL(ath6kl_core_cleanup); - -void ath6kl_core_destroy(struct ath6kl *ar) -{ - ath6kl_cfg80211_destroy(ar); -} -EXPORT_SYMBOL(ath6kl_core_destroy); - -MODULE_AUTHOR("Qualcomm Atheros"); -MODULE_DESCRIPTION("Core module for AR600x SDIO and USB devices."); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index f1dd8906..5e3da091 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -24,10 +24,18 @@ #include #include #include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#ifdef CONFIG_HAS_WAKELOCK +#include +#endif #include "htc.h" #include "wmi.h" #include "bmi.h" #include "target.h" +#include "wmi_btcoex.h" #define MAX_ATH6KL 1 #define ATH6KL_MAX_RX_BUFFERS 16 @@ -54,13 +62,20 @@ /* MAX_HI_COOKIE_NUM are reserved for high priority traffic */ #define MAX_DEF_COOKIE_NUM 180 -#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */ +/* Reserved for data sync cmd to avoid htc dead lock */ +#define DATA_SYNC_RESERVED 10 +/* 10% of MAX_COOKIE_NUM(18) + DATA_SYNC_RESERVED(10) */ +#define MAX_HI_COOKIE_NUM 28 #define MAX_COOKIE_NUM (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM) +#define WMI_MAX_COOKIE_NUM 80 #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) #define DISCON_TIMER_INTVAL 10000 /* in msec */ +/* Channel dwell time in fg scan */ +#define ATH6KL_FG_SCAN_INTERVAL 50 /* in ms */ + /* Channel dwell time in fg scan */ #define ATH6KL_FG_SCAN_INTERVAL 50 /* in ms */ @@ -91,6 +106,57 @@ enum ath6kl_fw_capability { */ ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + /* + * Firmware has support to cleanup inactive stations + * in AP mode. + */ + ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, + + /* Firmware has support to override rsn cap of rsn ie */ + ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + + /* + * Multicast support in WOW and host awake mode. + * Allow all multicast in host awake mode. + * Apply multicast filter in WOW mode. + */ + ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, + + /* Firmware supports enhanced bmiss detection */ + ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, + + /* + * FW supports matching of ssid in schedule scan + */ + ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, + + /* Firmware supports filtering BSS results by RSSI */ + ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + + /* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */ + ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + + /* Firmware supports TX error rate notification */ + ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, + + /* supports WMI_SET_REGDOMAIN_CMDID command */ + ATH6KL_FW_CAPABILITY_REGDOMAIN, + + /* Firmware supports sched scan decoupled from host sleep */ + ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, + + /* + * Firmware capability for hang detection through heart beat + * challenge messages. + */ + ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, + + /* + * Firmware supports mac address based ACL with + * white/black list + */ + ATH6KL_FW_CAPABILITY_MAC_ACL, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -103,8 +169,13 @@ struct ath6kl_fw_ie { u8 data[0]; }; +enum ath6kl_hw_flags { + ATH6KL_HW_FLAG_64BIT_RATES = BIT(0), +}; + #define ATH6KL_FW_API2_FILE "fw-2.bin" #define ATH6KL_FW_API3_FILE "fw-3.bin" +#define ATH6KL_FW_API4_FILE "fw-4.bin" /* AR6003 1.0 definitions */ #define AR6003_HW_1_0_VERSION 0x300002ba @@ -179,7 +250,7 @@ struct ath6kl_fw_ie { #define AGGR_NUM_OF_FREE_NETBUFS 16 -#define AGGR_RX_TIMEOUT 400 /* in ms */ +#define AGGR_RX_TIMEOUT 100 /* in ms */ #define WMI_TIMEOUT (2 * HZ) @@ -205,6 +276,8 @@ struct ath6kl_fw_ie { #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) #define ATH6KL_CONF_UART_DEBUG BIT(4) +#define P2P_WILDCARD_SSID_LEN 7 /* DIRECT- */ + enum wlan_low_pwr_state { WLAN_POWER_STATE_ON, WLAN_POWER_STATE_CUT_PWR, @@ -233,12 +306,6 @@ struct rxtid { u32 hold_q_sz; struct skb_hold_q *hold_q; struct sk_buff_head q; - - /* - * FIXME: No clue what this should protect. Apparently it should - * protect some of the fields above but they are also accessed - * without taking the lock. - */ spinlock_t lock; }; @@ -317,10 +384,7 @@ struct ath6kl_sta { u8 auth; u8 wpa_ie[ATH6KL_MAX_IE]; struct sk_buff_head psq; - - /* protects psq, mgmt_psq, apsdq, and mgmt_psq_len fields */ spinlock_t psq_lock; - struct list_head mgmt_psq; size_t mgmt_psq_len; u8 apsd_info; @@ -342,6 +406,40 @@ struct ath6kl_bmi { u32 max_cmd_size; }; +/* Same as struct target_stats, expect it trackes only few + stats in u32 variable. */ +struct target_stats_dup { + u32 tx_retry_cnt[4]; + u32 tx_mult_retry_cnt[4]; + u32 tx_pkt_per_ac[4]; + u32 rx_pkt; + u32 rx_dupl_frame; + u32 tx_fail_cnt[4]; + u32 tx_rts_fail_cnt; + u32 tx_err; + u32 tx_rts_success_cnt; + u32 rx_err; + u32 tx_byte; +}; + +enum ath6kl_wlan_stats { + WLAN_STATS_INVALID, + WLAN_STATS_RETRY_CNT, + WLAN_STATS_MUL_RETRY_CNT, + WLAN_STATS_TX_FRM_CNT, + WLAN_STATS_RX_FRM_CNT, + WLAN_STATS_FRM_DUP_CNT, + WLAN_STATS_FAIL_CNT, + WLAN_STATS_RTS_FAIL_CNT, + WLAN_STATS_ACK_FAIL_CNT, + WLAN_STATS_RTS_SUC_CNT, + WLAN_STATS_RX_DISCARD_CNT, + WLAN_STATS_RX_ERROR_CNT, + WLAN_STATS_TX_BYTE_CNT, +}; + +#define ATH6KL_PRI_IOCTL_REPLY_BUF_MAX 1024 + struct target_stats { u64 tx_pkt; u64 tx_byte; @@ -449,6 +547,16 @@ struct ath6kl_req_key { u8 key_len; }; +/* + * Bluetooth WiFi co-ex information. + * This structure keeps track of the Bluetooth related status. + * This involves the Bluetooth ACL link role, Bluetooth remote lmp version. + */ +struct ath6kl_btcoex { + u32 acl_role; /* Master/slave role of Bluetooth ACL link */ + u32 remote_lmp_ver; /* LMP version of the remote device. */ + u32 bt_vendor; /* Keeps track of the Bluetooth chip vendor */ +}; enum ath6kl_hif_type { ATH6KL_HIF_TYPE_SDIO, ATH6KL_HIF_TYPE_USB, @@ -461,6 +569,12 @@ struct ath6kl_mc_filter { char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; }; +struct ath6kl_htcap { + bool ht_enable; + u8 ampdu_factor; + unsigned short cap_info; +}; + /* * Driver's maximum limit, note that some firmwares support only one vif * and the runtime (current) limit must be checked from ar->vif_max. @@ -480,6 +594,9 @@ enum ath6kl_vif_state { WLAN_ENABLED, STATS_UPDATE_PEND, HOST_SLEEP_MODE_CMD_PROCESSED, + NETDEV_MCAST_ALL_ON, + NETDEV_MCAST_ALL_OFF, + SCHED_SCANNING, }; struct ath6kl_vif { @@ -509,6 +626,7 @@ struct ath6kl_vif { struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; struct aggr_info *aggr_cntxt; + struct ath6kl_htcap htcap[IEEE80211_NUM_BANDS]; struct timer_list disconnect_timer; struct timer_list sched_scan_timer; @@ -521,12 +639,20 @@ struct ath6kl_vif { u32 send_action_id; bool probe_req_report; u16 next_chan; + enum nl80211_channel_type next_ch_type; + enum ieee80211_band next_ch_band; u16 assoc_bss_beacon_int; + u8 scan_ctrl_flag; u16 listen_intvl_t; u16 bmiss_time_t; + u32 txe_intvl; + u16 bg_scan_period; u8 assoc_bss_dtim_period; struct net_device_stats net_stats; struct target_stats target_stats; + struct target_stats_dup target_stats_dup; + struct wmi_connect_cmd profile; + u16 rsn_capab; struct list_head mc_filter; }; @@ -536,6 +662,8 @@ struct ath6kl_vif { #define ATH6KL_SCHED_SCAN_RESULT_DELAY 5000 /* ms */ +#define ATH6KL_PRIV_GET_WLAN_STATS (SIOCIWFIRSTPRIV + 21) + /* Flag info */ enum ath6kl_dev_state { WMI_ENABLED, @@ -556,7 +684,16 @@ enum ath6kl_state { ATH6KL_STATE_DEEPSLEEP, ATH6KL_STATE_CUTPOWER, ATH6KL_STATE_WOW, - ATH6KL_STATE_SCHED_SCAN, + ATH6KL_STATE_RECOVERY, +}; + +/* Fw error recovery */ +#define ATH6KL_HB_RESP_MISS_THRES 5 + +enum ath6kl_fw_err { + ATH6KL_FW_ASSERT, + ATH6KL_FW_HB_RESP_FAILURE, + ATH6KL_FW_EP_FULL, }; struct ath6kl { @@ -564,7 +701,6 @@ struct ath6kl { struct wiphy *wiphy; enum ath6kl_state state; - unsigned int testmode; struct ath6kl_bmi bmi; const struct ath6kl_hif_ops *hif_ops; @@ -581,13 +717,7 @@ struct ath6kl { unsigned int vif_max; u8 max_norm_iface; u8 avail_idx_map; - - /* - * Protects at least amsdu_rx_buffer_queue, ath6kl_alloc_cookie() - * calls, tx_pending and total_tx_data_pend. - */ spinlock_t lock; - struct semaphore sem; u8 lrssi_roam_threshold; struct ath6kl_version version; @@ -600,6 +730,8 @@ struct ath6kl { u8 next_ep_id; struct ath6kl_cookie *cookie_list; u32 cookie_count; + struct ath6kl_cookie *wmi_cookie_list; + u32 wmi_cookie_count; enum htc_endpoint_id ac2ep_map[WMM_NUM_AC]; bool ac_stream_active[WMM_NUM_AC]; u8 ac_stream_pri_map[WMM_NUM_AC]; @@ -614,13 +746,9 @@ struct ath6kl { u8 sta_list_index; struct ath6kl_req_key ap_mode_bkey; struct sk_buff_head mcastpsq; - - /* - * FIXME: protects access to mcastpsq but is actually useless as - * all skbe_queue_*() functions provide serialisation themselves - */ + u32 want_ch_switch; + u16 last_ch; spinlock_t mcastpsq_lock; - u8 intra_bss; struct wmi_ap_mode_stat ap_stats; u8 ap_country_code[3]; @@ -646,6 +774,7 @@ struct ath6kl { u32 refclk_hz; u32 uarttx_pin; u32 testscript_addr; + u32 flags; struct ath6kl_hw_fw { const char *dir; @@ -668,6 +797,7 @@ struct ath6kl { struct ath6kl_mbox_info mbox_info; struct ath6kl_cookie cookie_mem[MAX_COOKIE_NUM]; + struct ath6kl_cookie wmi_cookie_mem[WMI_MAX_COOKIE_NUM]; unsigned long flag; u8 *fw_board; @@ -694,7 +824,18 @@ struct ath6kl { bool p2p; - bool wiphy_registered; + struct ath6kl_btcoex btcoex_info; + + struct ath6kl_fw_recovery { + bool enable; + struct work_struct recovery_work; + unsigned long err_reason; + unsigned long hb_poll; + struct timer_list hb_timer; + u32 seq_num; + bool hb_pending; + u8 hb_misscnt; + } fw_recovery; #ifdef CONFIG_ATH6KL_DEBUG struct { @@ -719,6 +860,17 @@ struct ath6kl { u8 disc_timeout; } debug; #endif /* CONFIG_ATH6KL_DEBUG */ + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; + bool screen_off; +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +#ifdef CONFIG_HAS_WAKELOCK + struct wake_lock wake_lock; + struct wake_lock p2p_wake_lock; +#endif /* CONFIG_HAS_WAKELOCK */ + }; static inline struct ath6kl *ath6kl_priv(struct net_device *dev) @@ -746,7 +898,8 @@ void init_netdev(struct net_device *dev); void ath6kl_cookie_init(struct ath6kl *ar); void ath6kl_cookie_cleanup(struct ath6kl *ar); void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); -void ath6kl_tx_complete(void *context, struct list_head *packet_queue); +void ath6kl_tx_complete(struct htc_target *context, + struct list_head *packet_queue); enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, struct htc_packet *packet); void ath6kl_stop_txrx(struct ath6kl *ar); @@ -759,8 +912,9 @@ int ath6kl_read_fwlogs(struct ath6kl *ar); void ath6kl_init_profile_info(struct ath6kl_vif *vif); void ath6kl_tx_data_cleanup(struct ath6kl *ar); -struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar); -void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie); +struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar, bool isctrl); +void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie, + bool ctrl_ep); int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); struct aggr_info *aggr_init(struct ath6kl_vif *vif); @@ -775,10 +929,10 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, void aggr_module_destroy(struct aggr_info *aggr_info); void aggr_reset_state(struct aggr_info_conn *aggr_conn); -struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr); +struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr); struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); -void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver); +void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver); int ath6kl_control_tx(void *devt, struct sk_buff *skb, enum htc_endpoint_id eid); void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, @@ -812,18 +966,27 @@ void ath6kl_wakeup_event(void *dev); void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, bool wait_fot_compltn, bool cold_reset); void ath6kl_init_control_info(struct ath6kl_vif *vif); +void ath6kl_deinit_if_data(struct ath6kl_vif *vif); +void ath6kl_core_free(struct ath6kl *ar); struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); int ath6kl_init_hw_start(struct ath6kl *ar); int ath6kl_init_hw_stop(struct ath6kl *ar); -int ath6kl_init_fetch_firmwares(struct ath6kl *ar); -int ath6kl_init_hw_params(struct ath6kl *ar); - -void ath6kl_check_wow_status(struct ath6kl *ar); - -struct ath6kl *ath6kl_core_create(struct device *dev); -int ath6kl_core_init(struct ath6kl *ar); -void ath6kl_core_cleanup(struct ath6kl *ar); -void ath6kl_core_destroy(struct ath6kl *ar); - +void ath6kl_check_wow_status(struct ath6kl *ar, struct sk_buff *skb, + bool is_event_pkt); +void ath6kl_sdio_init_platform(void); +void ath6kl_sdio_exit_platform(void); +void ath6kl_mangle_mac_address(struct ath6kl *ar, u8 locally_administered_bit); + +int ath6kl_wait_for_init_comp(void); +void ath6kl_notify_init_done(void); + +/* Fw error recovery */ +void ath6kl_init_hw_restart(struct ath6kl *ar); +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason); +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie); +void ath6kl_recovery_init(struct ath6kl *ar); +void ath6kl_recovery_cleanup(struct ath6kl *ar); +void ath6kl_recovery_suspend(struct ath6kl *ar); +void ath6kl_recovery_resume(struct ath6kl *ar); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index d01403a2..b7e4ad1b 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -23,6 +23,7 @@ #include #include "debug.h" +#include "debugfs_pri.h" #include "target.h" struct ath6kl_fwlog_slot { @@ -39,57 +40,31 @@ struct ath6kl_fwlog_slot { int ath6kl_printk(const char *level, const char *fmt, ...) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) struct va_format vaf; +#endif va_list args; int rtn; va_start(args, fmt); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) vaf.fmt = fmt; vaf.va = &args; rtn = printk("%sath6kl: %pV", level, &vaf); +#else + printk("%sath6kl: ", level); + rtn = vprintk(fmt, args); +#endif va_end(args); return rtn; } -EXPORT_SYMBOL(ath6kl_printk); #ifdef CONFIG_ATH6KL_DEBUG -void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - if (!(debug_mask & mask)) - return; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - ath6kl_printk(KERN_DEBUG, "%pV", &vaf); - - va_end(args); -} -EXPORT_SYMBOL(ath6kl_dbg); - -void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, - const char *msg, const char *prefix, - const void *buf, size_t len) -{ - if (debug_mask & mask) { - if (msg) - ath6kl_dbg(mask, "%s\n", msg); - - print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); - } -} -EXPORT_SYMBOL(ath6kl_dbg_dump); - #define REG_OUTPUT_LEN_PER_LINE 25 #define REGTYPE_STR_LEN 100 @@ -115,63 +90,63 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_enable_reg *irq_enable_reg) { - ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n")); + ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); if (irq_proc_reg != NULL) { - ath6kl_dbg(ATH6KL_DBG_IRQ, - "Host Int status: 0x%x\n", - irq_proc_reg->host_int_status); - ath6kl_dbg(ATH6KL_DBG_IRQ, + ath6kl_dbg(ATH6KL_DBG_ANY, + "Host Int status: 0x%x\n", + irq_proc_reg->host_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, "CPU Int status: 0x%x\n", - irq_proc_reg->cpu_int_status); - ath6kl_dbg(ATH6KL_DBG_IRQ, + irq_proc_reg->cpu_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, "Error Int status: 0x%x\n", - irq_proc_reg->error_int_status); - ath6kl_dbg(ATH6KL_DBG_IRQ, + irq_proc_reg->error_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status: 0x%x\n", - irq_proc_reg->counter_int_status); - ath6kl_dbg(ATH6KL_DBG_IRQ, + irq_proc_reg->counter_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, "Mbox Frame: 0x%x\n", - irq_proc_reg->mbox_frame); - ath6kl_dbg(ATH6KL_DBG_IRQ, + irq_proc_reg->mbox_frame); + ath6kl_dbg(ATH6KL_DBG_ANY, "Rx Lookahead Valid: 0x%x\n", - irq_proc_reg->rx_lkahd_valid); - ath6kl_dbg(ATH6KL_DBG_IRQ, + irq_proc_reg->rx_lkahd_valid); + ath6kl_dbg(ATH6KL_DBG_ANY, "Rx Lookahead 0: 0x%x\n", - irq_proc_reg->rx_lkahd[0]); - ath6kl_dbg(ATH6KL_DBG_IRQ, + irq_proc_reg->rx_lkahd[0]); + ath6kl_dbg(ATH6KL_DBG_ANY, "Rx Lookahead 1: 0x%x\n", - irq_proc_reg->rx_lkahd[1]); + irq_proc_reg->rx_lkahd[1]); if (dev->ar->mbox_info.gmbox_addr != 0) { /* * If the target supports GMBOX hardware, dump some * additional state. */ - ath6kl_dbg(ATH6KL_DBG_IRQ, - "GMBOX Host Int status 2: 0x%x\n", - irq_proc_reg->host_int_status2); - ath6kl_dbg(ATH6KL_DBG_IRQ, - "GMBOX RX Avail: 0x%x\n", - irq_proc_reg->gmbox_rx_avail); - ath6kl_dbg(ATH6KL_DBG_IRQ, - "GMBOX lookahead alias 0: 0x%x\n", - irq_proc_reg->rx_gmbox_lkahd_alias[0]); - ath6kl_dbg(ATH6KL_DBG_IRQ, - "GMBOX lookahead alias 1: 0x%x\n", - irq_proc_reg->rx_gmbox_lkahd_alias[1]); + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX Host Int status 2: 0x%x\n", + irq_proc_reg->host_int_status2); + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX RX Avail: 0x%x\n", + irq_proc_reg->gmbox_rx_avail); + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX lookahead alias 0: 0x%x\n", + irq_proc_reg->rx_gmbox_lkahd_alias[0]); + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX lookahead alias 1: 0x%x\n", + irq_proc_reg->rx_gmbox_lkahd_alias[1]); } } if (irq_enable_reg != NULL) { - ath6kl_dbg(ATH6KL_DBG_IRQ, - "Int status Enable: 0x%x\n", - irq_enable_reg->int_status_en); - ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n", - irq_enable_reg->cntr_int_status_en); + ath6kl_dbg(ATH6KL_DBG_ANY, + "Int status Enable: 0x%x\n", + irq_enable_reg->int_status_en); + ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", + irq_enable_reg->cntr_int_status_en); } - ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n"); + ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); } static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) @@ -208,6 +183,9 @@ void dump_cred_dist_stats(struct htc_target *target) { struct htc_endpoint_credit_dist *ep_list; + if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_CREDIT)) + return; + list_for_each_entry(ep_list, &target->cred_dist_list, list) dump_cred_dist(ep_list); @@ -217,6 +195,12 @@ void dump_cred_dist_stats(struct htc_target *target) target->credit_info->cur_free_credits); } +static int ath6kl_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) { switch (war) { @@ -257,7 +241,7 @@ static ssize_t read_file_war_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_war_stats = { .read = read_file_war_stats, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -401,8 +385,10 @@ static ssize_t ath6kl_fwlog_block_read(struct file *file, ret = wait_for_completion_interruptible( &ar->debug.fwlog_completion); - if (ret == -ERESTARTSYS) + if (ret == -ERESTARTSYS) { + vfree(buf); return ret; + } spin_lock(&ar->debug.fwlog_queue.lock); } @@ -482,7 +468,7 @@ static ssize_t ath6kl_fwlog_mask_write(struct file *file, } static const struct file_operations fops_fwlog_mask = { - .open = simple_open, + .open = ath6kl_debugfs_open, .read = ath6kl_fwlog_mask_read, .write = ath6kl_fwlog_mask_write, .owner = THIS_MODULE, @@ -616,6 +602,12 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, "Num disconnects", tgt_stats->cs_discon_cnt); len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "ARP pkt received", tgt_stats->arp_received); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "ARP pkt matched", tgt_stats->arp_matched); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "ARP pkt replied", tgt_stats->arp_replied); if (len > buf_len) len = buf_len; @@ -628,7 +620,7 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_stats = { .read = read_file_tgt_stats, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -693,7 +685,7 @@ static ssize_t read_file_credit_dist_stats(struct file *file, static const struct file_operations fops_credit_dist_stats = { .read = read_file_credit_dist_stats, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -734,13 +726,9 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file, return -ENOMEM; #define EPSTAT(name) \ - do { \ - len = print_endpoint_stat(target, buf, buf_len, len, \ - offsetof(struct htc_endpoint_stats, \ - name), \ - #name); \ - } while (0) - + len = print_endpoint_stat(target, buf, buf_len, len, \ + offsetof(struct htc_endpoint_stats, name), \ + #name) EPSTAT(cred_low_indicate); EPSTAT(tx_issued); EPSTAT(tx_pkt_bundled); @@ -796,7 +784,7 @@ static ssize_t ath6kl_endpoint_stats_write(struct file *file, } static const struct file_operations fops_endpoint_stats = { - .open = simple_open, + .open = ath6kl_debugfs_open, .read = ath6kl_endpoint_stats_read, .write = ath6kl_endpoint_stats_write, .owner = THIS_MODULE, @@ -850,9 +838,17 @@ static ssize_t ath6kl_regread_write(struct file *file, size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; + u8 buf[50]; + unsigned int len; unsigned long reg_addr; - if (kstrtoul_from_user(user_buf, count, 0, ®_addr)) + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (strict_strtoul(buf, 0, ®_addr)) return -EINVAL; if ((reg_addr % 4) != 0) @@ -869,7 +865,7 @@ static ssize_t ath6kl_regread_write(struct file *file, static const struct file_operations fops_diag_reg_read = { .read = ath6kl_regread_read, .write = ath6kl_regread_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -966,8 +962,15 @@ static ssize_t ath6kl_lrssi_roam_write(struct file *file, { struct ath6kl *ar = file->private_data; unsigned long lrssi_roam_threshold; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; - if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold)) + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &lrssi_roam_threshold)) return -EINVAL; ar->lrssi_roam_threshold = lrssi_roam_threshold; @@ -993,7 +996,7 @@ static ssize_t ath6kl_lrssi_roam_read(struct file *file, static const struct file_operations fops_lrssi_roam_threshold = { .read = ath6kl_lrssi_roam_read, .write = ath6kl_lrssi_roam_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1055,7 +1058,7 @@ static ssize_t ath6kl_regwrite_write(struct file *file, static const struct file_operations fops_diag_reg_write = { .read = ath6kl_regwrite_read, .write = ath6kl_regwrite_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1160,7 +1163,7 @@ static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf, static const struct file_operations fops_roam_table = { .read = ath6kl_roam_table_read, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1198,7 +1201,7 @@ static ssize_t ath6kl_force_roam_write(struct file *file, static const struct file_operations fops_force_roam = { .write = ath6kl_force_roam_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1238,7 +1241,7 @@ static ssize_t ath6kl_roam_mode_write(struct file *file, static const struct file_operations fops_roam_mode = { .write = ath6kl_roam_mode_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1280,7 +1283,7 @@ static ssize_t ath6kl_keepalive_write(struct file *file, } static const struct file_operations fops_keepalive = { - .open = simple_open, + .open = ath6kl_debugfs_open, .read = ath6kl_keepalive_read, .write = ath6kl_keepalive_write, .owner = THIS_MODULE, @@ -1325,7 +1328,7 @@ static ssize_t ath6kl_disconnect_timeout_write(struct file *file, } static const struct file_operations fops_disconnect_timeout = { - .open = simple_open, + .open = ath6kl_debugfs_open, .read = ath6kl_disconnect_timeout_read, .write = ath6kl_disconnect_timeout_write, .owner = THIS_MODULE, @@ -1497,7 +1500,7 @@ static ssize_t ath6kl_create_qos_write(struct file *file, return -EINVAL; pstream.medium_time = cpu_to_le32(val32); - pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000; + pstream.nominal_phy = ((le32_to_cpu(pstream.min_phy_rate) / 1000) / 1000); ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream); @@ -1506,7 +1509,7 @@ static ssize_t ath6kl_create_qos_write(struct file *file, static const struct file_operations fops_create_qos = { .write = ath6kl_create_qos_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1554,7 +1557,7 @@ static ssize_t ath6kl_delete_qos_write(struct file *file, static const struct file_operations fops_delete_qos = { .write = ath6kl_delete_qos_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1564,10 +1567,15 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file, size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; + struct ath6kl_vif *vif; u16 bgscan_int; char buf[32]; ssize_t len; + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; @@ -1579,15 +1587,17 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file, if (bgscan_int == 0) bgscan_int = 0xffff; + vif->bg_scan_period = bgscan_int; + ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3, - 0, 0, 0); + vif->scan_ctrl_flag, 0, 0); return count; } static const struct file_operations fops_bgscan_int = { .write = ath6kl_bgscan_int_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1645,7 +1655,7 @@ static ssize_t ath6kl_listen_int_read(struct file *file, static const struct file_operations fops_listen_int = { .read = ath6kl_listen_int_read, .write = ath6kl_listen_int_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1705,12 +1715,12 @@ static ssize_t ath6kl_power_params_write(struct file *file, static const struct file_operations fops_power_params = { .write = ath6kl_power_params_write, - .open = simple_open, + .open = ath6kl_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; -void ath6kl_debug_init(struct ath6kl *ar) +int ath6kl_debug_init(struct ath6kl *ar) { skb_queue_head_init(&ar->debug.fwlog_queue); init_completion(&ar->debug.fwlog_completion); @@ -1720,15 +1730,7 @@ void ath6kl_debug_init(struct ath6kl *ar) * value from the firmware. */ ar->debug.fwlog_mask = 0; -} -/* - * Initialisation needs to happen in two stages as fwlog events can come - * before cfg80211 is initialised, and debugfs depends on cfg80211 - * initialisation. - */ -int ath6kl_debug_init_fs(struct ath6kl *ar) -{ ar->debugfs_phy = debugfs_create_dir("ath6kl", ar->wiphy->debugfsdir); if (!ar->debugfs_phy) @@ -1783,21 +1785,21 @@ int ath6kl_debug_init_fs(struct ath6kl *ar) ar->debugfs_phy, ar, &fops_disconnect_timeout); debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar, - &fops_create_qos); + &fops_create_qos); debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar, - &fops_delete_qos); + &fops_delete_qos); debugfs_create_file("bgscan_interval", S_IWUSR, - ar->debugfs_phy, ar, &fops_bgscan_int); + ar->debugfs_phy, ar, &fops_bgscan_int); debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, &fops_listen_int); debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, - &fops_power_params); + &fops_power_params); - return 0; + return ath6kl_init_debugfs_pri(ar); } void ath6kl_debug_cleanup(struct ath6kl *ar) diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 1803a0ba..65f2a334 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -43,6 +43,8 @@ enum ATH6K_DEBUG_MASK { ATH6KL_DBG_WMI_DUMP = BIT(19), ATH6KL_DBG_SUSPEND = BIT(20), ATH6KL_DBG_USB = BIT(21), + ATH6KL_DBG_RECOVERY = BIT(22), + ATH6KL_DBG_STACK_DUMP = BIT(23), ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ }; @@ -57,16 +59,35 @@ int ath6kl_printk(const char *level, const char *fmt, ...); #define ath6kl_warn(fmt, ...) \ ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__) +#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) + enum ath6kl_war { ATH6KL_WAR_INVALID_RATE, }; #ifdef CONFIG_ATH6KL_DEBUG +#define ath6kl_dbg(mask, fmt, ...) \ + ({ \ + int rtn; \ + if (debug_mask & mask) \ + rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \ + else \ + rtn = 0; \ + \ + rtn; \ + }) + +static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, + const char *msg, const char *prefix, + const void *buf, size_t len) +{ + if (debug_mask & mask) { + if (msg) + ath6kl_dbg(mask, "%s\n", msg); -void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...); -void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, - const char *msg, const char *prefix, - const void *buf, size_t len); + print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); + } +} void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_proc_registers *irq_proc_reg, @@ -78,8 +99,7 @@ int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf, size_t len); void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive); void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout); -void ath6kl_debug_init(struct ath6kl *ar); -int ath6kl_debug_init_fs(struct ath6kl *ar); +int ath6kl_debug_init(struct ath6kl *ar); void ath6kl_debug_cleanup(struct ath6kl *ar); #else @@ -129,11 +149,7 @@ static inline void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, { } -static inline void ath6kl_debug_init(struct ath6kl *ar) -{ -} - -static inline int ath6kl_debug_init_fs(struct ath6kl *ar) +static inline int ath6kl_debug_init(struct ath6kl *ar) { return 0; } diff --git a/drivers/net/wireless/ath/ath6kl/debugfs_pri.c b/drivers/net/wireless/ath/ath6kl/debugfs_pri.c new file mode 100644 index 00000000..69552a45 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/debugfs_pri.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifdef CONFIG_ATH6KL_DEBUG + +#include +#include +#include "core.h" +#include "wmi.h" +#include "debug.h" +#include "debugfs_pri.h" + +struct wmi_set_inact_period_cmd { + __le32 inact_period; + u8 num_null_func; +} __packed; + +static inline struct sk_buff *ath6kl_wmi_get_new_buf_pri(u32 size) +{ + struct sk_buff *skb; + + skb = ath6kl_buf_alloc(size); + if (!skb) + return NULL; + + skb_put(skb, size); + if (size) + memset(skb->data, 0, size); + + return skb; +} + +static int ath6kl_wmi_inact_period_cmd(struct wmi *wmi, u32 inact_period, + u8 num_null_func) +{ + struct sk_buff *skb; + struct wmi_set_inact_period_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf_pri(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_inact_period_cmd *) skb->data; + cmd->inact_period = cpu_to_le32(inact_period); + cmd->num_null_func = num_null_func; + + ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_AP_CONN_INACT_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +static int ath6kl_wmi_set_err_report_bitmask(struct wmi *wmi, u8 if_idx, + u32 mask) +{ + struct sk_buff *skb; + struct wmi_tgt_err_report_mask *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf_pri(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_tgt_err_report_mask *) skb->data; + cmd->mask = cpu_to_le32(mask); + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_TARGET_ERROR_REPORT_BITMASK_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_error_report_event(struct wmi *wmi, u8 *data, int len) +{ + struct wmi_tgt_err_report_evt *report; + + if (len < sizeof(*report)) + return -EINVAL; + + report = (struct wmi_tgt_err_report_evt *) data; + ath6kl_dbg(ATH6KL_DBG_WMI, "Reason for error report: 0x%x\n", + report->err_val); + + return 0; +} + +static int ath6kl_debugfs_open_pri(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t ath6kl_inact_period_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + int ret; + char buf[32]; + u32 inact_period; + size_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtou32(buf, 0, &inact_period)) + return -EINVAL; + + ret = ath6kl_wmi_inact_period_cmd(ar->wmi, inact_period, 0); + + if (ret) + return ret; + + return count; +} + +static const struct file_operations fops_inact_period = { + .write = ath6kl_inact_period_write, + .open = ath6kl_debugfs_open_pri, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath6kl_bmisstime_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct ath6kl_vif *vif; + u16 bmiss_time; + char buf[32]; + ssize_t len; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtou16(buf, 0, &bmiss_time)) + return -EINVAL; + + vif->bmiss_time_t = bmiss_time; + + /* Enable error report event for bmiss */ + ath6kl_wmi_set_err_report_bitmask(ar->wmi, vif->fw_vif_idx, + ATH6KL_ERR_REPORT_BMISS_MASK); + + ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, + vif->bmiss_time_t, 0); + return count; +} + +static ssize_t ath6kl_bmisstime_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct ath6kl_vif *vif; + char buf[32]; + int len; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + len = scnprintf(buf, sizeof(buf), "%u\n", vif->bmiss_time_t); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_bmisstime = { + .read = ath6kl_bmisstime_read, + .write = ath6kl_bmisstime_write, + .open = ath6kl_debugfs_open_pri, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath6kl_max_num_sta_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + int ret; + u8 val; + + ret = kstrtou8_from_user(user_buf, count, 0, &val); + if (ret) + return ret; + + ret = ath6kl_wmi_ap_set_num_sta(ar->wmi, 0, val); + if (ret) + return ret; + + return count; +} + +static const struct file_operations fops_max_num_sta = { + .open = ath6kl_debugfs_open_pri, + .write = ath6kl_max_num_sta_write, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int ath6kl_init_debugfs_pri(struct ath6kl *ar) +{ + debugfs_create_file("inactivity_period", S_IWUSR, ar->debugfs_phy, ar, + &fops_inact_period); + + debugfs_create_file("bmiss_time", S_IRUSR | S_IWUSR, ar->debugfs_phy, + ar, &fops_bmisstime); + + debugfs_create_file("max_num_sta", S_IWUSR, ar->debugfs_phy, + ar, &fops_max_num_sta); + + return 0; +} + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/debugfs_pri.h b/drivers/net/wireless/ath/ath6kl/debugfs_pri.h new file mode 100644 index 00000000..f29df302 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/debugfs_pri.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef DEBUG_PRI_H +#define DEBUG_PRI_H + +#ifdef CONFIG_ATH6KL_DEBUG + +#define ATH6KL_ERR_REPORT_BMISS_MASK BIT(3) + +struct wmi_tgt_err_report_mask { + __le32 mask; +}; + +struct wmi_tgt_err_report_evt { + __le32 err_val; +} __packed; + +int ath6kl_wmi_error_report_event(struct wmi *wmi, u8 *data, int len); +int ath6kl_init_debugfs_pri(struct ath6kl *ar); +#endif +#endif diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h index fd840866..fb2b1967 100644 --- a/drivers/net/wireless/ath/ath6kl/hif-ops.h +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h @@ -84,6 +84,7 @@ static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar) return ar->hif_ops->cleanup_scatter(ar); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) static inline int ath6kl_hif_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) { @@ -91,6 +92,7 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar, return ar->hif_ops->suspend(ar, wow); } +#endif /* * Read from the ATH6KL through its diagnostic window. No cooperation from @@ -122,12 +124,14 @@ static inline int ath6kl_hif_bmi_write(struct ath6kl *ar, u8 *buf, u32 len) return ar->hif_ops->bmi_write(ar, buf, len); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) static inline int ath6kl_hif_resume(struct ath6kl *ar) { ath6kl_dbg(ATH6KL_DBG_HIF, "hif resume\n"); return ar->hif_ops->resume(ar); } +#endif static inline int ath6kl_hif_power_on(struct ath6kl *ar) { diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 68ed6c26..4ad3a5f0 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -16,8 +16,6 @@ */ #include "hif.h" -#include - #include "core.h" #include "target.h" #include "hif-ops.h" @@ -62,8 +60,6 @@ int ath6kl_hif_rw_comp_handler(void *context, int status) return 0; } -EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler); - #define REG_DUMP_COUNT_AR6003 60 #define REGISTER_DUMP_LEN_MAX 60 @@ -90,7 +86,7 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) } ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n", - regdump_addr); + regdump_addr); regdump_addr = TARG_VTOP(ar->target_type, regdump_addr); /* fetch register dump data */ @@ -118,6 +114,93 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) } +#define DUMP_MASK_FULL_STACK 0x01 +#define DUMP_MASK_DBGLOG 0x02 + +#define AR6003_HW211_KERNELSTACK_BASE 0x543938 +#define AR6003_HW211_KERNELSTACK_SIZE 2560 +#define MAX_DUMP_BYTE_NUM_ONE_ITERATION 256 +#define DUMP_STACK_OFFSET 0x40 + +#define AR6003_HW211_DBGLOG_ADDR 0x543730 +#define AR6003_HW211_DBGLOG_SIZE 3300 + +static void ath6kl_hif_dump(struct ath6kl *ar, u32 fw_dump_addr, u32 len) +{ + __le32 regdump_val[MAX_DUMP_BYTE_NUM_ONE_ITERATION / 4]; + u32 read_len = 0; + u32 i = 0,count; + int ret; + u32 phy_addr = TARG_VTOP(ar->target_type, fw_dump_addr); + + len = (len + 3) & (~0x3); + fw_dump_addr = (fw_dump_addr + 3) & (~0x3); + + while(len) { + read_len = len; + if(read_len > MAX_DUMP_BYTE_NUM_ONE_ITERATION) + read_len = MAX_DUMP_BYTE_NUM_ONE_ITERATION; + + phy_addr = TARG_VTOP(ar->target_type, fw_dump_addr); + ret = ath6kl_diag_read(ar, phy_addr, (u8 *) ®dump_val[0], read_len); + if (ret) { + ath6kl_warn("failed to get register dump: %d\n", ret); + return; + } + + count = read_len / 4; + for (i = 0; i < count; i += 4) { + ath6kl_info("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", + le32_to_cpu(fw_dump_addr + 4 * i), + le32_to_cpu(regdump_val[i]), + le32_to_cpu(regdump_val[i + 1]), + le32_to_cpu(regdump_val[i + 2]), + le32_to_cpu(regdump_val[i + 3])); + } + + len -= read_len; + fw_dump_addr += read_len; + } +} + +static void ath6kl_hif_dump_fw_more(struct ath6kl *ar, u32 mask) +{ + u32 fw_dump_addr, fw_dump_len; + u32 address; + int ret; + + if (ar->target_type != TARGET_TYPE_AR6003 ) { + ath6kl_warn("not support dump stack for type: %x\n", ar->target_type); + return; + } + + if(mask & DUMP_MASK_FULL_STACK) { + if(ar->wiphy->hw_version == AR6003_HW_2_1_1_VERSION) { + fw_dump_addr = AR6003_HW211_KERNELSTACK_BASE - DUMP_STACK_OFFSET; + fw_dump_len = AR6003_HW211_KERNELSTACK_SIZE + DUMP_STACK_OFFSET; + ath6kl_warn("firmware stack:0x%x, len:0x%x\n", + AR6003_HW211_KERNELSTACK_BASE, + AR6003_HW211_KERNELSTACK_SIZE); + ath6kl_hif_dump(ar, fw_dump_addr, fw_dump_len); + } + } + + if(mask & DUMP_MASK_DBGLOG) { + if(ar->wiphy->hw_version == AR6003_HW_2_1_1_VERSION) { + address = TARG_VTOP(ar->target_type, + AR6003_HW211_DBGLOG_ADDR); + ret = ath6kl_diag_read32(ar, address, &fw_dump_addr); + if(!ret && fw_dump_addr) { + fw_dump_len = AR6003_HW211_DBGLOG_SIZE; + ath6kl_warn("fw dblog:0x%x, len:0x%x\n", + fw_dump_addr, + AR6003_HW211_DBGLOG_SIZE); + ath6kl_hif_dump(ar, fw_dump_addr, fw_dump_len); + } + } + } +} + static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) { u32 dummy; @@ -135,7 +218,10 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) ath6kl_warn("Failed to clear debug interrupt: %d\n", ret); ath6kl_hif_dump_fw_crash(dev->ar); + ath6kl_hif_dump_fw_more(dev->ar, DUMP_MASK_FULL_STACK | + DUMP_MASK_DBGLOG); ath6kl_read_fwlogs(dev->ar); + ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT); return ret; } @@ -285,7 +371,7 @@ static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev) dev->irq_en_reg.cntr_int_status_en; ath6kl_dbg(ATH6KL_DBG_IRQ, - "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", + "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", counter_int_status); /* @@ -360,7 +446,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev) } ath6kl_dbg(ATH6KL_DBG_IRQ, - "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", + "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", cpu_int_status); /* Clear the interrupt */ @@ -435,8 +521,9 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) if (status) goto out; - ath6kl_dump_registers(dev, &dev->irq_proc_reg, - &dev->irq_en_reg); + if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ)) + ath6kl_dump_registers(dev, &dev->irq_proc_reg, + &dev->irq_en_reg); /* Update only those registers that are enabled */ host_int_status = dev->irq_proc_reg.host_int_status & @@ -566,7 +653,6 @@ int ath6kl_hif_intr_bh_handler(struct ath6kl *ar) return status; } -EXPORT_SYMBOL(ath6kl_hif_intr_bh_handler); static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev) { diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 20ed6b73..7f757841 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -197,9 +197,9 @@ struct hif_scatter_req { /* bounce buffer for upper layers to copy to/from */ u8 *virt_dma_buf; - struct hif_scatter_item scat_list[1]; - u32 scat_q_depth; + + struct hif_scatter_item scat_list[1]; }; struct ath6kl_irq_proc_registers { @@ -223,7 +223,6 @@ struct ath6kl_irq_enable_reg { } __packed; struct ath6kl_device { - /* protects irq_proc_reg and irq_en_reg below */ spinlock_t lock; struct ath6kl_irq_proc_registers irq_proc_reg; struct ath6kl_irq_enable_reg irq_en_reg; diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index 4849d99c..35cf01bd 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -75,10 +75,7 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, * never goes inactive EVER. */ cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; - } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) - /* this is the lowest priority data endpoint */ - /* FIXME: this looks fishy, check */ - cred_info->lowestpri_ep_dist = cur_ep_dist->list; + } /* * Streams have to be created (explicit | implicit) for all @@ -92,6 +89,13 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, */ } + /* + * For ath6kl_credit_seek function, + * it use list_for_each_entry_reverse to walk around the whole ep list. + * Therefore assign this lowestpri_ep_dist after walk around the ep_list + */ + cred_info->lowestpri_ep_dist = cur_ep_dist->list; + WARN_ON(cred_info->cur_free_credits <= 0); list_for_each_entry(cur_ep_dist, ep_list, list) { @@ -172,29 +176,31 @@ static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info, static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info, struct list_head *epdist_list) { - struct htc_endpoint_credit_dist *cur_list; + struct htc_endpoint_credit_dist *cur_dist_list; - list_for_each_entry(cur_list, epdist_list, list) { - if (cur_list->endpoint == ENDPOINT_0) + list_for_each_entry(cur_dist_list, epdist_list, list) { + if (cur_dist_list->endpoint == ENDPOINT_0) continue; - if (cur_list->cred_to_dist > 0) { - cur_list->credits += cur_list->cred_to_dist; - cur_list->cred_to_dist = 0; - - if (cur_list->credits > cur_list->cred_assngd) + if (cur_dist_list->cred_to_dist > 0) { + cur_dist_list->credits += + cur_dist_list->cred_to_dist; + cur_dist_list->cred_to_dist = 0; + if (cur_dist_list->credits > + cur_dist_list->cred_assngd) ath6kl_credit_reduce(cred_info, - cur_list, - cur_list->cred_assngd); + cur_dist_list, + cur_dist_list->cred_assngd); - if (cur_list->credits > cur_list->cred_norm) - ath6kl_credit_reduce(cred_info, cur_list, - cur_list->cred_norm); + if (cur_dist_list->credits > + cur_dist_list->cred_norm) + ath6kl_credit_reduce(cred_info, cur_dist_list, + cur_dist_list->cred_norm); - if (!(cur_list->dist_flags & HTC_EP_ACTIVE)) { - if (cur_list->txq_depth == 0) + if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) { + if (cur_dist_list->txq_depth == 0) ath6kl_credit_reduce(cred_info, - cur_list, 0); + cur_dist_list, 0); } } } @@ -432,7 +438,7 @@ static void htc_tx_complete(struct htc_endpoint *endpoint, "htc tx complete ep %d pkts %d\n", endpoint->eid, get_queue_depth(txq)); - ath6kl_tx_complete(endpoint->target->dev->ar, txq); + ath6kl_tx_complete(endpoint->target, txq); } static void htc_tx_comp_handler(struct htc_target *target, @@ -462,8 +468,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target, INIT_LIST_HEAD(&tx_compq); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx scat complete len %d entries %d\n", - scat_req->len, scat_req->scat_entries); + "htc tx scat complete len %d entries %d\n", + scat_req->len, scat_req->scat_entries); if (scat_req->status) ath6kl_err("send scatter req failed: %d\n", scat_req->status); @@ -601,8 +607,8 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target, list); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx got packet 0x%p queue depth %d\n", - packet, get_queue_depth(&endpoint->txq)); + "htc tx got packet 0x%p queue depth %d\n", + packet, get_queue_depth(&endpoint->txq)); len = CALC_TXRX_PADDED_LEN(target, packet->act_len + HTC_HDR_LENGTH); @@ -672,7 +678,6 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, struct htc_packet *packet; int i, len, rem_scat, cred_pad; int status = 0; - u8 flags; rem_scat = target->max_tx_bndl_sz; @@ -699,9 +704,9 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, scat_req->scat_list[i].packet = packet; /* prepare packet and flag message as part of a send bundle */ - flags = packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE; - ath6kl_htc_tx_prep_pkt(packet, flags, - cred_pad, packet->info.tx.seqno); + ath6kl_htc_tx_prep_pkt(packet, + packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, + cred_pad, packet->info.tx.seqno); /* Make sure the buffer is 4-byte aligned */ ath6kl_htc_tx_buf_align(&packet->buf, packet->act_len + HTC_HDR_LENGTH); @@ -750,8 +755,8 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, u32 txb_mask; u8 ac = WMM_NUM_AC; - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || - (WMI_CONTROL_SVC != endpoint->svc_id)) + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) && + (WMI_CONTROL_SVC != endpoint->svc_id)) ac = target->dev->ar->ep2ac_map[endpoint->eid]; while (true) { @@ -768,7 +773,7 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, if (!scat_req) { /* no scatter resources */ ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx no more scatter resources\n"); + "htc tx no more scatter resources\n"); break; } @@ -841,6 +846,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, int bundle_sent; int n_pkts_bundle; u8 ac = WMM_NUM_AC; + int status; spin_lock_bh(&target->tx_lock); @@ -858,8 +864,8 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, */ INIT_LIST_HEAD(&txq); - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || - (WMI_CONTROL_SVC != endpoint->svc_id)) + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) && + (WMI_CONTROL_SVC != endpoint->svc_id)) ac = target->dev->ar->ep2ac_map[endpoint->eid]; while (true) { @@ -902,7 +908,12 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags, 0, packet->info.tx.seqno); - ath6kl_htc_tx_issue(target, packet); + status = ath6kl_htc_tx_issue(target, packet); + + if (packet->completion && status) { + packet->status = status; + packet->completion(packet->context, packet); + } } spin_lock_bh(&target->tx_lock); @@ -917,7 +928,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, */ if (!bundle_sent) { if (!(target->tx_bndl_mask & (1 << ac)) && - (ac < WMM_NUM_AC)) { + (ac < WMM_NUM_AC)) { if (++target->ac_tx_count[ac] >= TX_RESUME_BUNDLE_THRESHOLD) { target->ac_tx_count[ac] = 0; @@ -1041,8 +1052,8 @@ static int htc_setup_tx_complete(struct htc_target *target) memcpy(&setup_comp_ext->flags, &flags, sizeof(setup_comp_ext->flags)); set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, - sizeof(struct htc_setup_comp_ext_msg), - ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + sizeof(struct htc_setup_comp_ext_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); } else { struct htc_setup_comp_msg *setup_comp; @@ -1050,8 +1061,8 @@ static int htc_setup_tx_complete(struct htc_target *target) memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, - sizeof(struct htc_setup_comp_msg), - ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + sizeof(struct htc_setup_comp_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); } /* we want synchronous operation */ @@ -1150,9 +1161,9 @@ void ath6kl_htc_flush_txep(struct htc_target *target, packet->status = -ECANCELED; list_del(&packet->list); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", - packet, packet->act_len, - packet->endpoint, packet->info.tx.tag); + "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", + packet, packet->act_len, + packet->endpoint, packet->info.tx.tag); INIT_LIST_HEAD(&container); list_add_tail(&packet->list, &container); @@ -1552,7 +1563,7 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) if (packets->act_len > 0) { ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", - packets->act_len + HTC_HDR_LENGTH); + packets->act_len + HTC_HDR_LENGTH); ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx unexpected endpoint 0 message", "", @@ -1671,8 +1682,8 @@ static int htc_parse_trailer(struct htc_target *target, } lk_ahd = (struct htc_lookahead_report *) record_buf; - if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) && - next_lk_ahds) { + if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) + && next_lk_ahds) { ath6kl_dbg(ATH6KL_DBG_HTC, "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n", @@ -1685,7 +1696,8 @@ static int htc_parse_trailer(struct htc_target *target, "htc rx next look ahead", "", next_lk_ahds, 4); - *n_lk_ahds = 1; + if (n_lk_ahds) + *n_lk_ahds = 1; } break; case HTC_RECORD_LOOKAHEAD_BUNDLE: @@ -1710,7 +1722,8 @@ static int htc_parse_trailer(struct htc_target *target, bundle_lkahd_rpt++; } - *n_lk_ahds = i; + if (n_lk_ahds) + *n_lk_ahds = i; } break; default: @@ -1874,13 +1887,50 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target, return status; } +static void ath6kl_htc_rx_work(struct work_struct *work) +{ + struct htc_target *target; + struct htc_packet *packet, *tmp_pkt; + struct htc_endpoint *endpoint; + + target = container_of(work, struct htc_target, rx_work); + + spin_lock_bh(&target->rx_comp_lock); + list_for_each_entry_safe(packet, tmp_pkt, &target->rx_bufq, list) { + list_del(&packet->list); + + spin_unlock_bh(&target->rx_comp_lock); + endpoint = &target->endpoint[packet->endpoint]; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx complete ep %d packet 0x%p\n", + endpoint->eid, packet); + + endpoint->ep_cb.rx(endpoint->target, packet); + spin_lock_bh(&target->rx_comp_lock); + } + spin_unlock_bh(&target->rx_comp_lock); +} + static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint, struct htc_packet *packet) { + struct htc_target *target; + + if (endpoint->eid == ENDPOINT_0) { ath6kl_dbg(ATH6KL_DBG_HTC, "htc rx complete ep %d packet 0x%p\n", endpoint->eid, packet); endpoint->ep_cb.rx(endpoint->target, packet); + } else { + target = endpoint->target; + + spin_lock_bh(&target->rx_comp_lock); + list_add_tail(&packet->list, &target->rx_bufq); + spin_unlock_bh(&target->rx_comp_lock); + + queue_work(target->rx_wq, &target->rx_work); + } } static int ath6kl_htc_rx_bundle(struct htc_target *target, @@ -2100,13 +2150,13 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target, list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) { list_del(&packet->list); htc_reclaim_rxbuf(target, packet, - &target->endpoint[packet->endpoint]); + &target->endpoint[packet->endpoint]); } list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) { list_del(&packet->list); htc_reclaim_rxbuf(target, packet, - &target->endpoint[packet->endpoint]); + &target->endpoint[packet->endpoint]); } return status; @@ -2238,11 +2288,11 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) u32 look_ahead; if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, - HTC_TARGET_RESPONSE_TIMEOUT)) + HTC_TARGET_RESPONSE_TIMEOUT)) return NULL; ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); + "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); htc_hdr = (struct htc_frame_hdr *)&look_ahead; @@ -2307,7 +2357,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, depth = get_queue_depth(pkt_queue); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx add multiple ep id %d cnt %d len %d\n", + "htc rx add multiple ep id %d cnt %d len %d\n", first_pkt->endpoint, depth, first_pkt->buf_len); endpoint = &target->endpoint[first_pkt->endpoint]; @@ -2333,8 +2383,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { if (target->ep_waiting == first_pkt->endpoint) { ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx blocked on ep %d, unblocking\n", - target->ep_waiting); + "htc rx blocked on ep %d, unblocking\n", + target->ep_waiting); target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; target->ep_waiting = ENDPOINT_MAX; rx_unblock = true; @@ -2404,7 +2454,6 @@ int ath6kl_htc_conn_service(struct htc_target *target, enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; unsigned int max_msg_sz = 0; int status = 0; - u16 msg_id; ath6kl_dbg(ATH6KL_DBG_HTC, "htc connect service target 0x%p service id 0x%x\n", @@ -2448,10 +2497,9 @@ int ath6kl_htc_conn_service(struct htc_target *target, } resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; - msg_id = le16_to_cpu(resp_msg->msg_id); - if ((msg_id != HTC_MSG_CONN_SVC_RESP_ID) || - (rx_pkt->act_len < sizeof(*resp_msg))) { + if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID) + || (rx_pkt->act_len < sizeof(*resp_msg))) { status = -ENOMEM; goto fail_tx; } @@ -2469,7 +2517,8 @@ int ath6kl_htc_conn_service(struct htc_target *target, max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); } - if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { + if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED || + assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) { status = -ENOMEM; goto fail_tx; } @@ -2502,6 +2551,9 @@ int ath6kl_htc_conn_service(struct htc_target *target, case WMI_DATA_BK_SVC: endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3; break; + case WMI_DATA_VO_SVC: + endpoint->tx_drop_packet_threshold = DATA_SYNC_RESERVED; + break; default: endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; break; @@ -2677,8 +2729,8 @@ int ath6kl_htc_wait_target(struct htc_target *target) } ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n", - (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", - target->htc_tgt_ver); + (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", + target->htc_tgt_ver); if (target->msg_per_bndl_max > 0) htc_setup_msg_bndl(target); @@ -2834,13 +2886,24 @@ void *ath6kl_htc_create(struct ath6kl *ar) goto err_htc_cleanup; } + target->rx_wq = create_singlethread_workqueue("htc_rx"); + if (!target->rx_wq) { + ath6kl_err("unable to create rx_wq workqueue\n"); + status = -ENOMEM; + goto err_htc_cleanup; + } + spin_lock_init(&target->htc_lock); spin_lock_init(&target->rx_lock); spin_lock_init(&target->tx_lock); + spin_lock_init(&target->rx_comp_lock); INIT_LIST_HEAD(&target->free_ctrl_txbuf); INIT_LIST_HEAD(&target->free_ctrl_rxbuf); INIT_LIST_HEAD(&target->cred_dist_list); + INIT_LIST_HEAD(&target->rx_bufq); + + INIT_WORK(&target->rx_work, ath6kl_htc_rx_work); target->dev->ar = ar; target->dev->htc_cnxt = target; @@ -2867,19 +2930,21 @@ void ath6kl_htc_cleanup(struct htc_target *target) { struct htc_packet *packet, *tmp_packet; + destroy_workqueue(target->rx_wq); + /* FIXME: remove check once USB support is implemented */ if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) ath6kl_hif_cleanup_scatter(target->dev->ar); list_for_each_entry_safe(packet, tmp_packet, - &target->free_ctrl_txbuf, list) { + &target->free_ctrl_txbuf, list) { list_del(&packet->list); kfree(packet->buf_start); kfree(packet); } list_for_each_entry_safe(packet, tmp_packet, - &target->free_ctrl_rxbuf, list) { + &target->free_ctrl_rxbuf, list) { list_del(&packet->list); kfree(packet->buf_start); kfree(packet); diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 5027ccc3..83f5aa5a 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -112,7 +112,7 @@ #define HTC_TARGET_DEBUG_INTR_MASK 0x01 #define HTC_TARGET_CREDIT_INTR_MASK 0xF0 -#define HTC_HOST_MAX_MSG_PER_BUNDLE 8 +#define HTC_HOST_MAX_MSG_PER_BUNDLE 7 #define HTC_MIN_HTC_MSGS_TO_BUNDLE 2 /* packet flags */ @@ -523,16 +523,9 @@ struct htc_target { struct ath6kl_htc_credit_info *credit_info; int tgt_creds; unsigned int tgt_cred_sz; - - /* protects free_ctrl_txbuf and free_ctrl_rxbuf */ spinlock_t htc_lock; - - /* FIXME: does this protext rx_bufq and endpoint structures or what? */ spinlock_t rx_lock; - - /* protects endpoint->txq */ spinlock_t tx_lock; - struct ath6kl_device *dev; u32 htc_flags; u32 rx_st_flags; @@ -557,6 +550,13 @@ struct htc_target { /* counts the number of Tx without bundling continously per AC */ u32 ac_tx_count[WMM_NUM_AC]; + + /* protects rx_compq */ + spinlock_t rx_comp_lock; + + struct workqueue_struct *rx_wq; + struct work_struct rx_work; + struct list_head rx_bufq; }; void *ath6kl_htc_create(struct ath6kl *ar); diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 03cae142..e58c90f0 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -18,15 +18,50 @@ #include #include -#include -#include +//#include #include - +#include #include "core.h" #include "cfg80211.h" #include "target.h" #include "debug.h" #include "hif-ops.h" +#include "regd.h" +#include "pm.h" +/* + open log switches. + ATH6KL_DBG_TRC + ATH6KL_DBG_BOOT + ATH6KL_DBG_SUSPEND + ATH6KL_DBG_WLAN_CFG. (defined in debug.h) +*/ +unsigned int debug_mask = 0x142800; + +#ifdef WIFI_POWER_TUNED +unsigned int needPowerTuned = 1; +#endif + +static unsigned int testmode; +/* Set WOW mode as default suspend mode */ +static unsigned int suspend_mode = 3; +static unsigned int wow_mode; +static unsigned int uart_debug; +static unsigned int ar6k_clock = 19200000; +static unsigned short locally_administered_bit; +static unsigned int heart_beat_poll = 2000; + +module_param(debug_mask, uint, 0644); +module_param(testmode, uint, 0644); +module_param(suspend_mode, uint, 0644); +module_param(wow_mode, uint, 0644); +module_param(uart_debug, uint, 0644); + +#ifdef WIFI_POWER_TUNED +module_param(needPowerTuned, uint, 0644); +#endif + +module_param(ar6k_clock, uint, 0644); +module_param(locally_administered_bit, ushort, 0644); +module_param(heart_beat_poll, uint, 0644); +MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ + "polling. This also specifies the polling interval in msecs"); static const struct ath6kl_hw hw_list[] = { { @@ -41,6 +76,7 @@ static const struct ath6kl_hw hw_list[] = { /* hw2.0 needs override address hardcoded */ .app_start_override_addr = 0x944C00, + .flags = 0, .fw = { .dir = AR6003_HW_2_0_FW_DIR, @@ -63,6 +99,7 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 26000000, .uarttx_pin = 8, .testscript_addr = 0x57ef74, + .flags = 0, .fw = { .dir = AR6003_HW_2_1_1_FW_DIR, @@ -75,7 +112,7 @@ static const struct ath6kl_hw hw_list[] = { }, .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, - .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, + .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, }, { .id = AR6004_HW_1_0_VERSION, @@ -87,6 +124,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x433900, .refclk_hz = 26000000, .uarttx_pin = 11, + .flags = ATH6KL_HW_FLAG_64BIT_RATES, .fw = { .dir = AR6004_HW_1_0_FW_DIR, @@ -106,6 +144,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x43d400, .refclk_hz = 40000000, .uarttx_pin = 11, + .flags = ATH6KL_HW_FLAG_64BIT_RATES, .fw = { .dir = AR6004_HW_1_1_FW_DIR, @@ -140,7 +179,7 @@ static const struct ath6kl_hw hw_list[] = { * If the firmware successly roams within the disconnect timeout * it sends a new connect event */ -#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10 +#define WLAN_CONFIG_DISCONNECT_TIMEOUT 2 //10-->2 #define ATH6KL_DATA_OFFSET 64 @@ -150,8 +189,8 @@ struct sk_buff *ath6kl_buf_alloc(int size) u16 reserved; /* Add chacheline space at front and back of buffer */ - reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + - sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES; + reserved = roundup((2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + + sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES, 4); skb = dev_alloc_skb(size + reserved); if (skb) @@ -297,7 +336,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar) */ connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB; connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK; - connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF; + connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_QUAT; connect.svc_id = WMI_DATA_BE_SVC; @@ -352,7 +391,11 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, blk_size |= ((u32)htc_ctrl_buf) << 16; /* set the host interest area for the block size */ - status = ath6kl_bmi_write_hi32(ar, hi_mbox_io_block_sz, blk_size); + status = ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_mbox_io_block_sz)), + (u8 *)&blk_size, + 4); if (status) { ath6kl_err("bmi_write_memory for IO block size failed\n"); goto out; @@ -364,8 +407,11 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, if (mbox_isr_yield_val) { /* set the host interest area for the mbox ISR yield limit */ - status = ath6kl_bmi_write_hi32(ar, hi_mbox_isr_yield_limit, - mbox_isr_yield_val); + status = ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_mbox_isr_yield_limit)), + (u8 *)&mbox_isr_yield_val, + 4); if (status) { ath6kl_err("bmi_write_memory for yield limit failed\n"); goto out; @@ -378,6 +424,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) { + int status = 0; int ret; /* @@ -385,54 +432,43 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) * default values. Required if checksum offload is needed. Set * RxMetaVersion to 2. */ - ret = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, - ar->rx_meta_ver, 0, 0); - if (ret) { - ath6kl_err("unable to set the rx frame format: %d\n", ret); - return ret; + if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, + ar->rx_meta_ver, 0, 0)) { + ath6kl_err("unable to set the rx frame format\n"); + status = -EIO; } - if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) { - ret = ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, - IGNORE_PS_FAIL_DURING_SCAN); - if (ret) { - ath6kl_err("unable to set power save fail event policy: %d\n", - ret); - return ret; + if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) + if ((ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, + IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { + ath6kl_err("unable to set power save fail event policy\n"); + status = -EIO; } - } - if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) { - ret = ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, - WMI_FOLLOW_BARKER_IN_ERP); - if (ret) { - ath6kl_err("unable to set barker preamble policy: %d\n", - ret); - return ret; + if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) + if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, + WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { + ath6kl_err("unable to set barker preamble policy\n"); + status = -EIO; } - } - ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, - WLAN_CONFIG_KEEP_ALIVE_INTERVAL); - if (ret) { - ath6kl_err("unable to set keep alive interval: %d\n", ret); - return ret; + if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, + WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { + ath6kl_err("unable to set keep alive interval\n"); + status = -EIO; } - ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, - WLAN_CONFIG_DISCONNECT_TIMEOUT); - if (ret) { - ath6kl_err("unable to set disconnect timeout: %d\n", ret); - return ret; + if (ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, + WLAN_CONFIG_DISCONNECT_TIMEOUT)) { + ath6kl_err("unable to set disconnect timeout\n"); + status = -EIO; } - if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) { - ret = ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED); - if (ret) { - ath6kl_err("unable to set txop bursting: %d\n", ret); - return ret; + if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) + if (ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED)) { + ath6kl_err("unable to set txop bursting\n"); + status = -EIO; } - } if (ar->p2p && (ar->vif_max == 1 || idx)) { ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx, @@ -443,7 +479,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P " "capabilities (%d) - assuming P2P not " "supported\n", ret); - ar->p2p = false; + ar->p2p = 0; } } @@ -456,7 +492,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) } } - return ret; + return status; } int ath6kl_configure_target(struct ath6kl *ar) @@ -465,8 +501,9 @@ int ath6kl_configure_target(struct ath6kl *ar) u8 fw_iftype, fw_mode = 0, fw_submode = 0; int i, status; - param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG); - if (ath6kl_bmi_write_hi32(ar, hi_serial_enable, param)) { + param = uart_debug; + if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_serial_enable)), (u8 *)¶m, 4)) { ath6kl_err("bmi_write_memory for uart debug failed\n"); return -EIO; } @@ -485,25 +522,37 @@ int ath6kl_configure_target(struct ath6kl *ar) fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS); /* - * By default, submodes : + * Submodes when fw does not support dynamic interface + * switching: * vif[0] - AP/STA/IBSS * vif[1] - "P2P dev"/"P2P GO"/"P2P Client" * vif[2] - "P2P dev"/"P2P GO"/"P2P Client" + * Otherwise, All the interface are initialized to p2p dev. */ - for (i = 0; i < ar->max_norm_iface; i++) - fw_submode |= HI_OPTION_FW_SUBMODE_NONE << - (i * HI_OPTION_FW_SUBMODE_BITS); + if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + ar->fw_capabilities)) { + for (i = 0; i < ar->vif_max; i++) + fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << + (i * HI_OPTION_FW_SUBMODE_BITS); + } else { + for (i = 0; i < ar->max_norm_iface; i++) + fw_submode |= HI_OPTION_FW_SUBMODE_NONE << + (i * HI_OPTION_FW_SUBMODE_BITS); - for (i = ar->max_norm_iface; i < ar->vif_max; i++) - fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << - (i * HI_OPTION_FW_SUBMODE_BITS); + for (i = ar->max_norm_iface; i < ar->vif_max; i++) + fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << + (i * HI_OPTION_FW_SUBMODE_BITS); - if (ar->p2p && ar->vif_max == 1) - fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; + if (ar->p2p && ar->vif_max == 1) + fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; + } - if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest, - HTC_PROTOCOL_VERSION) != 0) { + param = HTC_PROTOCOL_VERSION; + if (ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_app_host_interest)), + (u8 *)¶m, 4) != 0) { ath6kl_err("bmi_write_memory for htc version failed\n"); return -EIO; } @@ -511,7 +560,10 @@ int ath6kl_configure_target(struct ath6kl *ar) /* set the firmware mode to STA/IBSS/AP */ param = 0; - if (ath6kl_bmi_read_hi32(ar, hi_option_flag, ¶m) != 0) { + if (ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_option_flag)), + (u8 *)¶m, 4) != 0) { ath6kl_err("bmi_read_memory for setting fwmode failed\n"); return -EIO; } @@ -523,7 +575,11 @@ int ath6kl_configure_target(struct ath6kl *ar) param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); - if (ath6kl_bmi_write_hi32(ar, hi_option_flag, param) != 0) { + if (ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_option_flag)), + (u8 *)¶m, + 4) != 0) { ath6kl_err("bmi_write_memory for setting fwmode failed\n"); return -EIO; } @@ -542,13 +598,16 @@ int ath6kl_configure_target(struct ath6kl *ar) param = ar->hw.board_ext_data_addr; ram_reserved_size = ar->hw.reserved_ram_size; - if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { + if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_ext_data)), + (u8 *)¶m, 4) != 0) { ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); return -EIO; } - if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, - ram_reserved_size) != 0) { + if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_end_ram_reserve_sz)), + (u8 *)&ram_reserved_size, 4) != 0) { ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); return -EIO; } @@ -559,19 +618,59 @@ int ath6kl_configure_target(struct ath6kl *ar) return -EIO; /* Configure GPIO AR600x UART */ - status = ath6kl_bmi_write_hi32(ar, hi_dbg_uart_txpin, - ar->hw.uarttx_pin); + param = ar->hw.uarttx_pin; + status = ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_dbg_uart_txpin)), + (u8 *)¶m, 4); if (status) return status; /* Configure target refclk_hz */ - status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz); + param = ar->hw.refclk_hz; + status = ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_refclk_hz)), + (u8 *)¶m, 4); if (status) return status; return 0; } +void ath6kl_core_free(struct ath6kl *ar) +{ + wiphy_free(ar->wiphy); +} + +void ath6kl_core_cleanup(struct ath6kl *ar) +{ + ath6kl_hif_power_off(ar); + + ath6kl_recovery_cleanup(ar); + + destroy_workqueue(ar->ath6kl_wq); + + if (ar->htc_target) + ath6kl_htc_cleanup(ar->htc_target); + + ath6kl_cookie_cleanup(ar); + + ath6kl_cleanup_amsdu_rxbufs(ar); + + ath6kl_bmi_cleanup(ar); + + ath6kl_debug_cleanup(ar); + + kfree(ar->fw_board); + kfree(ar->fw_otp); + vfree(ar->fw); + kfree(ar->fw_patch); + kfree(ar->fw_testscript); + + ath6kl_deinit_ieee80211_hw(ar); +} + /* firmware upload */ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, u8 **fw, size_t *fw_len) @@ -594,6 +693,7 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, return ret; } +#if 0 #ifdef CONFIG_OF /* * Check the device tree for a board-id and use it to construct @@ -636,7 +736,7 @@ static bool check_device_tree(struct ath6kl *ar) return false; } #endif /* CONFIG_OF */ - +#endif static int ath6kl_fetch_board_file(struct ath6kl *ar) { const char *filename; @@ -656,12 +756,12 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) /* managed to get proper board file */ return 0; } - +#if 0 if (check_device_tree(ar)) { /* got board file from device tree */ return 0; } - +#endif /* there was no proper board file, try to use default instead */ ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", filename, ret); @@ -715,12 +815,12 @@ static int ath6kl_fetch_testmode_file(struct ath6kl *ar) char filename[100]; int ret; - if (ar->testmode == 0) + if (testmode == 0) return 0; - ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", ar->testmode); + ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", testmode); - if (ar->testmode == 2) { + if (testmode == 2) { if (ar->hw.fw.utf == NULL) { ath6kl_warn("testmode 2 not supported\n"); return -EOPNOTSUPP; @@ -743,7 +843,7 @@ static int ath6kl_fetch_testmode_file(struct ath6kl *ar) ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); if (ret) { ath6kl_err("Failed to get testmode %d firmware file %s: %d\n", - ar->testmode, filename, ret); + testmode, filename, ret); return ret; } @@ -805,7 +905,7 @@ static int ath6kl_fetch_testscript_file(struct ath6kl *ar) char filename[100]; int ret; - if (ar->testmode != 2) + if (testmode != 2) return 0; if (ar->fw_testscript != NULL) @@ -815,13 +915,13 @@ static int ath6kl_fetch_testscript_file(struct ath6kl *ar) return 0; snprintf(filename, sizeof(filename), "%s/%s", - ar->hw.fw.dir, ar->hw.fw.testscript); + ar->hw.fw.dir, ar->hw.fw.testscript); ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript, &ar->fw_testscript_len); if (ret) { ath6kl_err("Failed to get testscript file %s: %d\n", - filename, ret); + filename, ret); return ret; } @@ -903,9 +1003,17 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) } switch (ie_id) { + case ATH6KL_FW_IE_FW_VERSION: + strlcpy(ar->wiphy->fw_version, data, + sizeof(ar->wiphy->fw_version)); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "found fw version %s\n", + ar->wiphy->fw_version); + break; case ATH6KL_FW_IE_OTP_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", - ie_len); + ie_len); ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); @@ -918,24 +1026,25 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) break; case ATH6KL_FW_IE_FW_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", - ie_len); + ie_len); /* in testmode we already might have a fw file */ if (ar->fw != NULL) break; - ar->fw = kmemdup(data, ie_len, GFP_KERNEL); + ar->fw = vmalloc(ie_len); if (ar->fw == NULL) { ret = -ENOMEM; goto out; } + memcpy(ar->fw, data, ie_len); ar->fw_len = ie_len; break; case ATH6KL_FW_IE_PATCH_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", - ie_len); + ie_len); ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); @@ -955,9 +1064,6 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ar->hw.reserved_ram_size); break; case ATH6KL_FW_IE_CAPABILITIES: - if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8)) - break; - ath6kl_dbg(ATH6KL_DBG_BOOT, "found firmware capabilities ie (%zd B)\n", ie_len); @@ -966,6 +1072,9 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) index = i / 8; bit = i % 8; + if (index == ie_len) + break; + if (data[index] & (1 << bit)) __set_bit(i, ar->fw_capabilities); } @@ -1020,6 +1129,8 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) data += ie_len; }; + __set_bit(ATH6KL_FW_CAPABILITY_MAC_ACL, ar->fw_capabilities); + ret = 0; out: release_firmware(fw); @@ -1027,7 +1138,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) return ret; } -int ath6kl_init_fetch_firmwares(struct ath6kl *ar) +static int ath6kl_fetch_firmwares(struct ath6kl *ar) { int ret; @@ -1039,6 +1150,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar) if (ret) return ret; + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); + if (ret == 0) { + ar->fw_api = 4; + goto out; + } + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); if (ret == 0) { ar->fw_api = 3; @@ -1079,14 +1196,22 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) */ if (ar->hw.board_addr != 0) { board_address = ar->hw.board_addr; - ath6kl_bmi_write_hi32(ar, hi_board_data, - board_address); + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_data)), + (u8 *) &board_address, 4); } else { - ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); + ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_data)), + (u8 *) &board_address, 4); } /* determine where in target ram to write extended board data */ - ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); + ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_ext_data)), + (u8 *) &board_ext_address, 4); if (ar->target_type == TARGET_TYPE_AR6003 && board_ext_address == 0) { @@ -1131,7 +1256,10 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) /* record that extended board data is initialized */ param = (board_ext_data_size << 16) | 1; - ath6kl_bmi_write_hi32(ar, hi_board_ext_data_config, param); + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_ext_data_config)), + (unsigned char *) ¶m, 4); } if (ar->fw_board_len < board_data_size) { @@ -1152,7 +1280,11 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) } /* record the fact that Board Data IS initialized */ - ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1); + param = 1; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_data_initialized)), + (u8 *)¶m, 4); return ret; } @@ -1179,7 +1311,10 @@ static int ath6kl_upload_otp(struct ath6kl *ar) } /* read firmware start address */ - ret = ath6kl_bmi_read_hi32(ar, hi_app_start, &address); + ret = ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_app_start)), + (u8 *) &address, sizeof(address)); if (ret) { ath6kl_err("Failed to read hi_app_start: %d\n", ret); @@ -1198,7 +1333,14 @@ static int ath6kl_upload_otp(struct ath6kl *ar) /* execute the OTP code */ ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n", ar->hw.app_start_override_addr); + +#ifdef CONFIG_MACH_PX + /* SOFTMAC has higher priority than OTP MAC */ + param = 1; +#else param = 0; +#endif + ath6kl_bmi_execute(ar, ar->hw.app_start_override_addr, ¶m); return ret; @@ -1237,7 +1379,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) static int ath6kl_upload_patch(struct ath6kl *ar) { - u32 address; + u32 address, param; int ret; if (ar->fw_patch == NULL) @@ -1254,17 +1396,21 @@ static int ath6kl_upload_patch(struct ath6kl *ar) return ret; } - ath6kl_bmi_write_hi32(ar, hi_dset_list_head, address); + param = address; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_dset_list_head)), + (unsigned char *) ¶m, 4); return 0; } static int ath6kl_upload_testscript(struct ath6kl *ar) { - u32 address; + u32 address, param; int ret; - if (ar->testmode != 2) + if (testmode != 2) return 0; if (ar->fw_testscript == NULL) @@ -1273,7 +1419,7 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) address = ar->hw.testscript_addr; ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n", - address, ar->fw_testscript_len); + address, ar->fw_testscript_len); ret = ath6kl_bmi_write(ar, address, ar->fw_testscript, ar->fw_testscript_len); @@ -1282,9 +1428,23 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) return ret; } - ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address); - ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); - ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1); + param = address; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_ota_testscript)), + (unsigned char *) ¶m, 4); + + param = 4096; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_end_ram_reserve_sz)), + (unsigned char *) ¶m, 4); + + param = 1; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_test_apps_related)), + (unsigned char *) ¶m, 4); return 0; } @@ -1295,7 +1455,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) int status = 0; if (ar->target_type != TARGET_TYPE_AR6003 && - ar->target_type != TARGET_TYPE_AR6004) + ar->target_type != TARGET_TYPE_AR6004) return -EINVAL; /* temporarily disable system sleep */ @@ -1356,6 +1516,12 @@ static int ath6kl_init_upload(struct ath6kl *ar) ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { ath6kl_err("temporary war to avoid sdio crc error\n"); + param = 0x28; + address = GPIO_BASE_ADDRESS + GPIO_PIN9_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + param = 0x20; address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS; @@ -1379,6 +1545,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; } + ath6kl_bmi_reg_write(ar, 0x540678, ar6k_clock); + /* write EEPROM data to Target RAM */ status = ath6kl_upload_board_file(ar); if (status) @@ -1410,7 +1578,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS; - param = options | 0x20; + param = options & ~0x20; /* enable ANI */ status = ath6kl_bmi_reg_write(ar, address, param); if (status) return status; @@ -1418,9 +1586,9 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; } -int ath6kl_init_hw_params(struct ath6kl *ar) +static int ath6kl_init_hw_params(struct ath6kl *ar) { - const struct ath6kl_hw *uninitialized_var(hw); + const struct ath6kl_hw *hw; int i; for (i = 0; i < ARRAY_SIZE(hw_list); i++) { @@ -1465,7 +1633,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type) return NULL; } -int ath6kl_init_hw_start(struct ath6kl *ar) +static int __ath6kl_init_hw_start(struct ath6kl *ar) { long timeleft; int ret, i; @@ -1484,6 +1652,8 @@ int ath6kl_init_hw_start(struct ath6kl *ar) if (ret) goto err_power_off; + if (ath6kl_set_reg_dmn(ar)) + goto err_power_off; /* Do we need to finish the BMI phase */ /* FIXME: return error from ath6kl_bmi_done() */ if (ath6kl_bmi_done(ar)) { @@ -1497,11 +1667,13 @@ int ath6kl_init_hw_start(struct ath6kl *ar) * size. */ if (ath6kl_htc_wait_target(ar->htc_target)) { + ath6kl_err("htc wait target failed: %d\n", ret); ret = -EIO; goto err_power_off; } if (ath6kl_init_service_ep(ar)) { + ath6kl_err("Endpoint service initilisation failed: %d\n", ret); ret = -EIO; goto err_cleanup_scatter; } @@ -1543,6 +1715,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar) } if (!timeleft || signal_pending(current)) { + clear_bit(WMI_READY, &ar->flag); ath6kl_err("wmi is not ready or wait was interrupted\n"); ret = -EIO; goto err_htc_stop; @@ -1561,8 +1734,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar) goto err_htc_stop; } - ar->state = ATH6KL_STATE_ON; - return 0; err_htc_stop: @@ -1575,7 +1746,18 @@ int ath6kl_init_hw_start(struct ath6kl *ar) return ret; } -int ath6kl_init_hw_stop(struct ath6kl *ar) +int ath6kl_init_hw_start(struct ath6kl *ar) +{ + int err; + + err = __ath6kl_init_hw_start(ar); + if (err) + return err; + ar->state = ATH6KL_STATE_ON; + return 0; +} + +static int __ath6kl_init_hw_stop(struct ath6kl *ar) { int ret; @@ -1591,12 +1773,241 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) if (ret) ath6kl_warn("failed to power off hif: %d\n", ret); - ar->state = ATH6KL_STATE_OFF; + return 0; +} +int ath6kl_init_hw_stop(struct ath6kl *ar) +{ + int err; + + err = __ath6kl_init_hw_stop(ar); + if (err) + return err; + ar->state = ATH6KL_STATE_OFF; return 0; } -/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ +int ath6kl_core_init(struct ath6kl *ar) +{ + struct ath6kl_bmi_target_info targ_info; + struct net_device *ndev; + int ret = 0, i; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) + struct net_device *ndev_p2p0; +#endif + ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); + if (!ar->ath6kl_wq) + return -ENOMEM; + + ret = ath6kl_bmi_init(ar); + if (ret) + goto err_wq; + + /* + * Turn on power to get hardware (target) version and leave power + * on delibrately as we will boot the hardware anyway within few + * seconds. + */ + ret = ath6kl_hif_power_on(ar); + if (ret) + goto err_bmi_cleanup; + + ret = ath6kl_bmi_get_target_info(ar, &targ_info); + if (ret) + goto err_power_off; + + ar->version.target_ver = le32_to_cpu(targ_info.version); + ar->target_type = le32_to_cpu(targ_info.type); + ar->wiphy->hw_version = le32_to_cpu(targ_info.version); + + ret = ath6kl_init_hw_params(ar); + if (ret) + goto err_power_off; + + ar->htc_target = ath6kl_htc_create(ar); + + if (!ar->htc_target) { + ret = -ENOMEM; + goto err_power_off; + } + + ret = ath6kl_fetch_firmwares(ar); + if (ret) + goto err_htc_cleanup; + ath6kl_mangle_mac_address(ar, locally_administered_bit); + + /* FIXME: we should free all firmwares in the error cases below */ + + /* Indicate that WMI is enabled (although not ready yet) */ + set_bit(WMI_ENABLED, &ar->flag); + ar->wmi = ath6kl_wmi_init(ar); + if (!ar->wmi) { + ath6kl_err("failed to initialize wmi\n"); + ret = -EIO; + goto err_htc_cleanup; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); + + ret = ath6kl_register_ieee80211_hw(ar); + if (ret) + goto err_node_cleanup; + + ret = ath6kl_debug_init(ar); + if (ret) { + wiphy_unregister(ar->wiphy); + goto err_node_cleanup; + } + + for (i = 0; i < ar->vif_max; i++) + ar->avail_idx_map |= BIT(i); + + rtnl_lock(); + + /* Add an initial station interface */ + ndev = ath6kl_interface_add(ar, "eth%d", NL80211_IFTYPE_STATION, 0, + INFRA_NETWORK); + + rtnl_unlock(); + + if (!ndev) { + ath6kl_err("Failed to instantiate a network device\n"); + ret = -ENOMEM; + wiphy_unregister(ar->wiphy); + goto err_debug_init; + } + + + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", + __func__, ndev->name, ndev, ar); + + /* setup access class priority mappings */ + ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ + ar->ac_stream_pri_map[WMM_AC_BE] = 1; + ar->ac_stream_pri_map[WMM_AC_VI] = 2; + ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ + + /* allocate some buffers that handle larger AMSDU frames */ + ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); + + ath6kl_cookie_init(ar); + + ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | + ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; + + if (suspend_mode && + suspend_mode >= WLAN_POWER_STATE_CUT_PWR && + suspend_mode <= WLAN_POWER_STATE_WOW) + ar->suspend_mode = suspend_mode; + else + ar->suspend_mode = 0; + + if (suspend_mode == WLAN_POWER_STATE_WOW && + (wow_mode == WLAN_POWER_STATE_CUT_PWR || + wow_mode == WLAN_POWER_STATE_DEEP_SLEEP)) + ar->wow_suspend_mode = wow_mode; + else + ar->wow_suspend_mode = 0; + + ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | + WIPHY_FLAG_HAVE_AP_SME | + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | + WIPHY_FLAG_SUPPORTS_ACS; + + if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities)) + ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + + ar->wiphy->probe_resp_offload = + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; + + set_bit(FIRST_BOOT, &ar->flag); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) + ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; +#endif + + ret = ath6kl_init_hw_start(ar); + if (ret) { + ath6kl_err("Failed to start hardware: %d\n", ret); + goto err_rxbuf_cleanup; + } + + /* give our connected endpoints some buffers */ + ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); + ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); + + /* + * Set mac address which is received in ready event + * FIXME: Move to ath6kl_interface_add() + */ + memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) + rtnl_lock(); + ndev_p2p0 = ath6kl_cfg80211_add_p2p0_iface(ar); + rtnl_unlock(); + + if (!ndev_p2p0) { + ath6kl_err("Failed to create p2p0 iface\n"); + ret = -ENOMEM; + goto err_rxbuf_cleanup; + } +#endif + if (heart_beat_poll && + test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, + ar->fw_capabilities)) + ar->fw_recovery.hb_poll = heart_beat_poll; + + ath6kl_recovery_init(ar); + + return ret; + +err_rxbuf_cleanup: + ath6kl_htc_flush_rx_buf(ar->htc_target); + ath6kl_cleanup_amsdu_rxbufs(ar); + rtnl_lock(); + ath6kl_deinit_if_data(netdev_priv(ndev)); + rtnl_unlock(); + wiphy_unregister(ar->wiphy); +err_debug_init: + ath6kl_debug_cleanup(ar); +err_node_cleanup: + ath6kl_cleanup_android_resource(ar); + ath6kl_wmi_shutdown(ar->wmi); + clear_bit(WMI_ENABLED, &ar->flag); + ar->wmi = NULL; +err_htc_cleanup: + ath6kl_htc_cleanup(ar->htc_target); +err_power_off: + ath6kl_hif_power_off(ar); +err_bmi_cleanup: + ath6kl_bmi_cleanup(ar); +err_wq: + destroy_workqueue(ar->ath6kl_wq); + + return ret; +} + +void ath6kl_init_hw_restart(struct ath6kl *ar) +{ + clear_bit(WMI_READY, &ar->flag); + + ath6kl_cfg80211_stop_all(ar); + + if (__ath6kl_init_hw_stop(ar)) { + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n"); + return; + } + + if (__ath6kl_init_hw_start(ar)) { + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n"); + return; + } +} + void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) { static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -1623,6 +2034,9 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) cfg80211_scan_done(vif->scan_req, true); vif->scan_req = NULL; } + + /* need to clean up enhanced bmiss detection fw state */ + ath6kl_cfg80211_sta_bmiss_enhance(vif, false); } void ath6kl_stop_txrx(struct ath6kl *ar) @@ -1646,7 +2060,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar) spin_unlock_bh(&ar->list_lock); ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); rtnl_lock(); - ath6kl_cfg80211_vif_cleanup(vif); + ath6kl_deinit_if_data(vif); rtnl_unlock(); spin_lock_bh(&ar->list_lock); } @@ -1654,6 +2068,8 @@ void ath6kl_stop_txrx(struct ath6kl *ar) clear_bit(WMI_READY, &ar->flag); + del_timer_sync(&ar->fw_recovery.hb_timer); + /* * After wmi_shudown all WMI events will be dropped. We * need to cleanup the buffers allocated in AP mode and @@ -1676,11 +2092,8 @@ void ath6kl_stop_txrx(struct ath6kl *ar) * configure NOT to reset the target during a debug session. */ ath6kl_dbg(ATH6KL_DBG_TRC, - "attempting to reset target on instance destroy\n"); + "attempting to reset target on instance destroy\n"); ath6kl_reset_device(ar, ar->target_type, true, true); clear_bit(WLAN_ENABLED, &ar->flag); - - up(&ar->sem); } -EXPORT_SYMBOL(ath6kl_stop_txrx); diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 229e1922..8a223bd9 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -20,6 +20,7 @@ #include "cfg80211.h" #include "target.h" #include "debug.h" +#include "wmiconfig.h" struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr) { @@ -147,14 +148,23 @@ enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac) return ar->ac2ep_map[ac]; } -struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar) +struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar, bool isctrl) { struct ath6kl_cookie *cookie; - cookie = ar->cookie_list; - if (cookie != NULL) { - ar->cookie_list = cookie->arc_list_next; - ar->cookie_count--; + /* If this cookie is for control packet*/ + if (isctrl) { + cookie = ar->wmi_cookie_list; + if (cookie != NULL) { + ar->wmi_cookie_list = cookie->arc_list_next; + ar->wmi_cookie_count--; + } + } else { + cookie = ar->cookie_list; + if (cookie != NULL) { + ar->cookie_list = cookie->arc_list_next; + ar->cookie_count--; + } } return cookie; @@ -164,31 +174,54 @@ void ath6kl_cookie_init(struct ath6kl *ar) { u32 i; + /* Initilize data cookie list */ ar->cookie_list = NULL; ar->cookie_count = 0; memset(ar->cookie_mem, 0, sizeof(ar->cookie_mem)); for (i = 0; i < MAX_COOKIE_NUM; i++) - ath6kl_free_cookie(ar, &ar->cookie_mem[i]); + ath6kl_free_cookie(ar, &ar->cookie_mem[i], false); + + /* Initilize control cookie list */ + ar->wmi_cookie_list = NULL; + ar->wmi_cookie_count = 0; + + memset(ar->wmi_cookie_mem, 0, sizeof(ar->wmi_cookie_mem)); + + for (i = 0; i < WMI_MAX_COOKIE_NUM; i++) + ath6kl_free_cookie(ar, &ar->wmi_cookie_mem[i], true); } void ath6kl_cookie_cleanup(struct ath6kl *ar) { + /* Cleanup the data cookie */ ar->cookie_list = NULL; ar->cookie_count = 0; + + /* Cleanup the control cookie */ + ar->wmi_cookie_list = NULL; + ar->wmi_cookie_count = 0; } -void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie) +void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie, + bool isctrl) { /* Insert first */ if (!ar || !cookie) return; - cookie->arc_list_next = ar->cookie_list; - ar->cookie_list = cookie; - ar->cookie_count++; + /* If it is control cookie */ + if (isctrl) { + cookie->arc_list_next = ar->wmi_cookie_list; + ar->wmi_cookie_list = cookie; + ar->wmi_cookie_count++; + } else { + cookie->arc_list_next = ar->cookie_list; + ar->cookie_list = cookie; + ar->cookie_count++; + } } /* @@ -350,7 +383,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, __le32 data; if (target_type != TARGET_TYPE_AR6003 && - target_type != TARGET_TYPE_AR6004) + target_type != TARGET_TYPE_AR6004) return; data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : @@ -434,11 +467,41 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) break; } + if (ar->last_ch != channel) + /* we actually don't know the phymode, default to HT20 */ + ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20); + ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); set_bit(CONNECTED, &vif->flags); netif_carrier_on(vif->ndev); } +/*add new_sta join uevent SOFTAP=STA_JOIN */ +void ath6kl_uevent_new_sta(struct ath6kl *ar, const u8 *mac_addr) +{ + char event[64]; + char *envp[] = { event, NULL }; + + memset(event, 0, sizeof(event)); + sprintf(event, "SOFTAP=STA_JOIN " "eth0" "0 wl0.1 %02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + ath6kl_err("%s(): send uevent=%s\n",__FUNCTION__, event); + kobject_uevent_env(&(ar->dev->kobj), KOBJ_CHANGE, envp); +} + +/*add new_sta leave uevent SOFTAP=STA_LEAVE */ +void ath6kl_uevent_del_sta(struct ath6kl *ar, const u8 *mac_addr) +{ + char event[64]; + char *envp[] = { event, NULL }; + + memset(event, 0, sizeof(event)); + sprintf(event, "SOFTAP=STA_LEAVE " "eth0" "0 wl0.1 %02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + ath6kl_err("%s(): send uevent=%s\n",__FUNCTION__, event); + kobject_uevent_env(&(ar->dev->kobj), KOBJ_CHANGE, envp); +} + void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, u8 keymgmt, u8 ucipher, u8 auth, u8 assoc_req_len, u8 *assoc_info, u8 apsd_info) @@ -511,6 +574,8 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL); + ath6kl_uevent_new_sta(vif->ar, mac_addr); + netif_wake_queue(vif->ndev); } @@ -544,19 +609,23 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) struct ath6kl *ar = devt; memcpy(ar->mac_addr, datap, ETH_ALEN); - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n", - __func__, ar->mac_addr); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "ready event mac addr %pM sw_ver 0x%x abi_ver 0x%x\n", + ar->mac_addr, sw_ver, abi_ver); ar->version.wlan_ver = sw_ver; ar->version.abi_ver = abi_ver; - snprintf(ar->wiphy->fw_version, - sizeof(ar->wiphy->fw_version), - "%u.%u.%u.%u", - (ar->version.wlan_ver & 0xf0000000) >> 28, - (ar->version.wlan_ver & 0x0f000000) >> 24, - (ar->version.wlan_ver & 0x00ff0000) >> 16, - (ar->version.wlan_ver & 0x0000ffff)); + if (strlen(ar->wiphy->fw_version) == 0) { + snprintf(ar->wiphy->fw_version, + sizeof(ar->wiphy->fw_version), + "%u.%u.%u.%u", + (ar->version.wlan_ver & 0xf0000000) >> 28, + (ar->version.wlan_ver & 0x0f000000) >> 24, + (ar->version.wlan_ver & 0x00ff0000) >> 16, + (ar->version.wlan_ver & 0x0000ffff)); + } /* indicate to the waiting thread that the ready event was received */ set_bit(WMI_READY, &ar->flag); @@ -582,6 +651,60 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status); } +static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) +{ + + struct ath6kl *ar = vif->ar; + + vif->next_chan = channel; + vif->profile.ch = cpu_to_le16(channel); + + switch (vif->nw_type) { + case AP_NETWORK: + /* + * reconfigure any saved RSN IE capabilites in the beacon / + * probe response to stay in sync with the supplicant. + */ + if (vif->rsn_capab && + test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities)) + ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, + WLAN_EID_RSN, WMI_RSN_IE_CAPB, + (const u8 *) &vif->rsn_capab, + sizeof(vif->rsn_capab)); + + return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, + &vif->profile); + default: + ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type); + return -ENOTSUPP; + } +} + +static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) +{ + + struct ath6kl_vif *vif; + int res = 0; + + if (!ar->want_ch_switch) + return; + + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) + res = ath6kl_commit_ch_switch(vif, channel); + + /* if channel switch failed, oh well we tried */ + ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); + + if (res) + ath6kl_err("channel switch failed nw_type %d res %d\n", + vif->nw_type, res); + } + spin_unlock_bh(&ar->list_lock); +} + void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, u16 listen_int, u16 beacon_int, enum network_type net_type, u8 beacon_ie_len, @@ -599,9 +722,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, memcpy(vif->bssid, bssid, sizeof(vif->bssid)); vif->bss_ch = channel; - if ((vif->nw_type == INFRA_NETWORK)) + if ((vif->nw_type == INFRA_NETWORK)) { ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, vif->listen_intvl_t, 0); + ath6kl_check_ch_switch(ar, channel); + } netif_wake_queue(vif->ndev); @@ -661,6 +786,7 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) (struct wmi_target_stats *) ptr; struct ath6kl *ar = vif->ar; struct target_stats *stats = &vif->target_stats; + struct target_stats_dup *stats_dup = &vif->target_stats_dup; struct tkip_ccmp_stats *ccmp_stats; u8 ac; @@ -671,6 +797,7 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt); stats->tx_byte += le32_to_cpu(tgt_stats->stats.tx.byte); + stats_dup->tx_byte += le32_to_cpu(tgt_stats->stats.tx.byte); stats->tx_ucast_pkt += le32_to_cpu(tgt_stats->stats.tx.ucast_pkt); stats->tx_ucast_byte += le32_to_cpu(tgt_stats->stats.tx.ucast_byte); stats->tx_mcast_pkt += le32_to_cpu(tgt_stats->stats.tx.mcast_pkt); @@ -679,22 +806,37 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) stats->tx_bcast_byte += le32_to_cpu(tgt_stats->stats.tx.bcast_byte); stats->tx_rts_success_cnt += le32_to_cpu(tgt_stats->stats.tx.rts_success_cnt); + stats_dup->tx_rts_success_cnt += + le32_to_cpu(tgt_stats->stats.tx.rts_success_cnt); - for (ac = 0; ac < WMM_NUM_AC; ac++) + for (ac = 0; ac < WMM_NUM_AC; ac++) { stats->tx_pkt_per_ac[ac] += le32_to_cpu(tgt_stats->stats.tx.pkt_per_ac[ac]); + stats_dup->tx_pkt_per_ac[ac] += + le32_to_cpu(tgt_stats->stats.tx.pkt_per_ac[ac]); + stats_dup->tx_retry_cnt[ac] += + le32_to_cpu(tgt_stats->stats.tx.retry_cnt); + stats_dup->tx_fail_cnt[ac] += + le32_to_cpu(tgt_stats->stats.tx.fail_cnt); + stats_dup->tx_mult_retry_cnt[ac] += + le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); + } stats->tx_err += le32_to_cpu(tgt_stats->stats.tx.err); + stats_dup->tx_err += le32_to_cpu(tgt_stats->stats.tx.err); stats->tx_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.fail_cnt); stats->tx_retry_cnt += le32_to_cpu(tgt_stats->stats.tx.retry_cnt); stats->tx_mult_retry_cnt += le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); stats->tx_rts_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); + stats_dup->tx_rts_fail_cnt += + le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); stats->tx_ucast_rate = ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate)); stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); + stats_dup->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte); stats->rx_ucast_pkt += le32_to_cpu(tgt_stats->stats.rx.ucast_pkt); stats->rx_ucast_byte += le32_to_cpu(tgt_stats->stats.rx.ucast_byte); @@ -704,11 +846,13 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) stats->rx_bcast_byte += le32_to_cpu(tgt_stats->stats.rx.bcast_byte); stats->rx_frgment_pkt += le32_to_cpu(tgt_stats->stats.rx.frgment_pkt); stats->rx_err += le32_to_cpu(tgt_stats->stats.rx.err); + stats_dup->rx_err += le32_to_cpu(tgt_stats->stats.rx.err); stats->rx_crc_err += le32_to_cpu(tgt_stats->stats.rx.crc_err); stats->rx_key_cache_miss += le32_to_cpu(tgt_stats->stats.rx.key_cache_miss); stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err); stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); + stats_dup->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); stats->rx_ucast_rate = ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate)); @@ -756,6 +900,12 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) stats->wow_evt_discarded += le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded); + stats->arp_received = le32_to_cpu(tgt_stats->arp_stats.arp_received); + stats->arp_replied = le32_to_cpu(tgt_stats->arp_stats.arp_replied); + stats->arp_matched = le32_to_cpu(tgt_stats->arp_stats.arp_matched); + + ath6kl_wmicfg_send_stats(vif, stats); + if (test_bit(STATS_UPDATE_PEND, &vif->flags)) { clear_bit(STATS_UPDATE_PEND, &vif->flags); wake_up(&ar->event_wq); @@ -920,6 +1070,28 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, struct ath6kl *ar = vif->ar; if (vif->nw_type == AP_NETWORK) { + /* disconnect due to other STA vif switching channels */ + if (reason == BSS_DISCONNECTED && + prot_reason_status == WMI_AP_REASON_STA_ROAM) { + ar->want_ch_switch |= 1 << vif->fw_vif_idx; + /* bail back to this channel if STA vif fails connect */ + ar->last_ch = le16_to_cpu(vif->profile.ch); + } + + if (prot_reason_status == WMI_AP_REASON_MAX_STA) { + /* send max client reached notification to user space */ + cfg80211_conn_failed(vif->ndev, bssid, + NL80211_CONN_FAIL_MAX_CLIENTS, + GFP_KERNEL); + } + + if (prot_reason_status == WMI_AP_REASON_ACL) { + /* send blocked client notification to user space */ + cfg80211_conn_failed(vif->ndev, bssid, + NL80211_CONN_FAIL_BLOCKED_CLIENT, + GFP_KERNEL); + } + if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) return; @@ -938,6 +1110,7 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, if (!is_broadcast_ether_addr(bssid)) { /* send event to application */ cfg80211_del_sta(vif->ndev, bssid, GFP_KERNEL); + ath6kl_uevent_del_sta(vif->ar, bssid); } if (memcmp(vif->ndev->dev_addr, bssid, ETH_ALEN) == 0) { @@ -948,8 +1121,8 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, } ath6kl_cfg80211_disconnect_event(vif, reason, bssid, - assoc_resp_len, assoc_info, - prot_reason_status); + assoc_resp_len, assoc_info, + prot_reason_status); aggr_reset_state(vif->aggr_cntxt->aggr_conn); @@ -969,14 +1142,17 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, } else { set_bit(CONNECT_PEND, &vif->flags); if (((reason == ASSOC_FAILED) && - (prot_reason_status == 0x11)) || - ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) && - (vif->reconnect_flag == 1))) { + (prot_reason_status == 0x11)) || + ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) + && (vif->reconnect_flag == 1))) { set_bit(CONNECTED, &vif->flags); return; } } + /* restart disconnected concurrent vifs waiting for new channel */ + ath6kl_check_ch_switch(ar, ar->last_ch); + /* update connect & link status atomically */ spin_lock_bh(&vif->if_lock); clear_bit(CONNECTED, &vif->flags); @@ -1048,8 +1224,12 @@ static struct net_device_stats *ath6kl_get_stats(struct net_device *dev) return &vif->net_stats; } -static int ath6kl_set_features(struct net_device *dev, - netdev_features_t features) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) +static int ath6kl_set_features(struct net_device *dev, netdev_features_t features) +#else +static int ath6kl_set_features(struct net_device *dev, u32 features) +#endif { struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl *ar = vif->ar; @@ -1080,11 +1260,12 @@ static int ath6kl_set_features(struct net_device *dev, return err; } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) */ static void ath6kl_set_multicast_list(struct net_device *ndev) { struct ath6kl_vif *vif = netdev_priv(ndev); - bool mc_all_on = false, mc_all_off = false; + bool mc_all_on = false; int mc_count = netdev_mc_count(ndev); struct netdev_hw_addr *ha; bool found; @@ -1096,29 +1277,46 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) !test_bit(WLAN_ENABLED, &vif->flags)) return; + /* Enable multicast-all filter. */ mc_all_on = !!(ndev->flags & IFF_PROMISC) || !!(ndev->flags & IFF_ALLMULTI) || !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); - mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0; + if (mc_all_on) + set_bit(NETDEV_MCAST_ALL_ON, &vif->flags); + else + clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags); - if (mc_all_on || mc_all_off) { - /* Enable/disable all multicast */ - ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", - mc_all_on ? "enabling" : "disabling"); - ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, - mc_all_on); - if (ret) - ath6kl_warn("Failed to %s multicast receive\n", - mc_all_on ? "enable" : "disable"); + mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON); + + if (!(ndev->flags & IFF_MULTICAST)) { + mc_all_on = false; + set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); + } else { + clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); + } + + /* Enable/disable "multicast-all" filter*/ + ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n", + mc_all_on ? "enabling" : "disabling"); + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, + mc_all_on); + + if (ret) { + ath6kl_warn("Failed to %s multicast-all receive\n", + mc_all_on ? "enable" : "disable"); return; } + if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) + return; + + /* Keep the driver and firmware mcast list in sync. */ list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { found = false; netdev_for_each_mc_addr(ha, ndev) { if (memcmp(ha->addr, mc_filter->hw_addr, - ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { + ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { found = true; break; } @@ -1137,7 +1335,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) false); if (ret) { ath6kl_warn("Failed to remove multicast filter:%pM\n", - mc_filter->hw_addr); + mc_filter->hw_addr); return; } @@ -1152,7 +1350,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) found = false; list_for_each_entry(mc_filter, &vif->mc_filter, list) { if (memcmp(ha->addr, mc_filter->hw_addr, - ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { + ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { found = true; break; } @@ -1177,7 +1375,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) true); if (ret) { ath6kl_warn("Failed to add multicast filter :%pM\n", - mc_filter->hw_addr); + mc_filter->hw_addr); kfree(mc_filter); goto out; } @@ -1190,18 +1388,146 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) list_splice_tail(&mc_filter_new, &vif->mc_filter); } -static const struct net_device_ops ath6kl_netdev_ops = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) + +static inline void ath6kl_pack_tlv(char *buf, char type, char size, + char *val, int *tlen) +{ + if (*tlen > ATH6KL_PRI_IOCTL_REPLY_BUF_MAX) + return; + + *buf++ = type; + *buf++ = size; + memcpy(buf, val, size); + *tlen += size + 2; +} + +static int ath6kl_update_stats(struct ath6kl *ar, struct ath6kl_vif *vif, + void __user *user_buf) +{ + struct target_stats_dup *stats; + char *buf; + int tlen = 0; + long left; + size_t ret; + + if (down_interruptible(&ar->sem)) + goto exit; + + set_bit(STATS_UPDATE_PEND, &vif->flags); + + if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) { + up(&ar->sem); + goto exit; + } + + left = wait_event_interruptible_timeout(ar->event_wq, + !test_bit(STATS_UPDATE_PEND, + &vif->flags), WMI_TIMEOUT); + up(&ar->sem); + + if (left <= 0) + goto exit; + + stats = &vif->target_stats_dup; + + buf = kzalloc(ATH6KL_PRI_IOCTL_REPLY_BUF_MAX, GFP_KERNEL); + if (!buf) + goto exit; + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_RETRY_CNT, + sizeof(stats->tx_retry_cnt), + (char *)&stats->tx_retry_cnt, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_MUL_RETRY_CNT, + sizeof(stats->tx_mult_retry_cnt), + (char *)&stats->tx_mult_retry_cnt, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_TX_FRM_CNT, + sizeof(stats->tx_pkt_per_ac), + (char *)&stats->tx_pkt_per_ac, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_RX_FRM_CNT, + sizeof(stats->rx_pkt), + (char *)&stats->rx_pkt, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_FRM_DUP_CNT, + sizeof(stats->rx_dupl_frame), + (char *)&stats->rx_dupl_frame, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_FAIL_CNT, + sizeof(stats->tx_fail_cnt), + (char *)&stats->tx_fail_cnt, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_RTS_FAIL_CNT, + sizeof(stats->tx_rts_fail_cnt), + (char *)&stats->tx_rts_fail_cnt, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_ACK_FAIL_CNT, + sizeof(stats->tx_err), + (char *)&stats->tx_err, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_RTS_SUC_CNT, + sizeof(stats->tx_rts_success_cnt), + (char *)&stats->tx_rts_success_cnt, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_RX_DISCARD_CNT, + sizeof(stats->rx_err), + (char *)&stats->rx_err, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_RX_ERROR_CNT, + sizeof(stats->rx_err), + (char *)&stats->rx_err, &tlen); + + ath6kl_pack_tlv(buf + tlen, WLAN_STATS_TX_BYTE_CNT, + sizeof(stats->tx_byte), + (char *)&stats->tx_byte, &tlen); + + ret = copy_to_user(user_buf, buf, tlen); + if (ret) + ath6kl_err("failed to copy target stats to user buffer\n"); + + kfree(buf); +exit: + return 0; +} + +static int ath6kl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl *ar = vif->ar; + + if (!ar || !vif) + goto exit; + + if (!test_bit(WMI_READY, &vif->ar->flag) || + !test_bit(WLAN_ENABLED, &vif->flags)) + goto exit; + + if (cmd == ATH6KL_PRIV_GET_WLAN_STATS) + ath6kl_update_stats(ar, vif, rq->ifr_data); +exit: + return 0; +} +#endif + +static struct net_device_ops ath6kl_netdev_ops = { .ndo_open = ath6kl_open, .ndo_stop = ath6kl_close, .ndo_start_xmit = ath6kl_data_tx, .ndo_get_stats = ath6kl_get_stats, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) .ndo_set_features = ath6kl_set_features, +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) */ .ndo_set_rx_mode = ath6kl_set_multicast_list, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)) + .ndo_do_ioctl = ath6kl_ioctl, +#endif }; void init_netdev(struct net_device *dev) { - dev->netdev_ops = &ath6kl_netdev_ops; + netdev_attach_ops(dev, &ath6kl_netdev_ops); dev->destructor = free_netdev; dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; @@ -1210,7 +1536,5 @@ void init_netdev(struct net_device *dev) sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES; - dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - return; } diff --git a/drivers/net/wireless/ath/ath6kl/platform.c b/drivers/net/wireless/ath/ath6kl/platform.c new file mode 100644 index 00000000..dc10ec13 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/platform.c @@ -0,0 +1,206 @@ +#ifdef CONFIG_ARCH_MSM7X27A +#include +#else +#include +#include +#include +#include +#include +/* replace with plaftform specific changes */ +#endif + +#include "core.h" + +/* BeginMMC polling stuff */ +#ifdef CONFIG_ARCH_MSM7X27A +#define MMC_PLATFORM_DEV "msm_sdcc.2" +#else +#define MMC_PLATFORM_DEV "sdcc" +#endif + +/* End MMC polling stuff */ + +#define GET_INODE_FROM_FILEP(filp) \ + ((filp)->f_path.dentry->d_inode) + + + +#define ATH6KL_INIT_TIMEOUT (3 * HZ) + +wait_queue_head_t init_wq; +static atomic_t init_done = ATOMIC_INIT(0); + + +int android_readwrite_file(const char *filename, + char *rbuf, const char *wbuf, size_t length) +{ + int ret = 0; + struct file *filp = (struct file *)-ENOENT; + mm_segment_t oldfs; + oldfs = get_fs(); + set_fs(KERNEL_DS); + + do { + int mode = (wbuf) ? O_RDWR : O_RDONLY; + filp = filp_open(filename, mode, S_IRUSR); + + if (IS_ERR(filp) || !filp->f_op) { + ret = -ENOENT; + break; + } + + if (length == 0) { + /* Read the length of the file only */ + struct inode *inode; + + inode = GET_INODE_FROM_FILEP(filp); + if (!inode) { + printk(KERN_ERR "android_readwrite_file: Error 2\n"); + ret = -ENOENT; + break; + } + ret = i_size_read(inode->i_mapping->host); + break; + } + + if (wbuf) { + ret = filp->f_op->write(filp, wbuf, length, &filp->f_pos); + if (ret < 0) { + printk(KERN_ERR + "android_readwrite_file: Error 3\n"); + break; + } + } else { + ret = filp->f_op->read(filp, rbuf, length, &filp->f_pos); + if (ret < 0) { + printk(KERN_ERR + "android_readwrite_file: Error 4\n"); + break; + } + } + } while (0); + + if (!IS_ERR(filp)) + filp_close(filp, NULL); + + set_fs(oldfs); + printk(KERN_ERR "android_readwrite_file: ret=%d\n", ret); + + return ret; +} + +//extern void ar600x_wlan_power(bool on); + +static int ath6kl_pm_probe(struct platform_device *pdev) +{ +#if 1 + int (*plat_setup_power)(int on); + plat_setup_power = pdev->dev.platform_data; + printk(KERN_ERR "%s () enter and will invoke power-up sequence\n", + __func__); + if (plat_setup_power) + plat_setup_power(1); +#else + /* replace with plaftform specific changes */ +#endif + return 0; +} + +static int ath6kl_pm_remove(struct platform_device *pdev) +{ +#if 1 + int (*plat_setup_power)(int on); + plat_setup_power = pdev->dev.platform_data; + printk(KERN_ERR "%s () enter and will invoke power-down sequence\n", + __func__); + if (plat_setup_power) + plat_setup_power(0); +#else + /* replace with plaftform specific changes */ +#endif + return 0; +} + +static int ath6kl_pm_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static inline void *ar6k_priv(struct net_device *dev) +{ + return wdev_priv(dev->ieee80211_ptr); +} + +static int ath6kl_pm_resume(struct platform_device *pdev) +{ + return 0; +} + + +static struct platform_driver ath6kl_pm_device = { + .probe = ath6kl_pm_probe, + .remove = ath6kl_pm_remove, + .suspend = ath6kl_pm_suspend, + .resume = ath6kl_pm_resume, + .driver = { + .name = "wlan_ar6000_pm_dev", + }, +}; + +void __init ath6kl_sdio_init_platform(void) +{ + char buf[3]; + int length; + + platform_driver_register(&ath6kl_pm_device); + + length = snprintf(buf, sizeof(buf), "%d\n", 1 ? 1 : 0); + android_readwrite_file("/sys/devices/platform/" MMC_PLATFORM_DEV + "/polling", NULL, buf, length); + length = snprintf(buf, sizeof(buf), "%d\n", 0 ? 1 : 0); + android_readwrite_file("/sys/devices/platform/" MMC_PLATFORM_DEV + "/polling", NULL, buf, length); + + mdelay(50); +} + +void __exit ath6kl_sdio_exit_platform(void) +{ + char buf[3]; + int length; + platform_driver_unregister(&ath6kl_pm_device); + + length = snprintf(buf, sizeof(buf), "%d\n", 1 ? 1 : 0); + /* fall back to polling */ + android_readwrite_file("/sys/devices/platform/" MMC_PLATFORM_DEV + "/polling", NULL, buf, length); + length = snprintf(buf, sizeof(buf), "%d\n", 0 ? 1 : 0); + /* fall back to polling */ + android_readwrite_file("/sys/devices/platform/" MMC_PLATFORM_DEV + "/polling", NULL, buf, length); + mdelay(1000); + +} + +int ath6kl_wait_for_init_comp(void) +{ + int left; + + if (atomic_read(&init_done) == 1) + return 0; + + left = wait_event_interruptible_timeout(init_wq, + atomic_read(&init_done) == 1, + ATH6KL_INIT_TIMEOUT); + if (left == 0) + printk(KERN_ERR "timeout while waiting for init operation\n"); + else if (left < 0) + printk(KERN_ERR "wait for init operation failed: %d\n", left); + + return 0; +} +void ath6kl_notify_init_done(void) +{ + atomic_set(&init_done, 1); + wake_up(&init_wq); +} diff --git a/drivers/net/wireless/ath/ath6kl/pm.c b/drivers/net/wireless/ath/ath6kl/pm.c new file mode 100644 index 00000000..6ff5fafc --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/pm.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include "core.h" + +static bool ath6kl_parse_event_pkt_for_wake_lock(struct sk_buff *skb) +{ + u16 cmd_id; + bool need_wake = false; + + if (skb->len < sizeof(u16)) + return need_wake; + + cmd_id = *(const u16 *) skb->data; + cmd_id = le16_to_cpu(cmd_id); + + switch (cmd_id) { + case WMI_CONNECT_EVENTID: + need_wake = true; + break; + default: + /* Don't wake lock the system for other events */ + break; + } + + return need_wake; +} + +static bool ath6kl_parse_ip_pkt_for_wake_lock(struct sk_buff *skb) +{ + const u8 ipsec_keepalve[] = { 0x11, 0x94, 0x11, 0x94, 0x00, + 0x09, 0x00, 0x00, 0xff }; + bool need_wake = true; + u16 size; + u8 *udp; + u8 ihl; + + if (skb->len >= 24 && (*((u8 *)skb->data + 23) == 0x11)) { + + udp = (u8 *)skb->data + 14; + ihl = (*udp & 0x0f) * sizeof(u32); + udp += ihl; + size = 14 + ihl + sizeof(ipsec_keepalve); + + if ((skb->len >= size) && + !memcmp(udp, ipsec_keepalve, sizeof(ipsec_keepalve) - 3) && + udp[8] == 0xff) { + /* + * RFC 3948 UDP Encapsulation of IPsec ESP Packets + * src and dest port must be 4500 + * Receivers MUST NOT depend upon the UDP checksum + * being zero + * Sender must use 1 byte payload with 0xff + * Receiver SHOULD ignore a received NAT-keepalive pkt + * + * IPSec over UDP NAT keepalive packet. Just ignore + */ + need_wake = false; + } + } + + return need_wake; +} + +static bool ath6kl_parse_data_pkt_for_wake_lock(struct ath6kl *ar, + struct sk_buff *skb) +{ + struct net_device *ndev; + struct ath6kl_vif *vif; + struct ethhdr *hdr; + bool need_wake = false; + u16 dst_port; + + vif = ath6kl_vif_first(ar); + if (!vif) + return need_wake; + + if (skb->len < sizeof(struct ethhdr)) + return need_wake; + + hdr = (struct ethhdr *) skb->data; + + if (!is_multicast_ether_addr(hdr->h_dest)) { + switch (ntohs(hdr->h_proto)) { + case 0x0800: /* IP */ + need_wake = ath6kl_parse_ip_pkt_for_wake_lock(skb); + break; + case 0x888e: /* EAPOL */ + case 0x88c7: /* RSN_PREAUTH */ + case 0x88b4: /* WAPI */ + need_wake = true; + break; + default: + break; + } + } else if (!is_broadcast_ether_addr(hdr->h_dest)) { + if (skb->len >= 14 + 20) { /* mDNS packets */ + u8 *dst_ipaddr = (u8 *)(skb->data + 14 + 20 - 4); + ndev = vif->ndev; + if (((dst_ipaddr[3] & 0xf8) == 0xf8) && + (vif->nw_type == AP_NETWORK || + (ndev->flags & IFF_ALLMULTI || + ndev->flags & IFF_MULTICAST))) + need_wake = true; + } + } else if (vif->nw_type == AP_NETWORK) { + switch (ntohs(hdr->h_proto)) { + case 0x0800: /* IP */ + if (skb->len >= 14 + 20 + 2) { + dst_port = *(u16 *)(skb->data + 14 + 20); + /* dhcp req */ + need_wake = (ntohs(dst_port) == 0x43); + } + break; + case 0x0806: + need_wake = true; + default: + break; + } + } + + return need_wake; +} + +void ath6kl_config_suspend_wake_lock(struct ath6kl *ar, struct sk_buff *skb, + bool is_event_pkt) +{ + struct ath6kl_vif *vif; +#ifdef CONFIG_HAS_WAKELOCK + unsigned long wl_timeout = 5; +#endif + bool need_wake = false; + + vif = ath6kl_vif_first(ar); + if (!vif) + return; + + if ( +#ifdef CONFIG_HAS_EARLYSUSPEND + ar->screen_off && +#endif + skb && test_bit(CONNECTED, &vif->flags)) { + if (is_event_pkt) { /* Ctrl pkt received */ + need_wake = + ath6kl_parse_event_pkt_for_wake_lock(skb); + if (need_wake) { +#ifdef CONFIG_HAS_WAKELOCK + wl_timeout = 3 * HZ; +#endif + } + } else /* Data pkt received */ + need_wake = ath6kl_parse_data_pkt_for_wake_lock(ar, + skb); + } + + if (need_wake) { +#ifdef CONFIG_HAS_WAKELOCK + /* + * Keep the host wake up if there is any event + * and pkt comming in. + */ + wake_lock_timeout(&ar->wake_lock, wl_timeout); +#endif + } +} +#ifdef CONFIG_HAS_WAKELOCK +void ath6kl_p2p_acquire_wakelock(struct ath6kl *ar, int wl_timeout) +{ + if (!wake_lock_active(&ar->p2p_wake_lock)) + wake_lock_timeout(&ar->p2p_wake_lock, wl_timeout); + return; +} + +void ath6kl_p2p_release_wakelock(struct ath6kl *ar) +{ + if (wake_lock_active(&ar->p2p_wake_lock)) + wake_unlock(&ar->p2p_wake_lock); + return; +} +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ath6kl_early_suspend(struct early_suspend *handler) +{ + struct ath6kl *ar = container_of(handler, struct ath6kl, early_suspend); + + if (ar) + ar->screen_off = true; +} + +static void ath6kl_late_resume(struct early_suspend *handler) +{ + struct ath6kl *ar = container_of(handler, struct ath6kl, early_suspend); + + if (ar) + ar->screen_off = false; +} +#endif + +void ath6kl_setup_android_resource(struct ath6kl *ar) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + ar->screen_off = false; + ar->early_suspend.suspend = ath6kl_early_suspend; + ar->early_suspend.resume = ath6kl_late_resume; + ar->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + register_early_suspend(&ar->early_suspend); +#endif +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&ar->wake_lock, WAKE_LOCK_SUSPEND, "ath6kl_suspend_wl"); + wake_lock_init(&ar->p2p_wake_lock, + WAKE_LOCK_SUSPEND, + "ath6kl_p2p_suspend_wl"); +#endif +} + +void ath6kl_cleanup_android_resource(struct ath6kl *ar) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ar->early_suspend); +#endif +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_destroy(&ar->wake_lock); + wake_lock_destroy(&ar->p2p_wake_lock); +#endif +} diff --git a/drivers/net/wireless/ath/ath6kl/pm.h b/drivers/net/wireless/ath/ath6kl/pm.h new file mode 100644 index 00000000..1ac989bf --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/pm.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +void ath6kl_config_suspend_wake_lock(struct ath6kl *ar, struct sk_buff *skb, + bool is_event_pkt); +void ath6kl_setup_android_resource(struct ath6kl *ar); +void ath6kl_cleanup_android_resource(struct ath6kl *ar); +#ifdef CONFIG_HAS_WAKELOCK +void ath6kl_p2p_acquire_wakelock(struct ath6kl *ar, int wl_timeout); +void ath6kl_p2p_release_wakelock(struct ath6kl *ar); +#endif diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c new file mode 100644 index 00000000..3fe75cb8 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include "core.h" +#include "cfg80211.h" +#include "debug.h" + +static void ath6kl_recovery_work(struct work_struct *work) +{ + struct ath6kl *ar = container_of(work, struct ath6kl, + fw_recovery.recovery_work); + + ar->state = ATH6KL_STATE_RECOVERY; + + del_timer_sync(&ar->fw_recovery.hb_timer); + + ath6kl_init_hw_restart(ar); + + ar->state = ATH6KL_STATE_ON; + clear_bit(WMI_CTRL_EP_FULL, &ar->flag); + + ar->fw_recovery.err_reason = 0; + + if (ar->fw_recovery.hb_poll) + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) +{ + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n", + reason); + + set_bit(reason, &ar->fw_recovery.err_reason); + + if (ar->fw_recovery.enable && ar->state != ATH6KL_STATE_RECOVERY) + queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie) +{ + if (cookie == ar->fw_recovery.seq_num) + ar->fw_recovery.hb_pending = false; +} + +static void ath6kl_recovery_hb_timer(unsigned long data) +{ + struct ath6kl *ar = (struct ath6kl *) data; + int err; + + if (!ar->fw_recovery.enable || + !test_bit(WMI_READY, &ar->flag) || + !ar->fw_recovery.hb_poll) + return; + + if (ar->fw_recovery.hb_pending) + ar->fw_recovery.hb_misscnt++; + else + ar->fw_recovery.hb_misscnt = 0; + + if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) { + ar->fw_recovery.hb_misscnt = 0; + ar->fw_recovery.seq_num = 0; + ar->fw_recovery.hb_pending = false; + ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE); + return; + } + + ar->fw_recovery.seq_num++; + ar->fw_recovery.hb_pending = true; + + err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi, + ar->fw_recovery.seq_num, 0); + if (err) + ath6kl_warn("Failed to send hb challenge request, err:%d\n", + err); + + if ((ar->state == ATH6KL_STATE_RECOVERY) || !ar->fw_recovery.enable) + return; + + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_init(struct ath6kl *ar) +{ + struct ath6kl_fw_recovery *recovery = &ar->fw_recovery; + + recovery->enable = true; + INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work); + recovery->seq_num = 0; + recovery->hb_misscnt = 0; + ar->fw_recovery.hb_pending = false; + ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer; + ar->fw_recovery.hb_timer.data = (unsigned long) ar; + init_timer_deferrable(&ar->fw_recovery.hb_timer); + + if (ar->fw_recovery.hb_poll) + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_cleanup(struct ath6kl *ar) +{ + ar->fw_recovery.enable = false; + + del_timer_sync(&ar->fw_recovery.hb_timer); + cancel_work_sync(&ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_suspend(struct ath6kl *ar) +{ + ath6kl_recovery_cleanup(ar); + + if (!ar->fw_recovery.err_reason) + return; + + /* Process pending fw error detection */ + ar->fw_recovery.err_reason = 0; + WARN_ON(ar->state != ATH6KL_STATE_ON); + ar->state = ATH6KL_STATE_RECOVERY; + ath6kl_init_hw_restart(ar); + ar->state = ATH6KL_STATE_ON; +} + +void ath6kl_recovery_resume(struct ath6kl *ar) +{ + ar->fw_recovery.enable = true; + + if (!ar->fw_recovery.hb_poll) + return; + + ar->fw_recovery.hb_pending = false; + ar->fw_recovery.seq_num = 0; + ar->fw_recovery.hb_misscnt = 0; + mod_timer(&ar->fw_recovery.hb_timer, + jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} diff --git a/drivers/net/wireless/ath/ath6kl/regd.c b/drivers/net/wireless/ath/ath6kl/regd.c new file mode 100644 index 00000000..effe7a9f --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/regd.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include +#include "regd.h" + +/* + * The regcode init number 0x809c is provided by QUALCOMM; + * This means the Ar6005 wifi chip support 13 channel; + */ +static unsigned short reg_domain = 0x809c; +module_param(reg_domain, ushort, 0644); + +/* + * Number of bytes in board data that we are interested + * in while setting regulatory domain from host + */ +#define REG_DMN_BOARD_DATA_LEN 16 + + + +int ath6kl_set_reg_dmn(struct ath6kl *ar) +{ + u8 buf[REG_DMN_BOARD_DATA_LEN]; + __le16 old_sum, old_ver, old_rd, old_rd_next; + __le32 brd_dat_addr = 0, new_sum, new_rd; + int ret; + + if (reg_domain == 0xffff) + return 0; + printk("%s enter \n",__FUNCTION__); + ret = ath6kl_bmi_read(ar, AR6003_BOARD_DATA_ADDR, + (u8 *)&brd_dat_addr, 4); + if (ret) + return ret; + + memset(buf, 0, sizeof(buf)); + ret = ath6kl_bmi_read(ar, brd_dat_addr, buf, sizeof(buf)); + if (ret) + return ret; + + memcpy((u8 *)&old_sum, buf + AR6003_BOARD_DATA_OFFSET, 2); + memcpy((u8 *)&old_ver, buf + AR6003_BOARD_DATA_OFFSET + 2, 2); + memcpy((u8 *)&old_rd, buf + AR6003_RD_OFFSET, 2); + memcpy((u8 *)&old_rd_next, buf + AR6003_RD_OFFSET + 2, 2); + + /* + * Overwrite the new regulatory domain and preserve the + * MAC addr which is in the same word. + */ + new_rd = cpu_to_le32((le32_to_cpu(old_rd_next) << 16) + reg_domain); + ret = ath6kl_bmi_write(ar, + cpu_to_le32(le32_to_cpu(brd_dat_addr) + AR6003_RD_OFFSET), + (u8 *)&new_rd, 4); + if (ret) + return ret; + + /* + * Recompute the board data checksum with the new regulatory + * domain, preserve the version information which is in the + * same word. + */ + new_sum = cpu_to_le32((le32_to_cpu(old_ver) << 16) + + (le32_to_cpu(old_sum) ^ le32_to_cpu(old_rd) ^ + reg_domain)); + ret = ath6kl_bmi_write(ar, + cpu_to_le32(le32_to_cpu(brd_dat_addr) + + AR6003_BOARD_DATA_OFFSET), + (u8 *)&new_sum, 4); + + return ret; +} diff --git a/drivers/net/wireless/ath/ath6kl/regd.h b/drivers/net/wireless/ath/ath6kl/regd.h new file mode 100644 index 00000000..4d4756a2 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/regd.h @@ -0,0 +1,13 @@ +#ifndef REGD_H +#define REGD_H + +#include "core.h" + +#define AR6003_BOARD_DATA_ADDR 0x00540654 +#define AR6003_BOARD_DATA_INIT_ADDR 0x00540658 +#define AR6003_BOARD_DATA_OFFSET 4 +#define AR6003_RD_OFFSET 12 + +int ath6kl_set_reg_dmn(struct ath6kl *ar); + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/regd_ath.h b/drivers/net/wireless/ath/ath6kl/regd_ath.h new file mode 100644 index 00000000..03a8268c --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/regd_ath.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef REGD_H +#define REGD_H + +#include +#include + +#include "ath.h" + +enum ctl_group { + CTL_FCC = 0x10, + CTL_MKK = 0x40, + CTL_ETSI = 0x30, +}; + +#define NO_CTL 0xff +#define SD_NO_CTL 0xE0 +#define NO_CTL 0xff +#define CTL_11A 0 +#define CTL_11B 1 +#define CTL_11G 2 +#define CTL_2GHT20 5 +#define CTL_5GHT20 6 +#define CTL_2GHT40 7 +#define CTL_5GHT40 8 + +#define CTRY_DEBUG 0x1ff +#define CTRY_DEFAULT 0 + +#define COUNTRY_ERD_FLAG 0x8000 +#define WORLDWIDE_ROAMING_FLAG 0x4000 + +#define MULTI_DOMAIN_MASK 0xFF00 + +#define WORLD_SKU_MASK 0x00F0 +#define WORLD_SKU_PREFIX 0x0060 + +#define CHANNEL_HALF_BW 10 +#define CHANNEL_QUARTER_BW 5 + +struct country_code_to_enum_rd { + u16 countryCode; + u16 regDmnEnum; + const char *isoName; +}; + +enum CountryCode { + CTRY_ALBANIA = 8, + CTRY_ALGERIA = 12, + CTRY_ARGENTINA = 32, + CTRY_ARMENIA = 51, + CTRY_ARUBA = 533, + CTRY_AUSTRALIA = 36, + CTRY_AUSTRIA = 40, + CTRY_AZERBAIJAN = 31, + CTRY_BAHRAIN = 48, + CTRY_BANGLADESH = 50, + CTRY_BARBADOS = 52, + CTRY_BELARUS = 112, + CTRY_BELGIUM = 56, + CTRY_BELIZE = 84, + CTRY_BOLIVIA = 68, + CTRY_BOSNIA_HERZ = 70, + CTRY_BRAZIL = 76, + CTRY_BRUNEI_DARUSSALAM = 96, + CTRY_BULGARIA = 100, + CTRY_CAMBODIA = 116, + CTRY_CANADA = 124, + CTRY_CHILE = 152, + CTRY_CHINA = 156, + CTRY_COLOMBIA = 170, + CTRY_COSTA_RICA = 188, + CTRY_CROATIA = 191, + CTRY_CYPRUS = 196, + CTRY_CZECH = 203, + CTRY_DENMARK = 208, + CTRY_DOMINICAN_REPUBLIC = 214, + CTRY_ECUADOR = 218, + CTRY_EGYPT = 818, + CTRY_EL_SALVADOR = 222, + CTRY_ESTONIA = 233, + CTRY_FAEROE_ISLANDS = 234, + CTRY_FINLAND = 246, + CTRY_FRANCE = 250, + CTRY_GEORGIA = 268, + CTRY_GERMANY = 276, + CTRY_GREECE = 300, + CTRY_GREENLAND = 304, + CTRY_GRENADA = 308, + CTRY_GUAM = 316, + CTRY_GUATEMALA = 320, + CTRY_HAITI = 332, + CTRY_HONDURAS = 340, + CTRY_HONG_KONG = 344, + CTRY_HUNGARY = 348, + CTRY_ICELAND = 352, + CTRY_INDIA = 356, + CTRY_INDONESIA = 360, + CTRY_IRAN = 364, + CTRY_IRAQ = 368, + CTRY_IRELAND = 372, + CTRY_ISRAEL = 376, + CTRY_ITALY = 380, + CTRY_JAMAICA = 388, + CTRY_JAPAN = 392, + CTRY_JORDAN = 400, + CTRY_KAZAKHSTAN = 398, + CTRY_KENYA = 404, + CTRY_KOREA_NORTH = 408, + CTRY_KOREA_ROC = 410, + CTRY_KOREA_ROC2 = 411, + CTRY_KOREA_ROC3 = 412, + CTRY_KUWAIT = 414, + CTRY_LATVIA = 428, + CTRY_LEBANON = 422, + CTRY_LIBYA = 434, + CTRY_LIECHTENSTEIN = 438, + CTRY_LITHUANIA = 440, + CTRY_LUXEMBOURG = 442, + CTRY_MACAU = 446, + CTRY_MACEDONIA = 807, + CTRY_MALAYSIA = 458, + CTRY_MALTA = 470, + CTRY_MEXICO = 484, + CTRY_MONACO = 492, + CTRY_MOROCCO = 504, + CTRY_NEPAL = 524, + CTRY_NETHERLANDS = 528, + CTRY_NETHERLANDS_ANTILLES = 530, + CTRY_NEW_ZEALAND = 554, + CTRY_NICARAGUA = 558, + CTRY_NORWAY = 578, + CTRY_OMAN = 512, + CTRY_PAKISTAN = 586, + CTRY_PANAMA = 591, + CTRY_PAPUA_NEW_GUINEA = 598, + CTRY_PARAGUAY = 600, + CTRY_PERU = 604, + CTRY_PHILIPPINES = 608, + CTRY_POLAND = 616, + CTRY_PORTUGAL = 620, + CTRY_PUERTO_RICO = 630, + CTRY_QATAR = 634, + CTRY_ROMANIA = 642, + CTRY_RUSSIA = 643, + CTRY_SAUDI_ARABIA = 682, + CTRY_SERBIA_MONTENEGRO = 891, + CTRY_SINGAPORE = 702, + CTRY_SLOVAKIA = 703, + CTRY_SLOVENIA = 705, + CTRY_SOUTH_AFRICA = 710, + CTRY_SPAIN = 724, + CTRY_SRI_LANKA = 144, + CTRY_SWEDEN = 752, + CTRY_SWITZERLAND = 756, + CTRY_SYRIA = 760, + CTRY_TAIWAN = 158, + CTRY_THAILAND = 764, + CTRY_TRINIDAD_Y_TOBAGO = 780, + CTRY_TUNISIA = 788, + CTRY_TURKEY = 792, + CTRY_UAE = 784, + CTRY_UKRAINE = 804, + CTRY_UNITED_KINGDOM = 826, + CTRY_UNITED_STATES = 840, + CTRY_UNITED_STATES_FCC49 = 842, + CTRY_URUGUAY = 858, + CTRY_UZBEKISTAN = 860, + CTRY_VENEZUELA = 862, + CTRY_VIET_NAM = 704, + CTRY_YEMEN = 887, + CTRY_ZIMBABWE = 716, + CTRY_JAPAN1 = 393, + CTRY_JAPAN2 = 394, + CTRY_JAPAN3 = 395, + CTRY_JAPAN4 = 396, + CTRY_JAPAN5 = 397, + CTRY_JAPAN6 = 4006, + CTRY_JAPAN7 = 4007, + CTRY_JAPAN8 = 4008, + CTRY_JAPAN9 = 4009, + CTRY_JAPAN10 = 4010, + CTRY_JAPAN11 = 4011, + CTRY_JAPAN12 = 4012, + CTRY_JAPAN13 = 4013, + CTRY_JAPAN14 = 4014, + CTRY_JAPAN15 = 4015, + CTRY_JAPAN16 = 4016, + CTRY_JAPAN17 = 4017, + CTRY_JAPAN18 = 4018, + CTRY_JAPAN19 = 4019, + CTRY_JAPAN20 = 4020, + CTRY_JAPAN21 = 4021, + CTRY_JAPAN22 = 4022, + CTRY_JAPAN23 = 4023, + CTRY_JAPAN24 = 4024, + CTRY_JAPAN25 = 4025, + CTRY_JAPAN26 = 4026, + CTRY_JAPAN27 = 4027, + CTRY_JAPAN28 = 4028, + CTRY_JAPAN29 = 4029, + CTRY_JAPAN30 = 4030, + CTRY_JAPAN31 = 4031, + CTRY_JAPAN32 = 4032, + CTRY_JAPAN33 = 4033, + CTRY_JAPAN34 = 4034, + CTRY_JAPAN35 = 4035, + CTRY_JAPAN36 = 4036, + CTRY_JAPAN37 = 4037, + CTRY_JAPAN38 = 4038, + CTRY_JAPAN39 = 4039, + CTRY_JAPAN40 = 4040, + CTRY_JAPAN41 = 4041, + CTRY_JAPAN42 = 4042, + CTRY_JAPAN43 = 4043, + CTRY_JAPAN44 = 4044, + CTRY_JAPAN45 = 4045, + CTRY_JAPAN46 = 4046, + CTRY_JAPAN47 = 4047, + CTRY_JAPAN48 = 4048, + CTRY_JAPAN49 = 4049, + CTRY_JAPAN50 = 4050, + CTRY_JAPAN51 = 4051, + CTRY_JAPAN52 = 4052, + CTRY_JAPAN53 = 4053, + CTRY_JAPAN54 = 4054, + CTRY_JAPAN55 = 4055, + CTRY_JAPAN56 = 4056, + CTRY_JAPAN57 = 4057, + CTRY_JAPAN58 = 4058, + CTRY_JAPAN59 = 4059, + CTRY_AUSTRALIA2 = 5000, + CTRY_CANADA2 = 5001, + CTRY_BELGIUM2 = 5002 +}; + +bool ath_is_world_regd(struct ath_regulatory *reg); +bool ath_is_49ghz_allowed(u16 redomain); +int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)); +u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, + enum ieee80211_band band); +int ath_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct ath_regulatory *reg); + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/regd_common.h b/drivers/net/wireless/ath/ath6kl/regd_common.h new file mode 100644 index 00000000..bdd2b4d6 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/regd_common.h @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef REGD_COMMON_H +#define REGD_COMMON_H + +enum EnumRd { + NO_ENUMRD = 0x00, + NULL1_WORLD = 0x03, + NULL1_ETSIB = 0x07, + NULL1_ETSIC = 0x08, + FCC1_FCCA = 0x10, + FCC1_WORLD = 0x11, + FCC4_FCCA = 0x12, + FCC5_FCCA = 0x13, + FCC6_FCCA = 0x14, + + FCC2_FCCA = 0x20, + FCC2_WORLD = 0x21, + FCC2_ETSIC = 0x22, + FCC6_WORLD = 0x23, + FRANCE_RES = 0x31, + FCC3_FCCA = 0x3A, + FCC3_WORLD = 0x3B, + + ETSI1_WORLD = 0x37, + ETSI3_ETSIA = 0x32, + ETSI2_WORLD = 0x35, + ETSI3_WORLD = 0x36, + ETSI4_WORLD = 0x30, + ETSI4_ETSIC = 0x38, + ETSI5_WORLD = 0x39, + ETSI6_WORLD = 0x34, + ETSI_RESERVED = 0x33, + + MKK1_MKKA = 0x40, + MKK1_MKKB = 0x41, + APL4_WORLD = 0x42, + MKK2_MKKA = 0x43, + APL_RESERVED = 0x44, + APL2_WORLD = 0x45, + APL2_APLC = 0x46, + APL3_WORLD = 0x47, + MKK1_FCCA = 0x48, + APL2_APLD = 0x49, + MKK1_MKKA1 = 0x4A, + MKK1_MKKA2 = 0x4B, + MKK1_MKKC = 0x4C, + + APL3_FCCA = 0x50, + APL1_WORLD = 0x52, + APL1_FCCA = 0x53, + APL1_APLA = 0x54, + APL1_ETSIC = 0x55, + APL2_ETSIC = 0x56, + APL5_WORLD = 0x58, + APL6_WORLD = 0x5B, + APL7_FCCA = 0x5C, + APL8_WORLD = 0x5D, + APL9_WORLD = 0x5E, + + WOR0_WORLD = 0x60, + WOR1_WORLD = 0x61, + WOR2_WORLD = 0x62, + WOR3_WORLD = 0x63, + WOR4_WORLD = 0x64, + WOR5_ETSIC = 0x65, + + WOR01_WORLD = 0x66, + WOR02_WORLD = 0x67, + EU1_WORLD = 0x68, + + WOR9_WORLD = 0x69, + WORA_WORLD = 0x6A, + WORB_WORLD = 0x6B, + WORC_WORLD = 0x6C, + + MKK3_MKKB = 0x80, + MKK3_MKKA2 = 0x81, + MKK3_MKKC = 0x82, + + MKK4_MKKB = 0x83, + MKK4_MKKA2 = 0x84, + MKK4_MKKC = 0x85, + + MKK5_MKKB = 0x86, + MKK5_MKKA2 = 0x87, + MKK5_MKKC = 0x88, + + MKK6_MKKB = 0x89, + MKK6_MKKA2 = 0x8A, + MKK6_MKKC = 0x8B, + + MKK7_MKKB = 0x8C, + MKK7_MKKA2 = 0x8D, + MKK7_MKKC = 0x8E, + + MKK8_MKKB = 0x8F, + MKK8_MKKA2 = 0x90, + MKK8_MKKC = 0x91, + + MKK14_MKKA1 = 0x92, + MKK15_MKKA1 = 0x93, + + MKK10_FCCA = 0xD0, + MKK10_MKKA1 = 0xD1, + MKK10_MKKC = 0xD2, + MKK10_MKKA2 = 0xD3, + + MKK11_MKKA = 0xD4, + MKK11_FCCA = 0xD5, + MKK11_MKKA1 = 0xD6, + MKK11_MKKC = 0xD7, + MKK11_MKKA2 = 0xD8, + + MKK12_MKKA = 0xD9, + MKK12_FCCA = 0xDA, + MKK12_MKKA1 = 0xDB, + MKK12_MKKC = 0xDC, + MKK12_MKKA2 = 0xDD, + + MKK13_MKKB = 0xDE, + + MKK3_MKKA = 0xF0, + MKK3_MKKA1 = 0xF1, + MKK3_FCCA = 0xF2, + MKK4_MKKA = 0xF3, + MKK4_MKKA1 = 0xF4, + MKK4_FCCA = 0xF5, + MKK9_MKKA = 0xF6, + MKK10_MKKA = 0xF7, + MKK6_MKKA1 = 0xF8, + MKK6_FCCA = 0xF9, + MKK7_MKKA1 = 0xFA, + MKK7_FCCA = 0xFB, + MKK9_FCCA = 0xFC, + MKK9_MKKA1 = 0xFD, + MKK9_MKKC = 0xFE, + MKK9_MKKA2 = 0xFF, + + WORLD = 0x0199, + DEBUG_REG_DMN = 0x01ff, +}; + +/* Regpair to CTL band mapping */ +static struct reg_dmn_pair_mapping regDomainPairs[] = { + /* regpair, 5 GHz CTL, 2 GHz CTL */ + {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN}, + {NULL1_WORLD, NO_CTL, CTL_ETSI}, + {NULL1_ETSIB, NO_CTL, CTL_ETSI}, + {NULL1_ETSIC, NO_CTL, CTL_ETSI}, + + {FCC2_FCCA, CTL_FCC, CTL_FCC}, + {FCC2_WORLD, CTL_FCC, CTL_ETSI}, + {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC3_FCCA, CTL_FCC, CTL_FCC}, + {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC4_FCCA, CTL_FCC, CTL_FCC}, + {FCC5_FCCA, CTL_FCC, CTL_FCC}, + {FCC6_FCCA, CTL_FCC, CTL_FCC}, + {FCC6_WORLD, CTL_FCC, CTL_ETSI}, + + {ETSI1_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI2_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI3_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + + /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ + {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, + {FRANCE_RES, CTL_ETSI, CTL_ETSI}, + + {FCC1_WORLD, CTL_FCC, CTL_ETSI}, + {FCC1_FCCA, CTL_FCC, CTL_FCC}, + {APL1_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL3_WORLD, CTL_FCC, CTL_ETSI}, + {APL4_WORLD, CTL_FCC, CTL_ETSI}, + {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL6_WORLD, CTL_ETSI, CTL_ETSI}, + {APL8_WORLD, CTL_ETSI, CTL_ETSI}, + {APL9_WORLD, CTL_ETSI, CTL_ETSI}, + + {APL3_FCCA, CTL_FCC, CTL_FCC}, + {APL7_FCCA, CTL_FCC, CTL_FCC}, + {APL1_ETSIC, CTL_FCC, CTL_ETSI}, + {APL2_ETSIC, CTL_FCC, CTL_ETSI}, + {APL2_APLD, CTL_FCC, NO_CTL}, + + {MKK1_MKKA, CTL_MKK, CTL_MKK}, + {MKK1_MKKB, CTL_MKK, CTL_MKK}, + {MKK1_FCCA, CTL_MKK, CTL_FCC}, + {MKK1_MKKA1, CTL_MKK, CTL_MKK}, + {MKK1_MKKA2, CTL_MKK, CTL_MKK}, + {MKK1_MKKC, CTL_MKK, CTL_MKK}, + + {MKK2_MKKA, CTL_MKK, CTL_MKK}, + {MKK3_MKKA, CTL_MKK, CTL_MKK}, + {MKK3_MKKB, CTL_MKK, CTL_MKK}, + {MKK3_MKKA1, CTL_MKK, CTL_MKK}, + {MKK3_MKKA2, CTL_MKK, CTL_MKK}, + {MKK3_MKKC, CTL_MKK, CTL_MKK}, + {MKK3_FCCA, CTL_MKK, CTL_FCC}, + + {MKK4_MKKA, CTL_MKK, CTL_MKK}, + {MKK4_MKKB, CTL_MKK, CTL_MKK}, + {MKK4_MKKA1, CTL_MKK, CTL_MKK}, + {MKK4_MKKA2, CTL_MKK, CTL_MKK}, + {MKK4_MKKC, CTL_MKK, CTL_MKK}, + {MKK4_FCCA, CTL_MKK, CTL_FCC}, + + {MKK5_MKKB, CTL_MKK, CTL_MKK}, + {MKK5_MKKA2, CTL_MKK, CTL_MKK}, + {MKK5_MKKC, CTL_MKK, CTL_MKK}, + + {MKK6_MKKB, CTL_MKK, CTL_MKK}, + {MKK6_MKKA1, CTL_MKK, CTL_MKK}, + {MKK6_MKKA2, CTL_MKK, CTL_MKK}, + {MKK6_MKKC, CTL_MKK, CTL_MKK}, + {MKK6_FCCA, CTL_MKK, CTL_FCC}, + + {MKK7_MKKB, CTL_MKK, CTL_MKK}, + {MKK7_MKKA1, CTL_MKK, CTL_MKK}, + {MKK7_MKKA2, CTL_MKK, CTL_MKK}, + {MKK7_MKKC, CTL_MKK, CTL_MKK}, + {MKK7_FCCA, CTL_MKK, CTL_FCC}, + + {MKK8_MKKB, CTL_MKK, CTL_MKK}, + {MKK8_MKKA2, CTL_MKK, CTL_MKK}, + {MKK8_MKKC, CTL_MKK, CTL_MKK}, + + {MKK9_MKKA, CTL_MKK, CTL_MKK}, + {MKK9_FCCA, CTL_MKK, CTL_FCC}, + {MKK9_MKKA1, CTL_MKK, CTL_MKK}, + {MKK9_MKKA2, CTL_MKK, CTL_MKK}, + {MKK9_MKKC, CTL_MKK, CTL_MKK}, + + {MKK10_MKKA, CTL_MKK, CTL_MKK}, + {MKK10_FCCA, CTL_MKK, CTL_FCC}, + {MKK10_MKKA1, CTL_MKK, CTL_MKK}, + {MKK10_MKKA2, CTL_MKK, CTL_MKK}, + {MKK10_MKKC, CTL_MKK, CTL_MKK}, + + {MKK11_MKKA, CTL_MKK, CTL_MKK}, + {MKK11_FCCA, CTL_MKK, CTL_FCC}, + {MKK11_MKKA1, CTL_MKK, CTL_MKK}, + {MKK11_MKKA2, CTL_MKK, CTL_MKK}, + {MKK11_MKKC, CTL_MKK, CTL_MKK}, + + {MKK12_MKKA, CTL_MKK, CTL_MKK}, + {MKK12_FCCA, CTL_MKK, CTL_FCC}, + {MKK12_MKKA1, CTL_MKK, CTL_MKK}, + {MKK12_MKKA2, CTL_MKK, CTL_MKK}, + {MKK12_MKKC, CTL_MKK, CTL_MKK}, + + {MKK13_MKKB, CTL_MKK, CTL_MKK}, + {MKK14_MKKA1, CTL_MKK, CTL_MKK}, + {MKK15_MKKA1, CTL_MKK, CTL_MKK}, + + {WOR0_WORLD, NO_CTL, NO_CTL}, + {WOR1_WORLD, NO_CTL, NO_CTL}, + {WOR2_WORLD, NO_CTL, NO_CTL}, + {WOR3_WORLD, NO_CTL, NO_CTL}, + {WOR4_WORLD, NO_CTL, NO_CTL}, + {WOR5_ETSIC, NO_CTL, NO_CTL}, + {WOR01_WORLD, NO_CTL, NO_CTL}, + {WOR02_WORLD, NO_CTL, NO_CTL}, + {EU1_WORLD, NO_CTL, NO_CTL}, + {WOR9_WORLD, NO_CTL, NO_CTL}, + {WORA_WORLD, NO_CTL, NO_CTL}, + {WORB_WORLD, NO_CTL, NO_CTL}, + {WORC_WORLD, NO_CTL, NO_CTL}, +}; + +static struct country_code_to_enum_rd allCountries[] = { + {CTRY_DEBUG, NO_ENUMRD, "DB"}, + {CTRY_DEFAULT, FCC1_FCCA, "CO"}, + {CTRY_ALBANIA, NULL1_WORLD, "AL"}, + {CTRY_ALGERIA, NULL1_WORLD, "DZ"}, + {CTRY_ARGENTINA, FCC3_WORLD, "AR"}, + {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, + {CTRY_ARUBA, ETSI1_WORLD, "AW"}, + {CTRY_AUSTRALIA, FCC2_WORLD, "AU"}, + {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, + {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, + {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHRAIN, APL6_WORLD, "BH"}, + {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, + {CTRY_BARBADOS, FCC2_WORLD, "BB"}, + {CTRY_BELARUS, ETSI1_WORLD, "BY"}, + {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, + {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, + {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, + {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, + {CTRY_BRAZIL, FCC3_WORLD, "BR"}, + {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"}, + {CTRY_BULGARIA, ETSI6_WORLD, "BG"}, + {CTRY_CAMBODIA, ETSI1_WORLD, "KH"}, + {CTRY_CANADA, FCC3_FCCA, "CA"}, + {CTRY_CANADA2, FCC6_FCCA, "CA"}, + {CTRY_CHILE, APL6_WORLD, "CL"}, + {CTRY_CHINA, APL1_WORLD, "CN"}, + {CTRY_COLOMBIA, FCC1_FCCA, "CO"}, + {CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, + {CTRY_CROATIA, ETSI1_WORLD, "HR"}, + {CTRY_CYPRUS, ETSI1_WORLD, "CY"}, + {CTRY_CZECH, ETSI3_WORLD, "CZ"}, + {CTRY_DENMARK, ETSI1_WORLD, "DK"}, + {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO"}, + {CTRY_ECUADOR, FCC1_WORLD, "EC"}, + {CTRY_EGYPT, ETSI3_WORLD, "EG"}, + {CTRY_EL_SALVADOR, FCC1_WORLD, "SV"}, + {CTRY_ESTONIA, ETSI1_WORLD, "EE"}, + {CTRY_FINLAND, ETSI1_WORLD, "FI"}, + {CTRY_FRANCE, ETSI1_WORLD, "FR"}, + {CTRY_GEORGIA, ETSI4_WORLD, "GE"}, + {CTRY_GERMANY, ETSI1_WORLD, "DE"}, + {CTRY_GREECE, ETSI1_WORLD, "GR"}, + {CTRY_GREENLAND, ETSI1_WORLD, "GL"}, + {CTRY_GRENADA, FCC3_FCCA, "GD"}, + {CTRY_GUAM, FCC1_FCCA, "GU"}, + {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, + {CTRY_HAITI, ETSI1_WORLD, "HT"}, + {CTRY_HONDURAS, NULL1_WORLD, "HN"}, + {CTRY_HONG_KONG, FCC3_WORLD, "HK"}, + {CTRY_HUNGARY, ETSI1_WORLD, "HU"}, + {CTRY_ICELAND, ETSI1_WORLD, "IS"}, + {CTRY_INDIA, APL6_WORLD, "IN"}, + {CTRY_INDONESIA, NULL1_WORLD, "ID"}, + {CTRY_IRAN, APL1_WORLD, "IR"}, + {CTRY_IRELAND, ETSI1_WORLD, "IE"}, + {CTRY_ISRAEL, NULL1_WORLD, "IL"}, + {CTRY_ITALY, ETSI1_WORLD, "IT"}, + {CTRY_JAMAICA, FCC3_WORLD, "JM"}, + + {CTRY_JAPAN, MKK1_MKKA, "JP"}, + {CTRY_JAPAN1, MKK1_MKKB, "JP"}, + {CTRY_JAPAN2, MKK1_FCCA, "JP"}, + {CTRY_JAPAN3, MKK2_MKKA, "JP"}, + {CTRY_JAPAN4, MKK1_MKKA1, "JP"}, + {CTRY_JAPAN5, MKK1_MKKA2, "JP"}, + {CTRY_JAPAN6, MKK1_MKKC, "JP"}, + {CTRY_JAPAN7, MKK3_MKKB, "JP"}, + {CTRY_JAPAN8, MKK3_MKKA2, "JP"}, + {CTRY_JAPAN9, MKK3_MKKC, "JP"}, + {CTRY_JAPAN10, MKK4_MKKB, "JP"}, + {CTRY_JAPAN11, MKK4_MKKA2, "JP"}, + {CTRY_JAPAN12, MKK4_MKKC, "JP"}, + {CTRY_JAPAN13, MKK5_MKKB, "JP"}, + {CTRY_JAPAN14, MKK5_MKKA2, "JP"}, + {CTRY_JAPAN15, MKK5_MKKC, "JP"}, + {CTRY_JAPAN16, MKK6_MKKB, "JP"}, + {CTRY_JAPAN17, MKK6_MKKA2, "JP"}, + {CTRY_JAPAN18, MKK6_MKKC, "JP"}, + {CTRY_JAPAN19, MKK7_MKKB, "JP"}, + {CTRY_JAPAN20, MKK7_MKKA2, "JP"}, + {CTRY_JAPAN21, MKK7_MKKC, "JP"}, + {CTRY_JAPAN22, MKK8_MKKB, "JP"}, + {CTRY_JAPAN23, MKK8_MKKA2, "JP"}, + {CTRY_JAPAN24, MKK8_MKKC, "JP"}, + {CTRY_JAPAN25, MKK3_MKKA, "JP"}, + {CTRY_JAPAN26, MKK3_MKKA1, "JP"}, + {CTRY_JAPAN27, MKK3_FCCA, "JP"}, + {CTRY_JAPAN28, MKK4_MKKA1, "JP"}, + {CTRY_JAPAN29, MKK4_FCCA, "JP"}, + {CTRY_JAPAN30, MKK6_MKKA1, "JP"}, + {CTRY_JAPAN31, MKK6_FCCA, "JP"}, + {CTRY_JAPAN32, MKK7_MKKA1, "JP"}, + {CTRY_JAPAN33, MKK7_FCCA, "JP"}, + {CTRY_JAPAN34, MKK9_MKKA, "JP"}, + {CTRY_JAPAN35, MKK10_MKKA, "JP"}, + {CTRY_JAPAN36, MKK4_MKKA, "JP"}, + {CTRY_JAPAN37, MKK9_FCCA, "JP"}, + {CTRY_JAPAN38, MKK9_MKKA1, "JP"}, + {CTRY_JAPAN39, MKK9_MKKC, "JP"}, + {CTRY_JAPAN40, MKK9_MKKA2, "JP"}, + {CTRY_JAPAN41, MKK10_FCCA, "JP"}, + {CTRY_JAPAN42, MKK10_MKKA1, "JP"}, + {CTRY_JAPAN43, MKK10_MKKC, "JP"}, + {CTRY_JAPAN44, MKK10_MKKA2, "JP"}, + {CTRY_JAPAN45, MKK11_MKKA, "JP"}, + {CTRY_JAPAN46, MKK11_FCCA, "JP"}, + {CTRY_JAPAN47, MKK11_MKKA1, "JP"}, + {CTRY_JAPAN48, MKK11_MKKC, "JP"}, + {CTRY_JAPAN49, MKK11_MKKA2, "JP"}, + {CTRY_JAPAN50, MKK12_MKKA, "JP"}, + {CTRY_JAPAN51, MKK12_FCCA, "JP"}, + {CTRY_JAPAN52, MKK12_MKKA1, "JP"}, + {CTRY_JAPAN53, MKK12_MKKC, "JP"}, + {CTRY_JAPAN54, MKK12_MKKA2, "JP"}, + {CTRY_JAPAN57, MKK13_MKKB, "JP"}, + {CTRY_JAPAN58, MKK14_MKKA1, "JP"}, + {CTRY_JAPAN59, MKK15_MKKA1, "JP"}, + + {CTRY_JORDAN, ETSI2_WORLD, "JO"}, + {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ"}, + {CTRY_KOREA_NORTH, APL9_WORLD, "KP"}, + {CTRY_KOREA_ROC, APL9_WORLD, "KR"}, + {CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, + {CTRY_KOREA_ROC3, APL9_WORLD, "K3"}, + {CTRY_KUWAIT, ETSI3_WORLD, "KW"}, + {CTRY_LATVIA, ETSI1_WORLD, "LV"}, + {CTRY_LEBANON, NULL1_WORLD, "LB"}, + {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"}, + {CTRY_LITHUANIA, ETSI1_WORLD, "LT"}, + {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU"}, + {CTRY_MACAU, FCC2_WORLD, "MO"}, + {CTRY_MACEDONIA, NULL1_WORLD, "MK"}, + {CTRY_MALAYSIA, APL8_WORLD, "MY"}, + {CTRY_MALTA, ETSI1_WORLD, "MT"}, + {CTRY_MEXICO, FCC1_FCCA, "MX"}, + {CTRY_MONACO, ETSI4_WORLD, "MC"}, + {CTRY_MOROCCO, APL4_WORLD, "MA"}, + {CTRY_NEPAL, APL1_WORLD, "NP"}, + {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, + {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, + {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, + {CTRY_NORWAY, ETSI1_WORLD, "NO"}, + {CTRY_OMAN, FCC3_WORLD, "OM"}, + {CTRY_PAKISTAN, NULL1_WORLD, "PK"}, + {CTRY_PANAMA, FCC1_FCCA, "PA"}, + {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, + {CTRY_PERU, APL1_WORLD, "PE"}, + {CTRY_PHILIPPINES, APL1_WORLD, "PH"}, + {CTRY_POLAND, ETSI1_WORLD, "PL"}, + {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, + {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, + {CTRY_QATAR, APL1_WORLD, "QA"}, + {CTRY_ROMANIA, NULL1_WORLD, "RO"}, + {CTRY_RUSSIA, NULL1_WORLD, "RU"}, + {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, + {CTRY_SINGAPORE, APL6_WORLD, "SG"}, + {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, + {CTRY_SLOVENIA, ETSI1_WORLD, "SI"}, + {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA"}, + {CTRY_SPAIN, ETSI1_WORLD, "ES"}, + {CTRY_SRI_LANKA, FCC3_WORLD, "LK"}, + {CTRY_SWEDEN, ETSI1_WORLD, "SE"}, + {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, + {CTRY_SYRIA, NULL1_WORLD, "SY"}, + {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_THAILAND, FCC3_WORLD, "TH"}, + {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, + {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, + {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UKRAINE, NULL1_WORLD, "UA"}, + {CTRY_UAE, NULL1_WORLD, "AE"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, + {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, + /* This "PS" is for US public safety actually... to support this we + * would need to assign new special alpha2 to CRDA db as with the world + * regdomain and use another alpha2 */ + {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"}, + {CTRY_URUGUAY, FCC3_WORLD, "UY"}, + {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"}, + {CTRY_VENEZUELA, APL2_ETSIC, "VE"}, + {CTRY_VIET_NAM, NULL1_WORLD, "VN"}, + {CTRY_YEMEN, NULL1_WORLD, "YE"}, + {CTRY_ZIMBABWE, NULL1_WORLD, "ZW"}, +}; + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 53528648..c9c76402 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -32,7 +32,6 @@ struct ath6kl_sdio { struct sdio_func *func; - /* protects access to bus_req_freeq */ spinlock_t lock; /* free list */ @@ -54,17 +53,13 @@ struct ath6kl_sdio { atomic_t irq_handling; wait_queue_head_t irq_wq; - /* protects access to scat_req */ spinlock_t scat_lock; - bool scatter_enabled; bool is_disabled; const struct sdio_device_id *id; struct work_struct wr_async_work; struct list_head wr_asyncq; - - /* protects access to wr_asyncq */ spinlock_t wr_async_lock; }; @@ -74,6 +69,8 @@ struct ath6kl_sdio { #define CMD53_ARG_FIXED_ADDRESS 0 #define CMD53_ARG_INCR_ADDRESS 1 +extern wait_queue_head_t init_wq; + static inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar) { return ar->hif_priv; @@ -335,10 +332,10 @@ static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio, { struct hif_scatter_req *s_req; struct bus_request *bus_req; - int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz; + int i, scat_req_sz, scat_list_sz, sg_sz = 0, buf_sz; u8 *virt_buf; - scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item); + scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item); scat_req_sz = sizeof(*s_req) + scat_list_sz; if (!virt_scat) @@ -480,7 +477,6 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); sdio_claim_host(ar_sdio->func); - atomic_set(&ar_sdio->irq_handling, 0); wake_up(&ar_sdio->irq_wq); @@ -602,7 +598,7 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar) sdio_release_host(ar_sdio->func); ret = wait_event_interruptible(ar_sdio->irq_wq, - ath6kl_sdio_is_on_irq(ar)); + ath6kl_sdio_is_on_irq(ar)); if (ret) return; @@ -661,8 +657,8 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, return -EINVAL; ath6kl_dbg(ATH6KL_DBG_SCATTER, - "hif-scatter: total len: %d scatter entries: %d\n", - scat_req->len, scat_req->scat_entries); + "hif-scatter: total len: %d scatter entries: %d\n", + scat_req->len, scat_req->scat_entries); if (request & HIF_SYNCHRONOUS) status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); @@ -709,7 +705,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) { struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); struct htc_target *target = ar->htc_target; - int ret; + int ret = 0; bool virt_scat = false; if (ar_sdio->scatter_enabled) @@ -836,6 +832,7 @@ static int ath6kl_set_sdio_pm_caps(struct ath6kl *ar) return ret; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) { struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); @@ -843,22 +840,8 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) mmc_pm_flag_t flags; bool try_deepsleep = false; int ret; - - if (ar->state == ATH6KL_STATE_SCHED_SCAN) { - ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n"); - - ret = ath6kl_set_sdio_pm_caps(ar); - if (ret) - goto cut_pwr; - - ret = ath6kl_cfg80211_suspend(ar, - ATH6KL_CFG_SUSPEND_SCHED_SCAN, - NULL); - if (ret) - goto cut_pwr; - - return 0; - } + struct ath6kl_vif *vif; + int no_if_up; if (ar->suspend_mode == WLAN_POWER_STATE_WOW || (!ar->suspend_mode && wow)) { @@ -867,17 +850,28 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ret) goto cut_pwr; + // check to see if any interfaces are up + // if not, then we can skip WOW + no_if_up = 1; + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) + if (vif->ndev->flags & IFF_UP) no_if_up = 0; + spin_unlock_bh(&ar->list_lock); + + if (no_if_up) { + ret = -ENOTCONN; + } else { ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); + } if (ret && ret != -ENOTCONN) ath6kl_err("wow suspend failed: %d\n", ret); - if (ret && - (!ar->wow_suspend_mode || - ar->wow_suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP)) - try_deepsleep = true; + if (ret && (!ar->wow_suspend_mode || + ar->wow_suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP)) + try_deepsleep = true; else if (ret && ar->wow_suspend_mode == WLAN_POWER_STATE_CUT_PWR) - goto cut_pwr; + goto cut_pwr; if (!ret) return 0; } @@ -915,6 +909,9 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) } cut_pwr: + if (func->card && func->card->host) + func->card->host->pm_flags &= ~MMC_PM_KEEP_POWER; + return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL); } @@ -939,20 +936,21 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) case ATH6KL_STATE_WOW: break; - case ATH6KL_STATE_SCHED_SCAN: - break; - case ATH6KL_STATE_SUSPENDING: break; case ATH6KL_STATE_RESUMING: break; + + case ATH6KL_STATE_RECOVERY: + break; } ath6kl_cfg80211_resume(ar); return 0; } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) */ /* set the window address register (using 4-byte register access ). */ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) @@ -1025,7 +1023,7 @@ static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data) (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC); if (status) { ath6kl_err("%s: failed to read from window data addr\n", - __func__); + __func__); return status; } @@ -1254,8 +1252,10 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = { .enable_scatter = ath6kl_sdio_enable_scatter, .scat_req_rw = ath6kl_sdio_async_rw_scatter, .cleanup_scatter = ath6kl_sdio_cleanup_scatter, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) .suspend = ath6kl_sdio_suspend, .resume = ath6kl_sdio_resume, +#endif .diag_read32 = ath6kl_sdio_diag_read32, .diag_write32 = ath6kl_sdio_diag_write32, .bmi_read = ath6kl_sdio_bmi_read, @@ -1265,7 +1265,7 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = { .stop = ath6kl_sdio_stop, }; -#ifdef CONFIG_PM_SLEEP +#if defined(CONFIG_PM_SLEEP) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) /* * Empty handlers so that mmc subsystem doesn't remove us entirely during @@ -1335,13 +1335,12 @@ static int ath6kl_sdio_probe(struct sdio_func *func, INIT_LIST_HEAD(&ar_sdio->wr_asyncq); INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); - init_waitqueue_head(&ar_sdio->irq_wq); for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); - ar = ath6kl_core_create(&ar_sdio->func->dev); + ar = ath6kl_core_alloc(&ar_sdio->func->dev); if (!ar) { ath6kl_err("Failed to alloc ath6kl core\n"); ret = -ENOMEM; @@ -1368,10 +1367,11 @@ static int ath6kl_sdio_probe(struct sdio_func *func, goto err_core_alloc; } + ath6kl_notify_init_done(); return ret; err_core_alloc: - ath6kl_core_destroy(ar_sdio->ar); + ath6kl_core_free(ar_sdio->ar); err_dma: kfree(ar_sdio->dma_buffer); err_hif: @@ -1394,7 +1394,6 @@ static void ath6kl_sdio_remove(struct sdio_func *func) cancel_work_sync(&ar_sdio->wr_async_work); ath6kl_core_cleanup(ar_sdio->ar); - ath6kl_core_destroy(ar_sdio->ar); kfree(ar_sdio->dma_buffer); kfree(ar_sdio); @@ -1415,16 +1414,26 @@ static struct sdio_driver ath6kl_sdio_driver = { .id_table = ath6kl_sdio_devices, .probe = ath6kl_sdio_probe, .remove = ath6kl_sdio_remove, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) .drv.pm = ATH6KL_SDIO_PM_OPS, +#endif }; static int __init ath6kl_sdio_init(void) { int ret; + ath6kl_sdio_init_platform(); + + init_waitqueue_head(&init_wq); + ret = sdio_register_driver(&ath6kl_sdio_driver); - if (ret) + if (ret) { ath6kl_err("sdio driver registration failed: %d\n", ret); + return ret; + } + + ret = ath6kl_wait_for_init_comp(); return ret; } @@ -1432,6 +1441,7 @@ static int __init ath6kl_sdio_init(void) static void __exit ath6kl_sdio_exit(void) { sdio_unregister_driver(&ath6kl_sdio_driver); + ath6kl_sdio_exit_platform(); } module_init(ath6kl_sdio_init); diff --git a/drivers/net/wireless/ath/ath6kl/softmac.c b/drivers/net/wireless/ath/ath6kl/softmac.c new file mode 100644 index 00000000..8b223a9b --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/softmac.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include "core.h" +#include "debug.h" +#include +#define MAC_FILE "ath6k/AR6003/hw2.1.1/softmac" + +typedef char A_CHAR; +extern int android_readwrite_file(const A_CHAR *filename, A_CHAR *rbuf, const A_CHAR *wbuf, size_t length); + +/* Bleh, same offsets. */ +#define AR6003_MAC_ADDRESS_OFFSET 0x16 +#define AR6004_MAC_ADDRESS_OFFSET 0x16 + +/* Global variables, sane coding be damned. */ +u8 *ath6kl_softmac; +size_t ath6kl_softmac_len; + +static void ath6kl_calculate_crc(u32 target_type, u8 *data, size_t len) +{ + u16 *crc, *data_idx; + u16 checksum; + int i; + + if (target_type == TARGET_TYPE_AR6003) { + crc = (u16 *)(data + 0x04); + } else if (target_type == TARGET_TYPE_AR6004) { + len = 1024; + crc = (u16 *)(data + 0x04); + } else { + ath6kl_err("Invalid target type\n"); + return; + } + + ath6kl_dbg(ATH6KL_DBG_BOOT, "Old Checksum: %u\n", *crc); + + *crc = 0; + checksum = 0; + data_idx = (u16 *)data; + + for (i = 0; i < len; i += 2) { + checksum = checksum ^ (*data_idx); + data_idx++; + } + + *crc = cpu_to_le16(checksum); + + ath6kl_dbg(ATH6KL_DBG_BOOT, "New Checksum: %u\n", checksum); +} + +#ifndef WIFI_MAC_FROM_NV + +#ifdef CONFIG_MACH_PX +static int ath6kl_fetch_nvmac_info(struct ath6kl *ar) +{ + char softmac_filename[256]; + int ret = 0; + + do { + snprintf(softmac_filename, sizeof(softmac_filename), + "/data/.nvmac.info"); + + if ( (ret = android_readwrite_file( + softmac_filename, NULL, NULL, 0)) < 0) { + break; + } else { + ath6kl_softmac_len = ret; + } + ath6kl_softmac = vmalloc(ath6kl_softmac_len); + if (!ath6kl_softmac) { + ath6kl_dbg(ATH6KL_DBG_BOOT, + "%s: Cannot allocate buffer for nvmac.info" + "(%d)\n", __func__,ath6kl_softmac_len); + ret = -ENOMEM; + break; + } + + if ( (ret = android_readwrite_file(softmac_filename, + (char*)ath6kl_softmac, NULL, ath6kl_softmac_len)) != + ath6kl_softmac_len) { + ath6kl_dbg(ATH6KL_DBG_BOOT,"%s: file read error, length %d\n", + __func__, ath6kl_softmac_len); + vfree(ath6kl_softmac); + ret = -1; + break; + } + + if (!strncmp(ath6kl_softmac,"00:00:00:00:00:00",17)) { + ath6kl_dbg(ATH6KL_DBG_BOOT,"%s: mac address is zero\n", + __func__); + vfree(ath6kl_softmac); + ret = -1; + break; + } + + ret = 0; + } while (0); + + return ret; +} + +#else +static int ath6kl_fetch_mac_file(struct ath6kl *ar) +{ + const struct firmware *fw_entry; + int ret = 0; + + + ret = request_firmware(&fw_entry, MAC_FILE, ar->dev); + if (ret) + return ret; + + ath6kl_softmac_len = fw_entry->size; + ath6kl_softmac = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + + if (ath6kl_softmac == NULL) + ret = -ENOMEM; + + release_firmware(fw_entry); + + return ret; +} +#endif /* CONFIG_MACH_PX */ + +#else + +extern int read_nv(unsigned int nv_item, void *buf); + +#endif /* WIFI_MAC_FROM_NV */ + +void ath6kl_mangle_mac_address(struct ath6kl *ar, u8 locally_administered_bit) +{ + u8 *ptr_mac; + int i = 0; + int ret; +#if defined(CONFIG_MACH_PX) || defined(FIX_HUAWEI_BUTCHERING) + unsigned int softmac[6]; +#endif +#ifdef WIFI_MAC_FROM_NV + u8 nvdata[24]; +#endif + + switch (ar->target_type) { + case TARGET_TYPE_AR6003: + ptr_mac = ar->fw_board + AR6003_MAC_ADDRESS_OFFSET; + break; + case TARGET_TYPE_AR6004: + ptr_mac = ar->fw_board + AR6004_MAC_ADDRESS_OFFSET; + break; + default: + ath6kl_err("Invalid Target Type\n"); + return; + } + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "MAC from EEPROM %02X:%02X:%02X:%02X:%02X:%02X\n", + ptr_mac[0], ptr_mac[1], ptr_mac[2], + ptr_mac[3], ptr_mac[4], ptr_mac[5]); + printk("MAC from EEPROM %02X:%02X:%02X:%02X:%02X:%02X\n", + ptr_mac[0], ptr_mac[1], ptr_mac[2], + ptr_mac[3], ptr_mac[4], ptr_mac[5]); + +#ifdef WIFI_MAC_FROM_NV + nvdata[0] = (u8)i; + ret = read_nv(4678, nvdata); + if (ret == 0) { + memcpy(ptr_mac, nvdata, ETH_ALEN); + printk("MAC from NV %02X:%02X:%02X:%02X:%02X:%02X\n", + ptr_mac[0], ptr_mac[1], ptr_mac[2], + ptr_mac[3], ptr_mac[4], ptr_mac[5]); + } + +#else + +#if defined(CONFIG_MACH_PX) || defined(CONFIG_MACH_JENA) +#ifdef CONFIG_MACH_JENA + ret = ath6kl_fetch_mac_file(ar); +#else + ret = ath6kl_fetch_nvmac_info(ar); +#endif + + if (ret) { + ath6kl_err("MAC address file not found\n"); + return; + } + + if (sscanf(ath6kl_softmac, "%02x:%02x:%02x:%02x:%02x:%02x", + &softmac[0], &softmac[1], &softmac[2], + &softmac[3], &softmac[4], &softmac[5])==6) { + + for (i=0; i<6; ++i) { + ptr_mac[i] = softmac[i] & 0xff; + } + } + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "MAC from SoftMAC %02X:%02X:%02X:%02X:%02X:%02X\n", + ptr_mac[0], ptr_mac[1], ptr_mac[2], + ptr_mac[3], ptr_mac[4], ptr_mac[5]); + printk("MAC from softmac %02X:%02X:%02X:%02X:%02X:%02X\n", + softmac[0], softmac[1], softmac[2], + softmac[3], softmac[4], softmac[5]); + printk("MAC from ptr_mac %02X:%02X:%02X:%02X:%02X:%02X\n", + ptr_mac[0], ptr_mac[1], ptr_mac[2], + ptr_mac[3], ptr_mac[4], ptr_mac[5]); +#ifdef CONFIG_MACH_JENA + kfree(ath6kl_softmac); +#else + vfree(ath6kl_softmac); +#endif +#else + ret = ath6kl_fetch_mac_file(ar); + if (ret) { + ath6kl_err("MAC address file not found\n"); + return; + } + + for (i = 0; i < ETH_ALEN; ++i) { + ptr_mac[i] = ath6kl_softmac[i] & 0xff; + } + + kfree(ath6kl_softmac); +#endif /* CONFIG_MACH_PX */ + +#endif /* WIFI_MAC_FROM_NV */ + + if (locally_administered_bit) + ptr_mac[0] |= 0x02; + + if (locally_administered_bit) + ptr_mac[0] |= 0x02; + + ath6kl_calculate_crc(ar->target_type, ar->fw_board, ar->fw_board_len); +} diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index 78e0ef45..a98c12ba 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -45,6 +45,7 @@ #define LPO_CAL_ENABLE_S 20 #define LPO_CAL_ENABLE 0x00100000 +#define GPIO_PIN9_ADDRESS 0x0000004c #define GPIO_PIN10_ADDRESS 0x00000050 #define GPIO_PIN11_ADDRESS 0x00000054 #define GPIO_PIN12_ADDRESS 0x00000058 diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index 6675c92b..942537cf 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c @@ -17,8 +17,10 @@ #include "testmode.h" #include "debug.h" +#include "cfg80211.h" #include +#include "wmiconfig.h" enum ath6kl_tm_attr { __ATH6KL_TM_ATTR_INVALID = 0, @@ -33,6 +35,7 @@ enum ath6kl_tm_attr { enum ath6kl_tm_cmd { ATH6KL_TM_CMD_TCMD = 0, ATH6KL_TM_CMD_RX_REPORT = 1, /* not used anymore */ + ATH6KL_TM_CMD_WMI_CMD = 0xF000, }; #define ATH6KL_TM_DATA_MAX_LEN 5000 @@ -43,6 +46,7 @@ static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { .len = ATH6KL_TM_DATA_MAX_LEN }, }; + void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len) { struct sk_buff *skb; @@ -69,8 +73,18 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) { struct ath6kl *ar = wiphy_priv(wiphy); struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; + struct ath6kl_vif *vif; int err, buf_len; void *buf; + u32 wmi_cmd; + struct sk_buff *skb; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, ath6kl_tm_policy); @@ -81,6 +95,25 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) return -EINVAL; switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) { + case ATH6KL_TM_CMD_WMI_CMD: + if (!tb[ATH6KL_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); + buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); + + /* First four bytes hold the wmi_cmd and the rest is the data */ + skb = ath6kl_wmi_get_buf(buf_len-4); + if (!skb) + return -ENOMEM; + + memcpy(&wmi_cmd, buf, sizeof(wmi_cmd)); + memcpy(skb->data, (u32 *)buf + 1, buf_len - 4); + ath6kl_wmi_cmd_send(ar->wmi, 0, skb, wmi_cmd, NO_SYNC_WMIFLAG); + + return 0; + + break; case ATH6KL_TM_CMD_TCMD: if (!tb[ATH6KL_TM_ATTR_DATA]) return -EINVAL; diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index f85353fd..cbf51225 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -140,6 +140,8 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, if (ether_type == IP_ETHERTYPE) up = ath6kl_wmi_determine_user_priority( ip_hdr, 0); + } else { + up = 0; } traffic_class = ath6kl_wmi_get_traffic_class(up); @@ -159,8 +161,8 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, */ if (is_apsdq_empty) { ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, - vif->fw_vif_idx, - conn->aid, 1, 0); + vif->fw_vif_idx, + conn->aid, 1, 0); } *flags |= WMI_DATA_HDR_FLAGS_UAPSD; @@ -285,8 +287,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, int status = 0; struct ath6kl_cookie *cookie = NULL; - if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) + if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { + dev_kfree_skb(skb); return -EACCES; + } + + if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED || + eid >= ENDPOINT_MAX)) { + status = -EINVAL; + goto fail_ctrl_tx; + } spin_lock_bh(&ar->lock); @@ -303,7 +313,7 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n", skb, skb->len); } else - cookie = ath6kl_alloc_cookie(ar); + cookie = ath6kl_alloc_cookie(ar, eid == ar->ctrl_ep); if (cookie == NULL) { spin_unlock_bh(&ar->lock); @@ -379,7 +389,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) if (test_bit(WMI_ENABLED, &ar->flag)) { if ((dev->features & NETIF_F_IP_CSUM) && - (csum == CHECKSUM_PARTIAL)) { + (csum == CHECKSUM_PARTIAL)) { csum_start = skb->csum_start - (skb_network_header(skb) - skb->head) + sizeof(struct ath6kl_llc_snap_hdr); @@ -403,7 +413,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) } if ((dev->features & NETIF_F_IP_CSUM) && - (csum == CHECKSUM_PARTIAL)) { + (csum == CHECKSUM_PARTIAL)) { meta_v2.csum_start = csum_start; meta_v2.csum_dest = csum_dest; @@ -428,7 +438,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) } if ((vif->nw_type == ADHOC_NETWORK) && - ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags)) + ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags)) chk_adhoc_ps_mapping = true; else { /* get the stream mapping */ @@ -455,7 +465,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) } /* allocate resource for this packet */ - cookie = ath6kl_alloc_cookie(ar); + cookie = ath6kl_alloc_cookie(ar, eid == ar->ctrl_ep); if (!cookie) { spin_unlock_bh(&ar->lock); @@ -590,6 +600,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, */ set_bit(WMI_CTRL_EP_FULL, &ar->flag); ath6kl_err("wmi ctrl ep is full\n"); + ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL); return action; } @@ -600,7 +611,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, * The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for * the highest active stream. */ - if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < + if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] <= ar->hiac_stream_active_pri && ar->cookie_count <= target->endpoint[endpoint].tx_drop_packet_threshold) @@ -666,9 +677,10 @@ static void ath6kl_tx_clear_node_map(struct ath6kl_vif *vif, } } -void ath6kl_tx_complete(void *context, struct list_head *packet_queue) +void ath6kl_tx_complete(struct htc_target *target, + struct list_head *packet_queue) { - struct ath6kl *ar = context; + struct ath6kl *ar = target->dev->ar; struct sk_buff_head skb_queue; struct htc_packet *packet; struct sk_buff *skb; @@ -693,22 +705,33 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue) list); list_del(&packet->list); + if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED || + packet->endpoint >= ENDPOINT_MAX)) + continue; + ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; - if (!ath6kl_cookie) - goto fatal; + if (WARN_ON_ONCE(!ath6kl_cookie)) + continue; status = packet->status; skb = ath6kl_cookie->skb; eid = packet->endpoint; map_no = ath6kl_cookie->map_no; - if (!skb || !skb->data) - goto fatal; + if (WARN_ON_ONCE(!skb || !skb->data)) { + dev_kfree_skb(skb); + ath6kl_free_cookie(ar, ath6kl_cookie, + eid == ar->ctrl_ep); + continue; + } __skb_queue_tail(&skb_queue, skb); - if (!status && (packet->act_len != skb->len)) - goto fatal; + if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) { + ath6kl_free_cookie(ar, ath6kl_cookie, + eid == ar->ctrl_ep); + continue; + } ar->tx_pending[eid]--; @@ -733,7 +756,8 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue) vif = ath6kl_get_vif_by_index(ar, if_idx); if (!vif) { - ath6kl_free_cookie(ar, ath6kl_cookie); + ath6kl_free_cookie(ar, ath6kl_cookie, + eid == ar->ctrl_ep); continue; } @@ -764,7 +788,7 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue) ath6kl_tx_clear_node_map(vif, eid, map_no); - ath6kl_free_cookie(ar, ath6kl_cookie); + ath6kl_free_cookie(ar, ath6kl_cookie, eid == ar->ctrl_ep); if (test_bit(NETQ_STOPPED, &vif->flags)) clear_bit(NETQ_STOPPED, &vif->flags); @@ -790,11 +814,6 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue) wake_up(&ar->event_wq); return; - -fatal: - WARN_ON(1); - spin_unlock_bh(&ar->lock); - return; } void ath6kl_tx_data_cleanup(struct ath6kl *ar) @@ -883,10 +902,13 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) break; packet = (struct htc_packet *) skb->head; - if (!IS_ALIGNED((unsigned long) skb->data, 4)) + if (!IS_ALIGNED((unsigned long) skb->data, 4)) { + size_t len = skb_headlen(skb); skb->data = PTR_ALIGN(skb->data - 4, 4); + skb_set_tail_pointer(skb, len); + } set_htc_rxpkt_info(packet, skb, skb->data, - ATH6KL_BUFFER_SIZE, endpoint); + ATH6KL_BUFFER_SIZE, endpoint); list_add_tail(&packet->list, &queue); } @@ -905,8 +927,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) return; packet = (struct htc_packet *) skb->head; - if (!IS_ALIGNED((unsigned long) skb->data, 4)) + if (!IS_ALIGNED((unsigned long) skb->data, 4)) { + size_t len = skb_headlen(skb); skb->data = PTR_ALIGN(skb->data - 4, 4); + skb_set_tail_pointer(skb, len); + } set_htc_rxpkt_info(packet, skb, skb->data, ATH6KL_AMSDU_BUFFER_SIZE, 0); spin_lock_bh(&ar->lock); @@ -1031,6 +1056,7 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, rxtid = &agg_conn->rx_tid[tid]; stats = &agg_conn->stat[tid]; + spin_lock_bh(&rxtid->lock); idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); /* @@ -1049,8 +1075,6 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, seq_end = seq_no ? seq_no : rxtid->seq_next; idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz); - spin_lock_bh(&rxtid->lock); - do { node = &rxtid->hold_q[idx]; if ((order == 1) && (!node->skb)) @@ -1122,11 +1146,13 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, ((end > extended_end) && (cur > extended_end) && (cur < end))) { aggr_deque_frms(agg_conn, tid, 0, 0); + spin_lock_bh(&rxtid->lock); if (cur >= rxtid->hold_q_sz - 1) rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); else rxtid->seq_next = ATH6KL_MAX_SEQ_NO - (rxtid->hold_q_sz - 2 - cur); + spin_unlock_bh(&rxtid->lock); } else { /* * Dequeue only those frames that are outside the @@ -1180,25 +1206,27 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, aggr_deque_frms(agg_conn, tid, 0, 1); if (agg_conn->timer_scheduled) - rxtid->progress = true; - else - for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { - if (rxtid->hold_q[idx].skb) { - /* - * There is a frame in the queue and no - * timer so start a timer to ensure that - * the frame doesn't remain stuck - * forever. - */ - agg_conn->timer_scheduled = true; - mod_timer(&agg_conn->timer, - (jiffies + - HZ * (AGGR_RX_TIMEOUT) / 1000)); - rxtid->progress = false; - rxtid->timer_mon = true; - break; - } + return is_queued; + + spin_lock_bh(&rxtid->lock); + for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { + if (rxtid->hold_q[idx].skb) { + /* + * There is a frame in the queue and no + * timer so start a timer to ensure that + * the frame doesn't remain stuck + * forever. + */ + agg_conn->timer_scheduled = true; + mod_timer(&agg_conn->timer, + (jiffies + + HZ * (AGGR_RX_TIMEOUT) / 1000)); + rxtid->progress = false; + rxtid->timer_mon = true; + break; } + } + spin_unlock_bh(&rxtid->lock); return is_queued; } @@ -1266,8 +1294,8 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif, flags = 0; ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, - vif->fw_vif_idx, - conn->aid, 0, flags); + vif->fw_vif_idx, + conn->aid, 0, flags); } return; @@ -1306,15 +1334,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) skb_put(skb, packet->act_len + HTC_HDR_LENGTH); skb_pull(skb, HTC_HDR_LENGTH); - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", - skb->data, skb->len); - if (ept == ar->ctrl_ep) { - if (test_bit(WMI_ENABLED, &ar->flag)) { - ath6kl_check_wow_status(ar); - ath6kl_wmi_control_rx(ar->wmi, skb); - return; - } if_idx = wmi_cmd_hdr_get_if_idx((struct wmi_cmd_hdr *) skb->data); } else { @@ -1339,6 +1359,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) spin_unlock_bh(&vif->if_lock); + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", + skb->data, skb->len); + skb->dev = vif->ndev; if (!test_bit(WMI_ENABLED, &ar->flag)) { @@ -1348,13 +1372,19 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) return; } - ath6kl_check_wow_status(ar); + if (ept == ar->ctrl_ep) { + ath6kl_check_wow_status(ar, skb, true); + ath6kl_wmi_control_rx(ar->wmi, skb); + return; + } min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) + sizeof(struct ath6kl_llc_snap_hdr); dhdr = (struct wmi_data_hdr *) skb->data; + ath6kl_check_wow_status(ar, skb, false); + /* * In the case of AP mode we may receive NULL data frames * that do not have LLC hdr. They are 16 bytes in size. @@ -1529,6 +1559,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) return; } + ath6kl_check_wow_status(ar, skb, false); + if (vif->nw_type == AP_NETWORK) { datap = (struct ethhdr *) skb->data; if (is_multicast_ether_addr(datap->h_dest)) @@ -1575,11 +1607,12 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) aggr_conn = vif->aggr_cntxt->aggr_conn; if (aggr_process_recv_frm(aggr_conn, tid, seq_no, - is_amsdu, skb)) { + is_amsdu, skb)) { /* aggregation code will handle the skb */ return; } - } + } else if (!is_broadcast_ether_addr(datap->h_dest)) + vif->net_stats.multicast++; ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); } @@ -1613,6 +1646,7 @@ static void aggr_timeout(unsigned long arg) rxtid = &aggr_conn->rx_tid[i]; if (rxtid->aggr && rxtid->hold_q) { + spin_lock_bh(&rxtid->lock); for (j = 0; j < rxtid->hold_q_sz; j++) { if (rxtid->hold_q[j].skb) { aggr_conn->timer_scheduled = true; @@ -1621,6 +1655,7 @@ static void aggr_timeout(unsigned long arg) break; } } + spin_unlock_bh(&rxtid->lock); if (j >= rxtid->hold_q_sz) rxtid->timer_mon = false; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 325b1224..daf51222 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -353,7 +353,7 @@ static int ath6kl_usb_probe(struct usb_interface *interface, goto err_usb_put; } - ar = ath6kl_core_create(&ar_usb->udev->dev); + ar = ath6kl_core_alloc(&ar_usb->udev->dev); if (ar == NULL) { ath6kl_err("Failed to alloc ath6kl core\n"); ret = -ENOMEM; @@ -377,7 +377,7 @@ static int ath6kl_usb_probe(struct usb_interface *interface, return ret; err_core_free: - ath6kl_core_destroy(ar); + ath6kl_core_free(ar); err_usb_destroy: ath6kl_usb_destroy(ar_usb); err_usb_put: @@ -424,9 +424,10 @@ module_exit(ath6kl_usb_exit); MODULE_AUTHOR("Atheros Communications, Inc."); MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE); + +MODULE_FIRMWARE(AR6004_HW_1_0_FW_DIR "/" AR6004_HW_1_0_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); -MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 2b442332..9c7369f9 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -19,8 +19,10 @@ #include "core.h" #include "debug.h" #include "testmode.h" -#include "../regd.h" -#include "../regd_common.h" +#include "regd_ath.h" +#include "regd_common.h" +#include "btc.h" +#include "debugfs_pri.h" static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx); @@ -127,7 +129,7 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) if (!is_ethertype(be16_to_cpu(type))) { ath6kl_dbg(ATH6KL_DBG_WMI, - "%s: pkt is already in 802.3 format\n", __func__); + "%s: pkt is already in 802.3 format\n", __func__); return 0; } @@ -289,6 +291,13 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, layer2_priority); } else usr_pri = layer2_priority & 0x7; + + /* + * Queue the EAPOL frames in the same WMM_AC_VO queue + * as that of management frames. + */ + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + usr_pri = WMI_VOICE_USER_PRIORITY; } /* @@ -427,6 +436,9 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n", evt->num_msg, evt->msg_len, evt->msg_type); + if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI)) + return 0; + for (index = 0; index < evt->num_msg; index++) { size = sizeof(struct wmi_tx_complete_event) + (index * sizeof(struct tx_complete_msg_v1)); @@ -557,8 +569,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(vif->ndev, freq, 0, - ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); return 0; } @@ -597,8 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(vif->ndev, freq, 0, - ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); return 0; } @@ -715,7 +725,7 @@ int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi) cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi); cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR; cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS; - + ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID, NO_SYNC_WMIFLAG); @@ -828,8 +838,8 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 && pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) { /* WMM OUT (00:50:F2) */ - if (pie[1] > 5 && - pie[6] == WMM_PARAM_OUI_SUBTYPE) + if (pie[1] > 5 + && pie[6] == WMM_PARAM_OUI_SUBTYPE) wmi->is_wmm_enabled = true; } break; @@ -912,18 +922,22 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) regpair = ath6kl_get_regpair((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code); + if (regpair) ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", - regpair->regDmnEnum); + regpair->regDmnEnum); + else + ath6kl_warn("Regpair not found reg_code 0x%0x\n", + reg_code); } - if (country && wmi->parent_dev->wiphy_registered) { + if (country) { alpha2[0] = country->isoName[0]; alpha2[1] = country->isoName[1]; regulatory_hint(wmi->parent_dev->wiphy, alpha2); ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", - alpha2[0], alpha2[1]); + alpha2[0], alpha2[1]); } } @@ -1034,9 +1048,8 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, if (len < 8 + 2 + 2) return -EINVAL; - if (bih->frame_type == BEACON_FTYPE && - test_bit(CONNECTED, &vif->flags) && - memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) { + if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &vif->flags) + && memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) { const u8 *tim; tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, len - 8 - 2 - 2); @@ -1092,7 +1105,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, * the timer would not ever fire if the scan interval is short * enough. */ - if (ar->state == ATH6KL_STATE_SCHED_SCAN && + if (test_bit(SCHED_SCANNING, &vif->flags) && !timer_pending(&vif->sched_scan_timer)) { mod_timer(&vif->sched_scan_timer, jiffies + msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY)); @@ -1146,6 +1159,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) rate = RATE_AUTO; } else { index = reply->rate_index & 0x7f; + if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1))) + return -EINVAL; + sgi = (reply->rate_index & 0x80) ? 1 : 0; rate = wmi_rate_tbl[index][sgi]; } @@ -1368,8 +1384,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Upper threshold breached */ if (rssi < sq_thresh->upper_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious upper rssi threshold event: %d\n", - rssi); + "spurious upper rssi threshold event: %d\n", + rssi); } else if ((rssi < sq_thresh->upper_threshold[1]) && (rssi >= sq_thresh->upper_threshold[0])) { new_threshold = WMI_RSSI_THRESHOLD1_ABOVE; @@ -1392,7 +1408,7 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Lower threshold breached */ if (rssi > sq_thresh->lower_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious lower rssi threshold event: %d %d\n", + "spurious lower rssi threshold event: %d %d\n", rssi, sq_thresh->lower_threshold[0]); } else if ((rssi > sq_thresh->lower_threshold[1]) && (rssi <= sq_thresh->lower_threshold[0])) { @@ -1506,6 +1522,69 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, return 0; } +static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len, + struct ath6kl_vif *vif) +{ + struct wmi_txe_notify_event *ev; + u32 rate; + u32 pkts; + + if (len < sizeof(*ev)) + return -EINVAL; + + if (vif->sme_state != SME_CONNECTED) + return -ENOTCONN; + + ev = (struct wmi_txe_notify_event *) datap; + rate = le32_to_cpu(ev->rate); + pkts = le32_to_cpu(ev->pkts); + + ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d pkts %d\n", + vif->bssid, rate, pkts); + + cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts, + rate, vif->txe_intvl, GFP_KERNEL); + + return 0; +} + +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, + u32 rate, u32 pkts, u32 intvl) +{ + struct sk_buff *skb; + struct wmi_txe_notify_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_txe_notify_cmd *) skb->data; + cmd->rate = cpu_to_le32(rate); + cmd->pkts = cpu_to_le32(pkts); + cmd->intvl = cpu_to_le32(intvl); + + return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMD, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi) +{ + struct sk_buff *skb; + struct wmi_set_rssi_filter_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_rssi_filter_cmd *) skb->data; + cmd->rssi = rssi; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi, struct wmi_snr_threshold_params_cmd *snr_cmd) { @@ -1553,8 +1632,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Upper threshold breached */ if (snr < sq_thresh->upper_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious upper snr threshold event: %d\n", - snr); + "spurious upper snr threshold event: %d\n", + snr); } else if ((snr < sq_thresh->upper_threshold[1]) && (snr >= sq_thresh->upper_threshold[0])) { new_threshold = WMI_SNR_THRESHOLD1_ABOVE; @@ -1571,8 +1650,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Lower threshold breached */ if (snr > sq_thresh->lower_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious lower snr threshold event: %d\n", - sq_thresh->lower_threshold[0]); + "spurious lower snr threshold event: %d\n", + sq_thresh->lower_threshold[0]); } else if ((snr > sq_thresh->lower_threshold[1]) && (snr <= sq_thresh->lower_threshold[0])) { new_threshold = WMI_SNR_THRESHOLD4_BELOW; @@ -1652,8 +1731,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb, int ret; u16 info1; - if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1)))) + if (WARN_ON(skb == NULL || + (if_idx > (wmi->parent_dev->vif_max - 1)))) { + dev_kfree_skb(skb); return -EINVAL; + } ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", cmd_id, skb->len, sync_flag); @@ -1821,6 +1903,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, struct ath6kl *ar = wmi->parent_dev; int num_rates; + if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + ar->fw_capabilities)) { + return ath6kl_wmi_startscan_cmd(wmi, if_idx, + scan_type, force_fgscan, + is_legacy, home_dwell_time, + force_scan_interval, + num_chan, ch_list); + } + size = sizeof(struct wmi_begin_scan_cmd); if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) @@ -1917,6 +2008,27 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, return ret; } +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable) +{ + struct sk_buff *skb; + struct wmi_enable_sched_scan_cmd *sc; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*sc)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n", + enable ? "enabling" : "disabling", if_idx); + sc = (struct wmi_enable_sched_scan_cmd *) skb->data; + sc->enable = enable ? 1 : 0; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_ENABLE_SCHED_SCAN_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, u16 fg_end_sec, u16 bg_sec, @@ -1979,7 +2091,7 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag, struct wmi_probed_ssid_cmd *cmd; int ret; - if (index > MAX_PROBED_SSID_INDEX) + if (index >= MAX_PROBED_SSIDS) return -EINVAL; if (ssid_len > sizeof(cmd->ssid)) @@ -2245,8 +2357,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb, struct wmi_data_hdr *data_hdr; int ret; - if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) + if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) { + dev_kfree_skb(skb); return -EINVAL; + } skb_push(skb, sizeof(struct wmi_data_hdr)); @@ -2283,10 +2397,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) spin_unlock_bh(&wmi->lock); skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); - if (!skb) { - ret = -ENOMEM; - goto free_skb; - } + if (!skb) + return -ENOMEM; cmd = (struct wmi_sync_cmd *) skb->data; @@ -2309,7 +2421,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) * then do not send the Synchronize cmd on the control ep */ if (ret) - goto free_skb; + goto free_cmd_skb; /* * Send sync cmd followed by sync data messages on all @@ -2319,15 +2431,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) NO_SYNC_WMIFLAG); if (ret) - goto free_skb; - - /* cmd buffer sent, we no longer own it */ - skb = NULL; + goto free_data_skb; for (index = 0; index < num_pri_streams; index++) { if (WARN_ON(!data_sync_bufs[index].skb)) - break; + goto free_data_skb; ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, data_sync_bufs[index]. @@ -2336,17 +2445,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb, ep_id, if_idx); - if (ret) - break; - data_sync_bufs[index].skb = NULL; + + if (ret) + goto free_data_skb; } -free_skb: + return 0; + +free_cmd_skb: /* free up any resources left over (possibly due to an error) */ if (skb) dev_kfree_skb(skb); +free_data_skb: for (index = 0; index < num_pri_streams; index++) { if (data_sync_bufs[index].skb != NULL) { dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. @@ -2583,6 +2695,115 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi) spin_unlock_bh(&wmi->lock); } +static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask) +{ + struct sk_buff *skb; + int ret, mode, band; + u64 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + struct wmi_set_tx_select_rates64_cmd *cmd; + + memset(&ratemask, 0, sizeof(ratemask)); + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + /* copy legacy rate mask */ + ratemask[band] = mask->control[band].legacy; + if (band == IEEE80211_BAND_5GHZ) + ratemask[band] = + mask->control[band].legacy << 4; + + /* copy mcs rate mask */ + mcsrate = mask->control[band].mcs[1]; + mcsrate <<= 8; + mcsrate |= mask->control[band].mcs[0]; + ratemask[band] |= mcsrate << 12; + ratemask[band] |= mcsrate << 28; + } + + ath6kl_dbg(ATH6KL_DBG_WMI, + "Ratemask 64 bit: 2.4:%llx 5:%llx\n", + ratemask[0], ratemask[1]); + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data; + for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) { + /* A mode operate in 5GHZ band */ + if (mode == WMI_RATES_MODE_11A || + mode == WMI_RATES_MODE_11A_HT20 || + mode == WMI_RATES_MODE_11A_HT40) + band = IEEE80211_BAND_5GHZ; + else + band = IEEE80211_BAND_2GHZ; + cmd->ratemask[mode] = cpu_to_le64(ratemask[band]); + } + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_TX_SELECT_RATES_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask) +{ + struct sk_buff *skb; + int ret, mode, band; + u32 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + struct wmi_set_tx_select_rates32_cmd *cmd; + + memset(&ratemask, 0, sizeof(ratemask)); + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + /* copy legacy rate mask */ + ratemask[band] = mask->control[band].legacy; + if (band == IEEE80211_BAND_5GHZ) + ratemask[band] = + mask->control[band].legacy << 4; + + /* copy mcs rate mask */ + mcsrate = mask->control[band].mcs[0]; + ratemask[band] |= mcsrate << 12; + ratemask[band] |= mcsrate << 20; + } + + ath6kl_dbg(ATH6KL_DBG_WMI, + "Ratemask 32 bit: 2.4:%x 5:%x\n", + ratemask[0], ratemask[1]); + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data; + for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) { + /* A mode operate in 5GHZ band */ + if (mode == WMI_RATES_MODE_11A || + mode == WMI_RATES_MODE_11A_HT20 || + mode == WMI_RATES_MODE_11A_HT40) + band = IEEE80211_BAND_5GHZ; + else + band = IEEE80211_BAND_2GHZ; + cmd->ratemask[mode] = cpu_to_le32(ratemask[band]); + } + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_TX_SELECT_RATES_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask) +{ + struct ath6kl *ar = wmi->parent_dev; + + if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) + return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); + else + return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); +} + int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_host_mode host_mode) { @@ -2635,7 +2856,7 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, int ret; if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) && - wow_mode != ATH6KL_WOW_MODE_DISABLE) { + wow_mode != ATH6KL_WOW_MODE_DISABLE) { ath6kl_err("invalid wow mode: %d\n", wow_mode); return -EINVAL; } @@ -2882,6 +3103,43 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx, return ret; } +int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx, + enum ieee80211_band band, + struct ath6kl_htcap *htcap) +{ + struct sk_buff *skb; + struct wmi_set_htcap_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_htcap_cmd *) skb->data; + + /* + * NOTE: Band in firmware matches enum ieee80211_band, it is unlikely + * this will be changed in firmware. If at all there is any change in + * band value, the host needs to be fixed. + */ + cmd->band = band; + cmd->ht_enable = !!htcap->ht_enable; + cmd->ht20_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_20); + cmd->ht40_supported = + !!(htcap->cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40); + cmd->ht40_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_40); + cmd->intolerant_40mhz = + !!(htcap->cap_info & IEEE80211_HT_CAP_40MHZ_INTOLERANT); + cmd->max_ampdu_len_exp = htcap->ampdu_factor; + + ath6kl_dbg(ATH6KL_DBG_WMI, + "Set htcap: band:%d ht_enable:%d 40mhz:%d sgi_20mhz:%d sgi_40mhz:%d 40mhz_intolerant:%d ampdu_len_exp:%d\n", + cmd->band, cmd->ht_enable, cmd->ht40_supported, + cmd->ht20_sgi, cmd->ht40_sgi, cmd->intolerant_40mhz, + cmd->max_ampdu_len_exp); + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HT_CAP_CMDID, + NO_SYNC_WMIFLAG); +} + int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) { struct sk_buff *skb; @@ -2944,6 +3202,42 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, return ret; } +int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance) +{ + struct sk_buff *skb; + struct wmi_sta_bmiss_enhance_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data; + cmd->enable = enhance ? 1 : 0; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_STA_BMISS_ENHANCE_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) +{ + struct sk_buff *skb; + struct wmi_set_regdomain_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_regdomain_cmd *) skb->data; + memcpy(cmd->iso_name, alpha2, 2); + + return ath6kl_wmi_cmd_send(wmi, 0, skb, + WMI_SET_REGDOMAIN_CMDID, + NO_SYNC_WMIFLAG); +} + s32 ath6kl_wmi_get_rate(s8 rate_index) { if (rate_index == RATE_AUTO) @@ -3032,6 +3326,9 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac, cm->reason = cpu_to_le16(reason); cm->cmd = cmd; + ath6kl_dbg(ATH6KL_DBG_WMI, "ap_set_mlme: cmd=%d reason=%d\n", cm->cmd, + cm->reason); + return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID, NO_SYNC_WMIFLAG); } @@ -3181,6 +3478,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, NO_SYNC_WMIFLAG); } +int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, + const u8 *ie_info, u8 ie_len) +{ + struct sk_buff *skb; + struct wmi_set_ie_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u " + "ie_len=%u\n", ie_id, ie_field, ie_len); + p = (struct wmi_set_ie_cmd *) skb->data; + p->ie_id = ie_id; + p->ie_field = ie_field; + p->ie_len = ie_len; + if (ie_info != NULL && ie_len > 0) + memcpy(p->ie_info, ie_info, ie_len); + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID, + NO_SYNC_WMIFLAG); +} + int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) { struct sk_buff *skb; @@ -3392,6 +3712,91 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx) WMI_CANCEL_REMAIN_ON_CHNL_CMDID); } +int ath6kl_wmi_set_ch_params(struct wmi *wmi, u8 if_idx, + enum wmi_phy_mode phy_mode) +{ + struct sk_buff *skb; + struct wmi_set_ch_params *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_ch_params *) skb->data; + cmd->phy_mode = phy_mode; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_CHANNEL_PARAMS_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_set_acl_policy(struct wmi *wmi, u8 if_idx, bool enable_acl) +{ + struct sk_buff *skb; + struct wmi_ap_acl_policy_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_ap_acl_policy_cmd *) skb->data; + cmd->policy = enable_acl ? WMI_ACL_BLWL_MAC : 0; + + ath6kl_dbg(ATH6KL_DBG_WMI, "Set acl policy=%d\n", cmd->policy); + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_ACL_POLICY_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_set_acl_list(struct wmi *wmi, u8 if_idx, int index, + const u8 *mac_addr, + enum nl80211_acl_policy_attr acl_policy, bool reset) +{ + struct sk_buff *skb; + struct wmi_set_acl_list_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_acl_list_cmd *) skb->data; + cmd->index = index; + cmd->wildcard = 0; + memcpy(cmd->mac, mac_addr, ETH_ALEN); + if (reset) { + if (acl_policy == NL80211_ACL_POLICY_ACCEPT) + cmd->action = WMI_ACL_RESET_WHITE_LIST; + else + cmd->action = WMI_ACL_RESET_BLACK_LIST; + } else { + if (acl_policy == NL80211_ACL_POLICY_ACCEPT) + cmd->action = WMI_ACL_ADD_WHITE_MAC_ADDR; + else + cmd->action = WMI_ACL_ADD_BLACK_MAC_ADDR; + } + + ath6kl_dbg(ATH6KL_DBG_WMI, "set acl mac: index:%d action:%d mac:%pM reset:%d\n", + cmd->index, cmd->action, cmd->mac, reset); + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_ACL_MAC_LIST_CMDID, + NO_SYNC_WMIFLAG); +} + +static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmix_hb_challenge_resp_cmd *cmd; + + if (len < sizeof(struct wmix_hb_challenge_resp_cmd)) + return; + + cmd = (struct wmix_hb_challenge_resp_cmd *) datap; + ath6kl_recovery_hb_event(wmi->parent_dev, + le32_to_cpu(cmd->cookie)); +} + static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) { struct wmix_cmd_hdr *cmd; @@ -3416,6 +3821,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) switch (id) { case WMIX_HB_CHALLENGE_RESP_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); + ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len); break; case WMIX_DBGLOG_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); @@ -3435,101 +3841,32 @@ static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len) return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len); } -/* Process interface specific wmi events, caller would free the datap */ -static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id, - u8 *datap, u32 len) +/* Control Path */ +int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) { + struct wmi_cmd_hdr *cmd; struct ath6kl_vif *vif; + u32 len; + u16 id; + u8 if_idx; + u8 *datap; + int ret = 0; - vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx); - if (!vif) { - ath6kl_dbg(ATH6KL_DBG_WMI, - "Wmi event for unavailable vif, vif_index:%d\n", - if_idx); + if (WARN_ON(skb == NULL)) return -EINVAL; - } - switch (cmd_id) { - case WMI_CONNECT_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); - return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif); - case WMI_DISCONNECT_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); - return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif); - case WMI_TKIP_MICERR_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); - return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif); - case WMI_BSSINFO_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); - return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif); - case WMI_NEIGHBOR_REPORT_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); - return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len, - vif); - case WMI_SCAN_COMPLETE_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); - return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif); - case WMI_REPORT_STATISTICS_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); - return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif); - case WMI_CAC_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); - return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif); - case WMI_PSPOLL_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); - return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif); - case WMI_DTIMEXPIRY_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); - return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif); - case WMI_ADDBA_REQ_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); - return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif); - case WMI_DELBA_REQ_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); - return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif); - case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, - "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID"); - return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif); - case WMI_REMAIN_ON_CHNL_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); - return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); - case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, - "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); - return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, - len, vif); - case WMI_TX_STATUS_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); - return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif); - case WMI_RX_PROBE_REQ_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); - return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif); - case WMI_RX_ACTION_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); - return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); - default: - ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id); + if (skb->len < sizeof(struct wmi_cmd_hdr)) { + ath6kl_err("bad packet 1\n"); + dev_kfree_skb(skb); return -EINVAL; } - return 0; -} - -static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) -{ - struct wmi_cmd_hdr *cmd; - int ret = 0; - u32 len; - u16 id; - u8 if_idx; - u8 *datap; - cmd = (struct wmi_cmd_hdr *) skb->data; id = le16_to_cpu(cmd->cmd_id); if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK; skb_pull(skb, sizeof(struct wmi_cmd_hdr)); + datap = skb->data; len = skb->len; @@ -3537,6 +3874,15 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", datap, len); + vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx); + if (!vif) { + ath6kl_dbg(ATH6KL_DBG_WMI, + "Wmi event for unavailable vif, vif_index:%d\n", + if_idx); + dev_kfree_skb(skb); + return -EINVAL; + } + switch (id) { case WMI_GET_BITRATE_CMDID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n"); @@ -3553,10 +3899,30 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) case WMI_READY_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n"); ret = ath6kl_wmi_ready_event_rx(wmi, datap, len); + cfg80211_send_event_to_app(skb->dev, id, datap, len); + break; + case WMI_CONNECT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); + ret = ath6kl_wmi_connect_event_rx(wmi, datap, len, vif); + cfg80211_send_genevent_to_app(skb->dev, id, datap, len); + break; + case WMI_DISCONNECT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); + ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif); + cfg80211_send_event_to_app(skb->dev, id, datap, len); break; case WMI_PEER_NODE_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n"); ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len); + cfg80211_send_event_to_app(skb->dev, id, datap, len); + break; + case WMI_TKIP_MICERR_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); + ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif); + break; + case WMI_BSSINFO_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); + ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif); break; case WMI_REGDOMAIN_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); @@ -3565,17 +3931,36 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) case WMI_PSTREAM_TIMEOUT_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len); + cfg80211_send_event_to_app(skb->dev, id, datap, len); + break; + case WMI_NEIGHBOR_REPORT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); + ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len, + vif); + break; + case WMI_SCAN_COMPLETE_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); + ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif); + cfg80211_send_event_to_app(skb->dev, id, datap, len); break; case WMI_CMDERROR_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n"); ret = ath6kl_wmi_error_event_rx(wmi, datap, len); break; + case WMI_REPORT_STATISTICS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); + ret = ath6kl_wmi_stats_event_rx(wmi, datap, len, vif); + break; case WMI_RSSI_THRESHOLD_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n"); ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len); break; case WMI_ERROR_REPORT_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n"); +#if 0 + ath6kl_wmi_error_report_event(wmi, datap, len); +#endif + cfg80211_send_event_to_app(skb->dev, id, datap, len); break; case WMI_OPT_RX_FRAME_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n"); @@ -3589,6 +3974,10 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n"); ret = ath6kl_wmi_control_rx_xtnd(wmi, skb); break; + case WMI_CAC_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); + ret = ath6kl_wmi_cac_event_rx(wmi, datap, len, vif); + break; case WMI_CHANNEL_CHANGE_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n"); break; @@ -3605,6 +3994,7 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) break; case WMI_TX_RETRY_ERR_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n"); + cfg80211_send_event_to_app(skb->dev, id, datap, len); break; case WMI_SNR_THRESHOLD_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n"); @@ -3612,6 +4002,7 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) break; case WMI_LQ_THRESHOLD_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n"); + cfg80211_send_event_to_app(skb->dev, id, datap, len); break; case WMI_APLIST_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n"); @@ -3628,12 +4019,28 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n"); ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len); break; + case WMI_PSPOLL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); + ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif); + break; + case WMI_DTIMEXPIRY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); + ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif); + break; case WMI_SET_PARAMS_REPLY_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n"); break; + case WMI_ADDBA_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); + ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif); + break; case WMI_ADDBA_RESP_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n"); break; + case WMI_DELBA_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); + ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif); + break; case WMI_REPORT_BTCOEX_CONFIG_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n"); @@ -3646,37 +4053,54 @@ static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); ret = ath6kl_wmi_tx_complete_event_rx(datap, len); break; + case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID"); + ret = ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif); + break; + case WMI_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); + ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); + break; + case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); + ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, + len, vif); + break; + case WMI_TX_STATUS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); + ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif); + break; + case WMI_RX_PROBE_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); + ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif); + break; case WMI_P2P_CAPABILITIES_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); break; + case WMI_RX_ACTION_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); + ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); + break; case WMI_P2P_INFO_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); ret = ath6kl_wmi_p2p_info_event_rx(datap, len); break; + case WMI_TXE_NOTIFY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n"); + ret = ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif); + break; default: - /* may be the event is interface specific */ - ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len); + ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); + ret = -EINVAL; break; } dev_kfree_skb(skb); - return ret; -} -/* Control Path */ -int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) -{ - if (WARN_ON(skb == NULL)) - return -EINVAL; - - if (skb->len < sizeof(struct wmi_cmd_hdr)) { - ath6kl_err("bad packet 1\n"); - dev_kfree_skb(skb); - return -EINVAL; - } - - return ath6kl_wmi_proc_events(wmi, skb); + return ret; } void ath6kl_wmi_reset(struct wmi *wmi) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 4092e3e8..9cee4eee 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -60,6 +60,9 @@ * Use a_ prefix so that it doesn't conflict if we get proper support to * linux/types.h. */ + + + typedef __s16 __bitwise a_sle16; typedef __s32 __bitwise a_sle32; @@ -106,13 +109,13 @@ struct wmi_data_sync_bufs { #define WMM_AC_VI 2 /* video */ #define WMM_AC_VO 3 /* voice */ +#define WMI_VOICE_USER_PRIORITY 0x7 + struct wmi { u16 stream_exist_for_ac[WMM_NUM_AC]; u8 fat_pipe_exist; struct ath6kl *parent_dev; u8 pwr_mode; - - /* protects fat_pipe_exist and stream_exist_for_ac */ spinlock_t lock; enum htc_endpoint_id ep_id; struct sq_threshold_params @@ -423,6 +426,7 @@ enum wmi_cmd_id { WMI_SET_FRAMERATES_CMDID, WMI_SET_AP_PS_CMDID, WMI_SET_QOS_SUPP_CMDID, + WMI_SET_IE_CMDID, /* WMI_THIN_RESERVED_... mark the start and end * values for WMI_THIN_RESERVED command IDs. These @@ -618,6 +622,24 @@ enum wmi_cmd_id { WMI_SEND_MGMT_CMDID, WMI_BEGIN_SCAN_CMDID, + WMI_SET_BLACK_LIST, + WMI_SET_MCASTRATE, + + WMI_STA_BMISS_ENHANCE_CMDID, + + WMI_SET_REGDOMAIN_CMDID, + + WMI_SET_RSSI_FILTER_CMDID, + + WMI_SET_KEEP_ALIVE_EXT, + + WMI_VOICE_DETECTION_ENABLE_CMDID, + + WMI_SET_TXE_NOTIFY_CMD, + + WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/ + + WMI_ENABLE_SCHED_SCAN_CMDID, }; enum wmi_mgmt_frame_type { @@ -629,6 +651,11 @@ enum wmi_mgmt_frame_type { WMI_NUM_MGMT_FRAME }; +enum wmi_ie_field_type { + WMI_RSN_IE_CAPB = 0x1, + WMI_IE_FULL = 0xFF /* indicats full IE */ +}; + /* WMI_CONNECT_CMDID */ enum network_type { INFRA_NETWORK = 0x01, @@ -926,6 +953,11 @@ struct wmi_scan_params_cmd { __le32 max_dfsch_act_time; } __packed; +/* WMI_ENABLE_SCHED_SCAN_CMDID */ +struct wmi_enable_sched_scan_cmd { + u8 enable; +} __packed; + /* WMI_SET_BSS_FILTER_CMDID */ enum wmi_bss_filter { /* no beacons forwarded */ @@ -949,6 +981,9 @@ enum wmi_bss_filter { /* beacons matching probed ssid */ PROBED_SSID_FILTER, + /* beacons matching matched ssid */ + MATCHED_SSID_FILTER, + /* marker only */ LAST_BSS_FILTER, }; @@ -967,7 +1002,7 @@ struct wmi_bss_filter_cmd { } __packed; /* WMI_SET_PROBED_SSID_CMDID */ -#define MAX_PROBED_SSID_INDEX 9 +#define MAX_PROBED_SSIDS 16 enum wmi_ssid_flag { /* disables entry */ @@ -978,10 +1013,13 @@ enum wmi_ssid_flag { /* probes for any ssid */ ANY_SSID_FLAG = 0x02, + + /* match for ssid */ + MATCH_SSID_FLAG = 0x08, }; struct wmi_probed_ssid_cmd { - /* 0 to MAX_PROBED_SSID_INDEX */ + /* 0 to MAX_PROBED_SSIDS - 1 */ u8 entry_index; /* see, enum wmi_ssid_flg */ @@ -1006,6 +1044,16 @@ struct wmi_bmiss_time_cmd { __le16 num_beacons; }; +/* WMI_STA_ENHANCE_BMISS_CMDID */ +struct wmi_sta_bmiss_enhance_cmd { + u8 enable; +} __packed; + +struct wmi_set_regdomain_cmd { + u8 length; + u8 iso_name[2]; +} __packed; + /* WMI_SET_POWER_MODE_CMDID */ enum wmi_power_mode { REC_POWER = 0x01, @@ -1023,7 +1071,7 @@ struct wmi_power_mode_cmd { */ enum power_save_fail_event_policy { SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1, - IGNORE_PS_FAIL_DURING_SCAN = 2, + IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2, }; struct wmi_power_params_cmd { @@ -1037,6 +1085,36 @@ struct wmi_power_params_cmd { __le16 ps_fail_event_policy; } __packed; +/* + * Ratemask for below modes should be passed + * to WMI_SET_TX_SELECT_RATES_CMDID. + * AR6003 has 32 bit mask for each modes. + * First 12 bits for legacy rates, 13 to 20 + * bits for HT 20 rates and 21 to 28 bits for + * HT 40 rates + */ +enum wmi_mode_phy { + WMI_RATES_MODE_11A = 0, + WMI_RATES_MODE_11G, + WMI_RATES_MODE_11B, + WMI_RATES_MODE_11GONLY, + WMI_RATES_MODE_11A_HT20, + WMI_RATES_MODE_11G_HT20, + WMI_RATES_MODE_11A_HT40, + WMI_RATES_MODE_11G_HT40, + WMI_RATES_MODE_MAX +}; + +/* WMI_SET_TX_SELECT_RATES_CMDID */ +struct wmi_set_tx_select_rates32_cmd { + __le32 ratemask[WMI_RATES_MODE_MAX]; +} __packed; + +/* WMI_SET_TX_SELECT_RATES_CMDID */ +struct wmi_set_tx_select_rates64_cmd { + __le64 ratemask[WMI_RATES_MODE_MAX]; +} __packed; + /* WMI_SET_DISC_TIMEOUT_CMDID */ struct wmi_disc_timeout_cmd { /* seconds */ @@ -1142,8 +1220,17 @@ enum wmi_phy_mode { WMI_11AG_MODE = 0x3, WMI_11B_MODE = 0x4, WMI_11GONLY_MODE = 0x5, + WMI_11G_HT20 = 0x6, }; +struct wmi_set_ch_params { + u8 rsved; + u8 sca; + u8 phy_mode; + u8 no_ch; + __le16 ch_list[1]; +} __packed; + #define WMI_MAX_CHANNELS 32 /* @@ -1219,9 +1306,14 @@ struct wmi_snr_threshold_params_cmd { u8 reserved[3]; } __packed; +/* Don't report BSSs with signal (RSSI) below this threshold */ +struct wmi_set_rssi_filter_cmd { + s8 rssi; +} __packed; + enum wmi_preamble_policy { WMI_IGNORE_BARKER_IN_ERP = 0, - WMI_FOLLOW_BARKER_IN_ERP, + WMI_DONOT_IGNORE_BARKER_IN_ERP }; struct wmi_set_lpreamble_cmd { @@ -1268,6 +1360,16 @@ struct wmi_mcast_filter_add_del_cmd { u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; } __packed; +struct wmi_set_htcap_cmd { + u8 band; + u8 ht_enable; + u8 ht40_supported; + u8 ht20_sgi; + u8 ht40_sgi; + u8 intolerant_40mhz; + u8 max_ampdu_len_exp; +} __packed; + /* Command Replies */ /* WMI_GET_CHANNEL_LIST_CMDID reply */ @@ -1388,6 +1490,20 @@ enum wmi_event_id { WMI_P2P_CAPABILITIES_EVENTID, WMI_RX_ACTION_EVENTID, WMI_P2P_INFO_EVENTID, + + /* WPS Events */ + WMI_WPS_GET_STATUS_EVENTID, + WMI_WPS_PROFILE_EVENTID, + + /* more P2P events */ + WMI_NOA_INFO_EVENTID, + WMI_OPPPS_INFO_EVENTID, + WMI_PORT_STATUS_EVENTID, + + /* 802.11w */ + WMI_GET_RSN_CAP_EVENTID, + + WMI_TXE_NOTIFY_EVENTID, }; struct wmi_ready_event_2 { @@ -1449,6 +1565,17 @@ enum wmi_disconnect_reason { IBSS_MERGE = 0xe, }; +/* AP mode disconnect proto_reasons */ +enum ap_disconnect_reason { + WMI_AP_REASON_STA_LEFT = 101, + WMI_AP_REASON_FROM_HOST = 102, + WMI_AP_REASON_COMM_TIMEOUT = 103, + WMI_AP_REASON_MAX_STA = 104, + WMI_AP_REASON_ACL = 105, + WMI_AP_REASON_STA_ROAM = 106, + WMI_AP_REASON_DFS_CHANNEL = 107, +}; + #define ATH6KL_COUNTRY_RD_SHIFT 16 struct ath6kl_wmi_regdomain { @@ -1913,6 +2040,14 @@ struct wmi_set_appie_cmd { u8 ie_info[0]; } __packed; +struct wmi_set_ie_cmd { + u8 ie_id; + u8 ie_field; /* enum wmi_ie_field_type */ + u8 ie_len; + u8 reserved; + u8 ie_info[0]; +} __packed; + /* Notify the WSC registration status to the target */ #define WSC_REG_ACTIVE 1 #define WSC_REG_INACTIVE 0 @@ -1987,6 +2122,19 @@ struct wmi_del_wow_pattern_cmd { __le16 filter_id; } __packed; +/* WMI_SET_TXE_NOTIFY_CMD */ +struct wmi_txe_notify_cmd { + __le32 rate; + __le32 pkts; + __le32 intvl; +} __packed; + +/* WMI_TXE_NOTIFY_EVENTID */ +struct wmi_txe_notify_event { + __le32 rate; + __le32 pkts; +} __packed; + /* WMI_SET_AKMP_PARAMS_CMD */ struct wmi_pmkid { @@ -2178,6 +2326,35 @@ struct wmi_ap_mode_stat { struct wmi_per_sta_stat sta[AP_MAX_NUM_STA + 1]; } __packed; +#define MAX_ACL_MAC_ADDRS 10 + +/* Special mac index to notify eol */ +#define MAC_ACL_INDEX_EOL 0xff + +#define WMI_ACL_BLWL_MAC 0x3 + +enum wmi_mac_acl_action { + WMI_ACL_ADD_WHITE_MAC_ADDR = 0x01, + WMI_ACL_ADD_BLACK_MAC_ADDR, + WMI_ACL_RESET_WHITE_LIST, + WMI_ACL_RESET_BLACK_LIST, + WMI_ACL_RESET_BW_LIST = 0x10, +}; + +struct wmi_set_acl_list_cmd { + /* Takes one of actions from enum wmi_mac_acl_action */ + u8 action; + + u8 index; + u8 mac[ETH_ALEN]; + u8 wildcard; +} __packed; + +struct wmi_ap_acl_policy_cmd { + /* Type of acl that fw supports, WMI_ACL_BLWL_MAC */ + u8 policy; +} __packed; + /* End of AP mode definitions */ struct wmi_remain_on_chnl_cmd { @@ -2412,6 +2589,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, u32 home_dwell_time, u32 force_scan_interval, s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates); +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable); int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, u16 fg_end_sec, u16 bg_sec, @@ -2462,9 +2640,14 @@ int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 if_idx, u8 dbM); int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi, u8 if_idx); int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi); + int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg); +int ath6kl_wmi_ap_set_num_sta(struct wmi *wmip, u8 if_idx, u8 num_sta); int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx, u8 keep_alive_intvl); +int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx, + enum ieee80211_band band, + struct ath6kl_htcap *htcap); int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); s32 ath6kl_wmi_get_rate(s8 rate_index); @@ -2473,6 +2656,8 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, __be32 ips0, __be32 ips1); int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_host_mode host_mode); +int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask); int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_wow_mode wow_mode, u32 filter, u16 host_req_delay); @@ -2482,12 +2667,18 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, const u8 *mask); int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, u16 list_id, u16 filter_id); +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, u8 *filter, bool add_filter); +int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2); +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, + u32 rate, u32 pkts, u32 intvl); + /* AP mode uAPSD */ int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); @@ -2495,6 +2686,10 @@ int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx, u16 aid, u16 bitmap, u32 flags); +int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); +int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, + u8 *filter, bool add_filter); + u8 ath6kl_wmi_get_traffic_class(u8 user_priority); u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri); @@ -2515,6 +2710,14 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, const u8 *ie, u8 ie_len); +int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, + const u8 *ie_info, u8 ie_len); + +int ath6kl_wmi_set_acl_policy(struct wmi *wmi, u8 if_idx, bool enable_acl); +int ath6kl_wmi_set_acl_list(struct wmi *wmi, u8 if_idx, int index, + const u8 *mac_addr, + enum nl80211_acl_policy_attr acl_policy, + bool reset); /* P2P */ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); @@ -2537,9 +2740,12 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx); int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, const u8 *ie, u8 ie_len); - +int ath6kl_wmi_set_ch_params(struct wmi *wmi, u8 if_idx, + enum wmi_phy_mode phy_mode); void ath6kl_wmi_sscan_timer(unsigned long ptr); +int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); + struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); void *ath6kl_wmi_init(struct ath6kl *devt); void ath6kl_wmi_shutdown(struct wmi *wmi); diff --git a/drivers/net/wireless/ath/ath6kl/wmi_btcoex.c b/drivers/net/wireless/ath/ath6kl/wmi_btcoex.c new file mode 100644 index 00000000..0a5a8ed4 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmi_btcoex.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include +#include "core.h" +#include "wmi_btcoex.h" +#include "debug.h" + +static inline struct sk_buff *ath6kl_wmi_btcoex_get_new_buf(u32 size) +{ + struct sk_buff *skb; + + skb = ath6kl_buf_alloc(size); + if (!skb) + return NULL; + + skb_put(skb, size); + if (size) + memset(skb->data, 0, size); + + return skb; +} + +static int ath6kl_get_wmi_cmd(int nl_cmd) +{ + int wmi_cmd = 0; + switch (nl_cmd) { + case NL80211_WMI_SET_BT_STATUS: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT status\n"); + wmi_cmd = WMI_SET_BT_STATUS_CMDID; + break; + + case NL80211_WMI_SET_BT_PARAMS: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT params\n"); + wmi_cmd = WMI_SET_BT_PARAMS_CMDID; + break; + + case NL80211_WMI_SET_BT_FT_ANT: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT FT antenna\n"); + wmi_cmd = WMI_SET_BTCOEX_FE_ANT_CMDID; + break; + + case NL80211_WMI_SET_COLOCATED_BT_DEV: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT collocated dev\n"); + wmi_cmd = WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID; + break; + + case NL80211_WMI_SET_BT_INQUIRY_PAGE_CONFIG: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT inquiry page\n"); + wmi_cmd = WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID; + break; + + case NL80211_WMI_SET_BT_SCO_CONFIG: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT sco config\n"); + wmi_cmd = WMI_SET_BTCOEX_SCO_CONFIG_CMDID; + break; + + case NL80211_WMI_SET_BT_A2DP_CONFIG: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT a2dp config\n"); + wmi_cmd = WMI_SET_BTCOEX_A2DP_CONFIG_CMDID; + break; + + case NL80211_WMI_SET_BT_ACLCOEX_CONFIG: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT acl config\n"); + wmi_cmd = WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID; + break; + + case NL80211_WMI_SET_BT_DEBUG: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT bt debug\n"); + wmi_cmd = WMI_SET_BTCOEX_DEBUG_CMDID; + break; + + case NL80211_WMI_SET_BT_OPSTATUS: + ath6kl_dbg(ATH6KL_DBG_WMI, "Set BT op status\n"); + wmi_cmd = WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID; + break; + + case NL80211_WMI_GET_BT_CONFIG: + ath6kl_dbg(ATH6KL_DBG_WMI, "Get BT config\n"); + wmi_cmd = WMI_GET_BTCOEX_CONFIG_CMDID; + break; + + case NL80211_WMI_GET_BT_STATS: + ath6kl_dbg(ATH6KL_DBG_WMI, "Get BT status\n"); + wmi_cmd = WMI_GET_BTCOEX_STATS_CMDID; + break; + } + return wmi_cmd; +} + +int ath6kl_wmi_send_btcoex_cmd(struct wmi *wmi, + u8 *buf, int len) +{ + struct sk_buff *skb; + u32 nl_cmd; + int wmi_cmd; + + nl_cmd = *(u32 *)buf; + buf += sizeof(u32); + len -= sizeof(u32); + wmi_cmd = ath6kl_get_wmi_cmd(nl_cmd); + if (wmi_cmd == 0) + return -ENOMEM; + + skb = ath6kl_wmi_btcoex_get_new_buf(len); + if (!skb) + return -ENOMEM; + + memcpy(skb->data, buf, len); + + return ath6kl_wmi_cmd_send(wmi, 0, skb, + (enum wmi_cmd_id)wmi_cmd, + NO_SYNC_WMIFLAG); +} diff --git a/drivers/net/wireless/ath/ath6kl/wmi_btcoex.h b/drivers/net/wireless/ath/ath6kl/wmi_btcoex.h new file mode 100644 index 00000000..d07194ca --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmi_btcoex.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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 file contains the definitions of the WMI protocol specified in the + * Wireless Module Interface (WMI). It includes definitions of all the + * commands and events. Commands are messages from the host to the WM. + * Events and Replies are messages from the WM to the host. + */ + +#ifndef WMI_BTCOEX_H +#define WMI_BTCOEX_H + +#include + +int ath6kl_wmi_send_btcoex_cmd(struct wmi *wmi, + u8 *buf, int len); + +#endif /* WMI_BTCOEX_H */ diff --git a/drivers/net/wireless/ath/ath6kl/wmiconfig.c b/drivers/net/wireless/ath/ath6kl/wmiconfig.c new file mode 100644 index 00000000..bb60ed23 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmiconfig.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include "testmode.h" +#include "debug.h" +#include "wmi.h" + +#include + +enum ath6kl_tm_attr { + __ATH6KL_TM_ATTR_INVALID = 0, + ATH6KL_TM_ATTR_CMD = 1, + ATH6KL_TM_ATTR_DATA = 2, + + /* keep last */ + __ATH6KL_TM_ATTR_AFTER_LAST, + ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1, +}; + +enum ath6kl_tm_cmd { + ATH6KL_TM_CMD_TCMD = 0, + ATH6KL_TM_CMD_RX_REPORT = 1, /* not used anymore */ + ATH6KL_TM_CMD_WMI_CMD = 0xF000, +}; + +struct sk_buff *ath6kl_wmi_get_buf(u32 size) +{ + struct sk_buff *skb; + + skb = ath6kl_buf_alloc(size); + if (!skb) + return NULL; + + skb_put(skb, size); + if (size) + memset(skb->data, 0, size); + + return skb; +} +void ath6kl_tm_rx_wmi_event(struct ath6kl *ar, void *buf, size_t buf_len) +{ + struct sk_buff *skb; + + + if (!buf || buf_len == 0) + return; + + skb = cfg80211_testmode_alloc_event_skb(ar->wiphy, buf_len, GFP_KERNEL); + if (!skb) { + ath6kl_warn("failed to allocate testmode rx skb!\n"); + return; + } + NLA_PUT_U32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_WMI_CMD); + NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf); + cfg80211_testmode_event(skb, GFP_KERNEL); + return; + +nla_put_failure: + kfree_skb(skb); + ath6kl_warn("nla_put failed on testmode rx skb!\n"); +} + + +void ath6kl_wmicfg_send_stats(struct ath6kl_vif *vif, + struct target_stats *stats) +{ + u32 *buff = kzalloc(sizeof(*stats) + 4, GFP_KERNEL); + + buff[0] = WMI_REPORT_STATISTICS_EVENTID; + memcpy(buff+1, stats, sizeof(struct target_stats)); + ath6kl_tm_rx_wmi_event(vif->ar->wmi->parent_dev, buff, + sizeof(struct target_stats)+4); + kfree(buff); +} diff --git a/drivers/net/wireless/ath/ath6kl/wmiconfig.h b/drivers/net/wireless/ath/ath6kl/wmiconfig.h new file mode 100644 index 00000000..bcc29ae2 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmiconfig.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef WMICONFIG_H +#define WMICONFIG_H + +struct sk_buff *ath6kl_wmi_get_buf(u32 size); +void ath6kl_tm_rx_wmi_event(struct ath6kl *ar, void *buf, size_t buf_len); +void ath6kl_wmicfg_send_stats(struct ath6kl_vif *vif, + struct target_stats *stats); +#endif diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig old mode 100644 new mode 100755 index 3b8c9306..c4d4db9b --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -2,17 +2,6 @@ config ATH9K_HW tristate config ATH9K_COMMON tristate -config ATH9K_DFS_DEBUGFS - def_bool y - depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED - -config ATH9K_BTCOEX_SUPPORT - bool "Atheros bluetooth coexistence support" - depends on (ATH9K || ATH9K_HTC) - default y - ---help--- - Say Y, if you want to use the ath9k/ath9k_htc radios together with - Bluetooth modules in the same system. config ATH9K tristate "Atheros 802.11n wireless cards support" @@ -62,33 +51,6 @@ config ATH9K_DEBUGFS Also required for changing debug message flags at run time. -config ATH9K_DFS_CERTIFIED - bool "Atheros DFS support for certified platforms" - depends on ATH9K && EXPERT - default n - ---help--- - This option enables DFS support for initiating radiation on - ath9k. There is no way to dynamically detect if a card was DFS - certified and as such this is left as a build time option. This - option should only be enabled by system integrators that can - guarantee that all the platforms that their kernel will run on - have obtained appropriate regulatory body certification for a - respective Atheros card by using ath9k on the target shipping - platforms. - - This is currently only a placeholder for future DFS support, - as DFS support requires more components that still need to be - developed. At this point enabling this option won't do anything - except increase code size. - -config ATH9K_MAC_DEBUG - bool "Atheros MAC statistics" - depends on ATH9K_DEBUGFS - default y - ---help--- - This option enables collection of statistics for Rx/Tx status - data and some other MAC related statistics - config ATH9K_LEGACY_RATE_CONTROL bool "Atheros ath9k rate control" depends on ATH9K diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 24ae2e6a..49d3f25f 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -3,15 +3,13 @@ ath9k-y += beacon.o \ init.o \ main.o \ recv.o \ - xmit.o + xmit.o \ + mci.o \ -ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o -ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o +ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o -ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o -ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o obj-$(CONFIG_ATH9K) += ath9k.o @@ -31,14 +29,13 @@ ath9k_hw-y:= \ eeprom_4k.o \ eeprom_9287.o \ ani.o \ + btcoex.o \ mac.o \ ar9002_mac.o \ ar9003_mac.o \ ar9003_eeprom.o \ ar9003_paprd.o -ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ - ar9003_mci.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 7e0ea4e9..a639b94f 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -136,8 +136,8 @@ static void ath9k_ani_restart(struct ath_hw *ah) cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; } - ath_dbg(common, ANI, "Writing ofdmbase=%u cckbase=%u\n", - ofdm_base, cck_base); + ath_dbg(common, ATH_DBG_ANI, + "Writing ofdmbase=%u cckbase=%u\n", ofdm_base, cck_base); ENABLE_REGWRITE_BUFFER(ah); @@ -268,7 +268,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) aniState->noiseFloor = BEACON_RSSI(ah); - ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", + ath_dbg(common, ATH_DBG_ANI, + "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", aniState->ofdmNoiseImmunityLevel, immunityLevel, aniState->noiseFloor, aniState->rssiThrLow, aniState->rssiThrHigh); @@ -335,7 +336,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) const struct ani_cck_level_entry *entry_cck; aniState->noiseFloor = BEACON_RSSI(ah); - ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", + ath_dbg(common, ATH_DBG_ANI, + "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", aniState->cckNoiseImmunityLevel, immunityLevel, aniState->noiseFloor, aniState->rssiThrLow, aniState->rssiThrHigh); @@ -407,20 +409,20 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah) if (aniState->ofdmWeakSigDetectOff) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true)) + true) == true) return; } if (aniState->firstepLevel > 0) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) + aniState->firstepLevel - 1) == true) return; } } else { if (aniState->firstepLevel > 0) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) + aniState->firstepLevel - 1) == true) return; } } @@ -479,7 +481,8 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) if (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC) { - ath_dbg(common, ANI, "Reset ANI state opmode %u\n", ah->opmode); + ath_dbg(common, ATH_DBG_ANI, + "Reset ANI state opmode %u\n", ah->opmode); ah->stats.ast_ani_reset++; if (ah->opmode == NL80211_IFTYPE_AP) { @@ -579,7 +582,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) ATH9K_ANI_OFDM_DEF_LEVEL || aniState->cckNoiseImmunityLevel != ATH9K_ANI_CCK_DEF_LEVEL) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, @@ -596,7 +599,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) /* * restore historical levels for this channel */ - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, @@ -659,7 +662,7 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) { if (phyCnt1 < ofdm_base) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "phyCnt1 0x%x, resetting counter value to 0x%x\n", phyCnt1, ofdm_base); REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); @@ -667,7 +670,7 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) AR_PHY_ERR_OFDM_TIMING); } if (phyCnt2 < cck_base) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "phyCnt2 0x%x, resetting counter value to 0x%x\n", phyCnt2, cck_base); REG_WRITE(ah, AR_PHY_ERR_2, cck_base); @@ -710,7 +713,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) cckPhyErrRate = aniState->cckPhyErrCount * 1000 / aniState->listenTime; - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", aniState->listenTime, aniState->ofdmNoiseImmunityLevel, @@ -745,7 +748,7 @@ void ath9k_enable_mib_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - ath_dbg(common, ANI, "Enable MIB counters\n"); + ath_dbg(common, ATH_DBG_ANI, "Enable MIB counters\n"); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -767,7 +770,7 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - ath_dbg(common, ANI, "Disable MIB counters\n"); + ath_dbg(common, ATH_DBG_ANI, "Disable MIB counters\n"); REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -842,7 +845,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); int i; - ath_dbg(common, ANI, "Initialize ANI\n"); + ath_dbg(common, ATH_DBG_ANI, "Initialize ANI\n"); if (use_new_ani(ah)) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index aba08800..f199e9e2 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -158,7 +158,7 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq) /* pre-reverse this field */ tmp_reg = ath9k_hw_reverse_bits(new_bias, 3); - ath_dbg(common, CONFIG, "Force rf_pwd_icsyndiv to %1d on %4d\n", + ath_dbg(common, ATH_DBG_CONFIG, "Force rf_pwd_icsyndiv to %1d on %4d\n", new_bias, synth_freq); /* swizzle rf_pwd_icsyndiv */ @@ -489,6 +489,8 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows); ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows); ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows); + ATH_ALLOC_BANK(ah->addac5416_21, + ah->iniAddac.ia_rows * ah->iniAddac.ia_columns); ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows); return 0; @@ -517,6 +519,7 @@ static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah) ATH_FREE_BANK(ah->analogBank6Data); ATH_FREE_BANK(ah->analogBank6TPCData); ATH_FREE_BANK(ah->analogBank7Data); + ATH_FREE_BANK(ah->addac5416_21); ATH_FREE_BANK(ah->bank6Temp); #undef ATH_FREE_BANK @@ -802,7 +805,27 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, if (ah->eep_ops->set_addac) ah->eep_ops->set_addac(ah, chan); - REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); + if (AR_SREV_5416_22_OR_LATER(ah)) { + REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); + } else { + struct ar5416IniArray temp; + u32 addacSize = + sizeof(u32) * ah->iniAddac.ia_rows * + ah->iniAddac.ia_columns; + + /* For AR5416 2.0/2.1 */ + memcpy(ah->addac5416_21, + ah->iniAddac.ia_array, addacSize); + + /* override CLKDRV value at [row, column] = [31, 1] */ + (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; + + temp.ia_array = ah->addac5416_21; + temp.ia_columns = ah->iniAddac.ia_columns; + temp.ia_rows = ah->iniAddac.ia_rows; + REG_WRITE_ARRAY(&temp, 1, regWrites); + } + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); ENABLE_REGWRITE_BUFFER(ah); @@ -834,10 +857,9 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, AR_SREV_9287_11_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); - if (AR_SREV_9271_10(ah)) { - REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENA); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_ADC_ON, 0xa); - } + if (AR_SREV_9271_10(ah)) + REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, + modesIndex, regWrites); ENABLE_REGWRITE_BUFFER(ah); @@ -859,17 +881,27 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REGWRITE_BUFFER_FLUSH(ah); + if (AR_SREV_9271(ah)) { + if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1) + REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271, + modesIndex, regWrites); + else + REG_WRITE_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, + modesIndex, regWrites); + } + REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); - if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex, + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) { + REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); + } ar5008_hw_override_ini(ah, chan); ar5008_hw_set_channel_regs(ah, chan); ar5008_hw_init_chain_masks(ah); ath9k_olc_init(ah); - ath9k_hw_apply_txpower(ah, chan, false); + ath9k_hw_apply_txpower(ah, chan); /* Write analog registers */ if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { @@ -1021,7 +1053,8 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { - ath_dbg(common, ANI, "level out of range (%u > %zu)\n", + ath_dbg(common, ATH_DBG_ANI, + "level out of range (%u > %zu)\n", level, ARRAY_SIZE(ah->totalSizeDesired)); return false; } @@ -1124,7 +1157,8 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(firstep)) { - ath_dbg(common, ANI, "level out of range (%u > %zu)\n", + ath_dbg(common, ATH_DBG_ANI, + "level out of range (%u > %zu)\n", level, ARRAY_SIZE(firstep)); return false; } @@ -1143,7 +1177,8 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(cycpwrThr1)) { - ath_dbg(common, ANI, "level out of range (%u > %zu)\n", + ath_dbg(common, ATH_DBG_ANI, + "level out of range (%u > %zu)\n", level, ARRAY_SIZE(cycpwrThr1)); return false; } @@ -1160,22 +1195,23 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, case ATH9K_ANI_PRESENT: break; default: - ath_dbg(common, ANI, "invalid cmd %u\n", cmd); + ath_dbg(common, ATH_DBG_ANI, "invalid cmd %u\n", cmd); return false; } - ath_dbg(common, ANI, "ANI parameters:\n"); - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "ANI parameters:\n"); + ath_dbg(common, ATH_DBG_ANI, "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n", aniState->noiseImmunityLevel, aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff); - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n", aniState->cckWeakSigThreshold, aniState->firstepLevel, aniState->listenTime); - ath_dbg(common, ANI, "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", + ath_dbg(common, ATH_DBG_ANI, + "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); @@ -1259,7 +1295,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); if (!on != aniState->ofdmWeakSigDetectOff) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: ofdm weak signal: %s=>%s\n", chan->channel, !aniState->ofdmWeakSigDetectOff ? @@ -1277,7 +1313,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(firstep_table)) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n", level, ARRAY_SIZE(firstep_table)); return false; @@ -1314,7 +1350,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, AR_PHY_FIND_SIG_FIRSTEP_LOW, value2); if (level != aniState->firstepLevel) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", chan->channel, aniState->firstepLevel, @@ -1322,7 +1358,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, ATH9K_ANI_FIRSTEP_LVL_NEW, value, aniState->iniDef.firstep); - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] firstep_low[level]=%d ini=%d\n", chan->channel, aniState->firstepLevel, @@ -1342,7 +1378,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(cycpwrThr1_table)) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n", level, ARRAY_SIZE(cycpwrThr1_table)); return false; @@ -1378,7 +1414,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2); if (level != aniState->spurImmunityLevel) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n", chan->channel, aniState->spurImmunityLevel, @@ -1386,7 +1422,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, ATH9K_ANI_SPUR_IMMUNE_LVL_NEW, value, aniState->iniDef.cycpwrThr1); - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n", chan->channel, aniState->spurImmunityLevel, @@ -1412,11 +1448,11 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_PRESENT: break; default: - ath_dbg(common, ANI, "invalid cmd %u\n", cmd); + ath_dbg(common, ATH_DBG_ANI, "invalid cmd %u\n", cmd); return false; } - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n", aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff ? "on" : "off", @@ -1470,7 +1506,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) iniDef = &aniState->iniDef; - ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", + ath_dbg(common, ATH_DBG_ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", ah->hw_version.macVersion, ah->hw_version.macRev, ah->opmode, diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h index ea4a2309..e8bdc754 100644 --- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h @@ -459,6 +459,97 @@ static const u32 ar5416Common_9100[][2] = { {0x0000a3e0, 0x000001ce}, }; +static const u32 ar5416Bank0_9100[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x1e5795e5}, + {0x000098e0, 0x02008020}, +}; + +static const u32 ar5416BB_RfGain_9100[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00009a00, 0x00000000, 0x00000000}, + {0x00009a04, 0x00000040, 0x00000040}, + {0x00009a08, 0x00000080, 0x00000080}, + {0x00009a0c, 0x000001a1, 0x00000141}, + {0x00009a10, 0x000001e1, 0x00000181}, + {0x00009a14, 0x00000021, 0x000001c1}, + {0x00009a18, 0x00000061, 0x00000001}, + {0x00009a1c, 0x00000168, 0x00000041}, + {0x00009a20, 0x000001a8, 0x000001a8}, + {0x00009a24, 0x000001e8, 0x000001e8}, + {0x00009a28, 0x00000028, 0x00000028}, + {0x00009a2c, 0x00000068, 0x00000068}, + {0x00009a30, 0x00000189, 0x000000a8}, + {0x00009a34, 0x000001c9, 0x00000169}, + {0x00009a38, 0x00000009, 0x000001a9}, + {0x00009a3c, 0x00000049, 0x000001e9}, + {0x00009a40, 0x00000089, 0x00000029}, + {0x00009a44, 0x00000170, 0x00000069}, + {0x00009a48, 0x000001b0, 0x00000190}, + {0x00009a4c, 0x000001f0, 0x000001d0}, + {0x00009a50, 0x00000030, 0x00000010}, + {0x00009a54, 0x00000070, 0x00000050}, + {0x00009a58, 0x00000191, 0x00000090}, + {0x00009a5c, 0x000001d1, 0x00000151}, + {0x00009a60, 0x00000011, 0x00000191}, + {0x00009a64, 0x00000051, 0x000001d1}, + {0x00009a68, 0x00000091, 0x00000011}, + {0x00009a6c, 0x000001b8, 0x00000051}, + {0x00009a70, 0x000001f8, 0x00000198}, + {0x00009a74, 0x00000038, 0x000001d8}, + {0x00009a78, 0x00000078, 0x00000018}, + {0x00009a7c, 0x00000199, 0x00000058}, + {0x00009a80, 0x000001d9, 0x00000098}, + {0x00009a84, 0x00000019, 0x00000159}, + {0x00009a88, 0x00000059, 0x00000199}, + {0x00009a8c, 0x00000099, 0x000001d9}, + {0x00009a90, 0x000000d9, 0x00000019}, + {0x00009a94, 0x000000f9, 0x00000059}, + {0x00009a98, 0x000000f9, 0x00000099}, + {0x00009a9c, 0x000000f9, 0x000000d9}, + {0x00009aa0, 0x000000f9, 0x000000f9}, + {0x00009aa4, 0x000000f9, 0x000000f9}, + {0x00009aa8, 0x000000f9, 0x000000f9}, + {0x00009aac, 0x000000f9, 0x000000f9}, + {0x00009ab0, 0x000000f9, 0x000000f9}, + {0x00009ab4, 0x000000f9, 0x000000f9}, + {0x00009ab8, 0x000000f9, 0x000000f9}, + {0x00009abc, 0x000000f9, 0x000000f9}, + {0x00009ac0, 0x000000f9, 0x000000f9}, + {0x00009ac4, 0x000000f9, 0x000000f9}, + {0x00009ac8, 0x000000f9, 0x000000f9}, + {0x00009acc, 0x000000f9, 0x000000f9}, + {0x00009ad0, 0x000000f9, 0x000000f9}, + {0x00009ad4, 0x000000f9, 0x000000f9}, + {0x00009ad8, 0x000000f9, 0x000000f9}, + {0x00009adc, 0x000000f9, 0x000000f9}, + {0x00009ae0, 0x000000f9, 0x000000f9}, + {0x00009ae4, 0x000000f9, 0x000000f9}, + {0x00009ae8, 0x000000f9, 0x000000f9}, + {0x00009aec, 0x000000f9, 0x000000f9}, + {0x00009af0, 0x000000f9, 0x000000f9}, + {0x00009af4, 0x000000f9, 0x000000f9}, + {0x00009af8, 0x000000f9, 0x000000f9}, + {0x00009afc, 0x000000f9, 0x000000f9}, +}; + +static const u32 ar5416Bank1_9100[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x02108421}, + {0x000098ec, 0x00000008}, +}; + +static const u32 ar5416Bank2_9100[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x0e73ff17}, + {0x000098e0, 0x00000420}, +}; + +static const u32 ar5416Bank3_9100[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x000098f0, 0x01400018, 0x01c00018}, +}; + static const u32 ar5416Bank6_9100[][3] = { /* Addr 5G_HT20 5G_HT40 */ {0x0000989c, 0x00000000, 0x00000000}, @@ -533,6 +624,13 @@ static const u32 ar5416Bank6TPC_9100[][3] = { {0x000098d0, 0x0000000f, 0x0010000f}, }; +static const u32 ar5416Bank7_9100[][2] = { + /* Addr allmodes */ + {0x0000989c, 0x00000500}, + {0x0000989c, 0x00000800}, + {0x000098cc, 0x0000000e}, +}; + static const u32 ar5416Addac_9100[][2] = { /* Addr allmodes */ {0x0000989c, 0x00000000}, @@ -1015,6 +1113,178 @@ static const u32 ar5416Common_9160[][2] = { {0x0000a3e0, 0x000001ce}, }; +static const u32 ar5416Bank0_9160[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x1e5795e5}, + {0x000098e0, 0x02008020}, +}; + +static const u32 ar5416BB_RfGain_9160[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00009a00, 0x00000000, 0x00000000}, + {0x00009a04, 0x00000040, 0x00000040}, + {0x00009a08, 0x00000080, 0x00000080}, + {0x00009a0c, 0x000001a1, 0x00000141}, + {0x00009a10, 0x000001e1, 0x00000181}, + {0x00009a14, 0x00000021, 0x000001c1}, + {0x00009a18, 0x00000061, 0x00000001}, + {0x00009a1c, 0x00000168, 0x00000041}, + {0x00009a20, 0x000001a8, 0x000001a8}, + {0x00009a24, 0x000001e8, 0x000001e8}, + {0x00009a28, 0x00000028, 0x00000028}, + {0x00009a2c, 0x00000068, 0x00000068}, + {0x00009a30, 0x00000189, 0x000000a8}, + {0x00009a34, 0x000001c9, 0x00000169}, + {0x00009a38, 0x00000009, 0x000001a9}, + {0x00009a3c, 0x00000049, 0x000001e9}, + {0x00009a40, 0x00000089, 0x00000029}, + {0x00009a44, 0x00000170, 0x00000069}, + {0x00009a48, 0x000001b0, 0x00000190}, + {0x00009a4c, 0x000001f0, 0x000001d0}, + {0x00009a50, 0x00000030, 0x00000010}, + {0x00009a54, 0x00000070, 0x00000050}, + {0x00009a58, 0x00000191, 0x00000090}, + {0x00009a5c, 0x000001d1, 0x00000151}, + {0x00009a60, 0x00000011, 0x00000191}, + {0x00009a64, 0x00000051, 0x000001d1}, + {0x00009a68, 0x00000091, 0x00000011}, + {0x00009a6c, 0x000001b8, 0x00000051}, + {0x00009a70, 0x000001f8, 0x00000198}, + {0x00009a74, 0x00000038, 0x000001d8}, + {0x00009a78, 0x00000078, 0x00000018}, + {0x00009a7c, 0x00000199, 0x00000058}, + {0x00009a80, 0x000001d9, 0x00000098}, + {0x00009a84, 0x00000019, 0x00000159}, + {0x00009a88, 0x00000059, 0x00000199}, + {0x00009a8c, 0x00000099, 0x000001d9}, + {0x00009a90, 0x000000d9, 0x00000019}, + {0x00009a94, 0x000000f9, 0x00000059}, + {0x00009a98, 0x000000f9, 0x00000099}, + {0x00009a9c, 0x000000f9, 0x000000d9}, + {0x00009aa0, 0x000000f9, 0x000000f9}, + {0x00009aa4, 0x000000f9, 0x000000f9}, + {0x00009aa8, 0x000000f9, 0x000000f9}, + {0x00009aac, 0x000000f9, 0x000000f9}, + {0x00009ab0, 0x000000f9, 0x000000f9}, + {0x00009ab4, 0x000000f9, 0x000000f9}, + {0x00009ab8, 0x000000f9, 0x000000f9}, + {0x00009abc, 0x000000f9, 0x000000f9}, + {0x00009ac0, 0x000000f9, 0x000000f9}, + {0x00009ac4, 0x000000f9, 0x000000f9}, + {0x00009ac8, 0x000000f9, 0x000000f9}, + {0x00009acc, 0x000000f9, 0x000000f9}, + {0x00009ad0, 0x000000f9, 0x000000f9}, + {0x00009ad4, 0x000000f9, 0x000000f9}, + {0x00009ad8, 0x000000f9, 0x000000f9}, + {0x00009adc, 0x000000f9, 0x000000f9}, + {0x00009ae0, 0x000000f9, 0x000000f9}, + {0x00009ae4, 0x000000f9, 0x000000f9}, + {0x00009ae8, 0x000000f9, 0x000000f9}, + {0x00009aec, 0x000000f9, 0x000000f9}, + {0x00009af0, 0x000000f9, 0x000000f9}, + {0x00009af4, 0x000000f9, 0x000000f9}, + {0x00009af8, 0x000000f9, 0x000000f9}, + {0x00009afc, 0x000000f9, 0x000000f9}, +}; + +static const u32 ar5416Bank1_9160[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x02108421}, + {0x000098ec, 0x00000008}, +}; + +static const u32 ar5416Bank2_9160[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x0e73ff17}, + {0x000098e0, 0x00000420}, +}; + +static const u32 ar5416Bank3_9160[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x000098f0, 0x01400018, 0x01c00018}, +}; + +static const u32 ar5416Bank6_9160[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x0000989c, 0x00000000, 0x00000000}, + {0x0000989c, 0x00000000, 0x00000000}, + {0x0000989c, 0x00000000, 0x00000000}, + {0x0000989c, 0x00e00000, 0x00e00000}, + {0x0000989c, 0x005e0000, 0x005e0000}, + {0x0000989c, 0x00120000, 0x00120000}, + {0x0000989c, 0x00620000, 0x00620000}, + {0x0000989c, 0x00020000, 0x00020000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x40ff0000, 0x40ff0000}, + {0x0000989c, 0x005f0000, 0x005f0000}, + {0x0000989c, 0x00870000, 0x00870000}, + {0x0000989c, 0x00f90000, 0x00f90000}, + {0x0000989c, 0x007b0000, 0x007b0000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x00f50000, 0x00f50000}, + {0x0000989c, 0x00dc0000, 0x00dc0000}, + {0x0000989c, 0x00110000, 0x00110000}, + {0x0000989c, 0x006100a8, 0x006100a8}, + {0x0000989c, 0x004210a2, 0x004210a2}, + {0x0000989c, 0x0014008f, 0x0014008f}, + {0x0000989c, 0x00c40003, 0x00c40003}, + {0x0000989c, 0x003000f2, 0x003000f2}, + {0x0000989c, 0x00440016, 0x00440016}, + {0x0000989c, 0x00410040, 0x00410040}, + {0x0000989c, 0x0001805e, 0x0001805e}, + {0x0000989c, 0x0000c0ab, 0x0000c0ab}, + {0x0000989c, 0x000000f1, 0x000000f1}, + {0x0000989c, 0x00002081, 0x00002081}, + {0x0000989c, 0x000000d4, 0x000000d4}, + {0x000098d0, 0x0000000f, 0x0010000f}, +}; + +static const u32 ar5416Bank6TPC_9160[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x0000989c, 0x00000000, 0x00000000}, + {0x0000989c, 0x00000000, 0x00000000}, + {0x0000989c, 0x00000000, 0x00000000}, + {0x0000989c, 0x00e00000, 0x00e00000}, + {0x0000989c, 0x005e0000, 0x005e0000}, + {0x0000989c, 0x00120000, 0x00120000}, + {0x0000989c, 0x00620000, 0x00620000}, + {0x0000989c, 0x00020000, 0x00020000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x40ff0000, 0x40ff0000}, + {0x0000989c, 0x005f0000, 0x005f0000}, + {0x0000989c, 0x00870000, 0x00870000}, + {0x0000989c, 0x00f90000, 0x00f90000}, + {0x0000989c, 0x007b0000, 0x007b0000}, + {0x0000989c, 0x00ff0000, 0x00ff0000}, + {0x0000989c, 0x00f50000, 0x00f50000}, + {0x0000989c, 0x00dc0000, 0x00dc0000}, + {0x0000989c, 0x00110000, 0x00110000}, + {0x0000989c, 0x006100a8, 0x006100a8}, + {0x0000989c, 0x00423022, 0x00423022}, + {0x0000989c, 0x2014008f, 0x2014008f}, + {0x0000989c, 0x00c40002, 0x00c40002}, + {0x0000989c, 0x003000f2, 0x003000f2}, + {0x0000989c, 0x00440016, 0x00440016}, + {0x0000989c, 0x00410040, 0x00410040}, + {0x0000989c, 0x0001805e, 0x0001805e}, + {0x0000989c, 0x0000c0ab, 0x0000c0ab}, + {0x0000989c, 0x000000e1, 0x000000e1}, + {0x0000989c, 0x00007080, 0x00007080}, + {0x0000989c, 0x000000d4, 0x000000d4}, + {0x000098d0, 0x0000000f, 0x0010000f}, +}; + +static const u32 ar5416Bank7_9160[][2] = { + /* Addr allmodes */ + {0x0000989c, 0x00000500}, + {0x0000989c, 0x00000800}, + {0x000098cc, 0x0000000e}, +}; + static const u32 ar5416Addac_9160[][2] = { /* Addr allmodes */ {0x0000989c, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index c55e5bba..88279e32 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -61,16 +61,18 @@ static void ar9002_hw_setup_calibration(struct ath_hw *ah, switch (currCal->calData->calType) { case IQ_MISMATCH_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "starting IQ Mismatch Calibration\n"); break; case ADC_GAIN_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - ath_dbg(common, CALIBRATE, "starting ADC Gain Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "starting ADC Gain Calibration\n"); break; case ADC_DC_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - ath_dbg(common, CALIBRATE, "starting ADC DC Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "starting ADC DC Calibration\n"); break; } @@ -127,7 +129,7 @@ static void ar9002_hw_iqcal_collect(struct ath_hw *ah) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); ah->totalIqCorrMeas[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ath_dbg(ath9k_hw_common(ah), CALIBRATE, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", ah->cal_samples, i, ah->totalPowerMeasI[i], ah->totalPowerMeasQ[i], @@ -149,7 +151,7 @@ static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah) ah->totalAdcQEvenPhase[i] += REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - ath_dbg(ath9k_hw_common(ah), CALIBRATE, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", ah->cal_samples, i, ah->totalAdcIOddPhase[i], @@ -173,7 +175,7 @@ static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah) ah->totalAdcDcOffsetQEvenPhase[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - ath_dbg(ath9k_hw_common(ah), CALIBRATE, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", ah->cal_samples, i, ah->totalAdcDcOffsetIOddPhase[i], @@ -196,12 +198,12 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) powerMeasQ = ah->totalPowerMeasQ[i]; iqCorrMeas = ah->totalIqCorrMeas[i]; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Starting IQ Cal and Correction for Chain %d\n", i); - ath_dbg(common, CALIBRATE, - "Original: Chn %d iq_corr_meas = 0x%08x\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", i, ah->totalIqCorrMeas[i]); iqCorrNeg = 0; @@ -211,11 +213,12 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) iqCorrNeg = 1; } - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n", - i, powerMeasI); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n", - i, powerMeasQ); - ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + ath_dbg(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; qCoffDenom = powerMeasQ / 64; @@ -224,13 +227,13 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) (qCoffDenom != 0)) { iCoff = iqCorrMeas / iCoffDenom; qCoff = powerMeasI / qCoffDenom - 64; - ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n", - i, iCoff); - ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n", - i, qCoff); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); iCoff = iCoff & 0x3f; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "New: Chn %d iCoff = 0x%08x\n", i, iCoff); if (iqCorrNeg == 0x0) iCoff = 0x40 - iCoff; @@ -240,7 +243,7 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) else if (qCoff <= -16) qCoff = -16; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", i, iCoff, qCoff); @@ -250,7 +253,7 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "IQ Cal and Correction done for Chain %d\n", i); } @@ -272,17 +275,21 @@ static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) qOddMeasOffset = ah->totalAdcQOddPhase[i]; qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Starting ADC Gain Cal for Chain %d\n", i); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = 0x%08x\n", - i, iOddMeasOffset); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = 0x%08x\n", - i, iEvenMeasOffset); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = 0x%08x\n", - i, qOddMeasOffset); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = 0x%08x\n", - i, qEvenMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = 0x%08x\n", i, + iOddMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = 0x%08x\n", i, + iEvenMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = 0x%08x\n", i, + qOddMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = 0x%08x\n", i, + qEvenMeasOffset); if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { iGainMismatch = @@ -292,19 +299,19 @@ static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) ((qOddMeasOffset * 32) / qEvenMeasOffset) & 0x3f; - ath_dbg(common, CALIBRATE, - "Chn %d gain_mismatch_i = 0x%08x\n", - i, iGainMismatch); - ath_dbg(common, CALIBRATE, - "Chn %d gain_mismatch_q = 0x%08x\n", - i, qGainMismatch); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_i = 0x%08x\n", i, + iGainMismatch); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_q = 0x%08x\n", i, + qGainMismatch); val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); val &= 0xfffff000; val |= (qGainMismatch) | (iGainMismatch << 6); REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "ADC Gain Cal done for Chain %d\n", i); } } @@ -330,36 +337,40 @@ static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Starting ADC DC Offset Cal for Chain %d\n", i); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = %d\n", - i, iOddMeasOffset); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = %d\n", - i, iEvenMeasOffset); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = %d\n", - i, qOddMeasOffset); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = %d\n", - i, qEvenMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = %d\n", i, + iOddMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = %d\n", i, + iEvenMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = %d\n", i, + qOddMeasOffset); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = %d\n", i, + qEvenMeasOffset); iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / numSamples) & 0x1ff; qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / numSamples) & 0x1ff; - ath_dbg(common, CALIBRATE, - "Chn %d dc_offset_mismatch_i = 0x%08x\n", - i, iDcMismatch); - ath_dbg(common, CALIBRATE, - "Chn %d dc_offset_mismatch_q = 0x%08x\n", - i, qDcMismatch); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, + iDcMismatch); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, + qDcMismatch); val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); val &= 0xc0000fff; val |= (qDcMismatch << 12) | (iDcMismatch << 21); REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "ADC DC Offset Cal done for Chain %d\n", i); } @@ -549,7 +560,7 @@ static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) { 0x7838, 0 }, }; - ath_dbg(common, CALIBRATE, "Running PA Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); /* PA CAL is not needed for high power solution */ if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == @@ -730,7 +741,7 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "offset calibration failed to complete in 1ms; noisy environment?\n"); return false; } @@ -744,7 +755,7 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "offset calibration failed to complete in 1ms; noisy environment?\n"); return false; } @@ -840,7 +851,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "offset calibration failed to complete in 1ms; noisy environment?\n"); return false; } @@ -875,21 +886,22 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); - ath_dbg(common, CALIBRATE, - "enabling ADC Gain Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling ADC Gain Calibration.\n"); } if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); - ath_dbg(common, CALIBRATE, - "enabling ADC DC Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling ADC DC Calibration.\n"); } if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); } ah->cal_list_curr = ah->cal_list; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index d9a69fc4..11f192a1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -34,37 +34,74 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9271Modes_9271), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, ARRAY_SIZE(ar9271Common_9271), 2); + INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271, + ar9271Common_normal_cck_fir_coeff_9271, + ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2); + INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271, + ar9271Common_japan_2484_cck_fir_coeff_9271, + ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2); + INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, + ar9271Modes_9271_1_0_only, + ARRAY_SIZE(ar9271Modes_9271_1_0_only), 5); INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg, ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 5); + INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271, + ar9271Modes_high_power_tx_gain_9271, + ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5); + INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, + ar9271Modes_normal_power_tx_gain_9271, + ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5); return; } - if (ah->config.pcie_clock_req) - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2); - else - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); - if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, ARRAY_SIZE(ar9287Modes_9287_1_1), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, ARRAY_SIZE(ar9287Common_9287_1_1), 2); + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_off_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_always_on_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1), + 2); } else if (AR_SREV_9285_12_OR_LATER(ah)) { + + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, ARRAY_SIZE(ar9285Modes_9285_1_2), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, ARRAY_SIZE(ar9285Common_9285_1_2), 2); + + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), + 2); + } } else if (AR_SREV_9280_20_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, ARRAY_SIZE(ar9280Modes_9280_2), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, ARRAY_SIZE(ar9280Common_9280_2), 2); - INIT_INI_ARRAY(&ah->iniModesFastClock, + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_off_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + } + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9280Modes_fast_clock_9280_2, ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); } else if (AR_SREV_9160_10_OR_LATER(ah)) { @@ -72,6 +109,22 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar5416Modes_9160), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, ARRAY_SIZE(ar5416Common_9160), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, + ARRAY_SIZE(ar5416Bank0_9160), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160, + ARRAY_SIZE(ar5416BB_RfGain_9160), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160, + ARRAY_SIZE(ar5416Bank1_9160), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160, + ARRAY_SIZE(ar5416Bank2_9160), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160, + ARRAY_SIZE(ar5416Bank3_9160), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160, + ARRAY_SIZE(ar5416Bank6_9160), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160, + ARRAY_SIZE(ar5416Bank6TPC_9160), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160, + ARRAY_SIZE(ar5416Bank7_9160), 2); if (AR_SREV_9160_11(ah)) { INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160_1_1, @@ -85,8 +138,22 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar5416Modes_9100), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, ARRAY_SIZE(ar5416Common_9100), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, + ARRAY_SIZE(ar5416Bank0_9100), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100, + ARRAY_SIZE(ar5416BB_RfGain_9100), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100, + ARRAY_SIZE(ar5416Bank1_9100), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100, + ARRAY_SIZE(ar5416Bank2_9100), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100, + ARRAY_SIZE(ar5416Bank3_9100), 3); INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, ARRAY_SIZE(ar5416Bank6_9100), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, + ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100, + ARRAY_SIZE(ar5416Bank7_9100), 2); INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, ARRAY_SIZE(ar5416Addac_9100), 2); } else { @@ -94,57 +161,30 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar5416Modes), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); - } - - if (!AR_SREV_9280_20_OR_LATER(ah)) { - /* Common for AR5416, AR913x, AR9160 */ - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, - ARRAY_SIZE(ar5416BB_RfGain), 3); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, ARRAY_SIZE(ar5416Bank0), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, + ARRAY_SIZE(ar5416BB_RfGain), 3); INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, ARRAY_SIZE(ar5416Bank1), 2); INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, ARRAY_SIZE(ar5416Bank2), 2); INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, ARRAY_SIZE(ar5416Bank3), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, + ARRAY_SIZE(ar5416Bank6), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, + ARRAY_SIZE(ar5416Bank6TPC), 3); INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, ARRAY_SIZE(ar5416Bank7), 2); - - /* Common for AR5416, AR9160 */ - if (!AR_SREV_9100(ah)) - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); - - /* Common for AR913x, AR9160 */ - if (!AR_SREV_5416(ah)) - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, + ARRAY_SIZE(ar5416Addac), 2); } +} - /* iniAddac needs to be modified for these chips */ - if (AR_SREV_9160(ah) || !AR_SREV_5416_22_OR_LATER(ah)) { - struct ar5416IniArray *addac = &ah->iniAddac; - u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns; - u32 *data; - - data = kmalloc(size, GFP_KERNEL); - if (!data) - return; - - memcpy(data, addac->ia_array, size); - addac->ia_array = data; - - if (!AR_SREV_5416_22_OR_LATER(ah)) { - /* override CLKDRV value */ - INI_RA(addac, 31,1) = 0; - } - } +/* Support for Japan ch.14 (2484) spread */ +void ar9002_hw_cck_chan14_spread(struct ath_hw *ah) +{ if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniCckfirNormal, ar9287Common_normal_cck_fir_coeff_9287_1_1, @@ -184,10 +224,14 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) } } -static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) +static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah) { + u32 txgain_type; + if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { + txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_high_power_tx_gain_9280_2, @@ -203,22 +247,8 @@ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) } } -static void ar9271_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) -{ - if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9271Modes_high_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9271Modes_normal_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5); -} - static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) { - u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); - if (AR_SREV_9287_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9287Modes_rx_gain_9287_1_1, @@ -226,15 +256,15 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) else if (AR_SREV_9280_20(ah)) ar9280_20_hw_init_rxgain_ini(ah); - if (AR_SREV_9271(ah)) { - ar9271_hw_init_txgain_ini(ah, txgain_type); - } else if (AR_SREV_9287_11_OR_LATER(ah)) { + if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModesTxGain, ar9287Modes_tx_gain_9287_1_1, ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 5); } else if (AR_SREV_9280_20(ah)) { - ar9280_20_hw_init_txgain_ini(ah, txgain_type); + ar9280_20_hw_init_txgain_ini(ah); } else if (AR_SREV_9285_12_OR_LATER(ah)) { + u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + /* txgain table */ if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { if (AR_SREV_9285E_20(ah)) { diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h index 4d18c66a..863db321 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h @@ -925,6 +925,34 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { {0x00004044, 0x00000000}, }; +static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { + /* Addr allmodes */ + {0x00004040, 0x9248fd00}, + {0x00004040, 0x24924924}, + {0x00004040, 0xa8000019}, + {0x00004040, 0x13160820}, + {0x00004040, 0xe5980560}, + {0x00004040, 0xc01dcffd}, + {0x00004040, 0x1aaabe41}, + {0x00004040, 0xbe105554}, + {0x00004040, 0x00043007}, + {0x00004044, 0x00000000}, +}; + +static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = { + /* Addr allmodes */ + {0x00004040, 0x9248fd00}, + {0x00004040, 0x24924924}, + {0x00004040, 0xa8000019}, + {0x00004040, 0x13160820}, + {0x00004040, 0xe5980560}, + {0x00004040, 0xc01dcffc}, + {0x00004040, 0x1aaabe41}, + {0x00004040, 0xbe105554}, + {0x00004040, 0x00043007}, + {0x00004044, 0x00000000}, +}; + static const u32 ar9285Modes_9285_1_2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, @@ -1715,6 +1743,34 @@ static const u32 ar9285Modes_XE2_0_high_power[][5] = { {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, }; +static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { + /* Addr allmodes */ + {0x00004040, 0x9248fd00}, + {0x00004040, 0x24924924}, + {0x00004040, 0xa8000019}, + {0x00004040, 0x13160820}, + {0x00004040, 0xe5980560}, + {0x00004040, 0xc01dcffd}, + {0x00004040, 0x1aaabe41}, + {0x00004040, 0xbe105554}, + {0x00004040, 0x00043007}, + {0x00004044, 0x00000000}, +}; + +static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { + /* Addr allmodes */ + {0x00004040, 0x9248fd00}, + {0x00004040, 0x24924924}, + {0x00004040, 0xa8000019}, + {0x00004040, 0x13160820}, + {0x00004040, 0xe5980560}, + {0x00004040, 0xc01dcffc}, + {0x00004040, 0x1aaabe41}, + {0x00004040, 0xbe105554}, + {0x00004040, 0x00043007}, + {0x00004044, 0x00000000}, +}; + static const u32 ar9287Modes_9287_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160}, @@ -2456,6 +2512,34 @@ static const u32 ar9287Modes_rx_gain_9287_1_1[][5] = { {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067}, }; +static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { + /* Addr allmodes */ + {0x00004040, 0x9248fd00}, + {0x00004040, 0x24924924}, + {0x00004040, 0xa8000019}, + {0x00004040, 0x13160820}, + {0x00004040, 0xe5980560}, + {0x00004040, 0xc01dcffd}, + {0x00004040, 0x1aaabe41}, + {0x00004040, 0xbe105554}, + {0x00004040, 0x00043007}, + {0x00004044, 0x00000000}, +}; + +static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { + /* Addr allmodes */ + {0x00004040, 0x9248fd00}, + {0x00004040, 0x24924924}, + {0x00004040, 0xa8000019}, + {0x00004040, 0x13160820}, + {0x00004040, 0xe5980560}, + {0x00004040, 0xc01dcffc}, + {0x00004040, 0x1aaabe41}, + {0x00004040, 0xbe105554}, + {0x00004040, 0x00043007}, + {0x00004044, 0x00000000}, +}; + static const u32 ar9271Modes_9271[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, @@ -3092,6 +3176,26 @@ static const u32 ar9271Common_9271[][2] = { {0x0000d384, 0xf3307ff0}, }; +static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = { + /* Addr allmodes */ + {0x0000a1f4, 0x00fffeff}, + {0x0000a1f8, 0x00f5f9ff}, + {0x0000a1fc, 0xb79f6427}, +}; + +static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = { + /* Addr allmodes */ + {0x0000a1f4, 0x00000000}, + {0x0000a1f8, 0xefff0301}, + {0x0000a1fc, 0xca9228ee}, +}; + +static const u32 ar9271Modes_9271_1_0_only[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311}, + {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, +}; + static const u32 ar9271Modes_9271_ANI_reg[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c old mode 100644 new mode 100755 index fa7581a5..f4caeb32 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -126,7 +126,7 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) } if (isr & AR_ISR_RXORN) { - ath_dbg(common, INTERRUPT, + ath_dbg(common, ATH_DBG_INTERRUPT, "receive FIFO overrun interrupt\n"); } @@ -177,24 +177,24 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) if (fatal_int) { if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { - ath_dbg(common, ANY, + ath_dbg(common, ATH_DBG_ANY, "received PCI FATAL interrupt\n"); } if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { - ath_dbg(common, ANY, + ath_dbg(common, ATH_DBG_ANY, "received PCI PERR interrupt\n"); } *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { - ath_dbg(common, INTERRUPT, + ath_dbg(common, ATH_DBG_INTERRUPT, "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { - ath_dbg(common, INTERRUPT, + ath_dbg(common, ATH_DBG_INTERRUPT, "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); } @@ -381,12 +381,15 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { struct ar5416_desc *ads = AR5416DESC(ds); + struct ath9k_hw_capabilities *pCap = &ah->caps; ads->ds_ctl1 = size & AR_BufLen; if (flags & ATH9K_RXDESC_INTREQ) ads->ds_ctl1 |= AR_RxIntrReq; - memset(&ads->u.rx, 0, sizeof(ads->u.rx)); + ads->ds_rxstatus8 &= ~AR_RxDone; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + memset(&(ads->u), 0, sizeof(ads->u)); } EXPORT_SYMBOL(ath9k_hw_setuprxdesc); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index f9eb2c35..453af6dc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -60,8 +60,6 @@ #define AR_PHY_RF_CTL3 0x9828 #define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 #define AR_PHY_TX_END_TO_A2_RX_ON_S 16 -#define AR_PHY_TX_END_TO_ADC_ON 0xFF000000 -#define AR_PHY_TX_END_TO_ADC_ON_S 24 #define AR_PHY_ADC_CTL 0x982C #define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h old mode 100644 new mode 100755 index 4e2a52c3..498a3c11 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -295,6 +295,266 @@ static const u32 ar9300_2p2_radio_core[][2] = { {0x00016bd4, 0x00000000}, }; +static const u32 ar9300Common_rx_gain_table_merlin_2p2[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x02000101}, + {0x0000a004, 0x02000102}, + {0x0000a008, 0x02000103}, + {0x0000a00c, 0x02000104}, + {0x0000a010, 0x02000200}, + {0x0000a014, 0x02000201}, + {0x0000a018, 0x02000202}, + {0x0000a01c, 0x02000203}, + {0x0000a020, 0x02000204}, + {0x0000a024, 0x02000205}, + {0x0000a028, 0x02000208}, + {0x0000a02c, 0x02000302}, + {0x0000a030, 0x02000303}, + {0x0000a034, 0x02000304}, + {0x0000a038, 0x02000400}, + {0x0000a03c, 0x02010300}, + {0x0000a040, 0x02010301}, + {0x0000a044, 0x02010302}, + {0x0000a048, 0x02000500}, + {0x0000a04c, 0x02010400}, + {0x0000a050, 0x02020300}, + {0x0000a054, 0x02020301}, + {0x0000a058, 0x02020302}, + {0x0000a05c, 0x02020303}, + {0x0000a060, 0x02020400}, + {0x0000a064, 0x02030300}, + {0x0000a068, 0x02030301}, + {0x0000a06c, 0x02030302}, + {0x0000a070, 0x02030303}, + {0x0000a074, 0x02030400}, + {0x0000a078, 0x02040300}, + {0x0000a07c, 0x02040301}, + {0x0000a080, 0x02040302}, + {0x0000a084, 0x02040303}, + {0x0000a088, 0x02030500}, + {0x0000a08c, 0x02040400}, + {0x0000a090, 0x02050203}, + {0x0000a094, 0x02050204}, + {0x0000a098, 0x02050205}, + {0x0000a09c, 0x02040500}, + {0x0000a0a0, 0x02050301}, + {0x0000a0a4, 0x02050302}, + {0x0000a0a8, 0x02050303}, + {0x0000a0ac, 0x02050400}, + {0x0000a0b0, 0x02050401}, + {0x0000a0b4, 0x02050402}, + {0x0000a0b8, 0x02050403}, + {0x0000a0bc, 0x02050500}, + {0x0000a0c0, 0x02050501}, + {0x0000a0c4, 0x02050502}, + {0x0000a0c8, 0x02050503}, + {0x0000a0cc, 0x02050504}, + {0x0000a0d0, 0x02050600}, + {0x0000a0d4, 0x02050601}, + {0x0000a0d8, 0x02050602}, + {0x0000a0dc, 0x02050603}, + {0x0000a0e0, 0x02050604}, + {0x0000a0e4, 0x02050700}, + {0x0000a0e8, 0x02050701}, + {0x0000a0ec, 0x02050702}, + {0x0000a0f0, 0x02050703}, + {0x0000a0f4, 0x02050704}, + {0x0000a0f8, 0x02050705}, + {0x0000a0fc, 0x02050708}, + {0x0000a100, 0x02050709}, + {0x0000a104, 0x0205070a}, + {0x0000a108, 0x0205070b}, + {0x0000a10c, 0x0205070c}, + {0x0000a110, 0x0205070d}, + {0x0000a114, 0x02050710}, + {0x0000a118, 0x02050711}, + {0x0000a11c, 0x02050712}, + {0x0000a120, 0x02050713}, + {0x0000a124, 0x02050714}, + {0x0000a128, 0x02050715}, + {0x0000a12c, 0x02050730}, + {0x0000a130, 0x02050731}, + {0x0000a134, 0x02050732}, + {0x0000a138, 0x02050733}, + {0x0000a13c, 0x02050734}, + {0x0000a140, 0x02050735}, + {0x0000a144, 0x02050750}, + {0x0000a148, 0x02050751}, + {0x0000a14c, 0x02050752}, + {0x0000a150, 0x02050753}, + {0x0000a154, 0x02050754}, + {0x0000a158, 0x02050755}, + {0x0000a15c, 0x02050770}, + {0x0000a160, 0x02050771}, + {0x0000a164, 0x02050772}, + {0x0000a168, 0x02050773}, + {0x0000a16c, 0x02050774}, + {0x0000a170, 0x02050775}, + {0x0000a174, 0x00000776}, + {0x0000a178, 0x00000776}, + {0x0000a17c, 0x00000776}, + {0x0000a180, 0x00000776}, + {0x0000a184, 0x00000776}, + {0x0000a188, 0x00000776}, + {0x0000a18c, 0x00000776}, + {0x0000a190, 0x00000776}, + {0x0000a194, 0x00000776}, + {0x0000a198, 0x00000776}, + {0x0000a19c, 0x00000776}, + {0x0000a1a0, 0x00000776}, + {0x0000a1a4, 0x00000776}, + {0x0000a1a8, 0x00000776}, + {0x0000a1ac, 0x00000776}, + {0x0000a1b0, 0x00000776}, + {0x0000a1b4, 0x00000776}, + {0x0000a1b8, 0x00000776}, + {0x0000a1bc, 0x00000776}, + {0x0000a1c0, 0x00000776}, + {0x0000a1c4, 0x00000776}, + {0x0000a1c8, 0x00000776}, + {0x0000a1cc, 0x00000776}, + {0x0000a1d0, 0x00000776}, + {0x0000a1d4, 0x00000776}, + {0x0000a1d8, 0x00000776}, + {0x0000a1dc, 0x00000776}, + {0x0000a1e0, 0x00000776}, + {0x0000a1e4, 0x00000776}, + {0x0000a1e8, 0x00000776}, + {0x0000a1ec, 0x00000776}, + {0x0000a1f0, 0x00000776}, + {0x0000a1f4, 0x00000776}, + {0x0000a1f8, 0x00000776}, + {0x0000a1fc, 0x00000776}, + {0x0000b000, 0x02000101}, + {0x0000b004, 0x02000102}, + {0x0000b008, 0x02000103}, + {0x0000b00c, 0x02000104}, + {0x0000b010, 0x02000200}, + {0x0000b014, 0x02000201}, + {0x0000b018, 0x02000202}, + {0x0000b01c, 0x02000203}, + {0x0000b020, 0x02000204}, + {0x0000b024, 0x02000205}, + {0x0000b028, 0x02000208}, + {0x0000b02c, 0x02000302}, + {0x0000b030, 0x02000303}, + {0x0000b034, 0x02000304}, + {0x0000b038, 0x02000400}, + {0x0000b03c, 0x02010300}, + {0x0000b040, 0x02010301}, + {0x0000b044, 0x02010302}, + {0x0000b048, 0x02000500}, + {0x0000b04c, 0x02010400}, + {0x0000b050, 0x02020300}, + {0x0000b054, 0x02020301}, + {0x0000b058, 0x02020302}, + {0x0000b05c, 0x02020303}, + {0x0000b060, 0x02020400}, + {0x0000b064, 0x02030300}, + {0x0000b068, 0x02030301}, + {0x0000b06c, 0x02030302}, + {0x0000b070, 0x02030303}, + {0x0000b074, 0x02030400}, + {0x0000b078, 0x02040300}, + {0x0000b07c, 0x02040301}, + {0x0000b080, 0x02040302}, + {0x0000b084, 0x02040303}, + {0x0000b088, 0x02030500}, + {0x0000b08c, 0x02040400}, + {0x0000b090, 0x02050203}, + {0x0000b094, 0x02050204}, + {0x0000b098, 0x02050205}, + {0x0000b09c, 0x02040500}, + {0x0000b0a0, 0x02050301}, + {0x0000b0a4, 0x02050302}, + {0x0000b0a8, 0x02050303}, + {0x0000b0ac, 0x02050400}, + {0x0000b0b0, 0x02050401}, + {0x0000b0b4, 0x02050402}, + {0x0000b0b8, 0x02050403}, + {0x0000b0bc, 0x02050500}, + {0x0000b0c0, 0x02050501}, + {0x0000b0c4, 0x02050502}, + {0x0000b0c8, 0x02050503}, + {0x0000b0cc, 0x02050504}, + {0x0000b0d0, 0x02050600}, + {0x0000b0d4, 0x02050601}, + {0x0000b0d8, 0x02050602}, + {0x0000b0dc, 0x02050603}, + {0x0000b0e0, 0x02050604}, + {0x0000b0e4, 0x02050700}, + {0x0000b0e8, 0x02050701}, + {0x0000b0ec, 0x02050702}, + {0x0000b0f0, 0x02050703}, + {0x0000b0f4, 0x02050704}, + {0x0000b0f8, 0x02050705}, + {0x0000b0fc, 0x02050708}, + {0x0000b100, 0x02050709}, + {0x0000b104, 0x0205070a}, + {0x0000b108, 0x0205070b}, + {0x0000b10c, 0x0205070c}, + {0x0000b110, 0x0205070d}, + {0x0000b114, 0x02050710}, + {0x0000b118, 0x02050711}, + {0x0000b11c, 0x02050712}, + {0x0000b120, 0x02050713}, + {0x0000b124, 0x02050714}, + {0x0000b128, 0x02050715}, + {0x0000b12c, 0x02050730}, + {0x0000b130, 0x02050731}, + {0x0000b134, 0x02050732}, + {0x0000b138, 0x02050733}, + {0x0000b13c, 0x02050734}, + {0x0000b140, 0x02050735}, + {0x0000b144, 0x02050750}, + {0x0000b148, 0x02050751}, + {0x0000b14c, 0x02050752}, + {0x0000b150, 0x02050753}, + {0x0000b154, 0x02050754}, + {0x0000b158, 0x02050755}, + {0x0000b15c, 0x02050770}, + {0x0000b160, 0x02050771}, + {0x0000b164, 0x02050772}, + {0x0000b168, 0x02050773}, + {0x0000b16c, 0x02050774}, + {0x0000b170, 0x02050775}, + {0x0000b174, 0x00000776}, + {0x0000b178, 0x00000776}, + {0x0000b17c, 0x00000776}, + {0x0000b180, 0x00000776}, + {0x0000b184, 0x00000776}, + {0x0000b188, 0x00000776}, + {0x0000b18c, 0x00000776}, + {0x0000b190, 0x00000776}, + {0x0000b194, 0x00000776}, + {0x0000b198, 0x00000776}, + {0x0000b19c, 0x00000776}, + {0x0000b1a0, 0x00000776}, + {0x0000b1a4, 0x00000776}, + {0x0000b1a8, 0x00000776}, + {0x0000b1ac, 0x00000776}, + {0x0000b1b0, 0x00000776}, + {0x0000b1b4, 0x00000776}, + {0x0000b1b8, 0x00000776}, + {0x0000b1bc, 0x00000776}, + {0x0000b1c0, 0x00000776}, + {0x0000b1c4, 0x00000776}, + {0x0000b1c8, 0x00000776}, + {0x0000b1cc, 0x00000776}, + {0x0000b1d0, 0x00000776}, + {0x0000b1d4, 0x00000776}, + {0x0000b1d8, 0x00000776}, + {0x0000b1dc, 0x00000776}, + {0x0000b1e0, 0x00000776}, + {0x0000b1e4, 0x00000776}, + {0x0000b1e8, 0x00000776}, + {0x0000b1ec, 0x00000776}, + {0x0000b1f0, 0x00000776}, + {0x0000b1f4, 0x00000776}, + {0x0000b1f8, 0x00000776}, + {0x0000b1fc, 0x00000776}, +}; + static const u32 ar9300_2p2_mac_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, @@ -312,6 +572,48 @@ static const u32 ar9300_2p2_soc_postamble[][5] = { {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, }; +static const u32 ar9200_merlin_2p2_radio_core[][2] = { + /* Addr allmodes */ + {0x00007800, 0x00040000}, + {0x00007804, 0xdb005012}, + {0x00007808, 0x04924914}, + {0x0000780c, 0x21084210}, + {0x00007810, 0x6d801300}, + {0x00007814, 0x0019beff}, + {0x00007818, 0x07e41000}, + {0x0000781c, 0x00392000}, + {0x00007820, 0x92592480}, + {0x00007824, 0x00040000}, + {0x00007828, 0xdb005012}, + {0x0000782c, 0x04924914}, + {0x00007830, 0x21084210}, + {0x00007834, 0x6d801300}, + {0x00007838, 0x0019beff}, + {0x0000783c, 0x07e40000}, + {0x00007840, 0x00392000}, + {0x00007844, 0x92592480}, + {0x00007848, 0x00100000}, + {0x0000784c, 0x773f0567}, + {0x00007850, 0x54214514}, + {0x00007854, 0x12035828}, + {0x00007858, 0x92592692}, + {0x0000785c, 0x00000000}, + {0x00007860, 0x56400000}, + {0x00007864, 0x0a8e370e}, + {0x00007868, 0xc0102850}, + {0x0000786c, 0x812d4000}, + {0x00007870, 0x807ec400}, + {0x00007874, 0x001b6db0}, + {0x00007878, 0x00376b63}, + {0x0000787c, 0x06db6db6}, + {0x00007880, 0x006d8000}, + {0x00007884, 0xffeffffe}, + {0x00007888, 0xffeffffe}, + {0x0000788c, 0x00010000}, + {0x00007890, 0x02060aeb}, + {0x00007894, 0x5a108000}, +}; + static const u32 ar9300_2p2_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c old mode 100644 new mode 100755 index 7c864150..39653561 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -18,7 +18,6 @@ #include "hw-ops.h" #include "ar9003_phy.h" #include "ar9003_rtt.h" -#include "ar9003_mci.h" #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT #define MAX_MAG_DELTA 11 @@ -52,7 +51,7 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, currCal->calData->calCountMax); REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "starting IQ Mismatch Calibration\n"); /* Kick-off cal */ @@ -64,7 +63,7 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "starting Temperature Compensation Calibration\n"); break; } @@ -194,7 +193,7 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); ah->totalIqCorrMeas[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ath_dbg(ath9k_hw_common(ah), CALIBRATE, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", ah->cal_samples, i, ah->totalPowerMeasI[i], ah->totalPowerMeasQ[i], @@ -221,11 +220,12 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) powerMeasQ = ah->totalPowerMeasQ[i]; iqCorrMeas = ah->totalIqCorrMeas[i]; - ath_dbg(common, CALIBRATE, - "Starting IQ Cal and Correction for Chain %d\n", i); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); - ath_dbg(common, CALIBRATE, - "Original: Chn %d iq_corr_meas = 0x%08x\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", i, ah->totalIqCorrMeas[i]); iqCorrNeg = 0; @@ -235,11 +235,12 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) iqCorrNeg = 1; } - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n", - i, powerMeasI); - ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n", - i, powerMeasQ); - ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + ath_dbg(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256; qCoffDenom = powerMeasQ / 64; @@ -247,10 +248,10 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) if ((iCoffDenom != 0) && (qCoffDenom != 0)) { iCoff = iqCorrMeas / iCoffDenom; qCoff = powerMeasI / qCoffDenom - 64; - ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n", - i, iCoff); - ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n", - i, qCoff); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); /* Force bounds on iCoff */ if (iCoff >= 63) @@ -271,10 +272,10 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) iCoff = iCoff & 0x7f; qCoff = qCoff & 0x7f; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", i, iCoff, qCoff); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Register offset (0x%04x) before update = 0x%x\n", offset_array[i], REG_READ(ah, offset_array[i])); @@ -285,25 +286,25 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) REG_RMW_FIELD(ah, offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, qCoff); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n", offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, REG_READ(ah, offset_array[i])); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n", offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, REG_READ(ah, offset_array[i])); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "IQ Cal and Correction done for Chain %d\n", i); } } REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n", (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, @@ -347,7 +348,7 @@ static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah, f2 = (f1 * f1 + f3 * f3) / result_shift; if (!f2) { - ath_dbg(common, CALIBRATE, "Divide by 0\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, "Divide by 0\n"); return false; } @@ -468,7 +469,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) || (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Divide by 0:\n" "a0_d0=%d\n" "a0_d1=%d\n" @@ -508,7 +509,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); if ((mag1 == 0) || (mag2 == 0)) { - ath_dbg(common, CALIBRATE, "Divide by 0: mag1=%d, mag2=%d\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "Divide by 0: mag1=%d, mag2=%d\n", mag1, mag2); return false; } @@ -526,8 +528,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, mag_a0_d0, phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq)) { - ath_dbg(common, CALIBRATE, - "Call to ar9003_hw_solve_iq_cal() failed\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Call to ar9003_hw_solve_iq_cal() failed.\n"); return false; } @@ -536,12 +538,12 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, mag_rx = solved_eq[2]; phs_rx = solved_eq[3]; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "chain %d: mag mismatch=%d phase mismatch=%d\n", chain_idx, mag_tx/res_scale, phs_tx/res_scale); if (res_scale == mag_tx) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Divide by 0: mag_tx=%d, res_scale=%d\n", mag_tx, res_scale); return false; @@ -554,7 +556,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, q_q_coff = (mag_corr_tx * 128 / res_scale); q_i_coff = (phs_corr_tx * 256 / res_scale); - ath_dbg(common, CALIBRATE, "tx chain %d: mag corr=%d phase corr=%d\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "tx chain %d: mag corr=%d phase corr=%d\n", chain_idx, q_q_coff, q_i_coff); if (q_i_coff < -63) @@ -568,11 +571,12 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; - ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "tx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[0]); if (-mag_rx == res_scale) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Divide by 0: mag_rx=%d, res_scale=%d\n", mag_rx, res_scale); return false; @@ -585,7 +589,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, q_q_coff = (mag_corr_rx * 128 / res_scale); q_i_coff = (phs_corr_rx * 256 / res_scale); - ath_dbg(common, CALIBRATE, "rx chain %d: mag corr=%d phase corr=%d\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "rx chain %d: mag corr=%d phase corr=%d\n", chain_idx, q_q_coff, q_i_coff); if (q_i_coff < -63) @@ -599,7 +604,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; - ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "rx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[1]); return true; @@ -746,7 +752,8 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, AR_PHY_TX_IQCAL_START_DO_CAL, 0, AH_WAIT_TIMEOUT)) { - ath_dbg(common, CALIBRATE, "Tx IQ Cal is not completed\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal is not completed.\n"); return false; } return true; @@ -784,13 +791,13 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) nmeasurement = MAX_MEASUREMENT; for (im = 0; im < nmeasurement; im++) { - ath_dbg(common, CALIBRATE, - "Doing Tx IQ Cal for chain %d\n", i); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Doing Tx IQ Cal for chain %d.\n", i); if (REG_READ(ah, txiqcal_status[i]) & AR_PHY_TX_IQCAL_STATUS_FAILED) { - ath_dbg(common, CALIBRATE, - "Tx IQ Cal failed for chain %d\n", i); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal failed for chain %d.\n", i); goto tx_iqcal_fail; } @@ -816,16 +823,18 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) iq_res[idx + 1] = 0xffff & REG_READ(ah, chan_info_tab[i] + offset); - ath_dbg(common, CALIBRATE, - "IQ_RES[%d]=0x%x IQ_RES[%d]=0x%x\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "IQ RES[%d]=0x%x" + "IQ_RES[%d]=0x%x\n", idx, iq_res[idx], idx + 1, iq_res[idx + 1]); } if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, coeff.iqc_coeff)) { - ath_dbg(common, CALIBRATE, - "Failed in calculation of IQ correction\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Failed in calculation of \ + IQ correction.\n"); goto tx_iqcal_fail; } @@ -845,7 +854,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) return; tx_iqcal_fail: - ath_dbg(common, CALIBRATE, "Tx IQ Cal failed\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); return; } @@ -929,7 +938,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, bool is_reusable = true, status = true; bool run_rtt_cal = false, run_agc_cal; bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); - bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI); u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_PKDET_CAL; @@ -945,7 +953,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (!ar9003_hw_rtt_restore(ah, chan)) run_rtt_cal = true; - ath_dbg(common, CALIBRATE, "RTT restore %s\n", + ath_dbg(common, ATH_DBG_CALIBRATE, "RTT restore %s\n", run_rtt_cal ? "failed" : "succeed"); } run_agc_cal = run_rtt_cal; @@ -1000,9 +1008,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, } else if (caldata && !caldata->done_txiqcal_once) run_agc_cal = true; - if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal) - ar9003_mci_init_cal_req(ah, &is_reusable); - txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); udelay(5); @@ -1020,10 +1025,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); } - - if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal) - ar9003_mci_init_cal_done(ah); - if (rtt && !run_rtt_cal) { agc_ctrl |= agc_supp_cals; REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); @@ -1033,8 +1034,9 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (run_rtt_cal) ar9003_hw_rtt_disable(ah); - ath_dbg(common, CALIBRATE, - "offset calibration failed to complete in 1ms; noisy environment?\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "offset calibration failed to complete in 1ms;" + "noisy environment?\n"); return false; } @@ -1096,14 +1098,15 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (ah->supp_cals & IQ_MISMATCH_CAL) { INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); } if (ah->supp_cals & TEMP_COMP_CAL) { INIT_CAL(&ah->tempCompCalData); INSERT_CAL(ah, &ah->tempCompCalData); - ath_dbg(common, CALIBRATE, - "enabling Temperature Compensation Calibration\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling Temperature Compensation Calibration.\n"); } /* Initialize current pointer to first element in list */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 6f2fff30..2bee2240 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3043,7 +3043,8 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer, int i; if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) { - ath_dbg(common, EEPROM, "eeprom address not in range\n"); + ath_dbg(common, ATH_DBG_EEPROM, + "eeprom address not in range\n"); return false; } @@ -3074,8 +3075,8 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer, return true; error: - ath_dbg(common, EEPROM, "unable to read eeprom region at offset %d\n", - address); + ath_dbg(common, ATH_DBG_EEPROM, + "unable to read eeprom region at offset %d\n", address); return false; } @@ -3159,13 +3160,13 @@ static bool ar9300_uncompress_block(struct ath_hw *ah, length &= 0xff; if (length > 0 && spot >= 0 && spot+length <= mdataSize) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Restore at %d: spot=%d offset=%d length=%d\n", it, spot, offset, length); memcpy(&mptr[spot], &block[it+2], length); spot += length; } else if (length > 0) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Bad restore at %d: spot=%d offset=%d length=%d\n", it, spot, offset, length); return false; @@ -3187,13 +3188,13 @@ static int ar9300_compress_decision(struct ath_hw *ah, switch (code) { case _CompressNone: if (length != mdata_size) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "EEPROM structure size mismatch memory=%d eeprom=%d\n", mdata_size, length); return -1; } memcpy(mptr, (u8 *) (word + COMP_HDR_LEN), length); - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "restored eeprom %d: uncompressed, length %d\n", it, length); break; @@ -3202,21 +3203,22 @@ static int ar9300_compress_decision(struct ath_hw *ah, } else { eep = ar9003_eeprom_struct_find_by_id(reference); if (eep == NULL) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "can't find reference eeprom struct %d\n", reference); return -1; } memcpy(mptr, eep, mdata_size); } - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "restore eeprom %d: block, reference %d, length %d\n", it, reference, length); ar9300_uncompress_block(ah, mptr, mdata_size, (u8 *) (word + COMP_HDR_LEN), length); break; default: - ath_dbg(common, EEPROM, "unknown compression code %d\n", code); + ath_dbg(common, ATH_DBG_EEPROM, + "unknown compression code %d\n", code); return -1; } return 0; @@ -3292,32 +3294,34 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, cptr = AR9300_BASE_ADDR_512; else cptr = AR9300_BASE_ADDR; - ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n", - cptr); + ath_dbg(common, ATH_DBG_EEPROM, + "Trying EEPROM access at Address 0x%04x\n", cptr); if (ar9300_check_eeprom_header(ah, read, cptr)) goto found; cptr = AR9300_BASE_ADDR_512; - ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n", - cptr); + ath_dbg(common, ATH_DBG_EEPROM, + "Trying EEPROM access at Address 0x%04x\n", cptr); if (ar9300_check_eeprom_header(ah, read, cptr)) goto found; read = ar9300_read_otp; cptr = AR9300_BASE_ADDR; - ath_dbg(common, EEPROM, "Trying OTP access at Address 0x%04x\n", cptr); + ath_dbg(common, ATH_DBG_EEPROM, + "Trying OTP access at Address 0x%04x\n", cptr); if (ar9300_check_eeprom_header(ah, read, cptr)) goto found; cptr = AR9300_BASE_ADDR_512; - ath_dbg(common, EEPROM, "Trying OTP access at Address 0x%04x\n", cptr); + ath_dbg(common, ATH_DBG_EEPROM, + "Trying OTP access at Address 0x%04x\n", cptr); if (ar9300_check_eeprom_header(ah, read, cptr)) goto found; goto fail; found: - ath_dbg(common, EEPROM, "Found valid EEPROM data\n"); + ath_dbg(common, ATH_DBG_EEPROM, "Found valid EEPROM data\n"); for (it = 0; it < MSTATE; it++) { if (!read(ah, cptr, word, COMP_HDR_LEN)) @@ -3328,12 +3332,13 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, ar9300_comp_hdr_unpack(word, &code, &reference, &length, &major, &minor); - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n", cptr, code, reference, length, major, minor); if ((!AR_SREV_9485(ah) && length >= 1024) || (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) { - ath_dbg(common, EEPROM, "Skipping bad header\n"); + ath_dbg(common, ATH_DBG_EEPROM, + "Skipping bad header\n"); cptr -= COMP_HDR_LEN; continue; } @@ -3342,13 +3347,13 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, read(ah, cptr, word, COMP_HDR_LEN + osize + COMP_CKSUM_LEN); checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length); mchecksum = get_unaligned_le16(&word[COMP_HDR_LEN + osize]); - ath_dbg(common, EEPROM, "checksum %x %x\n", - checksum, mchecksum); + ath_dbg(common, ATH_DBG_EEPROM, + "checksum %x %x\n", checksum, mchecksum); if (checksum == mchecksum) { ar9300_compress_decision(ah, it, code, reference, mptr, word, length, mdata_size); } else { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "skipping block with bad checksum\n"); } cptr -= (COMP_HDR_LEN + osize + COMP_CKSUM_LEN); @@ -3538,13 +3543,13 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is_2ghz) { struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - __le16 val; + __le32 val; if (is_2ghz) val = eep->modalHeader2G.switchcomspdt; else val = eep->modalHeader5G.switchcomspdt; - return le16_to_cpu(val); + return le32_to_cpu(val); } @@ -3607,6 +3612,10 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); if (AR_SREV_9462(ah)) { + if (AR_SREV_9462_10(ah)) { + value &= ~AR_SWITCH_TABLE_COM_SPDT; + value |= 0x00100000; + } REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9462_ALL, value); } else @@ -4419,8 +4428,8 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, is2GHz) + ht40PowerIncForPdadc; for (i = 0; i < ar9300RateSize; i++) { - ath_dbg(common, EEPROM, "TPC[%02d] 0x%08x\n", - i, targetPowerValT2[i]); + ath_dbg(common, ATH_DBG_EEPROM, + "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); } } @@ -4439,7 +4448,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); if (ichain >= AR9300_MAX_CHAINS) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Invalid chain index, must be less than %d\n", AR9300_MAX_CHAINS); return -1; @@ -4447,7 +4456,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, if (mode) { /* 5GHz */ if (ipier >= AR9300_NUM_5G_CAL_PIERS) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Invalid 5GHz cal pier index, must be less than %d\n", AR9300_NUM_5G_CAL_PIERS); return -1; @@ -4457,7 +4466,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, is2GHz = 0; } else { if (ipier >= AR9300_NUM_2G_CAL_PIERS) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Invalid 2GHz cal pier index, must be less than %d\n", AR9300_NUM_2G_CAL_PIERS); return -1; @@ -4619,7 +4628,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) /* interpolate */ for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { - ath_dbg(common, EEPROM, "ch=%d f=%d low=%d %d h=%d %d\n", + ath_dbg(common, ATH_DBG_EEPROM, + "ch=%d f=%d low=%d %d h=%d %d\n", ichain, frequency, lfrequency[ichain], lcorrection[ichain], hfrequency[ichain], hcorrection[ichain]); @@ -4674,7 +4684,7 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ar9003_hw_power_control_override(ah, frequency, correction, voltage, temperature); - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "for frequency=%d, calibration correction = %d %d %d\n", frequency, correction[0], correction[1], correction[2]); @@ -4773,7 +4783,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, { struct ath_common *common = ath9k_hw_common(ah); struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep; - u16 twiceMaxEdgePower; + u16 twiceMaxEdgePower = MAX_RATE_POWER; int i; u16 scaledPower = 0, minCtlPower; static const u16 ctlModesFor11a[] = { @@ -4860,7 +4870,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - ath_dbg(common, REGULATORY, + ath_dbg(common, ATH_DBG_REGULATORY, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); @@ -4874,9 +4884,8 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, ctlNum = AR9300_NUM_CTLS_5G; } - twiceMaxEdgePower = MAX_RATE_POWER; for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) { - ath_dbg(common, REGULATORY, + ath_dbg(common, ATH_DBG_REGULATORY, "LOOP-Ctlidx %d: cfgCtl 0x%2.2x pCtlMode 0x%2.2x ctlIndex 0x%2.2x chan %d\n", i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i], chan->channel); @@ -4918,7 +4927,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - ath_dbg(common, REGULATORY, + ath_dbg(common, ATH_DBG_REGULATORY, "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n", ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, scaledPower, minCtlPower); @@ -5042,7 +5051,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, target_power_val_t2_eep[i]) > paprd_scale_factor)) { ah->paprd_ratemask &= ~(1 << i); - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "paprd disabled for mcs %d\n", i); } } @@ -5060,8 +5069,8 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, return; for (i = 0; i < ar9300RateSize; i++) { - ath_dbg(common, EEPROM, "TPC[%02d] 0x%08x\n", - i, targetPowerValT2[i]); + ath_dbg(common, ATH_DBG_EEPROM, + "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); } ah->txpower_limit = regulatory->max_power_level; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h old mode 100644 new mode 100755 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 42ad784b..979d2254 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -22,6 +22,7 @@ #include "ar9330_1p1_initvals.h" #include "ar9330_1p2_initvals.h" #include "ar9580_1p0_initvals.h" +#include "ar9462_1p0_initvals.h" #include "ar9462_2p0_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -84,11 +85,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* additional clock settings */ if (ah->is_clk_25mhz) - INIT_INI_ARRAY(&ah->iniAdditional, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9331_1p1_xtal_25M, ARRAY_SIZE(ar9331_1p1_xtal_25M), 2); else - INIT_INI_ARRAY(&ah->iniAdditional, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9331_1p1_xtal_40M, ARRAY_SIZE(ar9331_1p1_xtal_40M), 2); } else if (AR_SREV_9330_12(ah)) { @@ -137,11 +138,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* additional clock settings */ if (ah->is_clk_25mhz) - INIT_INI_ARRAY(&ah->iniAdditional, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9331_1p2_xtal_25M, ARRAY_SIZE(ar9331_1p2_xtal_25M), 2); else - INIT_INI_ARRAY(&ah->iniAdditional, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9331_1p2_xtal_40M, ARRAY_SIZE(ar9331_1p2_xtal_40M), 2); } else if (AR_SREV_9340(ah)) { @@ -191,16 +192,15 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), 5); - INIT_INI_ARRAY(&ah->iniModesFastClock, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9340Modes_fast_clock_1p0, ARRAY_SIZE(ar9340Modes_fast_clock_1p0), 3); - if (!ah->is_clk_25mhz) - INIT_INI_ARRAY(&ah->iniAdditional, - ar9340_1p0_radio_core_40M, - ARRAY_SIZE(ar9340_1p0_radio_core_40M), - 2); + INIT_INI_ARRAY(&ah->iniModesAdditional_40M, + ar9340_1p0_radio_core_40M, + ARRAY_SIZE(ar9340_1p0_radio_core_40M), + 2); } else if (AR_SREV_9485_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -261,6 +261,63 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9485_1_1_pcie_phy_clkreq_disable_L1, ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), 2); + } else if (AR_SREV_9462_10(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_1p0_mac_core, + ARRAY_SIZE(ar9462_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9462_1p0_mac_postamble, + ARRAY_SIZE(ar9462_1p0_mac_postamble), + 5); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9462_1p0_baseband_core, + ARRAY_SIZE(ar9462_1p0_baseband_core), + 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9462_1p0_baseband_postamble, + ARRAY_SIZE(ar9462_1p0_baseband_postamble), 5); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9462_1p0_radio_core, + ARRAY_SIZE(ar9462_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9462_1p0_radio_postamble, + ARRAY_SIZE(ar9462_1p0_radio_postamble), 5); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9462_1p0_soc_preamble, + ARRAY_SIZE(ar9462_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9462_1p0_soc_postamble, + ARRAY_SIZE(ar9462_1p0_soc_postamble), 5); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), 2); + + /* Awake -> Sleep Setting */ + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9462_pcie_phy_clkreq_disable_L1_1p0, + ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0), + 2); + + /* Sleep -> Awake Setting */ + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9462_pcie_phy_clkreq_disable_L1_1p0, + ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0), + 2); + + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9462_modes_fast_clock_1p0, + ARRAY_SIZE(ar9462_modes_fast_clock_1p0), 3); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + AR9462_BB_CTX_COEFJ(1p0), + ARRAY_SIZE(AR9462_BB_CTX_COEFJ(1p0)), 2); + } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -319,7 +376,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) 2); /* Fast clock modal settings */ - INIT_INI_ARRAY(&ah->iniModesFastClock, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9462_modes_fast_clock_2p0, ARRAY_SIZE(ar9462_modes_fast_clock_2p0), 3); @@ -376,7 +433,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table), 5); - INIT_INI_ARRAY(&ah->iniModesFastClock, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9580_1p0_modes_fast_clock, ARRAY_SIZE(ar9580_1p0_modes_fast_clock), 3); @@ -443,7 +500,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) 2); /* Fast clock modal settings */ - INIT_INI_ARRAY(&ah->iniModesFastClock, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9300Modes_fast_clock_2p2, ARRAY_SIZE(ar9300Modes_fast_clock_2p2), 3); @@ -477,6 +534,11 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) ar9580_1p0_lowest_ob_db_tx_gain_table, ARRAY_SIZE(ar9580_1p0_lowest_ob_db_tx_gain_table), 5); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9462_modes_low_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_1p0), + 5); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_modes_low_ob_db_tx_gain_table_2p0, @@ -516,6 +578,11 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) ar9580_1p0_high_ob_db_tx_gain_table, ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table), 5); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9462_modes_high_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_1p0), + 5); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_modes_high_ob_db_tx_gain_table_2p0, @@ -642,6 +709,11 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) ar9580_1p0_rx_gain_table, ARRAY_SIZE(ar9580_1p0_rx_gain_table), 2); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), + 2); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9462_common_rx_gain_table_2p0, @@ -676,6 +748,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_1p0), + 2); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9462_common_wo_xlna_rx_gain_table_2p0, @@ -695,10 +772,14 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) static void ar9003_rx_gain_table_mode2(struct ath_hw *ah) { - if (AR_SREV_9462_20(ah)) + if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_mixed_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_1p0), 2); + else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_mixed_rx_gain_table_2p0, - ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2); + ar9462_common_mixed_rx_gain_table_2p0, + ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2); } static void ar9003_rx_gain_table_apply(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index a66a13b7..ccde784a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -16,7 +16,6 @@ #include #include "hw.h" #include "ar9003_mac.h" -#include "ar9003_mci.h" static void ar9003_hw_rx_enable(struct ath_hw *hw) { @@ -29,14 +28,11 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) struct ar9003_txc *ads = ds; int checksum = 0; u32 val, ctl12, ctl17; - u8 desc_len; - - desc_len = (AR_SREV_9462(ah) ? 0x18 : 0x17); val = (ATHEROS_VENDOR_ID << AR_DescId_S) | (1 << AR_TxRxDesc_S) | (1 << AR_CtrlStat_S) | - (i->qcu << AR_TxQcuNum_S) | desc_len; + (i->qcu << AR_TxQcuNum_S) | 0x17; checksum += val; ACCESS_ONCE(ads->info) = val; @@ -85,7 +81,6 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ads->ctl20 = 0; ads->ctl21 = 0; ads->ctl22 = 0; - ads->ctl23 = 0; ctl17 = SM(i->keytype, AR_EncrType); if (!i->is_first) { @@ -180,23 +175,20 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) u32 isr = 0; u32 mask2 = 0; struct ath9k_hw_capabilities *pCap = &ah->caps; + u32 sync_cause = 0; struct ath_common *common = ath9k_hw_common(ah); - u32 sync_cause = 0, async_cause; - - async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE); - if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) { + if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) isr = REG_READ(ah, AR_ISR); } - sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; *masked = 0; - if (!isr && !sync_cause && !async_cause) + if (!isr && !sync_cause) return false; if (isr) { @@ -302,9 +294,6 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ar9003_hw_bb_watchdog_read(ah); } - if (async_cause & AR_INTR_ASYNC_MASK_MCI) - ar9003_mci_get_isr(ah, masked); - if (sync_cause) { if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); @@ -313,7 +302,7 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) - ath_dbg(common, INTERRUPT, + ath_dbg(common, ATH_DBG_INTERRUPT, "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); @@ -326,6 +315,7 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { + struct ar9003_txc *txc = (struct ar9003_txc *) ds; struct ar9003_txs *ads; u32 status; @@ -335,11 +325,15 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, if ((status & AR_TxDone) == 0) return -EINPROGRESS; - ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; + ts->qid = MS(ads->ds_info, AR_TxQcuNum); + if (!txc || (MS(txc->info, AR_TxQcuNum) == ts->qid)) + ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; + else + return -ENOENT; if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) || (MS(ads->ds_info, AR_TxRxDesc) != 1)) { - ath_dbg(ath9k_hw_common(ah), XMIT, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT, "Tx Descriptor error %x\n", ads->ds_info); memset(ads, 0, sizeof(*ads)); return -EIO; @@ -349,7 +343,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_seqnum = MS(status, AR_SeqNum); ts->tid = MS(status, AR_TxTid); - ts->qid = MS(ads->ds_info, AR_TxQcuNum); ts->desc_id = MS(ads->status1, AR_TxDescId); ts->ts_tstamp = ads->status4; ts->ts_status = 0; @@ -436,14 +429,20 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr; unsigned int phyerr; - if ((rxsp->status11 & AR_RxDone) == 0) - return -EINPROGRESS; + /* TODO: byte swap on big endian for ar9300_10 */ - if (MS(rxsp->ds_info, AR_DescId) != 0x168c) - return -EINVAL; + if (!rxs) { + if ((rxsp->status11 & AR_RxDone) == 0) + return -EINPROGRESS; - if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) - return -EINPROGRESS; + if (MS(rxsp->ds_info, AR_DescId) != 0x168c) + return -EINVAL; + + if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) + return -EINPROGRESS; + + return 0; + } rxs->rs_status = 0; rxs->rs_flags = 0; @@ -500,11 +499,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, */ if (rxsp->status11 & AR_CRCErr) rxs->rs_status |= ATH9K_RXERR_CRC; - else if (rxsp->status11 & AR_DecryptCRCErr) - rxs->rs_status |= ATH9K_RXERR_DECRYPT; - else if (rxsp->status11 & AR_MichaelErr) - rxs->rs_status |= ATH9K_RXERR_MIC; - if (rxsp->status11 & AR_PHYErr) { + else if (rxsp->status11 & AR_PHYErr) { phyerr = MS(rxsp->status11, AR_PHYErrCode); /* * If we reach a point here where AR_PostDelimCRCErr is @@ -526,11 +521,14 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_status |= ATH9K_RXERR_PHY; rxs->rs_phyerr = phyerr; } - }; - } - if (rxsp->status11 & AR_KeyMiss) - rxs->rs_status |= ATH9K_RXERR_KEYMISS; + } else if (rxsp->status11 & AR_DecryptCRCErr) + rxs->rs_status |= ATH9K_RXERR_DECRYPT; + else if (rxsp->status11 & AR_MichaelErr) + rxs->rs_status |= ATH9K_RXERR_MIC; + if (rxsp->status11 & AR_KeyMiss) + rxs->rs_status |= ATH9K_RXERR_KEYMISS; + } return 0; } @@ -543,7 +541,7 @@ void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah) memset((void *) ah->ts_ring, 0, ah->ts_size * sizeof(struct ar9003_txs)); - ath_dbg(ath9k_hw_common(ah), XMIT, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT, "TS Start 0x%x End 0x%x Virt %p, Size %d\n", ah->ts_paddr_start, ah->ts_paddr_end, ah->ts_ring, ah->ts_size); @@ -554,7 +552,7 @@ void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah) void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, u32 ts_paddr_start, - u16 size) + u8 size) { ah->ts_paddr_start = ts_paddr_start; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h index cbf60b09..c5044938 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h @@ -92,8 +92,7 @@ struct ar9003_txc { u32 ctl20; /* DMA control 20 */ u32 ctl21; /* DMA control 21 */ u32 ctl22; /* DMA control 22 */ - u32 ctl23; /* DMA control 23 */ - u32 pad[8]; /* pad to cache line (128 bytes/32 dwords) */ + u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */ } __packed __aligned(4); struct ar9003_txs { @@ -119,5 +118,5 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah); void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, u32 ts_paddr_start, - u16 size); + u8 size); #endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 3d400e8d..a4450cba 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -54,7 +54,7 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val) if (val) { ah->paprd_table_write_done = true; - ath9k_hw_apply_txpower(ah, chan, false); + ath9k_hw_apply_txpower(ah, chan); } REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0, @@ -119,8 +119,8 @@ static int ar9003_get_training_power_5g(struct ath_hw *ah) break; default: delta = 0; - ath_dbg(common, CALIBRATE, "Invalid tx-chainmask: %u\n", - ah->txchainmask); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Invalid tx-chainmask: %u\n", ah->txchainmask); } power += delta; @@ -148,12 +148,13 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) else training_power = ar9003_get_training_power_5g(ah); - ath_dbg(common, CALIBRATE, "Training power: %d, Target power: %d\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "Training power: %d, Target power: %d\n", training_power, ah->paprd_target_power); if (training_power < 0) { - ath_dbg(common, CALIBRATE, - "PAPRD target power delta out of range\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, + "PAPRD target power delta out of range"); return -ERANGE; } ah->paprd_training_power = training_power; @@ -310,8 +311,8 @@ static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, reg_cl_gain = AR_PHY_CL_TAB_2; break; default: - ath_dbg(ath9k_hw_common(ah), CALIBRATE, - "Invalid chainmask: %d\n", chain); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "Invalid chainmask: %d\n", chain); break; } @@ -849,7 +850,7 @@ bool ar9003_paprd_is_done(struct ath_hw *ah) agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR); - ath_dbg(ath9k_hw_common(ah), CALIBRATE, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, "AGC2_PWR = 0x%x training done = 0x%x\n", agc2_pwr, paprd_done); /* diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 8783500a..aa2eb463 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -46,7 +46,7 @@ static const int m2ThreshExt_off = 127; * @chan: * * This is the function to change channel on single-chip devices, that is - * for AR9300 family of chipsets. + * all devices after ar9280. * * This function takes the channel value in MHz and sets * hardware channel value. Assumes writes have been enabled to analog bus. @@ -373,7 +373,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, else spur_subchannel_sd = 0; - spur_freq_sd = ((freq_offset + 10) << 9) / 11; + spur_freq_sd = (freq_offset << 9) / 11; } else { if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, @@ -382,7 +382,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, else spur_subchannel_sd = 1; - spur_freq_sd = ((freq_offset - 10) << 9) / 11; + spur_freq_sd = (freq_offset << 9) / 11; } @@ -666,22 +666,23 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, * different modal values. */ if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - REG_WRITE_ARRAY(&ah->iniModesFastClock, + REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); - REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); + if (AR_SREV_9330(ah)) + REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites); + + if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) + REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); if (AR_SREV_9462(ah)) ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1); - if (chan->channel == 2484) - ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1); - ah->modes_index = modesIndex; ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); - ath9k_hw_apply_txpower(ah, chan, false); + ath9k_hw_apply_txpower(ah, chan); if (AR_SREV_9462(ah)) { if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, @@ -868,7 +869,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); if (!on != aniState->ofdmWeakSigDetectOff) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: ofdm weak signal: %s=>%s\n", chan->channel, !aniState->ofdmWeakSigDetectOff ? @@ -886,7 +887,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(firstep_table)) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n", level, ARRAY_SIZE(firstep_table)); return false; @@ -923,7 +924,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); if (level != aniState->firstepLevel) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", chan->channel, aniState->firstepLevel, @@ -931,7 +932,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, ATH9K_ANI_FIRSTEP_LVL_NEW, value, aniState->iniDef.firstep); - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] firstep_low[level]=%d ini=%d\n", chan->channel, aniState->firstepLevel, @@ -951,7 +952,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(cycpwrThr1_table)) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n", level, ARRAY_SIZE(cycpwrThr1_table)); return false; @@ -987,7 +988,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, AR_PHY_EXT_CYCPWR_THR1, value2); if (level != aniState->spurImmunityLevel) { - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n", chan->channel, aniState->spurImmunityLevel, @@ -995,7 +996,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, ATH9K_ANI_SPUR_IMMUNE_LVL_NEW, value, aniState->iniDef.cycpwrThr1); - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n", chan->channel, aniState->spurImmunityLevel, @@ -1026,7 +1027,8 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_MUX_REG, is_on); if (!is_on != aniState->mrcCCKOff) { - ath_dbg(common, ANI, "** ch %d: MRC CCK: %s=>%s\n", + ath_dbg(common, ATH_DBG_ANI, + "** ch %d: MRC CCK: %s=>%s\n", chan->channel, !aniState->mrcCCKOff ? "on" : "off", is_on ? "on" : "off"); @@ -1041,11 +1043,11 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, case ATH9K_ANI_PRESENT: break; default: - ath_dbg(common, ANI, "invalid cmd %u\n", cmd); + ath_dbg(common, ATH_DBG_ANI, "invalid cmd %u\n", cmd); return false; } - ath_dbg(common, ANI, + ath_dbg(common, ATH_DBG_ANI, "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n", aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff ? "on" : "off", @@ -1089,20 +1091,13 @@ static void ar9003_hw_set_nf_limits(struct ath_hw *ah) { ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ; ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ; - ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ; + if (AR_SREV_9330(ah)) + ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ; + else + ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ; ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ; ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ; ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ; - - if (AR_SREV_9330(ah)) - ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ; - - if (AR_SREV_9462(ah)) { - ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ; - ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9462_2GHZ; - ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ; - ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9462_5GHZ; - } } /* @@ -1121,7 +1116,8 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) aniState = &ah->curchan->ani; iniDef = &aniState->iniDef; - ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", + ath_dbg(common, ATH_DBG_ANI, + "ver %d.%d opmode %u chan %d Mhz/0x%x\n", ah->hw_version.macVersion, ah->hw_version.macRev, ah->opmode, @@ -1310,9 +1306,13 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, * different modal values. */ if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex, regWrites); + REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); + + if (AR_SREV_9330(ah)) + REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites); - REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); + if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) + REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); ah->modes_index = modesIndex; *ini_reloaded = true; @@ -1379,7 +1379,7 @@ void ar9003_hw_bb_watchdog_config(struct ath_hw *ah) ~(AR_PHY_WATCHDOG_NON_IDLE_ENABLE | AR_PHY_WATCHDOG_IDLE_ENABLE)); - ath_dbg(common, RESET, "Disabled BB Watchdog\n"); + ath_dbg(common, ATH_DBG_RESET, "Disabled BB Watchdog\n"); return; } @@ -1415,7 +1415,8 @@ void ar9003_hw_bb_watchdog_config(struct ath_hw *ah) AR_PHY_WATCHDOG_IDLE_MASK | (AR_PHY_WATCHDOG_NON_IDLE_MASK & (idle_count << 2))); - ath_dbg(common, RESET, "Enabled BB Watchdog timeout (%u ms)\n", + ath_dbg(common, ATH_DBG_RESET, + "Enabled BB Watchdog timeout (%u ms)\n", idle_tmo_ms); } @@ -1444,9 +1445,9 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah) return; status = ah->bb_watchdog_last_status; - ath_dbg(common, RESET, + ath_dbg(common, ATH_DBG_RESET, "\n==== BB update: BB status=0x%08x ====\n", status); - ath_dbg(common, RESET, + ath_dbg(common, ATH_DBG_RESET, "** BB state: wd=%u det=%u rdar=%u rOFDM=%d rCCK=%u tOFDM=%u tCCK=%u agc=%u src=%u **\n", MS(status, AR_PHY_WATCHDOG_INFO), MS(status, AR_PHY_WATCHDOG_DET_HANG), @@ -1458,19 +1459,22 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah) MS(status, AR_PHY_WATCHDOG_AGC_SM), MS(status, AR_PHY_WATCHDOG_SRCH_SM)); - ath_dbg(common, RESET, "** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n", + ath_dbg(common, ATH_DBG_RESET, + "** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n", REG_READ(ah, AR_PHY_WATCHDOG_CTL_1), REG_READ(ah, AR_PHY_WATCHDOG_CTL_2)); - ath_dbg(common, RESET, "** BB mode: BB_gen_controls=0x%08x **\n", + ath_dbg(common, ATH_DBG_RESET, + "** BB mode: BB_gen_controls=0x%08x **\n", REG_READ(ah, AR_PHY_GEN_CTRL)); #define PCT(_field) (common->cc_survey._field * 100 / common->cc_survey.cycles) if (common->cc_survey.cycles) - ath_dbg(common, RESET, + ath_dbg(common, ATH_DBG_RESET, "** BB busy times: rx_clear=%d%%, rx_frame=%d%%, tx_frame=%d%% **\n", PCT(rx_busy), PCT(rx_frame), PCT(tx_frame)); - ath_dbg(common, RESET, "==== BB update: done ====\n\n"); + ath_dbg(common, ATH_DBG_RESET, + "==== BB update: done ====\n\n"); } EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 6402b9e4..55931054 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -325,18 +325,13 @@ #define AR_PHY_RX_OCGAIN (AR_AGC_BASE + 0x200) -#define AR_PHY_CCA_NOM_VAL_9300_2GHZ -110 -#define AR_PHY_CCA_NOM_VAL_9300_5GHZ -115 -#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ -125 -#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ -125 +#define AR_PHY_CCA_NOM_VAL_9300_2GHZ (AR_SREV_9462(ah) ? -127 : -110) +#define AR_PHY_CCA_NOM_VAL_9300_5GHZ (AR_SREV_9462(ah) ? -127 : -115) +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ (AR_SREV_9462(ah) ? -127 : -125) +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ (AR_SREV_9462(ah) ? -127 : -125) #define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -95 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100 -#define AR_PHY_CCA_NOM_VAL_9462_2GHZ -127 -#define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ -127 -#define AR_PHY_CCA_NOM_VAL_9462_5GHZ -127 -#define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ -127 - #define AR_PHY_CCA_NOM_VAL_9330_2GHZ -118 #define AR9300_EXT_LNA_CTL_GPIO_AR9485 9 @@ -497,8 +492,6 @@ #define AR_PHY_TEST_CTL_TSTADC_EN_S 8 #define AR_PHY_TEST_CTL_RX_OBS_SEL 0x3C00 #define AR_PHY_TEST_CTL_RX_OBS_SEL_S 10 -#define AR_PHY_TEST_CTL_DEBUGPORT_SEL 0xe0000000 -#define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S 29 #define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) @@ -619,14 +612,16 @@ #define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) #define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) #define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc) -#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4)) -#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8)) +#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + (AR_SREV_9462_10(ah) ? \ + 0x4c0 : 0x4c4)) +#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + (AR_SREV_9462_10(ah) ? \ + 0x4c4 : 0x4c8)) #define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) #define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) #define AR_PHY_65NM_CH0_SYNTH4 0x1608c -#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002) -#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1) +#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT 0x00000002 +#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S 1 #define AR_PHY_65NM_CH0_SYNTH7 0x16098 #define AR_PHY_65NM_CH0_BIAS1 0x160c0 #define AR_PHY_65NM_CH0_BIAS2 0x160c4 @@ -1008,7 +1003,6 @@ /* GLB Registers */ #define AR_GLB_BASE 0x20000 -#define AR_GLB_GPIO_CONTROL (AR_GLB_BASE) #define AR_PHY_GLB_CONTROL (AR_GLB_BASE + 0x44) #define AR_GLB_SCRATCH(_ah) (AR_GLB_BASE + \ (AR_SREV_9462_20(_ah) ? 0x4c : 0x50)) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c index 458bedf0..48803ee9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c @@ -16,7 +16,6 @@ #include "hw.h" #include "ar9003_phy.h" -#include "ar9003_rtt.h" #define RTT_RESTORE_TIMEOUT 1000 #define RTT_ACCESS_TIMEOUT 100 diff --git a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h new file mode 100644 index 00000000..5c55ae38 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h @@ -0,0 +1,1833 @@ +/* + * Copyright (c) 2010 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef INITVALS_9462_1P0_H +#define INITVALS_9462_1P0_H + +/* AR9462 1.0 */ + +static const u32 ar9462_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00060085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00001810, 0x0f000003}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00080000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008050, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c20}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00005}, + {0x000080d8, 0x00400002}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486e00}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c4, 0x33332210}, + {0x000081c8, 0x00000000}, + {0x000081cc, 0x00000000}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f400}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e800}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x99c00010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x0000001f}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0xffff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x000301ff}, +}; + +static const u32 ar9462_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x6f7f0301}, + {0x0000a3a0, 0xca9228ee}, +}; + +static const u32 ar9462_1p0_sys3ant[][2] = { + /* Addr allmodes */ + {0x00063280, 0x00040807}, + {0x00063284, 0x104ccccc}, +}; + +static const u32 ar9462_pcie_phy_clkreq_enable_L1_1p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x10053e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000580c}, +}; + +static const u32 ar9462_1p0_mac_core_emulation[][2] = { + /* Addr allmodes */ + {0x00000030, 0x00060085}, + {0x00000044, 0x00000008}, + {0x0000805c, 0xffffc7ff}, + {0x00008344, 0xaa4a105b}, +}; + +static const u32 ar9462_common_rx_gain_table_ar9280_2p0_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x02000101}, + {0x0000a004, 0x02000102}, + {0x0000a008, 0x02000103}, + {0x0000a00c, 0x02000104}, + {0x0000a010, 0x02000200}, + {0x0000a014, 0x02000201}, + {0x0000a018, 0x02000202}, + {0x0000a01c, 0x02000203}, + {0x0000a020, 0x02000204}, + {0x0000a024, 0x02000205}, + {0x0000a028, 0x02000208}, + {0x0000a02c, 0x02000302}, + {0x0000a030, 0x02000303}, + {0x0000a034, 0x02000304}, + {0x0000a038, 0x02000400}, + {0x0000a03c, 0x02010300}, + {0x0000a040, 0x02010301}, + {0x0000a044, 0x02010302}, + {0x0000a048, 0x02000500}, + {0x0000a04c, 0x02010400}, + {0x0000a050, 0x02020300}, + {0x0000a054, 0x02020301}, + {0x0000a058, 0x02020302}, + {0x0000a05c, 0x02020303}, + {0x0000a060, 0x02020400}, + {0x0000a064, 0x02030300}, + {0x0000a068, 0x02030301}, + {0x0000a06c, 0x02030302}, + {0x0000a070, 0x02030303}, + {0x0000a074, 0x02030400}, + {0x0000a078, 0x02040300}, + {0x0000a07c, 0x02040301}, + {0x0000a080, 0x02040302}, + {0x0000a084, 0x02040303}, + {0x0000a088, 0x02030500}, + {0x0000a08c, 0x02040400}, + {0x0000a090, 0x02050203}, + {0x0000a094, 0x02050204}, + {0x0000a098, 0x02050205}, + {0x0000a09c, 0x02040500}, + {0x0000a0a0, 0x02050301}, + {0x0000a0a4, 0x02050302}, + {0x0000a0a8, 0x02050303}, + {0x0000a0ac, 0x02050400}, + {0x0000a0b0, 0x02050401}, + {0x0000a0b4, 0x02050402}, + {0x0000a0b8, 0x02050403}, + {0x0000a0bc, 0x02050500}, + {0x0000a0c0, 0x02050501}, + {0x0000a0c4, 0x02050502}, + {0x0000a0c8, 0x02050503}, + {0x0000a0cc, 0x02050504}, + {0x0000a0d0, 0x02050600}, + {0x0000a0d4, 0x02050601}, + {0x0000a0d8, 0x02050602}, + {0x0000a0dc, 0x02050603}, + {0x0000a0e0, 0x02050604}, + {0x0000a0e4, 0x02050700}, + {0x0000a0e8, 0x02050701}, + {0x0000a0ec, 0x02050702}, + {0x0000a0f0, 0x02050703}, + {0x0000a0f4, 0x02050704}, + {0x0000a0f8, 0x02050705}, + {0x0000a0fc, 0x02050708}, + {0x0000a100, 0x02050709}, + {0x0000a104, 0x0205070a}, + {0x0000a108, 0x0205070b}, + {0x0000a10c, 0x0205070c}, + {0x0000a110, 0x0205070d}, + {0x0000a114, 0x02050710}, + {0x0000a118, 0x02050711}, + {0x0000a11c, 0x02050712}, + {0x0000a120, 0x02050713}, + {0x0000a124, 0x02050714}, + {0x0000a128, 0x02050715}, + {0x0000a12c, 0x02050730}, + {0x0000a130, 0x02050731}, + {0x0000a134, 0x02050732}, + {0x0000a138, 0x02050733}, + {0x0000a13c, 0x02050734}, + {0x0000a140, 0x02050735}, + {0x0000a144, 0x02050750}, + {0x0000a148, 0x02050751}, + {0x0000a14c, 0x02050752}, + {0x0000a150, 0x02050753}, + {0x0000a154, 0x02050754}, + {0x0000a158, 0x02050755}, + {0x0000a15c, 0x02050770}, + {0x0000a160, 0x02050771}, + {0x0000a164, 0x02050772}, + {0x0000a168, 0x02050773}, + {0x0000a16c, 0x02050774}, + {0x0000a170, 0x02050775}, + {0x0000a174, 0x00000776}, + {0x0000a178, 0x00000776}, + {0x0000a17c, 0x00000776}, + {0x0000a180, 0x00000776}, + {0x0000a184, 0x00000776}, + {0x0000a188, 0x00000776}, + {0x0000a18c, 0x00000776}, + {0x0000a190, 0x00000776}, + {0x0000a194, 0x00000776}, + {0x0000a198, 0x00000776}, + {0x0000a19c, 0x00000776}, + {0x0000a1a0, 0x00000776}, + {0x0000a1a4, 0x00000776}, + {0x0000a1a8, 0x00000776}, + {0x0000a1ac, 0x00000776}, + {0x0000a1b0, 0x00000776}, + {0x0000a1b4, 0x00000776}, + {0x0000a1b8, 0x00000776}, + {0x0000a1bc, 0x00000776}, + {0x0000a1c0, 0x00000776}, + {0x0000a1c4, 0x00000776}, + {0x0000a1c8, 0x00000776}, + {0x0000a1cc, 0x00000776}, + {0x0000a1d0, 0x00000776}, + {0x0000a1d4, 0x00000776}, + {0x0000a1d8, 0x00000776}, + {0x0000a1dc, 0x00000776}, + {0x0000a1e0, 0x00000776}, + {0x0000a1e4, 0x00000776}, + {0x0000a1e8, 0x00000776}, + {0x0000a1ec, 0x00000776}, + {0x0000a1f0, 0x00000776}, + {0x0000a1f4, 0x00000776}, + {0x0000a1f8, 0x00000776}, + {0x0000a1fc, 0x00000776}, + {0x0000b000, 0x02000101}, + {0x0000b004, 0x02000102}, + {0x0000b008, 0x02000103}, + {0x0000b00c, 0x02000104}, + {0x0000b010, 0x02000200}, + {0x0000b014, 0x02000201}, + {0x0000b018, 0x02000202}, + {0x0000b01c, 0x02000203}, + {0x0000b020, 0x02000204}, + {0x0000b024, 0x02000205}, + {0x0000b028, 0x02000208}, + {0x0000b02c, 0x02000302}, + {0x0000b030, 0x02000303}, + {0x0000b034, 0x02000304}, + {0x0000b038, 0x02000400}, + {0x0000b03c, 0x02010300}, + {0x0000b040, 0x02010301}, + {0x0000b044, 0x02010302}, + {0x0000b048, 0x02000500}, + {0x0000b04c, 0x02010400}, + {0x0000b050, 0x02020300}, + {0x0000b054, 0x02020301}, + {0x0000b058, 0x02020302}, + {0x0000b05c, 0x02020303}, + {0x0000b060, 0x02020400}, + {0x0000b064, 0x02030300}, + {0x0000b068, 0x02030301}, + {0x0000b06c, 0x02030302}, + {0x0000b070, 0x02030303}, + {0x0000b074, 0x02030400}, + {0x0000b078, 0x02040300}, + {0x0000b07c, 0x02040301}, + {0x0000b080, 0x02040302}, + {0x0000b084, 0x02040303}, + {0x0000b088, 0x02030500}, + {0x0000b08c, 0x02040400}, + {0x0000b090, 0x02050203}, + {0x0000b094, 0x02050204}, + {0x0000b098, 0x02050205}, + {0x0000b09c, 0x02040500}, + {0x0000b0a0, 0x02050301}, + {0x0000b0a4, 0x02050302}, + {0x0000b0a8, 0x02050303}, + {0x0000b0ac, 0x02050400}, + {0x0000b0b0, 0x02050401}, + {0x0000b0b4, 0x02050402}, + {0x0000b0b8, 0x02050403}, + {0x0000b0bc, 0x02050500}, + {0x0000b0c0, 0x02050501}, + {0x0000b0c4, 0x02050502}, + {0x0000b0c8, 0x02050503}, + {0x0000b0cc, 0x02050504}, + {0x0000b0d0, 0x02050600}, + {0x0000b0d4, 0x02050601}, + {0x0000b0d8, 0x02050602}, + {0x0000b0dc, 0x02050603}, + {0x0000b0e0, 0x02050604}, + {0x0000b0e4, 0x02050700}, + {0x0000b0e8, 0x02050701}, + {0x0000b0ec, 0x02050702}, + {0x0000b0f0, 0x02050703}, + {0x0000b0f4, 0x02050704}, + {0x0000b0f8, 0x02050705}, + {0x0000b0fc, 0x02050708}, + {0x0000b100, 0x02050709}, + {0x0000b104, 0x0205070a}, + {0x0000b108, 0x0205070b}, + {0x0000b10c, 0x0205070c}, + {0x0000b110, 0x0205070d}, + {0x0000b114, 0x02050710}, + {0x0000b118, 0x02050711}, + {0x0000b11c, 0x02050712}, + {0x0000b120, 0x02050713}, + {0x0000b124, 0x02050714}, + {0x0000b128, 0x02050715}, + {0x0000b12c, 0x02050730}, + {0x0000b130, 0x02050731}, + {0x0000b134, 0x02050732}, + {0x0000b138, 0x02050733}, + {0x0000b13c, 0x02050734}, + {0x0000b140, 0x02050735}, + {0x0000b144, 0x02050750}, + {0x0000b148, 0x02050751}, + {0x0000b14c, 0x02050752}, + {0x0000b150, 0x02050753}, + {0x0000b154, 0x02050754}, + {0x0000b158, 0x02050755}, + {0x0000b15c, 0x02050770}, + {0x0000b160, 0x02050771}, + {0x0000b164, 0x02050772}, + {0x0000b168, 0x02050773}, + {0x0000b16c, 0x02050774}, + {0x0000b170, 0x02050775}, + {0x0000b174, 0x00000776}, + {0x0000b178, 0x00000776}, + {0x0000b17c, 0x00000776}, + {0x0000b180, 0x00000776}, + {0x0000b184, 0x00000776}, + {0x0000b188, 0x00000776}, + {0x0000b18c, 0x00000776}, + {0x0000b190, 0x00000776}, + {0x0000b194, 0x00000776}, + {0x0000b198, 0x00000776}, + {0x0000b19c, 0x00000776}, + {0x0000b1a0, 0x00000776}, + {0x0000b1a4, 0x00000776}, + {0x0000b1a8, 0x00000776}, + {0x0000b1ac, 0x00000776}, + {0x0000b1b0, 0x00000776}, + {0x0000b1b4, 0x00000776}, + {0x0000b1b8, 0x00000776}, + {0x0000b1bc, 0x00000776}, + {0x0000b1c0, 0x00000776}, + {0x0000b1c4, 0x00000776}, + {0x0000b1c8, 0x00000776}, + {0x0000b1cc, 0x00000776}, + {0x0000b1d0, 0x00000776}, + {0x0000b1d4, 0x00000776}, + {0x0000b1d8, 0x00000776}, + {0x0000b1dc, 0x00000776}, + {0x0000b1e0, 0x00000776}, + {0x0000b1e4, 0x00000776}, + {0x0000b1e8, 0x00000776}, + {0x0000b1ec, 0x00000776}, + {0x0000b1f0, 0x00000776}, + {0x0000b1f4, 0x00000776}, + {0x0000b1f8, 0x00000776}, + {0x0000b1fc, 0x00000776}, +}; + +static const u32 ar9200_ar9280_2p0_radio_core_1p0[][2] = { + /* Addr allmodes */ + {0x00007800, 0x00040000}, + {0x00007804, 0xdb005012}, + {0x00007808, 0x04924914}, + {0x0000780c, 0x21084210}, + {0x00007810, 0x6d801300}, + {0x00007814, 0x0019beff}, + {0x00007818, 0x07e41000}, + {0x0000781c, 0x00392000}, + {0x00007820, 0x92592480}, + {0x00007824, 0x00040000}, + {0x00007828, 0xdb005012}, + {0x0000782c, 0x04924914}, + {0x00007830, 0x21084210}, + {0x00007834, 0x6d801300}, + {0x00007838, 0x0019beff}, + {0x0000783c, 0x07e40000}, + {0x00007840, 0x00392000}, + {0x00007844, 0x92592480}, + {0x00007848, 0x00100000}, + {0x0000784c, 0x773f0567}, + {0x00007850, 0x54214514}, + {0x00007854, 0x12035828}, + {0x00007858, 0x92592692}, + {0x0000785c, 0x00000000}, + {0x00007860, 0x56400000}, + {0x00007864, 0x0a8e370e}, + {0x00007868, 0xc0102850}, + {0x0000786c, 0x812d4000}, + {0x00007870, 0x807ec400}, + {0x00007874, 0x001b6db0}, + {0x00007878, 0x00376b63}, + {0x0000787c, 0x06db6db6}, + {0x00007880, 0x006d8000}, + {0x00007884, 0xffeffffe}, + {0x00007888, 0xffeffffe}, + {0x0000788c, 0x00010000}, + {0x00007890, 0x02060aeb}, + {0x00007894, 0x5a108000}, +}; + +static const u32 ar9462_1p0_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221}, + {0x00009e44, 0x005c0000, 0x005c0000, 0x005c0000, 0x005c0000}, + {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111}, + {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20}, + {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c}, + {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a}, + {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c}, + {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc}, + {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4}, + {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc}, + {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede}, + {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e}, + {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e}, + {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; + +static const u32 ar9462_pcie_phy_pll_on_clkreq_disable_L1_1p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x10012e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000580c}, +}; + +static const u32 ar9462_common_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x2a2d2f32}, + {0x0000b084, 0x21232328}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9462_modes_high_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400}, + {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402}, + {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, + {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640}, + {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, + {0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060}, + {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, + {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, +}; + +static const u32 ar9462_common_wo_xlna_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9462_1p0_mac_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +}; + +static const u32 ar9462_1p0_mac_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8}, + {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017}, +}; + +static const u32 ar9462_1p0_tx_gain_table_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002}, + {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004}, + {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c}, + {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b}, + {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a}, + {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a}, + {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a}, + {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a}, + {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a}, + {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a}, + {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a}, + {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a}, +}; + +static const u32 ar9462_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, + {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24646c08, 0x24646c08}, + {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, + {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, + {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +static const u32 ar9462_1p0_soc_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00001133, 0x00001133, 0x00001133, 0x00001133}, +}; + +static const u32 ar9462_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x9280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a290}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x0d000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098e4, 0x01ffffff}, + {0x000098e8, 0x01ffffff}, + {0x000098ec, 0x01ffffff}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb514}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009e54, 0x64c355c7}, + {0x00009e58, 0xfd897735}, + {0x00009e5c, 0xe9198724}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000006}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a6b0, 0x0000000a}, + {0x0000a6b4, 0x28f12c01}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000001}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, + {0x0000b6b0, 0x0000000a}, + {0x0000b6b4, 0x00c00001}, +}; + +static const u32 ar9462_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x0131b7c0, 0x0131b7c4, 0x0131b7c4, 0x0131b7c0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, + {0x0000a288, 0x00000110, 0x00000110, 0x00100110, 0x00100110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, +}; + +static const u32 ar9462_modes_fast_clock_1p0[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00001030, 0x00000268, 0x000004d0}, + {0x00001070, 0x0000018c, 0x00000318}, + {0x000010b0, 0x00000fd0, 0x00001fa0}, + {0x00008014, 0x044c044c, 0x08980898}, + {0x0000801c, 0x148ec02b, 0x148ec057}, + {0x00008318, 0x000044c0, 0x00008980}, + {0x00009e00, 0x0372131c, 0x0372131c}, + {0x0000a230, 0x0000400b, 0x00004016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +static const u32 ar9462_modes_low_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, + {0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060}, + {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, + {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, +}; + +static const u32 ar9462_1p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233}, +}; + +static const u32 ar9462_common_mixed_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x2a2d2f32}, + {0x0000b084, 0x21232328}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9462_pcie_phy_clkreq_disable_L1_1p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x10013e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000580c}, +}; + +static const u32 ar9462_1p0_baseband_core_emulation[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafa68e30}, + {0x00009884, 0x00002842}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009e50, 0x00000000}, + {0x00009fcc, 0x00000014}, + {0x0000a344, 0x00000010}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x71733d01}, + {0x0000a3a0, 0xd0ad5c12}, + {0x0000a3c0, 0x22222220}, + {0x0000a3c4, 0x22222222}, + {0x0000a404, 0x00418a11}, + {0x0000a418, 0x050001ce}, + {0x0000a438, 0x00001800}, + {0x0000a458, 0x01444452}, + {0x0000a644, 0x3fad9d74}, + {0x0000a690, 0x00000038}, +}; + +static const u32 ar9462_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016010, 0x6d820001}, + {0x00016040, 0x7f80fff8}, + {0x0001604c, 0x2699e04f}, + {0x00016050, 0x6db6db6c}, + {0x00016054, 0x6db60000}, + {0x00016058, 0x6c200000}, + {0x00016080, 0x00040000}, + {0x00016084, 0x9a68048c}, + {0x00016088, 0x54214514}, + {0x0001608c, 0x12030409}, + {0x00016090, 0x24926490}, + {0x00016098, 0xd2888888}, + {0x000160a0, 0x0a108ffe}, + {0x000160a4, 0x812fc490}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92000000}, + {0x000160b8, 0x0285dddc}, + {0x000160bc, 0x02908888}, + {0x000160c0, 0x00adb6d0}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x0de6c1b0}, + {0x00016100, 0x3fffbe04}, + {0x00016104, 0xfff80000}, + {0x00016108, 0x00200400}, + {0x00016110, 0x00000000}, + {0x00016144, 0x02084080}, + {0x00016148, 0x000080c0}, + {0x00016280, 0x050a0001}, + {0x00016284, 0x3d841400}, + {0x00016288, 0x00000000}, + {0x0001628c, 0xe3000000}, + {0x00016290, 0xa1005080}, + {0x00016294, 0x00000020}, + {0x00016298, 0x50a02900}, + {0x00016340, 0x121e4276}, + {0x00016344, 0x00300000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016410, 0x6c800001}, + {0x00016440, 0x7f80fff8}, + {0x0001644c, 0x4699e04f}, + {0x00016450, 0x6db6db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x3fffbe04}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00200400}, + {0x00016510, 0x00000000}, + {0x00016544, 0x02084080}, + {0x00016548, 0x000080c0}, +}; + +static const u32 ar9462_1p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, +}; + +static const u32 ar9462_1p0_sys2ant[][2] = { + /* Addr allmodes */ + {0x00063120, 0x00801980}, +}; + +#endif /* INITVALS_9462_1P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 15960024..c720042f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -41,24 +41,24 @@ static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = { static const u32 ar9462_2p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, - {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae}, - {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da}, - {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x09143e81}, + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x5ac640de}, + {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x0796be89}, {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8}, - {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e}, - {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x92c84d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, - {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, {0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0}, @@ -81,15 +81,6 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a3a4, 0x00000010, 0x00000010, 0x00000000, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa}, - {0x0000a3ac, 0xaaaaaa00, 0xaaaaaa30, 0xaaaaaa00, 0xaaaaaa00}, - {0x0000a41c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, - {0x0000a420, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce}, - {0x0000a424, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, - {0x0000a428, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce}, - {0x0000a42c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -98,6 +89,14 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; +static const u32 ar9462_2p0_mac_core_emulation[][2] = { + /* Addr allmodes */ + {0x00000030, 0x000e0085}, + {0x00000044, 0x00000008}, + {0x0000805c, 0xffffc7ff}, + {0x00008344, 0xaa4a105b}, +}; + static const u32 ar9462_common_rx_gain_table_2p0[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, @@ -372,6 +371,349 @@ static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = { {0x00018c08, 0x0003580c}, }; +static const u32 ar9462_2p0_sys3ant[][2] = { + /* Addr allmodes */ + {0x00063280, 0x00040807}, + {0x00063284, 0x104ccccc}, +}; + +static const u32 ar9462_common_rx_gain_table_ar9280_2p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x02000101}, + {0x0000a004, 0x02000102}, + {0x0000a008, 0x02000103}, + {0x0000a00c, 0x02000104}, + {0x0000a010, 0x02000200}, + {0x0000a014, 0x02000201}, + {0x0000a018, 0x02000202}, + {0x0000a01c, 0x02000203}, + {0x0000a020, 0x02000204}, + {0x0000a024, 0x02000205}, + {0x0000a028, 0x02000208}, + {0x0000a02c, 0x02000302}, + {0x0000a030, 0x02000303}, + {0x0000a034, 0x02000304}, + {0x0000a038, 0x02000400}, + {0x0000a03c, 0x02010300}, + {0x0000a040, 0x02010301}, + {0x0000a044, 0x02010302}, + {0x0000a048, 0x02000500}, + {0x0000a04c, 0x02010400}, + {0x0000a050, 0x02020300}, + {0x0000a054, 0x02020301}, + {0x0000a058, 0x02020302}, + {0x0000a05c, 0x02020303}, + {0x0000a060, 0x02020400}, + {0x0000a064, 0x02030300}, + {0x0000a068, 0x02030301}, + {0x0000a06c, 0x02030302}, + {0x0000a070, 0x02030303}, + {0x0000a074, 0x02030400}, + {0x0000a078, 0x02040300}, + {0x0000a07c, 0x02040301}, + {0x0000a080, 0x02040302}, + {0x0000a084, 0x02040303}, + {0x0000a088, 0x02030500}, + {0x0000a08c, 0x02040400}, + {0x0000a090, 0x02050203}, + {0x0000a094, 0x02050204}, + {0x0000a098, 0x02050205}, + {0x0000a09c, 0x02040500}, + {0x0000a0a0, 0x02050301}, + {0x0000a0a4, 0x02050302}, + {0x0000a0a8, 0x02050303}, + {0x0000a0ac, 0x02050400}, + {0x0000a0b0, 0x02050401}, + {0x0000a0b4, 0x02050402}, + {0x0000a0b8, 0x02050403}, + {0x0000a0bc, 0x02050500}, + {0x0000a0c0, 0x02050501}, + {0x0000a0c4, 0x02050502}, + {0x0000a0c8, 0x02050503}, + {0x0000a0cc, 0x02050504}, + {0x0000a0d0, 0x02050600}, + {0x0000a0d4, 0x02050601}, + {0x0000a0d8, 0x02050602}, + {0x0000a0dc, 0x02050603}, + {0x0000a0e0, 0x02050604}, + {0x0000a0e4, 0x02050700}, + {0x0000a0e8, 0x02050701}, + {0x0000a0ec, 0x02050702}, + {0x0000a0f0, 0x02050703}, + {0x0000a0f4, 0x02050704}, + {0x0000a0f8, 0x02050705}, + {0x0000a0fc, 0x02050708}, + {0x0000a100, 0x02050709}, + {0x0000a104, 0x0205070a}, + {0x0000a108, 0x0205070b}, + {0x0000a10c, 0x0205070c}, + {0x0000a110, 0x0205070d}, + {0x0000a114, 0x02050710}, + {0x0000a118, 0x02050711}, + {0x0000a11c, 0x02050712}, + {0x0000a120, 0x02050713}, + {0x0000a124, 0x02050714}, + {0x0000a128, 0x02050715}, + {0x0000a12c, 0x02050730}, + {0x0000a130, 0x02050731}, + {0x0000a134, 0x02050732}, + {0x0000a138, 0x02050733}, + {0x0000a13c, 0x02050734}, + {0x0000a140, 0x02050735}, + {0x0000a144, 0x02050750}, + {0x0000a148, 0x02050751}, + {0x0000a14c, 0x02050752}, + {0x0000a150, 0x02050753}, + {0x0000a154, 0x02050754}, + {0x0000a158, 0x02050755}, + {0x0000a15c, 0x02050770}, + {0x0000a160, 0x02050771}, + {0x0000a164, 0x02050772}, + {0x0000a168, 0x02050773}, + {0x0000a16c, 0x02050774}, + {0x0000a170, 0x02050775}, + {0x0000a174, 0x00000776}, + {0x0000a178, 0x00000776}, + {0x0000a17c, 0x00000776}, + {0x0000a180, 0x00000776}, + {0x0000a184, 0x00000776}, + {0x0000a188, 0x00000776}, + {0x0000a18c, 0x00000776}, + {0x0000a190, 0x00000776}, + {0x0000a194, 0x00000776}, + {0x0000a198, 0x00000776}, + {0x0000a19c, 0x00000776}, + {0x0000a1a0, 0x00000776}, + {0x0000a1a4, 0x00000776}, + {0x0000a1a8, 0x00000776}, + {0x0000a1ac, 0x00000776}, + {0x0000a1b0, 0x00000776}, + {0x0000a1b4, 0x00000776}, + {0x0000a1b8, 0x00000776}, + {0x0000a1bc, 0x00000776}, + {0x0000a1c0, 0x00000776}, + {0x0000a1c4, 0x00000776}, + {0x0000a1c8, 0x00000776}, + {0x0000a1cc, 0x00000776}, + {0x0000a1d0, 0x00000776}, + {0x0000a1d4, 0x00000776}, + {0x0000a1d8, 0x00000776}, + {0x0000a1dc, 0x00000776}, + {0x0000a1e0, 0x00000776}, + {0x0000a1e4, 0x00000776}, + {0x0000a1e8, 0x00000776}, + {0x0000a1ec, 0x00000776}, + {0x0000a1f0, 0x00000776}, + {0x0000a1f4, 0x00000776}, + {0x0000a1f8, 0x00000776}, + {0x0000a1fc, 0x00000776}, + {0x0000b000, 0x02000101}, + {0x0000b004, 0x02000102}, + {0x0000b008, 0x02000103}, + {0x0000b00c, 0x02000104}, + {0x0000b010, 0x02000200}, + {0x0000b014, 0x02000201}, + {0x0000b018, 0x02000202}, + {0x0000b01c, 0x02000203}, + {0x0000b020, 0x02000204}, + {0x0000b024, 0x02000205}, + {0x0000b028, 0x02000208}, + {0x0000b02c, 0x02000302}, + {0x0000b030, 0x02000303}, + {0x0000b034, 0x02000304}, + {0x0000b038, 0x02000400}, + {0x0000b03c, 0x02010300}, + {0x0000b040, 0x02010301}, + {0x0000b044, 0x02010302}, + {0x0000b048, 0x02000500}, + {0x0000b04c, 0x02010400}, + {0x0000b050, 0x02020300}, + {0x0000b054, 0x02020301}, + {0x0000b058, 0x02020302}, + {0x0000b05c, 0x02020303}, + {0x0000b060, 0x02020400}, + {0x0000b064, 0x02030300}, + {0x0000b068, 0x02030301}, + {0x0000b06c, 0x02030302}, + {0x0000b070, 0x02030303}, + {0x0000b074, 0x02030400}, + {0x0000b078, 0x02040300}, + {0x0000b07c, 0x02040301}, + {0x0000b080, 0x02040302}, + {0x0000b084, 0x02040303}, + {0x0000b088, 0x02030500}, + {0x0000b08c, 0x02040400}, + {0x0000b090, 0x02050203}, + {0x0000b094, 0x02050204}, + {0x0000b098, 0x02050205}, + {0x0000b09c, 0x02040500}, + {0x0000b0a0, 0x02050301}, + {0x0000b0a4, 0x02050302}, + {0x0000b0a8, 0x02050303}, + {0x0000b0ac, 0x02050400}, + {0x0000b0b0, 0x02050401}, + {0x0000b0b4, 0x02050402}, + {0x0000b0b8, 0x02050403}, + {0x0000b0bc, 0x02050500}, + {0x0000b0c0, 0x02050501}, + {0x0000b0c4, 0x02050502}, + {0x0000b0c8, 0x02050503}, + {0x0000b0cc, 0x02050504}, + {0x0000b0d0, 0x02050600}, + {0x0000b0d4, 0x02050601}, + {0x0000b0d8, 0x02050602}, + {0x0000b0dc, 0x02050603}, + {0x0000b0e0, 0x02050604}, + {0x0000b0e4, 0x02050700}, + {0x0000b0e8, 0x02050701}, + {0x0000b0ec, 0x02050702}, + {0x0000b0f0, 0x02050703}, + {0x0000b0f4, 0x02050704}, + {0x0000b0f8, 0x02050705}, + {0x0000b0fc, 0x02050708}, + {0x0000b100, 0x02050709}, + {0x0000b104, 0x0205070a}, + {0x0000b108, 0x0205070b}, + {0x0000b10c, 0x0205070c}, + {0x0000b110, 0x0205070d}, + {0x0000b114, 0x02050710}, + {0x0000b118, 0x02050711}, + {0x0000b11c, 0x02050712}, + {0x0000b120, 0x02050713}, + {0x0000b124, 0x02050714}, + {0x0000b128, 0x02050715}, + {0x0000b12c, 0x02050730}, + {0x0000b130, 0x02050731}, + {0x0000b134, 0x02050732}, + {0x0000b138, 0x02050733}, + {0x0000b13c, 0x02050734}, + {0x0000b140, 0x02050735}, + {0x0000b144, 0x02050750}, + {0x0000b148, 0x02050751}, + {0x0000b14c, 0x02050752}, + {0x0000b150, 0x02050753}, + {0x0000b154, 0x02050754}, + {0x0000b158, 0x02050755}, + {0x0000b15c, 0x02050770}, + {0x0000b160, 0x02050771}, + {0x0000b164, 0x02050772}, + {0x0000b168, 0x02050773}, + {0x0000b16c, 0x02050774}, + {0x0000b170, 0x02050775}, + {0x0000b174, 0x00000776}, + {0x0000b178, 0x00000776}, + {0x0000b17c, 0x00000776}, + {0x0000b180, 0x00000776}, + {0x0000b184, 0x00000776}, + {0x0000b188, 0x00000776}, + {0x0000b18c, 0x00000776}, + {0x0000b190, 0x00000776}, + {0x0000b194, 0x00000776}, + {0x0000b198, 0x00000776}, + {0x0000b19c, 0x00000776}, + {0x0000b1a0, 0x00000776}, + {0x0000b1a4, 0x00000776}, + {0x0000b1a8, 0x00000776}, + {0x0000b1ac, 0x00000776}, + {0x0000b1b0, 0x00000776}, + {0x0000b1b4, 0x00000776}, + {0x0000b1b8, 0x00000776}, + {0x0000b1bc, 0x00000776}, + {0x0000b1c0, 0x00000776}, + {0x0000b1c4, 0x00000776}, + {0x0000b1c8, 0x00000776}, + {0x0000b1cc, 0x00000776}, + {0x0000b1d0, 0x00000776}, + {0x0000b1d4, 0x00000776}, + {0x0000b1d8, 0x00000776}, + {0x0000b1dc, 0x00000776}, + {0x0000b1e0, 0x00000776}, + {0x0000b1e4, 0x00000776}, + {0x0000b1e8, 0x00000776}, + {0x0000b1ec, 0x00000776}, + {0x0000b1f0, 0x00000776}, + {0x0000b1f4, 0x00000776}, + {0x0000b1f8, 0x00000776}, + {0x0000b1fc, 0x00000776}, +}; + +static const u32 ar9200_ar9280_2p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00007800, 0x00040000}, + {0x00007804, 0xdb005012}, + {0x00007808, 0x04924914}, + {0x0000780c, 0x21084210}, + {0x00007810, 0x6d801300}, + {0x00007814, 0x0019beff}, + {0x00007818, 0x07e41000}, + {0x0000781c, 0x00392000}, + {0x00007820, 0x92592480}, + {0x00007824, 0x00040000}, + {0x00007828, 0xdb005012}, + {0x0000782c, 0x04924914}, + {0x00007830, 0x21084210}, + {0x00007834, 0x6d801300}, + {0x00007838, 0x0019beff}, + {0x0000783c, 0x07e40000}, + {0x00007840, 0x00392000}, + {0x00007844, 0x92592480}, + {0x00007848, 0x00100000}, + {0x0000784c, 0x773f0567}, + {0x00007850, 0x54214514}, + {0x00007854, 0x12035828}, + {0x00007858, 0x92592692}, + {0x0000785c, 0x00000000}, + {0x00007860, 0x56400000}, + {0x00007864, 0x0a8e370e}, + {0x00007868, 0xc0102850}, + {0x0000786c, 0x812d4000}, + {0x00007870, 0x807ec400}, + {0x00007874, 0x001b6db0}, + {0x00007878, 0x00376b63}, + {0x0000787c, 0x06db6db6}, + {0x00007880, 0x006d8000}, + {0x00007884, 0xffeffffe}, + {0x00007888, 0xffeffffe}, + {0x0000788c, 0x00010000}, + {0x00007890, 0x02060aeb}, + {0x00007894, 0x5a108000}, +}; + +static const u32 ar9462_2p0_mac_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8}, + {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017}, +}; + +static const u32 ar9462_2p0_radio_postamble_sys3ant[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, + {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, + {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221}, + {0x00009e44, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000}, + {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111}, + {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20}, + {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c}, + {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a}, + {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c}, + {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc}, + {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4}, + {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc}, + {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede}, + {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e}, + {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e}, + {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; + static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, @@ -765,11 +1107,11 @@ static const u32 ar9462_2p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x15262820}, + {0x00009e40, 0x0d261820}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, - {0x00009e54, 0xe4c555c2}, - {0x00009e58, 0xfd857722}, + {0x00009e54, 0xe4c355c7}, + {0x00009e58, 0xfd897735}, {0x00009e5c, 0xe9198724}, {0x00009fc0, 0x803e4788}, {0x00009fc4, 0x0001efb5}, @@ -800,6 +1142,9 @@ static const u32 ar9462_2p0_baseband_core[][2] = { {0x0000a398, 0x001f0e0f}, {0x0000a39c, 0x0075393f}, {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, {0x0000a3c0, 0x20202020}, {0x0000a3c4, 0x22222220}, {0x0000a3c8, 0x20200020}, @@ -822,6 +1167,12 @@ static const u32 ar9462_2p0_baseband_core[][2] = { {0x0000a40c, 0x00820820}, {0x0000a414, 0x1ce739ce}, {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, {0x0000a434, 0x00000000}, {0x0000a438, 0x00001801}, {0x0000a43c, 0x00100000}, @@ -1005,6 +1356,24 @@ static const u32 ar9462_2p0_radio_core[][2] = { {0x00016548, 0x000080c0}, }; +static const u32 ar9462_2p0_tx_gain_table_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002}, + {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004}, + {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c}, + {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b}, + {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a}, + {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a}, + {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a}, + {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a}, + {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a}, + {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a}, + {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a}, + {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a}, +}; + static const u32 ar9462_2p0_soc_preamble[][2] = { /* Addr allmodes */ {0x00007020, 0x00000000}, @@ -1012,6 +1381,11 @@ static const u32 ar9462_2p0_soc_preamble[][2] = { {0x00007038, 0x000004c2}, }; +static const u32 ar9462_2p0_sys2ant[][2] = { + /* Addr allmodes */ + {0x00063120, 0x00801980}, +}; + static const u32 ar9462_2p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -1448,6 +1822,75 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = { {0x0000b1fc, 0x00000196}, }; +static const u32 ar9462_modes_green_ob_db_tx_gain_table_2p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400}, + {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402}, + {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, + {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640}, + {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, + {0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060}, + {0x00016054, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180}, + {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, + {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, + {0x00016454, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180}, +}; + static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = { /* Addr allmodes */ {0x000018c0, 0x10101010}, @@ -1460,4 +1903,26 @@ static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = { {0x000018dc, 0x10101010}, }; +static const u32 ar9462_2p0_baseband_core_emulation[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafa68e30}, + {0x00009884, 0x00002842}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009e50, 0x00000000}, + {0x00009fcc, 0x00000014}, + {0x0000a344, 0x00000010}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x71733d01}, + {0x0000a3a0, 0xd0ad5c12}, + {0x0000a3c0, 0x22222220}, + {0x0000a3c4, 0x22222222}, + {0x0000a404, 0x00418a11}, + {0x0000a418, 0x050001ce}, + {0x0000a438, 0x00001800}, + {0x0000a458, 0x01444452}, + {0x0000a644, 0x3fad9d74}, + {0x0000a690, 0x00000038}, +}; + #endif /* INITVALS_9462_2P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h old mode 100644 new mode 100755 diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h old mode 100644 new mode 100755 index e2ab182d..73bd5839 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -93,7 +93,7 @@ enum buffer_type { #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) -#define ATH_TXSTATUS_RING_SIZE 512 +#define ATH_TXSTATUS_RING_SIZE 64 #define DS2PHYS(_dd, _ds) \ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) @@ -155,9 +155,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, /* return block-ack bitmap index given sequence and starting sequence */ #define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) -/* return the seqno for _start + _offset */ -#define ATH_BA_INDEX2SEQ(_seq, _offset) (((_seq) + (_offset)) & (IEEE80211_SEQ_MAX - 1)) - /* returns delimiter padding required given the packet length */ #define ATH_AGGR_GET_NDELIM(_len) \ (((_len) >= ATH_AGGR_MINPLEN) ? 0 : \ @@ -192,7 +189,6 @@ struct ath_txq { u8 txq_headidx; u8 txq_tailidx; int pending_frames; - struct sk_buff_head complete_q; }; struct ath_atx_ac { @@ -239,7 +235,6 @@ struct ath_atx_tid { struct ath_node *an; struct ath_atx_ac *ac; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; - int bar_index; u16 seq_start; u16 seq_next; u16 baw_size; @@ -254,9 +249,9 @@ struct ath_atx_tid { struct ath_node { #ifdef CONFIG_ATH9K_DEBUGFS struct list_head list; /* for sc->nodes */ -#endif struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ +#endif struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_ac ac[WME_NUM_AC]; int ps_key; @@ -278,6 +273,7 @@ struct ath_tx_control { }; #define ATH_TX_ERROR 0x01 +#define ATH_TX_BAR 0x02 /** * @txq_map: Index is mac80211 queue number. This is @@ -296,6 +292,7 @@ struct ath_tx { struct ath_rx_edma { struct sk_buff_head rx_fifo; + struct sk_buff_head rx_buffers; u32 rx_fifo_hwsize; }; @@ -451,39 +448,9 @@ struct ath_btcoex { struct ath_mci_profile mci; }; -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT -int ath9k_init_btcoex(struct ath_softc *sc); -void ath9k_deinit_btcoex(struct ath_softc *sc); -void ath9k_start_btcoex(struct ath_softc *sc); -void ath9k_stop_btcoex(struct ath_softc *sc); +int ath_init_btcoex_timer(struct ath_softc *sc); void ath9k_btcoex_timer_resume(struct ath_softc *sc); void ath9k_btcoex_timer_pause(struct ath_softc *sc); -void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); -u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); -#else -static inline int ath9k_init_btcoex(struct ath_softc *sc) -{ - return 0; -} -static inline void ath9k_deinit_btcoex(struct ath_softc *sc) -{ -} -static inline void ath9k_start_btcoex(struct ath_softc *sc) -{ -} -static inline void ath9k_stop_btcoex(struct ath_softc *sc) -{ -} -static inline void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, - u32 status) -{ -} -static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, - u32 max_4ms_framelen) -{ - return 0; -} -#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ /********************/ /* LED Control */ @@ -493,7 +460,7 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, #define ATH_LED_PIN_9287 8 #define ATH_LED_PIN_9300 10 #define ATH_LED_PIN_9485 6 -#define ATH_LED_PIN_9462 4 +#define ATH_LED_PIN_9462 0 #ifdef CONFIG_MAC80211_LEDS void ath_init_leds(struct ath_softc *sc); @@ -573,7 +540,7 @@ struct ath_ant_comb { #define DEFAULT_CACHELINE 32 #define ATH_REGCLASSIDS_MAX 10 #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_MAX_SW_RETRIES 30 +#define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ @@ -581,13 +548,19 @@ struct ath_ant_comb { #define SC_OP_INVALID BIT(0) #define SC_OP_BEACONS BIT(1) -#define SC_OP_OFFCHANNEL BIT(2) -#define SC_OP_RXFLUSH BIT(3) -#define SC_OP_TSF_RESET BIT(4) -#define SC_OP_BT_PRIORITY_DETECTED BIT(5) -#define SC_OP_BT_SCAN BIT(6) -#define SC_OP_ANI_RUN BIT(7) -#define SC_OP_PRIM_STA_VIF BIT(8) +#define SC_OP_RXAGGR BIT(2) +#define SC_OP_TXAGGR BIT(3) +#define SC_OP_OFFCHANNEL BIT(4) +#define SC_OP_PREAMBLE_SHORT BIT(5) +#define SC_OP_PROTECT_ENABLE BIT(6) +#define SC_OP_RXFLUSH BIT(7) +#define SC_OP_LED_ASSOCIATED BIT(8) +#define SC_OP_LED_ON BIT(9) +#define SC_OP_TSF_RESET BIT(11) +#define SC_OP_BT_PRIORITY_DETECTED BIT(12) +#define SC_OP_BT_SCAN BIT(13) +#define SC_OP_ANI_RUN BIT(14) +#define SC_OP_PRIM_STA_VIF BIT(15) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) @@ -609,12 +582,15 @@ struct ath9k_vif_iter_data { int nstations; /* number of station vifs */ int nwds; /* number of WDS vifs */ int nadhocs; /* number of adhoc vifs */ + int nothers; /* number of vifs not specified above. */ }; struct ath_softc { struct ieee80211_hw *hw; struct device *dev; + int chan_idx; + int chan_is_ht; struct survey_info *cur_survey; struct survey_info survey[ATH9K_NUM_CHANNELS]; @@ -668,11 +644,7 @@ struct ath_softc { struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; - -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; - struct ath_mci_coex mci_coex; -#endif struct ath_descdma txsdma; @@ -700,6 +672,7 @@ void ath9k_deinit_device(struct ath_softc *sc); void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); void ath9k_reload_chainmask_settings(struct ath_softc *sc); +void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); bool ath9k_uses_beacons(int type); #ifdef CONFIG_ATH9K_PCI diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c old mode 100644 new mode 100755 index 2e4243fc..2bbc83e1 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -67,7 +67,7 @@ int ath_beaconq_config(struct ath_softc *sc) * up rate codes, and channel flags. Beacons are always sent out at the * lowest rate, and are not retried. */ -static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, +static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_buf *bf, int rateidx) { struct sk_buff *skb = bf->bf_mpdu; @@ -82,7 +82,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; - if (vif->bss_conf.use_short_preamble) + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= sband->bitrates[rateidx].hw_value_short; memset(&info, 0, sizeof(info)); @@ -91,7 +91,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, info.txpower = MAX_RATE_POWER; info.keyix = ATH9K_TXKEYIX_INVALID; info.keytype = ATH9K_KEY_TYPE_CLEAR; - info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ; + info.flags = ATH9K_TXDESC_NOACK; info.buf_addr[0] = bf->bf_buf_addr; info.buf_len[0] = roundup(skb->len, 4); @@ -117,11 +117,12 @@ static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) memset(&txctl, 0, sizeof(struct ath_tx_control)); txctl.txq = sc->beacon.cabq; - ath_dbg(common, XMIT, "transmitting CABQ packet, skb: %p\n", skb); + ath_dbg(common, ATH_DBG_XMIT, + "transmitting CABQ packet, skb: %p\n", skb); if (ath_tx_start(hw, skb, &txctl) != 0) { - ath_dbg(common, XMIT, "CABQ TX failed\n"); - ieee80211_free_txskb(hw, skb); + ath_dbg(common, ATH_DBG_XMIT, "CABQ TX failed\n"); + dev_kfree_skb_any(skb); } } @@ -204,13 +205,13 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, if (skb && cabq_depth) { if (sc->nvifs > 1) { - ath_dbg(common, BEACON, + ath_dbg(common, ATH_DBG_BEACON, "Flushing previous cabq traffic\n"); ath_draintxq(sc, cabq, false); } } - ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx); + ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx); while (skb) { ath_tx_cabq(hw, skb); @@ -297,7 +298,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; avp->tsf_adjust = cpu_to_le64(tsfadjust); - ath_dbg(common, BEACON, + ath_dbg(common, ATH_DBG_BEACON, "stagger beacons, bslot %d intval %u tsfadjust %llu\n", avp->av_bslot, intval, (unsigned long long)tsfadjust); @@ -356,7 +357,7 @@ void ath_beacon_tasklet(unsigned long data) struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; struct ieee80211_vif *vif; - bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); + struct ath_tx_status ts; int slot; u32 bfaddr, bc = 0; @@ -371,14 +372,15 @@ void ath_beacon_tasklet(unsigned long data) sc->beacon.bmisscnt++; if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { - ath_dbg(common, BSTUCK, + ath_dbg(common, ATH_DBG_BSTUCK, "missed %u consecutive beacons\n", sc->beacon.bmisscnt); ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); if (sc->beacon.bmisscnt > 3) ath9k_hw_bstuck_nfcal(ah); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { - ath_dbg(common, BSTUCK, "beacon is officially stuck\n"); + ath_dbg(common, ATH_DBG_BSTUCK, + "beacon is officially stuck\n"); sc->sc_flags |= SC_OP_TSF_RESET; ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } @@ -405,7 +407,7 @@ void ath_beacon_tasklet(unsigned long data) slot = (tsftu % (intval * ATH_BCBUF)) / intval; vif = sc->beacon.bslot[slot]; - ath_dbg(common, BEACON, + ath_dbg(common, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", slot, tsf, tsftu / ATH_BCBUF, intval, vif); } else { @@ -423,7 +425,7 @@ void ath_beacon_tasklet(unsigned long data) } if (sc->beacon.bmisscnt != 0) { - ath_dbg(common, BSTUCK, + ath_dbg(common, ATH_DBG_BSTUCK, "resume beacon xmit after %u misses\n", sc->beacon.bmisscnt); sc->beacon.bmisscnt = 0; @@ -457,11 +459,14 @@ void ath_beacon_tasklet(unsigned long data) if (bfaddr != 0) { /* NB: cabq traffic should already be queued and primed */ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); - - if (!edma) - ath9k_hw_txstart(ah, sc->beacon.beaconq); + ath9k_hw_txstart(ah, sc->beacon.beaconq); sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + spin_lock_bh(&sc->sc_pcu_lock); + ath9k_hw_txprocdesc(ah, bf->bf_desc, (void *)&ts); + spin_unlock_bh(&sc->sc_pcu_lock); + } } } @@ -537,7 +542,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, /* No need to configure beacon if we are not associated */ if (!common->curaid) { - ath_dbg(common, BEACON, + ath_dbg(common, ATH_DBG_BEACON, "STA is not yet associated..skipping beacon config\n"); return; } @@ -627,8 +632,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc, /* TSF out of range threshold fixed at 1 second */ bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); - ath_dbg(common, BEACON, + ath_dbg(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); + ath_dbg(common, ATH_DBG_BEACON, "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", bs.bs_bmissthreshold, bs.bs_sleepduration, bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); @@ -656,7 +661,8 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval); nexttbtt = tsf + intval; - ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n", + ath_dbg(common, ATH_DBG_BEACON, + "IBSS nexttbtt %u intval %u (%u)\n", nexttbtt, intval, conf->beacon_interval); /* @@ -694,8 +700,9 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, (sc->nbcnvifs > 1) && (vif->type == NL80211_IFTYPE_AP) && (cur_conf->beacon_interval != bss_conf->beacon_int)) { - ath_dbg(common, CONFIG, - "Changing beacon interval of multiple AP interfaces !\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "Changing beacon interval of multiple \ + AP interfaces !\n"); return false; } /* @@ -704,7 +711,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, */ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && (vif->type != NL80211_IFTYPE_AP)) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "STA vif's beacon not allowed on AP mode\n"); return false; } @@ -716,7 +723,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, (vif->type == NL80211_IFTYPE_STATION) && (sc->sc_flags & SC_OP_BEACONS) && !avp->primary_sta_vif) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Beacon already configured for a station interface\n"); return false; } @@ -796,7 +803,8 @@ void ath_set_beacon(struct ath_softc *sc) ath_beacon_config_sta(sc, cur_conf); break; default: - ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); return; } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index ec327199..9ac28d9d 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -21,7 +21,7 @@ enum ath_bt_mode { ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ - ATH_BT_COEX_MODE_DISABLED, /* coexistence disabled */ + ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ }; struct ath_btcoex_config { @@ -95,40 +95,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) } EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); -void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - - /* - * Check if BTCOEX is globally disabled. - */ - if (!common->btcoex_enabled) { - btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; - return; - } - - if (AR_SREV_9462(ah)) { - btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI; - } else if (AR_SREV_9300_20_OR_LATER(ah)) { - btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; - } else if (AR_SREV_9280_20_OR_LATER(ah)) { - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; - - if (AR_SREV_9285(ah)) { - btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9285; - } else { - btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; - } - } -} -EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme); - void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; @@ -177,30 +143,6 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire); -void ath9k_hw_btcoex_init_mci(struct ath_hw *ah) -{ - ah->btcoex_hw.mci.ready = false; - ah->btcoex_hw.mci.bt_state = 0; - ah->btcoex_hw.mci.bt_ver_major = 3; - ah->btcoex_hw.mci.bt_ver_minor = 0; - ah->btcoex_hw.mci.bt_version_known = false; - ah->btcoex_hw.mci.update_2g5g = true; - ah->btcoex_hw.mci.is_2g = true; - ah->btcoex_hw.mci.wlan_channels_update = false; - ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000; - ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff; - ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff; - ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff; - ah->btcoex_hw.mci.query_bt = true; - ah->btcoex_hw.mci.unhalt_bt_gpm = true; - ah->btcoex_hw.mci.halted_bt_gpm = false; - ah->btcoex_hw.mci.need_flush_btinfo = false; - ah->btcoex_hw.mci.wlan_cal_seq = 0; - ah->btcoex_hw.mci.wlan_cal_done = 0; - ah->btcoex_hw.mci.config = 0x2201; -} -EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci); - static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; @@ -277,9 +219,9 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - switch (ath9k_hw_get_btcoex_scheme(ah)) { + switch (btcoex_hw->scheme) { case ATH_BTCOEX_CFG_NONE: - return; + break; case ATH_BTCOEX_CFG_2WIRE: ath9k_hw_btcoex_enable_2wire(ah); break; @@ -371,7 +313,8 @@ void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, AR_STOMP_NONE_WLAN_WGHT); break; default: - ath_dbg(ath9k_hw_common(ah), BTCOEX, "Invalid Stomptype\n"); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); break; } } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 8f93aef4..d5e5db1f 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -54,38 +54,8 @@ enum ath_btcoex_scheme { ATH_BTCOEX_CFG_MCI, }; -struct ath9k_hw_mci { - u32 raw_intr; - u32 rx_msg_intr; - u32 cont_status; - u32 gpm_addr; - u32 gpm_len; - u32 gpm_idx; - u32 sched_addr; - u32 wlan_channels[4]; - u32 wlan_cal_seq; - u32 wlan_cal_done; - u32 config; - u8 *gpm_buf; - bool ready; - bool update_2g5g; - bool is_2g; - bool query_bt; - bool unhalt_bt_gpm; /* need send UNHALT */ - bool halted_bt_gpm; /* HALT sent */ - bool need_flush_btinfo; - bool bt_version_known; - bool wlan_channels_update; - u8 wlan_ver_major; - u8 wlan_ver_minor; - u8 bt_ver_major; - u8 bt_ver_minor; - u8 bt_state; -}; - struct ath_btcoex_hw { enum ath_btcoex_scheme scheme; - struct ath9k_hw_mci mci; bool enabled; u8 wlanactive_gpio; u8 btactive_gpio; @@ -97,14 +67,13 @@ struct ath_btcoex_hw { u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; }; -void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah); void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); -void ath9k_hw_btcoex_init_mci(struct ath_hw *ah); void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum); void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, u32 bt_weight, u32 wlan_weight); +void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, enum ath_stomp_type stomp_type); diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index a393e87e..7d0dba42 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -20,6 +20,7 @@ /* Common calibration code */ +#define ATH9K_NF_TOO_HIGH -60 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) { @@ -116,7 +117,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, if (h[i].privNF > limit->max) { high_nf_mid = true; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "NFmid[%d] (%d) > MAX (%d), %s\n", i, h[i].privNF, limit->max, (cal->nfcal_interference ? @@ -199,7 +200,8 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) return true; if (currCal->calState != CAL_DONE) { - ath_dbg(common, CALIBRATE, "Calibration state incorrect, %d\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "Calibration state incorrect, %d\n", currCal->calState); return true; } @@ -207,7 +209,8 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) if (!(ah->supp_cals & currCal->calData->calType)) return true; - ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n", + ath_dbg(common, ATH_DBG_CALIBRATE, + "Resetting Cal %d state for channel %u\n", currCal->calData->calType, conf->channel->center_freq); ah->caldata->CalValid &= ~currCal->calData->calType; @@ -300,7 +303,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) * noisefloor until the next calibration timer. */ if (j == 10000) { - ath_dbg(common, ANY, + ath_dbg(common, ATH_DBG_ANY, "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", REG_READ(ah, AR_PHY_AGC_CONTROL)); return; @@ -342,17 +345,17 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf) if (!nf[i]) continue; - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "NF calibrated [%s] [chain %d] is %d\n", (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]); - if (nf[i] > limit->max) { - ath_dbg(common, CALIBRATE, + if (nf[i] > ATH9K_NF_TOO_HIGH) { + ath_dbg(common, ATH_DBG_CALIBRATE, "NF[%d] (%d) > MAX (%d), correcting to MAX\n", - i, nf[i], limit->max); + i, nf[i], ATH9K_NF_TOO_HIGH); nf[i] = limit->max; } else if (nf[i] < limit->min) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "NF[%d] (%d) < MIN (%d), correcting to NOM\n", i, nf[i], limit->min); nf[i] = limit->nominal; @@ -371,7 +374,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) chan->channelFlags &= (~CHANNEL_CW_INT); if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "NF did not complete in calibration window\n"); return false; } @@ -381,7 +384,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) nf = nfarray[0]; if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh) && nf > nfThresh) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "noise floor failed detected; detected %d, threshold %d\n", nf, nfThresh); chan->channelFlags |= CHANNEL_CW_INT; @@ -399,7 +402,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) ah->noise = ath9k_hw_getchan_noise(ah, chan); return true; } -EXPORT_SYMBOL(ath9k_hw_getnf); void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan) diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h old mode 100644 new mode 100755 index 1f2e01a9..e300a738 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -19,6 +19,7 @@ #include "hw.h" +#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 #define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 /* Internal noise floor can vary by about 6db depending on the frequency */ diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h old mode 100644 new mode 100755 diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index ff47b32e..6fb719d8 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -26,6 +26,11 @@ #define REG_READ_D(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -78,7 +83,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, static const struct file_operations fops_debug = { .read = read_file_debug, .write = write_file_debug, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -124,7 +129,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use static const struct file_operations fops_tx_chainmask = { .read = read_file_tx_chainmask, .write = write_file_tx_chainmask, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -167,7 +172,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use static const struct file_operations fops_rx_chainmask = { .read = read_file_rx_chainmask, .write = write_file_rx_chainmask, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -218,7 +223,7 @@ static ssize_t write_file_disable_ani(struct file *file, static const struct file_operations fops_disable_ani = { .read = read_file_disable_ani, .write = write_file_disable_ani, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -319,7 +324,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, static const struct file_operations fops_dma = { .read = read_file_dma, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -441,7 +446,110 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, static const struct file_operations fops_interrupt = { .read = read_file_interrupt, - .open = simple_open, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const char *channel_type_str(enum nl80211_channel_type t) +{ + switch (t) { + case NL80211_CHAN_NO_HT: + return "no ht"; + case NL80211_CHAN_HT20: + return "ht20"; + case NL80211_CHAN_HT40MINUS: + return "ht40-"; + case NL80211_CHAN_HT40PLUS: + return "ht40+"; + default: + return "???"; + } +} + +static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ieee80211_channel *chan = sc->hw->conf.channel; + struct ieee80211_conf *conf = &(sc->hw->conf); + char buf[512]; + unsigned int len = 0; + u8 addr[ETH_ALEN]; + u32 tmp; + + len += snprintf(buf + len, sizeof(buf) - len, + "%s (chan=%d center-freq: %d MHz channel-type: %d (%s))\n", + wiphy_name(sc->hw->wiphy), + ieee80211_frequency_to_channel(chan->center_freq), + chan->center_freq, + conf->channel_type, + channel_type_str(conf->channel_type)); + + ath9k_ps_wakeup(sc); + put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr); + put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); + len += snprintf(buf + len, sizeof(buf) - len, + "addr: %pM\n", addr); + put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr); + put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); + len += snprintf(buf + len, sizeof(buf) - len, + "addrmask: %pM\n", addr); + tmp = ath9k_hw_getrxfilter(sc->sc_ah); + ath9k_ps_restore(sc); + len += snprintf(buf + len, sizeof(buf) - len, + "rfilt: 0x%x", tmp); + if (tmp & ATH9K_RX_FILTER_UCAST) + len += snprintf(buf + len, sizeof(buf) - len, " UCAST"); + if (tmp & ATH9K_RX_FILTER_MCAST) + len += snprintf(buf + len, sizeof(buf) - len, " MCAST"); + if (tmp & ATH9K_RX_FILTER_BCAST) + len += snprintf(buf + len, sizeof(buf) - len, " BCAST"); + if (tmp & ATH9K_RX_FILTER_CONTROL) + len += snprintf(buf + len, sizeof(buf) - len, " CONTROL"); + if (tmp & ATH9K_RX_FILTER_BEACON) + len += snprintf(buf + len, sizeof(buf) - len, " BEACON"); + if (tmp & ATH9K_RX_FILTER_PROM) + len += snprintf(buf + len, sizeof(buf) - len, " PROM"); + if (tmp & ATH9K_RX_FILTER_PROBEREQ) + len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ"); + if (tmp & ATH9K_RX_FILTER_PHYERR) + len += snprintf(buf + len, sizeof(buf) - len, " PHYERR"); + if (tmp & ATH9K_RX_FILTER_MYBEACON) + len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON"); + if (tmp & ATH9K_RX_FILTER_COMP_BAR) + len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR"); + if (tmp & ATH9K_RX_FILTER_PSPOLL) + len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL"); + if (tmp & ATH9K_RX_FILTER_PHYRADAR) + len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); + if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL) + len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); + + len += snprintf(buf + len, sizeof(buf) - len, + "\n\nReset causes:\n" + " baseband hang: %d\n" + " baseband watchdog: %d\n" + " fatal hardware error interrupt: %d\n" + " tx hardware error: %d\n" + " tx path hang: %d\n" + " pll rx hang: %d\n", + sc->debug.stats.reset[RESET_TYPE_BB_HANG], + sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG], + sc->debug.stats.reset[RESET_TYPE_FATAL_INT], + sc->debug.stats.reset[RESET_TYPE_TX_ERROR], + sc->debug.stats.reset[RESET_TYPE_TX_HANG], + sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_wiphy = { + .read = read_file_wiphy, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -655,126 +763,85 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; struct ieee80211_hw *hw = sc->hw; - struct ath9k_vif_iter_data iter_data; - char buf[512]; - unsigned int len = 0; + char *buf; + unsigned int len = 0, size = 8000; ssize_t retval = 0; unsigned int reg; - u32 rxfilter; + struct ath9k_vif_iter_data iter_data; - len += snprintf(buf + len, sizeof(buf) - len, - "BSSID: %pM\n", common->curbssid); - len += snprintf(buf + len, sizeof(buf) - len, - "BSSID-MASK: %pM\n", common->bssidmask); - len += snprintf(buf + len, sizeof(buf) - len, - "OPMODE: %s\n", ath_opmode_to_string(sc->sc_ah->opmode)); + ath9k_calculate_iter_data(hw, NULL, &iter_data); + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; ath9k_ps_wakeup(sc); - rxfilter = ath9k_hw_getrxfilter(sc->sc_ah); + len += snprintf(buf + len, size - len, + "curbssid: %pM\n" + "OP-Mode: %s(%i)\n" + "Beacon-Timer-Register: 0x%x\n", + common->curbssid, + ath_opmode_to_string(sc->sc_ah->opmode), + (int)(sc->sc_ah->opmode), + REG_READ(ah, AR_BEACON_PERIOD)); + + reg = REG_READ(ah, AR_TIMER_MODE); ath9k_ps_restore(sc); - - len += snprintf(buf + len, sizeof(buf) - len, - "RXFILTER: 0x%x", rxfilter); - - if (rxfilter & ATH9K_RX_FILTER_UCAST) - len += snprintf(buf + len, sizeof(buf) - len, " UCAST"); - if (rxfilter & ATH9K_RX_FILTER_MCAST) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST"); - if (rxfilter & ATH9K_RX_FILTER_BCAST) - len += snprintf(buf + len, sizeof(buf) - len, " BCAST"); - if (rxfilter & ATH9K_RX_FILTER_CONTROL) - len += snprintf(buf + len, sizeof(buf) - len, " CONTROL"); - if (rxfilter & ATH9K_RX_FILTER_BEACON) - len += snprintf(buf + len, sizeof(buf) - len, " BEACON"); - if (rxfilter & ATH9K_RX_FILTER_PROM) - len += snprintf(buf + len, sizeof(buf) - len, " PROM"); - if (rxfilter & ATH9K_RX_FILTER_PROBEREQ) - len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ"); - if (rxfilter & ATH9K_RX_FILTER_PHYERR) - len += snprintf(buf + len, sizeof(buf) - len, " PHYERR"); - if (rxfilter & ATH9K_RX_FILTER_MYBEACON) - len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON"); - if (rxfilter & ATH9K_RX_FILTER_COMP_BAR) - len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR"); - if (rxfilter & ATH9K_RX_FILTER_PSPOLL) - len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL"); - if (rxfilter & ATH9K_RX_FILTER_PHYRADAR) - len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); - if (rxfilter & ATH9K_RX_FILTER_MCAST_BCAST_ALL) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); - if (rxfilter & ATH9K_RX_FILTER_CONTROL_WRAPPER) - len += snprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER"); - - len += snprintf(buf + len, sizeof(buf) - len, "\n"); + len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (", + reg); + if (reg & AR_TBTT_TIMER_EN) + len += snprintf(buf + len, size - len, "TBTT "); + if (reg & AR_DBA_TIMER_EN) + len += snprintf(buf + len, size - len, "DBA "); + if (reg & AR_SWBA_TIMER_EN) + len += snprintf(buf + len, size - len, "SWBA "); + if (reg & AR_HCF_TIMER_EN) + len += snprintf(buf + len, size - len, "HCF "); + if (reg & AR_TIM_TIMER_EN) + len += snprintf(buf + len, size - len, "TIM "); + if (reg & AR_DTIM_TIMER_EN) + len += snprintf(buf + len, size - len, "DTIM "); + len += snprintf(buf + len, size - len, ")\n"); reg = sc->sc_ah->imask; - - len += snprintf(buf + len, sizeof(buf) - len, "INTERRUPT-MASK: 0x%x", reg); - + len += snprintf(buf + len, size - len, "imask: 0x%x (", reg); if (reg & ATH9K_INT_SWBA) - len += snprintf(buf + len, sizeof(buf) - len, " SWBA"); + len += snprintf(buf + len, size - len, "SWBA "); if (reg & ATH9K_INT_BMISS) - len += snprintf(buf + len, sizeof(buf) - len, " BMISS"); + len += snprintf(buf + len, size - len, "BMISS "); if (reg & ATH9K_INT_CST) - len += snprintf(buf + len, sizeof(buf) - len, " CST"); + len += snprintf(buf + len, size - len, "CST "); if (reg & ATH9K_INT_RX) - len += snprintf(buf + len, sizeof(buf) - len, " RX"); + len += snprintf(buf + len, size - len, "RX "); if (reg & ATH9K_INT_RXHP) - len += snprintf(buf + len, sizeof(buf) - len, " RXHP"); + len += snprintf(buf + len, size - len, "RXHP "); if (reg & ATH9K_INT_RXLP) - len += snprintf(buf + len, sizeof(buf) - len, " RXLP"); + len += snprintf(buf + len, size - len, "RXLP "); if (reg & ATH9K_INT_BB_WATCHDOG) - len += snprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG"); + len += snprintf(buf + len, size - len, "BB_WATCHDOG "); + /* there are other IRQs if one wanted to add them. */ + len += snprintf(buf + len, size - len, ")\n"); - len += snprintf(buf + len, sizeof(buf) - len, "\n"); - - ath9k_calculate_iter_data(hw, NULL, &iter_data); - - len += snprintf(buf + len, sizeof(buf) - len, - "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" - " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", + len += snprintf(buf + len, size - len, + "VIF Counts: AP: %i STA: %i MESH: %i WDS: %i" + " ADHOC: %i OTHER: %i nvifs: %hi beacon-vifs: %hi\n", iter_data.naps, iter_data.nstations, iter_data.nmeshes, - iter_data.nwds, iter_data.nadhocs, + iter_data.nwds, iter_data.nadhocs, iter_data.nothers, sc->nvifs, sc->nbcnvifs); - if (len > sizeof(buf)) - len = sizeof(buf); - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - return retval; -} - -static ssize_t read_file_reset(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; + len += snprintf(buf + len, size - len, + "Calculated-BSSID-Mask: %pM\n", + iter_data.mask); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Baseband Hang", - sc->debug.stats.reset[RESET_TYPE_BB_HANG]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Baseband Watchdog", - sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Fatal HW Error", - sc->debug.stats.reset[RESET_TYPE_FATAL_INT]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "TX HW error", - sc->debug.stats.reset[RESET_TYPE_TX_ERROR]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "TX Path Hang", - sc->debug.stats.reset[RESET_TYPE_TX_HANG]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "PLL RX Hang", - sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); + if (len > size) + len = size; - if (len > sizeof(buf)) - len = sizeof(buf); + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); + return retval; } void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, @@ -789,7 +856,7 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; if (bf_isampdu(bf)) { - if (flags & ATH_TX_ERROR) + if (flags & ATH_TX_BAR) TX_STAT_INC(qnum, a_xretries); else TX_STAT_INC(qnum, a_completed); @@ -813,7 +880,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) TX_STAT_INC(qnum, delim_underrun); -#ifdef CONFIG_ATH9K_MAC_DEBUG spin_lock(&sc->debug.samp_lock); TX_SAMP_DBG(jiffies) = jiffies; TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0; @@ -840,35 +906,27 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES; spin_unlock(&sc->debug.samp_lock); -#endif #undef TX_SAMP_DBG } static const struct file_operations fops_xmit = { .read = read_file_xmit, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static const struct file_operations fops_stations = { .read = read_file_stations, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static const struct file_operations fops_misc = { .read = read_file_misc, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static const struct file_operations fops_reset = { - .read = read_file_reset, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -877,12 +935,12 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { #define PHY_ERR(s, p) \ - len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \ + len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \ sc->debug.stats.rxstats.phy_err_stats[p]); struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 1600; + unsigned int len = 0, size = 1400; ssize_t retval = 0; buf = kzalloc(size, GFP_KERNEL); @@ -890,59 +948,87 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, return -ENOMEM; len += snprintf(buf + len, size - len, - "%22s : %10u\n", "CRC ERR", + "%18s : %10u\n", "CRC ERR", sc->debug.stats.rxstats.crc_err); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "DECRYPT CRC ERR", + "%18s : %10u\n", "DECRYPT CRC ERR", sc->debug.stats.rxstats.decrypt_crc_err); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "PHY ERR", + "%18s : %10u\n", "PHY ERR", sc->debug.stats.rxstats.phy_err); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "MIC ERR", + "%18s : %10u\n", "MIC ERR", sc->debug.stats.rxstats.mic_err); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "PRE-DELIM CRC ERR", + "%18s : %10u\n", "PRE-DELIM CRC ERR", sc->debug.stats.rxstats.pre_delim_crc_err); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "POST-DELIM CRC ERR", + "%18s : %10u\n", "POST-DELIM CRC ERR", sc->debug.stats.rxstats.post_delim_crc_err); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "DECRYPT BUSY ERR", + "%18s : %10u\n", "DECRYPT BUSY ERR", sc->debug.stats.rxstats.decrypt_busy_err); - PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); - PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); - PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); - PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); - PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); - PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); - PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); - PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); - PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); - PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); - PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); - PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); - PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); - PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); - PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); - PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); - PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); - PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); - PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); - PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); - PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); - PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); - PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); - PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); - PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); - PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL0", + sc->debug.stats.rxstats.rs_rssi_ctl0); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL1", + sc->debug.stats.rxstats.rs_rssi_ctl1); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL2", + sc->debug.stats.rxstats.rs_rssi_ctl2); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT0", + sc->debug.stats.rxstats.rs_rssi_ext0); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "RX-Pkts-All", + "%18s : %10d\n", "RSSI-EXT1", + sc->debug.stats.rxstats.rs_rssi_ext1); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT2", + sc->debug.stats.rxstats.rs_rssi_ext2); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "Rx Antenna", + sc->debug.stats.rxstats.rs_antenna); + + PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); + PHY_ERR("RATE", ATH9K_PHYERR_RATE); + PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); + PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); + PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); + PHY_ERR("TOR", ATH9K_PHYERR_TOR); + PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); + PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); + PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); + PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); + PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); + PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); + PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); + PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); + PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); + PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); + PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); + PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); + PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); + PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); + PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); + PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); + PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); + PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); + + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "RX-Pkts-All", sc->debug.stats.rxstats.rx_pkts_all); len += snprintf(buf + len, size - len, - "%22s : %10u\n", "RX-Bytes-All", + "%18s : %10u\n", "RX-Bytes-All", sc->debug.stats.rxstats.rx_bytes_all); if (len > size) @@ -963,6 +1049,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) #define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\ [sc->debug.rsidx].c) + u32 phyerr; + RX_STAT_INC(rx_pkts_all); sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; @@ -981,11 +1069,20 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) if (rs->rs_status & ATH9K_RXERR_PHY) { RX_STAT_INC(phy_err); - if (rs->rs_phyerr < ATH9K_PHYERR_MAX) - RX_PHY_ERR_INC(rs->rs_phyerr); + phyerr = rs->rs_phyerr & 0x24; + RX_PHY_ERR_INC(phyerr); } -#ifdef CONFIG_ATH9K_MAC_DEBUG + sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0; + sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1; + sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2; + + sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0; + sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1; + sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2; + + sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; + spin_lock(&sc->debug.samp_lock); RX_SAMP_DBG(jiffies) = jiffies; RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0; @@ -1002,8 +1099,6 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES; spin_unlock(&sc->debug.samp_lock); -#endif - #undef RX_STAT_INC #undef RX_PHY_ERR_INC #undef RX_SAMP_DBG @@ -1011,7 +1106,7 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) static const struct file_operations fops_recv = { .read = read_file_recv, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1050,7 +1145,7 @@ static ssize_t write_file_regidx(struct file *file, const char __user *user_buf, static const struct file_operations fops_regidx = { .read = read_file_regidx, .write = write_file_regidx, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1097,7 +1192,7 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf, static const struct file_operations fops_regval = { .read = read_file_regval, .write = write_file_regval, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1186,7 +1281,7 @@ static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf, static const struct file_operations fops_dump_nfcal = { .read = read_file_dump_nfcal, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1214,7 +1309,7 @@ static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_base_eeprom = { .read = read_file_base_eeprom, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1242,13 +1337,11 @@ static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_modal_eeprom = { .read = read_file_modal_eeprom, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; -#ifdef CONFIG_ATH9K_MAC_DEBUG - void ath9k_debug_samp_bb_mac(struct ath_softc *sc) { #define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c) @@ -1522,7 +1615,6 @@ static const struct file_operations fops_samps = { .llseek = default_llseek, }; -#endif int ath9k_init_debug(struct ath_hw *ah) { @@ -1538,21 +1630,18 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); #endif - - ath9k_dfs_init_debug(sc); - debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dma); debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_interrupt); + debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_wiphy); debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_xmit); debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_stations); debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_misc); - debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_reset); debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_recv); debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, @@ -1576,10 +1665,8 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_base_eeprom); debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_modal_eeprom); -#ifdef CONFIG_ATH9K_MAC_DEBUG debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_samps); -#endif debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); @@ -1587,5 +1674,10 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); + sc->debug.regidx = 0; + memset(&sc->debug.bb_mac_samp, 0, sizeof(sc->debug.bb_mac_samp)); + sc->debug.sampidx = 0; + sc->debug.tsidx = 0; + sc->debug.rsidx = 0; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 64fcfad4..356352ac 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -19,7 +19,6 @@ #include "hw.h" #include "rc.h" -#include "dfs_debug.h" struct ath_txq; struct ath_buf; @@ -165,6 +164,13 @@ struct ath_rx_stats { u32 post_delim_crc_err; u32 decrypt_busy_err; u32 phy_err_stats[ATH9K_PHYERR_MAX]; + int8_t rs_rssi_ctl0; + int8_t rs_rssi_ctl1; + int8_t rs_rssi_ctl2; + int8_t rs_rssi_ext0; + int8_t rs_rssi_ext1; + int8_t rs_rssi_ext2; + u8 rs_antenna; }; enum ath_reset_type { @@ -181,7 +187,6 @@ struct ath_stats { struct ath_interrupt_stats istats; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; - struct ath_dfs_stats dfs_stats; u32 reset[__RESET_TYPE_MAX]; }; @@ -228,17 +233,16 @@ struct ath9k_debug { struct dentry *debugfs_phy; u32 regidx; struct ath_stats stats; -#ifdef CONFIG_ATH9K_MAC_DEBUG spinlock_t samp_lock; struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES]; u8 sampidx; u8 tsidx; u8 rsidx; -#endif }; int ath9k_init_debug(struct ath_hw *ah); +void ath9k_debug_samp_bb_mac(struct ath_softc *sc); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq, @@ -252,6 +256,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) return 0; } +static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +} + static inline void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { @@ -272,17 +280,4 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc, #endif /* CONFIG_ATH9K_DEBUGFS */ -#ifdef CONFIG_ATH9K_MAC_DEBUG - -void ath9k_debug_samp_bb_mac(struct ath_softc *sc); - -#else - -static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) -{ -} - -#endif - - #endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index c4352323..e46f751a 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -305,7 +305,8 @@ void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah) regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: - ath_dbg(common, EEPROM, "Invalid chainmask configuration\n"); + ath_dbg(common, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); break; } } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 4322ac80..9a7520f9 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -38,7 +38,7 @@ static bool __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Unable to read eeprom region\n"); return false; } @@ -62,7 +62,8 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, EEPROM, "Reading from EEPROM, not flash\n"); + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); } if (common->bus_ops->ath_bus_type == ATH_USB) @@ -203,7 +204,8 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) return false; } - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); + ath_dbg(common, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -225,7 +227,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) } } - ath_dbg(common, EEPROM, "need_swap = %s\n", + ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? "True" : "False"); if (need_swap) @@ -247,7 +249,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) u32 integer; u16 word; - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "EEPROM Endianness is not native.. Changing\n"); word = swab16(eep->baseEepHeader.length); @@ -433,11 +435,11 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, reg32 = get_unaligned_le32(&pdadcValues[4 * j]); REG_WRITE(ah, regOffset, reg32); - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "PDADC: Chain %d | " "PDADC %3d Value %3d | " "PDADC %3d Value %3d | " @@ -471,7 +473,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, int i; u16 twiceMinEdgePower; - u16 twiceMaxEdgePower; + u16 twiceMaxEdgePower = MAX_RATE_POWER; u16 scaledPower = 0, minCtlPower; u16 numCtlModes; const u16 *pCtlMode; @@ -540,7 +542,9 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - twiceMaxEdgePower = MAX_RATE_POWER; + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = MAX_RATE_POWER; for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { @@ -1077,7 +1081,8 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) u16 spur_val = AR_NO_SPUR; - ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", + ath_dbg(common, ATH_DBG_ANI, + "Getting spur idx:%d is2Ghz:%d val:%x\n", i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { @@ -1085,8 +1090,8 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", - spur_val); + ath_dbg(common, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: spur_val = EEP_MAP4K_SPURCHAN; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index b34e8b29..4f5c50a8 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -41,7 +41,7 @@ static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "Unable to read eeprom region\n"); return false; } @@ -66,7 +66,8 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, EEPROM, "Reading from EEPROM, not flash\n"); + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); } if (common->bus_ops->ath_bus_type == ATH_USB) @@ -196,7 +197,8 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) return false; } - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); + ath_dbg(common, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -218,7 +220,7 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) } } - ath_dbg(common, EEPROM, "need_swap = %s\n", + ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? "True" : "False"); if (need_swap) @@ -567,7 +569,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - u16 twiceMaxEdgePower; + u16 twiceMaxEdgePower = MAX_RATE_POWER; int i; struct cal_ctl_data_ar9287 *rep; struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, @@ -667,7 +669,6 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - twiceMaxEdgePower = MAX_RATE_POWER; /* Walk through the CTL indices stored in EEPROM */ for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { struct cal_ctl_edges *pRdEdgesPower; @@ -824,8 +825,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, regulatory->max_power_level = ratesArray[i]; } - ath9k_hw_update_regulatory_maxpower(ah); - if (test) return; @@ -1041,7 +1040,8 @@ static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); u16 spur_val = AR_NO_SPUR; - ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", + ath_dbg(common, ATH_DBG_ANI, + "Getting spur idx:%d is2Ghz:%d val:%x\n", i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { @@ -1049,8 +1049,8 @@ static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah, break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", - spur_val); + ath_dbg(common, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: spur_val = EEP_MAP9287_SPURCHAN; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 619b95d7..81e62967 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -121,7 +121,8 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, EEPROM, "Reading from EEPROM, not flash\n"); + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); } if (common->bus_ops->ath_bus_type == ATH_USB) @@ -278,7 +279,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) } if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); + ath_dbg(common, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -301,7 +303,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) } } - ath_dbg(common, EEPROM, "need_swap = %s\n", + ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? "True" : "False"); if (need_swap) @@ -323,7 +325,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) u32 integer, j; u16 word; - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "EEPROM Endianness is not native.. Changing.\n"); word = swab16(eep->baseEepHeader.length); @@ -383,7 +385,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) if ((ah->hw_version.devid == AR9280_DEVID_PCI) && ((eep->baseEepHeader.version & 0xff) > 0x0a) && (eep->baseEepHeader.pwdclkind == 0)) - ah->need_an_top2_fixup = true; + ah->need_an_top2_fixup = 1; if ((common->bus_ops->ath_bus_type == ATH_USB) && (AR_SREV_9280(ah))) @@ -963,12 +965,15 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, reg32 = get_unaligned_le32(&pdadcValues[4 * j]); REG_WRITE(ah, regOffset, reg32); - ath_dbg(common, EEPROM, + ath_dbg(common, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - ath_dbg(common, EEPROM, - "PDADC: Chain %d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d |\n", + ath_dbg(common, ATH_DBG_EEPROM, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", i, 4 * j, pdadcValues[4 * j], 4 * j + 1, pdadcValues[4 * j + 1], 4 * j + 2, pdadcValues[4 * j + 2], @@ -995,7 +1000,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - u16 twiceMaxEdgePower; + u16 twiceMaxEdgePower = MAX_RATE_POWER; int i; struct cal_ctl_data *rep; struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { @@ -1116,7 +1121,9 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - twiceMaxEdgePower = MAX_RATE_POWER; + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = MAX_RATE_POWER; for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { if ((((cfgCtl & ~CTL_MODE_M) | @@ -1273,7 +1280,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: - ath_dbg(ath9k_hw_common(ah), EEPROM, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_EEPROM, "Invalid chainmask configuration\n"); break; } @@ -1391,7 +1398,8 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) u16 spur_val = AR_NO_SPUR; - ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", + ath_dbg(common, ATH_DBG_ANI, + "Getting spur idx:%d is2Ghz:%d val:%x\n", i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { @@ -1399,8 +1407,8 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", - spur_val); + ath_dbg(common, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: spur_val = EEP_DEF_SPURCHAN; diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index fbe23de1..e4ae08e0 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -110,8 +110,6 @@ void ath_start_rfkill_poll(struct ath_softc *sc) wiphy_rfkill_start_polling(sc->hw->wiphy); } -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT - /******************/ /* BTCOEX */ /******************/ @@ -132,12 +130,12 @@ static void ath_detect_bt_priority(struct ath_softc *sc) sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); /* Detect if colocated bt started scanning */ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { - ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX, + ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, "BT scan detected\n"); sc->sc_flags |= (SC_OP_BT_SCAN | SC_OP_BT_PRIORITY_DETECTED); } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { - ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX, + ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, "BT priority traffic detected\n"); sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; } @@ -232,7 +230,8 @@ static void ath_btcoex_no_stomp_timer(void *arg) struct ath_common *common = ath9k_hw_common(ah); bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN; - ath_dbg(common, BTCOEX, "no stomp timer running\n"); + ath_dbg(common, ATH_DBG_BTCOEX, + "no stomp timer running\n"); ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); @@ -247,7 +246,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) ath9k_ps_restore(sc); } -static int ath_init_btcoex_timer(struct ath_softc *sc) +int ath_init_btcoex_timer(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; @@ -281,7 +280,8 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; - ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Starting btcoex timers\n"); /* make sure duty cycle timer is also stopped when resuming */ if (btcoex->hw_timer_enabled) @@ -310,114 +310,3 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) btcoex->hw_timer_enabled = false; } - -u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) -{ - struct ath_mci_profile *mci = &sc->btcoex.mci; - u16 aggr_limit = 0; - - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit) - aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4; - else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED) - aggr_limit = min((max_4ms_framelen * 3) / 8, - (u32)ATH_AMPDU_LIMIT_MAX); - - return aggr_limit; -} - -void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) -{ - struct ath_hw *ah = sc->sc_ah; - - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - if (status & ATH9K_INT_GENTIMER) - ath_gen_timer_isr(sc->sc_ah); - - if (status & ATH9K_INT_MCI) - ath_mci_intr(sc); -} - -void ath9k_start_btcoex(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && - !ah->btcoex_hw.enabled) { - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - ath9k_hw_btcoex_enable(ah); - - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_resume(sc); - } -} - -void ath9k_stop_btcoex(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (ah->btcoex_hw.enabled && - ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - ath9k_hw_btcoex_disable(ah); - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_pause(sc); - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) - ath_mci_flush_profile(&sc->btcoex.mci); - } -} - -void ath9k_deinit_btcoex(struct ath_softc *sc) -{ - if ((sc->btcoex.no_stomp_timer) && - ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); - - if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI) - ath_mci_cleanup(sc); -} - -int ath9k_init_btcoex(struct ath_softc *sc) -{ - struct ath_txq *txq; - struct ath_hw *ah = sc->sc_ah; - int r; - - ath9k_hw_btcoex_init_scheme(ah); - - switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) { - case ATH_BTCOEX_CFG_NONE: - break; - case ATH_BTCOEX_CFG_2WIRE: - ath9k_hw_btcoex_init_2wire(sc->sc_ah); - break; - case ATH_BTCOEX_CFG_3WIRE: - ath9k_hw_btcoex_init_3wire(sc->sc_ah); - r = ath_init_btcoex_timer(sc); - if (r) - return -1; - txq = sc->tx.txq_map[WME_AC_BE]; - ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - break; - case ATH_BTCOEX_CFG_MCI: - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; - INIT_LIST_HEAD(&sc->btcoex.mci.info); - - r = ath_mci_setup(sc); - if (r) - return r; - - ath9k_hw_btcoex_init_mci(ah); - - break; - default: - WARN_ON(1); - break; - } - - return 0; -} - -#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 424aabb2..04352e16 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -968,7 +968,8 @@ static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) ath9k_hif_usb_dealloc_rx_urbs(hif_dev); } -static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) +static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev, + u32 drv_info) { int transfer, err; const void *data = hif_dev->firmware->data; @@ -981,7 +982,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) return -ENOMEM; while (len) { - transfer = min_t(size_t, len, 4096); + transfer = min_t(int, len, 4096); memcpy(buf, data, transfer); err = usb_control_msg(hif_dev->udev, @@ -999,7 +1000,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) } kfree(buf); - if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info)) + if (IS_AR7010_DEVICE(drv_info)) firm_offset = AR7010_FIRMWARE_TEXT; else firm_offset = AR9271_FIRMWARE_TEXT; @@ -1020,18 +1021,28 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) return 0; } -static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) +static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info) { + int ret, idx; struct usb_host_interface *alt = &hif_dev->interface->altsetting[0]; struct usb_endpoint_descriptor *endp; - int ret, idx; - ret = ath9k_hif_usb_download_fw(hif_dev); + /* Request firmware */ + ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name, + &hif_dev->udev->dev); + if (ret) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Firmware - %s not found\n", hif_dev->fw_name); + goto err_fw_req; + } + + /* Download firmware */ + ret = ath9k_hif_usb_download_fw(hif_dev, drv_info); if (ret) { dev_err(&hif_dev->udev->dev, "ath9k_htc: Firmware - %s download failed\n", hif_dev->fw_name); - return ret; + goto err_fw_download; } /* On downloading the firmware to the target, the USB descriptor of EP4 @@ -1053,84 +1064,23 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) if (ret) { dev_err(&hif_dev->udev->dev, "ath9k_htc: Unable to allocate URBs\n"); - return ret; + goto err_fw_download; } return 0; + +err_fw_download: + release_firmware(hif_dev->firmware); +err_fw_req: + hif_dev->firmware = NULL; + return ret; } static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev) { ath9k_hif_usb_dealloc_urbs(hif_dev); -} - -/* - * If initialization fails or the FW cannot be retrieved, - * detach the device. - */ -static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) -{ - struct device *parent = hif_dev->udev->dev.parent; - - complete(&hif_dev->fw_done); - - if (parent) - device_lock(parent); - - device_release_driver(&hif_dev->udev->dev); - - if (parent) - device_unlock(parent); -} - -static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) -{ - struct hif_device_usb *hif_dev = context; - int ret; - - if (!fw) { - dev_err(&hif_dev->udev->dev, - "ath9k_htc: Failed to get firmware %s\n", - hif_dev->fw_name); - goto err_fw; - } - - hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb, - &hif_dev->udev->dev); - if (hif_dev->htc_handle == NULL) { - goto err_fw; - } - - hif_dev->firmware = fw; - - /* Proceed with initialization */ - - ret = ath9k_hif_usb_dev_init(hif_dev); - if (ret) - goto err_dev_init; - - ret = ath9k_htc_hw_init(hif_dev->htc_handle, - &hif_dev->interface->dev, - hif_dev->usb_device_id->idProduct, - hif_dev->udev->product, - hif_dev->usb_device_id->driver_info); - if (ret) { - ret = -EINVAL; - goto err_htc_hw_init; - } - - complete(&hif_dev->fw_done); - - return; - -err_htc_hw_init: - ath9k_hif_usb_dev_deinit(hif_dev); -err_dev_init: - ath9k_htc_hw_free(hif_dev->htc_handle); - release_firmware(fw); - hif_dev->firmware = NULL; -err_fw: - ath9k_hif_usb_firmware_fail(hif_dev); + if (hif_dev->firmware) + release_firmware(hif_dev->firmware); } /* @@ -1205,16 +1155,20 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, } usb_get_dev(udev); - hif_dev->udev = udev; hif_dev->interface = interface; - hif_dev->usb_device_id = id; + hif_dev->device_id = id->idProduct; #ifdef CONFIG_PM udev->reset_resume = 1; #endif usb_set_intfdata(interface, hif_dev); - init_completion(&hif_dev->fw_done); + hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb, + &hif_dev->udev->dev); + if (hif_dev->htc_handle == NULL) { + ret = -ENOMEM; + goto err_htc_hw_alloc; + } /* Find out which firmware to load */ @@ -1223,22 +1177,29 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, else hif_dev->fw_name = FIRMWARE_AR9271; - ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name, - &hif_dev->udev->dev, GFP_KERNEL, - hif_dev, ath9k_hif_usb_firmware_cb); + ret = ath9k_hif_usb_dev_init(hif_dev, id->driver_info); if (ret) { - dev_err(&hif_dev->udev->dev, - "ath9k_htc: Async request for firmware %s failed\n", - hif_dev->fw_name); - goto err_fw_req; + ret = -EINVAL; + goto err_hif_init_usb; + } + + ret = ath9k_htc_hw_init(hif_dev->htc_handle, + &interface->dev, hif_dev->device_id, + hif_dev->udev->product, id->driver_info); + if (ret) { + ret = -EINVAL; + goto err_htc_hw_init; } - dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n", - hif_dev->fw_name); + dev_info(&hif_dev->udev->dev, "ath9k_htc: USB layer initialized\n"); return 0; -err_fw_req: +err_htc_hw_init: + ath9k_hif_usb_dev_deinit(hif_dev); +err_hif_init_usb: + ath9k_htc_hw_free(hif_dev->htc_handle); +err_htc_hw_alloc: usb_set_intfdata(interface, NULL); kfree(hif_dev); usb_put_dev(udev); @@ -1273,15 +1234,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) if (!hif_dev) return; - wait_for_completion(&hif_dev->fw_done); - - if (hif_dev->firmware) { - ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); - ath9k_htc_hw_free(hif_dev->htc_handle); - ath9k_hif_usb_dev_deinit(hif_dev); - release_firmware(hif_dev->firmware); - } - + ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); + ath9k_htc_hw_free(hif_dev->htc_handle); + ath9k_hif_usb_dev_deinit(hif_dev); usb_set_intfdata(interface, NULL); if (!unplugged && (hif_dev->flags & HIF_USB_START)) @@ -1321,7 +1276,8 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface) return ret; if (hif_dev->firmware) { - ret = ath9k_hif_usb_download_fw(hif_dev); + ret = ath9k_hif_usb_download_fw(hif_dev, + htc_handle->drv_priv->ah->hw_version.usbdev); if (ret) goto fail_resume; } else { @@ -1355,7 +1311,9 @@ static struct usb_driver ath9k_hif_usb_driver = { .reset_resume = ath9k_hif_usb_resume, #endif .id_table = ath9k_hif_usb_ids, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) .soft_unbind = 1, +#endif }; int ath9k_hif_usb_init(void) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 487ff658..794f6309 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -87,11 +87,10 @@ struct cmd_buf { #define HIF_USB_START BIT(0) struct hif_device_usb { + u16 device_id; struct usb_device *udev; struct usb_interface *interface; - const struct usb_device_id *usb_device_id; const struct firmware *firmware; - struct completion fw_done; struct htc_target *htc_handle; struct hif_usb_tx tx; struct usb_anchor regout_submitted; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 17f687bf..09be4078 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -401,21 +401,9 @@ struct ath_btcoex { u32 btscan_no_stomp; }; -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT -void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product); -void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv); -void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv); -#else -static inline void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product) -{ -} -static inline void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv) -{ -} -static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) -{ -} -#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ +void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv); +void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv); +void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) @@ -496,10 +484,7 @@ struct ath9k_htc_priv { int cabq; int hwq_map[WME_NUM_AC]; -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; -#endif - struct delayed_work coex_period_work; struct delayed_work duty_cycle_work; #ifdef CONFIG_ATH9K_HTC_DEBUGFS diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 2eadffb7..57fe22b2 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -167,9 +167,9 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, /* TSF out of range threshold fixed at 1 second */ bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n", + ath_dbg(common, ATH_DBG_CONFIG, "intval: %u tsf: %llu tsftu: %u\n", intval, tsf, tsftu); - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", bs.bs_bmissthreshold, bs.bs_sleepduration, bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); @@ -224,8 +224,9 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; - ath_dbg(common, CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n", + ath_dbg(common, ATH_DBG_CONFIG, + "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d " + "imask: 0x%x\n", bss_conf->beacon_interval, nexttbtt, priv->ah->config.sw_beacon_response_time, imask); @@ -272,8 +273,9 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; - ath_dbg(common, CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", + ath_dbg(common, ATH_DBG_CONFIG, + "IBSS Beacon config, intval: %d, nexttbtt: %u, " + "resp_time: %d, imask: 0x%x\n", bss_conf->beacon_interval, nexttbtt, priv->ah->config.sw_beacon_response_time, imask); @@ -321,7 +323,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, tx_slot = ath9k_htc_tx_get_slot(priv); if (tx_slot < 0) { - ath_dbg(common, XMIT, "No free CAB slot\n"); + ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n"); dev_kfree_skb_any(skb); goto next; } @@ -331,7 +333,8 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, ath9k_htc_tx_clear_slot(priv, tx_slot); dev_kfree_skb_any(skb); - ath_dbg(common, XMIT, "Failed to send CAB frame\n"); + ath_dbg(common, ATH_DBG_XMIT, + "Failed to send CAB frame\n"); } else { spin_lock_bh(&priv->tx.tx_lock); priv->tx.queued_cnt++; @@ -406,7 +409,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, ret = htc_send(priv->htc, beacon); if (ret != 0) { if (ret == -ENOMEM) { - ath_dbg(common, BSTUCK, + ath_dbg(common, ATH_DBG_BSTUCK, "Failed to send beacon, no free TX buffer\n"); } dev_kfree_skb_any(beacon); @@ -431,7 +434,7 @@ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval; slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1; - ath_dbg(common, BEACON, + ath_dbg(common, ATH_DBG_BEACON, "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n", slot, tsf, tsftu, intval); @@ -447,7 +450,8 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, if (swba->beacon_pending != 0) { priv->cur_beacon_conf.bmiss_cnt++; if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { - ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n"); + ath_dbg(common, ATH_DBG_BSTUCK, + "Beacon stuck, HW reset\n"); ieee80211_queue_work(priv->hw, &priv->fatal_work); } @@ -455,7 +459,7 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, } if (priv->cur_beacon_conf.bmiss_cnt) { - ath_dbg(common, BSTUCK, + ath_dbg(common, ATH_DBG_BSTUCK, "Resuming beacon xmit after %u misses\n", priv->cur_beacon_conf.bmiss_cnt); priv->cur_beacon_conf.bmiss_cnt = 0; @@ -491,8 +495,8 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, priv->cur_beacon_conf.bslot[avp->bslot] = vif; spin_unlock_bh(&priv->beacon_lock); - ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", - avp->bslot); + ath_dbg(common, ATH_DBG_CONFIG, + "Added interface at beacon slot: %d\n", avp->bslot); } void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, @@ -505,8 +509,8 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, priv->cur_beacon_conf.bslot[avp->bslot] = NULL; spin_unlock_bh(&priv->beacon_lock); - ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", - avp->bslot); + ath_dbg(common, ATH_DBG_CONFIG, + "Removed interface at beacon slot: %d\n", avp->bslot); } /* @@ -532,7 +536,8 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF; avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); - ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n", + ath_dbg(common, ATH_DBG_CONFIG, + "tsfadjust is: %llu for bslot: %d\n", (unsigned long long)tsfadjust, avp->bslot); } @@ -563,7 +568,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, (priv->num_ap_vif > 1) && (vif->type == NL80211_IFTYPE_AP) && (cur_conf->beacon_interval != bss_conf->beacon_int)) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Changing beacon interval of multiple AP interfaces !\n"); return false; } @@ -574,7 +579,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, */ if (priv->num_ap_vif && (vif->type != NL80211_IFTYPE_AP)) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "HW in AP mode, cannot set STA beacon parameters\n"); return false; } @@ -592,7 +597,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, &beacon_configured); if (beacon_configured) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Beacon already configured for a station interface\n"); return false; } @@ -632,7 +637,8 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, ath9k_htc_beacon_config_ap(priv, cur_conf); break; default: - ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); return; } } @@ -653,7 +659,8 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) ath9k_htc_beacon_config_ap(priv, cur_conf); break; default: - ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); return; } } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 3035deb7..d3ff33c7 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -16,6 +16,12 @@ #include "htc.h" +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -69,7 +75,7 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_int_stats = { .read = read_file_tgt_int_stats, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -139,7 +145,7 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_tx_stats = { .read = read_file_tgt_tx_stats, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -185,7 +191,7 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_rx_stats = { .read = read_file_tgt_rx_stats, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -237,7 +243,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, static const struct file_operations fops_xmit = { .read = read_file_xmit, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -358,7 +364,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, static const struct file_operations fops_recv = { .read = read_file_recv, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -393,7 +399,7 @@ static ssize_t read_file_slot(struct file *file, char __user *user_buf, static const struct file_operations fops_slot = { .read = read_file_slot, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -440,7 +446,7 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf, static const struct file_operations fops_queue = { .read = read_file_queue, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -481,7 +487,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, static const struct file_operations fops_debug = { .read = read_file_debug, .write = write_file_debug, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -630,7 +636,7 @@ static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_base_eeprom = { .read = read_file_base_eeprom, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -911,7 +917,7 @@ static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_modal_eeprom = { .read = read_file_modal_eeprom, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 1c10e2e5..ce606b61 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -20,10 +20,6 @@ /* BTCOEX */ /******************/ -#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193" - -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT - /* * Detects if there is any priority bt traffic */ @@ -40,12 +36,12 @@ static void ath_detect_bt_priority(struct ath9k_htc_priv *priv) priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN); /* Detect if colocated bt started scanning */ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { - ath_dbg(ath9k_hw_common(ah), BTCOEX, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "BT scan detected\n"); priv->op_flags |= (OP_BT_SCAN | OP_BT_PRIORITY_DETECTED); } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { - ath_dbg(ath9k_hw_common(ah), BTCOEX, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "BT priority traffic detected\n"); priv->op_flags |= OP_BT_PRIORITY_DETECTED; } @@ -106,7 +102,8 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work) struct ath_common *common = ath9k_hw_common(ah); bool is_btscan = priv->op_flags & OP_BT_SCAN; - ath_dbg(common, BTCOEX, "time slice work for bt and wlan\n"); + ath_dbg(common, ATH_DBG_BTCOEX, + "time slice work for bt and wlan\n"); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); @@ -115,7 +112,7 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work) ath9k_hw_btcoex_enable(priv->ah); } -static void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) +void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; @@ -132,12 +129,12 @@ static void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) * (Re)start btcoex work */ -static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) +void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; struct ath_hw *ah = priv->ah; - ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex work\n"); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work\n"); btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; @@ -149,66 +146,12 @@ static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) /* * Cancel btcoex and bt duty cycle work. */ -static void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) +void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) { cancel_delayed_work_sync(&priv->coex_period_work); cancel_delayed_work_sync(&priv->duty_cycle_work); } -void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv) -{ - struct ath_hw *ah = priv->ah; - - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) { - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - ath9k_hw_btcoex_enable(ah); - ath_htc_resume_btcoex_work(priv); - } -} - -void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) -{ - struct ath_hw *ah = priv->ah; - - if (ah->btcoex_hw.enabled && - ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - ath9k_hw_btcoex_disable(ah); - if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) - ath_htc_cancel_btcoex_work(priv); - } -} - -void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product) -{ - struct ath_hw *ah = priv->ah; - int qnum; - - if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) { - ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE; - } - - switch (ath9k_hw_get_btcoex_scheme(priv->ah)) { - case ATH_BTCOEX_CFG_NONE: - break; - case ATH_BTCOEX_CFG_3WIRE: - priv->ah->btcoex_hw.btactive_gpio = 7; - priv->ah->btcoex_hw.btpriority_gpio = 6; - priv->ah->btcoex_hw.wlanactive_gpio = 8; - priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - ath9k_hw_btcoex_init_3wire(priv->ah); - ath_htc_init_btcoex_work(priv); - qnum = priv->hwq_map[WME_AC_BE]; - ath9k_hw_init_btcoex_hw(priv->ah, qnum); - break; - default: - WARN_ON(1); - break; - } -} - -#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ - /*******/ /* LED */ /*******/ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c old mode 100644 new mode 100755 index 2b8406a8..ef921e1b --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -41,6 +41,8 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); .max_power = 20, \ } +#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193" + static struct ieee80211_channel ath9k_2ghz_channels[] = { CHAN2G(2412, 0), /* Channel 1 */ CHAN2G(2417, 1), /* Channel 2 */ @@ -297,7 +299,8 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) (u8 *) &val, sizeof(val), 100); if (unlikely(r)) { - ath_dbg(common, WMI, "REGISTER READ FAILED: (0x%04x, %d)\n", + ath_dbg(common, ATH_DBG_WMI, + "REGISTER READ FAILED: (0x%04x, %d)\n", reg_offset, r); return -EIO; } @@ -324,7 +327,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, (u8 *)tmpval, sizeof(u32) * count, 100); if (unlikely(ret)) { - ath_dbg(common, WMI, + ath_dbg(common, ATH_DBG_WMI, "Multiple REGISTER READ FAILED (count: %d)\n", count); } @@ -349,7 +352,8 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) (u8 *) &val, sizeof(val), 100); if (unlikely(r)) { - ath_dbg(common, WMI, "REGISTER WRITE FAILED:(0x%04x, %d)\n", + ath_dbg(common, ATH_DBG_WMI, + "REGISTER WRITE FAILED:(0x%04x, %d)\n", reg_offset, r); } } @@ -380,7 +384,7 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) (u8 *) &rsp_status, sizeof(rsp_status), 100); if (unlikely(r)) { - ath_dbg(common, WMI, + ath_dbg(common, ATH_DBG_WMI, "REGISTER WRITE FAILED, multi len: %d\n", priv->wmi->multi_write_idx); } @@ -430,7 +434,7 @@ static void ath9k_regwrite_flush(void *hw_priv) (u8 *) &rsp_status, sizeof(rsp_status), 100); if (unlikely(r)) { - ath_dbg(common, WMI, + ath_dbg(common, ATH_DBG_WMI, "REGISTER WRITE FAILED, multi len: %d\n", priv->wmi->multi_write_idx); } @@ -508,7 +512,8 @@ static void setup_ht_cap(struct ath9k_htc_priv *priv, tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", + ath_dbg(common, ATH_DBG_CONFIG, + "TX streams %d, RX streams: %d\n", tx_streams, rx_streams); if (tx_streams != rx_streams) { @@ -601,6 +606,29 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) priv->ah->opmode = NL80211_IFTYPE_STATION; } +static void ath9k_init_btcoex(struct ath9k_htc_priv *priv) +{ + int qnum; + + switch (priv->ah->btcoex_hw.scheme) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_3WIRE: + priv->ah->btcoex_hw.btactive_gpio = 7; + priv->ah->btcoex_hw.btpriority_gpio = 6; + priv->ah->btcoex_hw.wlanactive_gpio = 8; + priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + ath9k_hw_btcoex_init_3wire(priv->ah); + ath_htc_init_btcoex_work(priv); + qnum = priv->hwq_map[WME_AC_BE]; + ath9k_hw_init_btcoex_hw(priv->ah, qnum); + break; + default: + WARN_ON(1); + break; + } +} + static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid, char *product, u32 drv_info) @@ -673,7 +701,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ath9k_cmn_init_crypto(ah); ath9k_init_channels_rates(priv); ath9k_init_misc(priv); - ath9k_htc_init_btcoex(priv, product); + + if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) { + ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE; + ath9k_init_btcoex(priv); + } return 0; @@ -711,8 +743,6 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - hw->queues = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; @@ -847,8 +877,9 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, goto err_world; } - ath_dbg(common, CONFIG, - "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, BE:%d, BK:%d, VI:%d, VO:%d\n", + ath_dbg(common, ATH_DBG_CONFIG, + "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, " + "BE:%d, BK:%d, VI:%d, VO:%d\n", priv->wmi_cmd_ep, priv->beacon_ep, priv->cab_ep, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c old mode 100644 new mode 100755 index 204619e2..99bbf069 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -275,7 +275,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, ath9k_wmi_event_drain(priv); - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", priv->ah->curchan->channel, channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), @@ -424,7 +424,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) priv->vif_sta_pos[priv->mon_vif_idx] = sta_idx; priv->ah->is_monitoring = true; - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Attached a monitor interface at idx: %d, sta idx: %d\n", priv->mon_vif_idx, sta_idx); @@ -436,7 +436,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) */ __ath9k_htc_remove_monitor_interface(priv); err_vif: - ath_dbg(common, FATAL, "Unable to attach a monitor interface\n"); + ath_dbg(common, ATH_DBG_FATAL, "Unable to attach a monitor interface\n"); return ret; } @@ -461,7 +461,7 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) priv->nstations--; priv->ah->is_monitoring = false; - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Removed a monitor interface at idx: %d, sta idx: %d\n", priv->mon_vif_idx, sta_idx); @@ -521,11 +521,11 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, } if (sta) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Added a station entry for: %pM (idx: %d)\n", sta->addr, tsta.sta_index); } else { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Added a station entry for VIF %d (idx: %d)\n", avp->index, tsta.sta_index); } @@ -565,11 +565,11 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, } if (sta) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Removed a station entry for: %pM (idx: %d)\n", sta->addr, sta_idx); } else { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Removed a station entry for VIF %d (idx: %d)\n", avp->index, sta_idx); } @@ -674,7 +674,7 @@ static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv, ath9k_htc_setup_rate(priv, sta, &trate); ret = ath9k_htc_send_rate_cmd(priv, &trate); if (!ret) - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Updated target sta: %pM, rate caps: 0x%X\n", sta->addr, be32_to_cpu(trate.capflags)); } @@ -701,7 +701,7 @@ static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv, ret = ath9k_htc_send_rate_cmd(priv, &trate); if (!ret) - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Updated target sta: %pM, rate caps: 0x%X\n", bss_conf->bssid, be32_to_cpu(trate.capflags)); } @@ -730,11 +730,11 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv, WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr); if (ret) - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Unable to %s TX aggregation for (%pM, %d)\n", (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid); else - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "%s TX aggregation for (%pM, %d)\n", (aggr.aggr_enable) ? "Starting" : "Stopping", sta->addr, tid); @@ -793,7 +793,7 @@ void ath9k_htc_ani_work(struct work_struct *work) /* Long calibration runs independently of short calibration. */ if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; - ath_dbg(common, ANI, "longcal @%lu\n", jiffies); + ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); common->ani.longcal_timer = timestamp; } @@ -802,7 +802,8 @@ void ath9k_htc_ani_work(struct work_struct *work) if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; - ath_dbg(common, ANI, "shortcal @%lu\n", jiffies); + ath_dbg(common, ATH_DBG_ANI, + "shortcal @%lu\n", jiffies); common->ani.shortcal_timer = timestamp; common->ani.resetcal_timer = timestamp; } @@ -816,8 +817,7 @@ void ath9k_htc_ani_work(struct work_struct *work) } /* Verify whether we must check ANI */ - if (ah->config.enable_ani && - (timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { + if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { aniflag = true; common->ani.checkani_timer = timestamp; } @@ -847,7 +847,7 @@ void ath9k_htc_ani_work(struct work_struct *work) * short calibration and long calibration. */ cal_interval = ATH_LONG_CALINTERVAL; - if (ah->config.enable_ani) + if (priv->ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); if (!common->ani.caldone) cal_interval = min(cal_interval, (u32)short_cal_interval); @@ -874,7 +874,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) padsize = padpos & 3; if (padsize && skb->len > padpos) { if (skb_headroom(skb) < padsize) { - ath_dbg(common, XMIT, "No room for padding\n"); + ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n"); goto fail_tx; } skb_push(skb, padsize); @@ -883,13 +883,13 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) slot = ath9k_htc_tx_get_slot(priv); if (slot < 0) { - ath_dbg(common, XMIT, "No free TX slot\n"); + ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n"); goto fail_tx; } ret = ath9k_htc_tx_start(priv, skb, slot, false); if (ret != 0) { - ath_dbg(common, XMIT, "Tx failed\n"); + ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n"); goto clear_slot; } @@ -917,7 +917,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Starting driver with initial channel: %d MHz\n", curchan->center_freq); @@ -928,6 +928,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) /* setup initial channel */ init_channel = ath9k_cmn_get_curchannel(hw, ah); + ath9k_hw_htc_resetinit(ah); ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (ret) { ath_err(common, @@ -950,7 +951,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ret = ath9k_htc_update_cap_target(priv, 0); if (ret) - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Failed to update capability in target\n"); priv->op_flags &= ~OP_INVALID; @@ -965,8 +966,12 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) mod_timer(&priv->tx.cleanup_timer, jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); - ath9k_htc_start_btcoex(priv); - + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + ath9k_hw_btcoex_enable(ah); + ath_htc_resume_btcoex_work(priv); + } mutex_unlock(&priv->mutex); return ret; @@ -983,7 +988,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); if (priv->op_flags & OP_INVALID) { - ath_dbg(common, ANY, "Device not present\n"); + ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&priv->mutex); return; } @@ -1013,7 +1018,11 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - ath9k_htc_stop_btcoex(priv); + if (ah->btcoex_hw.enabled) { + ath9k_hw_btcoex_disable(ah); + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath_htc_cancel_btcoex_work(priv); + } /* Remove a monitor interface if it's present. */ if (priv->ah->is_monitoring) @@ -1026,7 +1035,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) priv->op_flags |= OP_INVALID; - ath_dbg(common, CONFIG, "Driver halt\n"); + ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n"); mutex_unlock(&priv->mutex); } @@ -1119,8 +1128,8 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ath9k_htc_start_ani(priv); } - ath_dbg(common, CONFIG, "Attach a VIF of type: %d at idx: %d\n", - vif->type, avp->index); + ath_dbg(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); out: ath9k_htc_ps_restore(priv); @@ -1176,7 +1185,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, ath9k_htc_stop_ani(priv); } - ath_dbg(common, CONFIG, "Detach Interface at idx: %d\n", avp->index); + ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface at idx: %d\n", avp->index); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); @@ -1201,7 +1210,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) mutex_unlock(&priv->htc_pm_lock); if (enable_radio) { - ath_dbg(common, CONFIG, "not-idle: enabling radio\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "not-idle: enabling radio\n"); ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); ath9k_htc_radio_enable(hw); } @@ -1223,7 +1233,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *curchan = hw->conf.channel; int pos = curchan->hw_value; - ath_dbg(common, CONFIG, "Set channel: %d MHz\n", + ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", curchan->center_freq); ath9k_cmn_update_ichannel(&priv->ah->channels[pos], @@ -1263,7 +1273,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) } mutex_unlock(&priv->htc_pm_lock); - ath_dbg(common, CONFIG, "idle: disabling radio\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "idle: disabling radio\n"); ath9k_htc_radio_disable(hw); } @@ -1295,7 +1306,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, *total_flags &= SUPPORTED_FILTERS; if (priv->op_flags & OP_INVALID) { - ath_dbg(ath9k_hw_common(priv->ah), ANY, + ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_ANY, "Unable to configure filter on invalid state\n"); mutex_unlock(&priv->mutex); return; @@ -1306,8 +1317,8 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, rfilt = ath9k_htc_calcrxfilter(priv); ath9k_hw_setrxfilter(priv->ah, rfilt); - ath_dbg(ath9k_hw_common(priv->ah), CONFIG, "Set HW RX filter: 0x%x\n", - rfilt); + ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG, + "Set HW RX filter: 0x%x\n", rfilt); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); @@ -1374,7 +1385,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, qnum = get_hw_qnum(queue, priv->hwq_map); - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Configure tx [queue/hwq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", queue, qnum, params->aifs, params->cw_min, params->cw_max, params->txop); @@ -1408,23 +1419,8 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, if (htc_modparam_nohwcrypt) return -ENOSPC; - if ((vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT) && - (key->cipher == WLAN_CIPHER_SUITE_TKIP || - key->cipher == WLAN_CIPHER_SUITE_CCMP) && - !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { - /* - * For now, disable hw crypto for the RSN IBSS group keys. This - * could be optimized in the future to use a modified key cache - * design to support per-STA RX GTK, but until that gets - * implemented, use of software crypto for group addressed - * frames is a acceptable to allow RSN IBSS to be used. - */ - return -EOPNOTSUPP; - } - mutex_lock(&priv->mutex); - ath_dbg(common, CONFIG, "Set HW Key\n"); + ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); ath9k_htc_ps_wakeup(priv); switch (cmd) { @@ -1460,7 +1456,8 @@ static void ath9k_htc_set_bssid(struct ath9k_htc_priv *priv) struct ath_common *common = ath9k_hw_common(priv->ah); ath9k_hw_write_associd(priv->ah); - ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n", + ath_dbg(common, ATH_DBG_CONFIG, + "BSSID: %pM aid: 0x%x\n", common->curbssid, common->curaid); } @@ -1498,7 +1495,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath9k_htc_ps_wakeup(priv); if (changed & BSS_CHANGED_ASSOC) { - ath_dbg(common, CONFIG, "BSS Changed ASSOC %d\n", + ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); bss_conf->assoc ? @@ -1522,8 +1519,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, } if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { - ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n", - bss_conf->bssid); + ath_dbg(common, ATH_DBG_CONFIG, + "Beacon enabled for BSS: %pM\n", bss_conf->bssid); ath9k_htc_set_tsfadjust(priv, vif); priv->op_flags |= OP_ENABLE_BEACON; ath9k_htc_beacon_config(priv, vif); @@ -1535,7 +1532,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, * AP/IBSS interfaces. */ if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) { - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Beacon disabled for BSS: %pM\n", bss_conf->bssid); priv->op_flags &= ~OP_ENABLE_BEACON; @@ -1553,7 +1550,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, (vif->type == NL80211_IFTYPE_AP)) { priv->op_flags |= OP_TSF_RESET; } - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Beacon interval changed for BSS: %pM\n", bss_conf->bssid); ath9k_htc_beacon_config(priv, vif); @@ -1743,7 +1740,8 @@ static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, goto out; } - ath_dbg(common, CONFIG, "Set bitrate masks: 0x%x, 0x%x\n", + ath_dbg(common, ATH_DBG_CONFIG, + "Set bitrate masks: 0x%x, 0x%x\n", mask->control[IEEE80211_BAND_2GHZ].legacy, mask->control[IEEE80211_BAND_5GHZ].legacy); out: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 6596a23e..9a571496 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -355,7 +355,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, vif_idx = avp->index; } else { if (!priv->ah->is_monitoring) { - ath_dbg(ath9k_hw_common(priv->ah), XMIT, + ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "VIF is null, but no monitor interface !\n"); return -EINVAL; } @@ -630,7 +630,8 @@ static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, } spin_unlock_irqrestore(&epid_queue->lock, flags); - ath_dbg(common, XMIT, "No matching packet for cookie: %d, epid: %d\n", + ath_dbg(common, ATH_DBG_XMIT, + "No matching packet for cookie: %d, epid: %d\n", txs->cookie, epid); return NULL; @@ -714,7 +715,8 @@ static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb if (time_after(jiffies, tx_ctl->timestamp + msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { - ath_dbg(common, XMIT, "Dropping a packet due to TX timeout\n"); + ath_dbg(common, ATH_DBG_XMIT, + "Dropping a packet due to TX timeout\n"); return true; } @@ -761,7 +763,7 @@ void ath9k_htc_tx_cleanup_timer(unsigned long data) skb = ath9k_htc_tx_get_packet(priv, &event->txs); if (skb) { - ath_dbg(common, XMIT, + ath_dbg(common, ATH_DBG_XMIT, "Found packet for cookie: %d, epid: %d\n", event->txs.cookie, MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); @@ -1179,7 +1181,8 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, spin_unlock(&priv->rx.rxbuflock); if (rxbuf == NULL) { - ath_dbg(common, ANY, "No free RX buffer\n"); + ath_dbg(common, ATH_DBG_ANY, + "No free RX buffer\n"); goto err; } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c old mode 100644 new mode 100755 index ec86d981..4f7843ae --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -433,8 +433,11 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle, struct htc_target *target; target = kzalloc(sizeof(struct htc_target), GFP_KERNEL); - if (!target) + if (!target) { + printk(KERN_ERR "Unable to allocate memory for" + "target device\n"); return NULL; + } init_completion(&target->target_wait); init_completion(&target->cmd_wait); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 265bf775..e74c2337 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -24,7 +24,7 @@ static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah, bool power_off) { - if (!ah->aspm_enabled) + if (ah->aspm_enabled != true) return; ath9k_hw_ops(ah)->config_pci_powersave(ah, power_off); @@ -212,13 +212,4 @@ static inline int ath9k_hw_fast_chan_change(struct ath_hw *ah, return ath9k_hw_private_ops(ah)->fast_chan_change(ah, chan, ini_reloaded); } - -static inline void ath9k_hw_set_radar_params(struct ath_hw *ah) -{ - if (!ath9k_hw_private_ops(ah)->set_radar_params) - return; - - ath9k_hw_private_ops(ah)->set_radar_params(ah, &ah->radar_conf); -} - #endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4b870110..7c7b377f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -23,7 +23,6 @@ #include "hw-ops.h" #include "rc.h" #include "ar9003_mac.h" -#include "ar9003_mci.h" static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); @@ -134,7 +133,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) udelay(AH_TIME_QUANTUM); } - ath_dbg(ath9k_hw_common(ah), ANY, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_ANY, "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", timeout, reg, REG_READ(ah, reg), mask, val); @@ -449,7 +448,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->slottime = ATH9K_SLOT_TIME_9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; - ah->htc_reset_init = true; } static int ath9k_hw_init_macaddr(struct ath_hw *ah) @@ -493,7 +491,8 @@ static int ath9k_hw_post_init(struct ath_hw *ah) if (ecode != 0) return ecode; - ath_dbg(ath9k_hw_common(ah), CONFIG, "Eeprom VER: %d, REV: %d\n", + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CONFIG, + "Eeprom VER: %d, REV: %d\n", ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); @@ -505,7 +504,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) return ecode; } - if (ah->config.enable_ani) { + if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) { ath9k_hw_ani_setup(ah); ath9k_hw_ani_init(ah); } @@ -538,17 +537,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ah->WARegVal |= (AR_WA_D3_L1_DISABLE | AR_WA_ASPM_TIMER_BASED_DISABLE); - /* - * Read back AR_WA into a permanent copy and set bits 14 and 17. - * We need to do this to avoid RMW of this register. We cannot - * read the reg when chip is asleep. - */ - ah->WARegVal = REG_READ(ah, AR_WA); - ah->WARegVal |= (AR_WA_D3_L1_DISABLE | - AR_WA_ASPM_TIMER_BASED_DISABLE); - - ath9k_hw_read_revisions(ah); - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { ath_err(common, "Couldn't reset chip\n"); return -EIO; @@ -567,7 +555,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EIO; } - if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && !ah->is_pciexpress)) { @@ -579,7 +567,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) } } - ath_dbg(common, RESET, "serialize_regmode is %d\n", + ath_dbg(common, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) @@ -622,15 +610,14 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (!AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_MRC_CCK; - /* disable ANI for 9340 */ - if (AR_SREV_9340(ah)) - ah->config.enable_ani = false; - ath9k_hw_init_mode_regs(ah); if (!ah->is_pciexpress) ath9k_hw_disablepcie(ah); + if (!AR_SREV_9300_20_OR_LATER(ah)) + ar9002_hw_cck_chan14_spread(ah); + r = ath9k_hw_post_init(ah); if (r) return r; @@ -980,8 +967,8 @@ static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) { if (tu > 0xFFFF) { - ath_dbg(ath9k_hw_common(ah), XMIT, "bad global tx timeout %u\n", - tu); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT, + "bad global tx timeout %u\n", tu); ah->globaltxtimeout = (u32) -1; return false; } else { @@ -1002,7 +989,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) int rx_lat = 0, tx_lat = 0, eifs = 0; u32 reg; - ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n", + ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", ah->misc_mode); if (!chan) @@ -1060,16 +1047,13 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) /* * Workaround for early ACK timeouts, add an offset to match the - * initval's 64us ack timeout value. Use 48us for the CTS timeout. + * initval's 64us ack timeout value. * This was initially only meant to work around an issue with delayed * BA frames in some implementations, but it has been found to fix ACK * timeout issues in other cases as well. */ - if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) { + if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) acktimeout += 64 - sifstime - ah->slottime; - ctstimeout += 48 - sifstime - ah->slottime; - } - ath9k_hw_set_sifs_time(ah, sifstime); ath9k_hw_setslottime(ah, slottime); @@ -1300,7 +1284,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) (npend || type == ATH9K_RESET_COLD)) { int reset_err = 0; - ath_dbg(ath9k_hw_common(ah), RESET, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, "reset MAC via external reset\n"); reset_err = ah->external_reset(); @@ -1323,7 +1307,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) REG_WRITE(ah, AR_RTC_RC, 0); if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { - ath_dbg(ath9k_hw_common(ah), RESET, "RTC stuck in MAC reset\n"); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, + "RTC stuck in MAC reset\n"); return false; } @@ -1368,7 +1353,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) AR_RTC_STATUS_M, AR_RTC_STATUS_ON, AH_WAIT_TIMEOUT)) { - ath_dbg(ath9k_hw_common(ah), RESET, "RTC not waking up\n"); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, + "RTC not waking up\n"); return false; } @@ -1377,7 +1363,6 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) { - bool ret = false; if (AR_SREV_9300_20_OR_LATER(ah)) { REG_WRITE(ah, AR_WA, ah->WARegVal); @@ -1389,37 +1374,22 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: - ret = ath9k_hw_set_reset_power_on(ah); - break; + return ath9k_hw_set_reset_power_on(ah); case ATH9K_RESET_WARM: case ATH9K_RESET_COLD: - ret = ath9k_hw_set_reset(ah, type); - break; + return ath9k_hw_set_reset(ah, type); default: - break; + return false; } - - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) - REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); - - return ret; } static bool ath9k_hw_chip_reset(struct ath_hw *ah, struct ath9k_channel *chan) { - int reset_type = ATH9K_RESET_WARM; - - if (AR_SREV_9280(ah)) { - if (ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) - reset_type = ATH9K_RESET_POWER_ON; - else - reset_type = ATH9K_RESET_COLD; - } else if (ah->chip_fullsleep || REG_READ(ah, AR_Q_TXE) || - (REG_READ(ah, AR_CR) & AR_CR_RXE)) - reset_type = ATH9K_RESET_COLD; - - if (!ath9k_hw_set_reset_reg(ah, reset_type)) + if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) { + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) + return false; + } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) return false; if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) @@ -1449,7 +1419,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { - ath_dbg(common, QUEUE, + ath_dbg(common, ATH_DBG_QUEUE, "Transmit frames pending on queue %d\n", qnum); return false; } @@ -1480,7 +1450,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return false; } ath9k_hw_set_clockrate(ah); - ath9k_hw_apply_txpower(ah, chan, false); + ath9k_hw_apply_txpower(ah, chan); ath9k_hw_rfbus_done(ah); if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) @@ -1545,95 +1515,23 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_check_alive); -/* - * Fast channel change: - * (Change synthesizer based on channel freq without resetting chip) - * - * Don't do FCC when - * - Flag is not set - * - Chip is just coming out of full sleep - * - Channel to be set is same as current channel - * - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel) - */ -static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath_common *common = ath9k_hw_common(ah); - int ret; - - if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) - goto fail; - - if (ah->chip_fullsleep) - goto fail; - - if (!ah->curchan) - goto fail; - - if (chan->channel == ah->curchan->channel) - goto fail; - - if ((chan->channelFlags & CHANNEL_ALL) != - (ah->curchan->channelFlags & CHANNEL_ALL)) - goto fail; - - if (!ath9k_hw_check_alive(ah)) - goto fail; - - /* - * For AR9462, make sure that calibration data for - * re-using are present. - */ - if (AR_SREV_9462(ah) && (!ah->caldata || - !ah->caldata->done_txiqcal_once || - !ah->caldata->done_txclcal_once || - !ah->caldata->rtt_hist.num_readings)) - goto fail; - - ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n", - ah->curchan->channel, chan->channel); - - ret = ath9k_hw_channel_change(ah, chan); - if (!ret) - goto fail; - - ath9k_hw_loadnf(ah, ah->curchan); - ath9k_hw_start_nfcal(ah, true); - - if ((ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && ar9003_mci_is_ready(ah)) - ar9003_mci_2g5g_switch(ah, true); - - if (AR_SREV_9271(ah)) - ar9002_hw_load_ani_reg(ah, chan); - - return 0; -fail: - return -EINVAL; -} - int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, - struct ath9k_hw_cal_data *caldata, bool fastcc) + struct ath9k_hw_cal_data *caldata, bool bChannelChange) { struct ath_common *common = ath9k_hw_common(ah); u32 saveLedState; + struct ath9k_channel *curchan = ah->curchan; u32 saveDefAntenna; u32 macStaId1; u64 tsf = 0; int i, r; - bool start_mci_reset = false; - bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI); - bool save_fullsleep = ah->chip_fullsleep; - - if (mci) { - start_mci_reset = ar9003_mci_start_reset(ah, chan); - if (start_mci_reset) - return 0; - } + bool allow_fbs = false; if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; - if (ah->curchan && !ah->chip_fullsleep) - ath9k_hw_getnf(ah, ah->curchan); + if (curchan && !ah->chip_fullsleep) + ath9k_hw_getnf(ah, curchan); ah->caldata = caldata; if (caldata && @@ -1647,14 +1545,30 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } ah->noise = ath9k_hw_getchan_noise(ah, chan); - if (fastcc) { - r = ath9k_hw_do_fastcc(ah, chan); - if (!r) - return r; - } + if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) + bChannelChange = false; - if (mci) - ar9003_mci_stop_bt(ah, save_fullsleep); + if (caldata && + caldata->done_txiqcal_once && + caldata->done_txclcal_once && + caldata->rtt_hist.num_readings) + allow_fbs = true; + + if (bChannelChange && + (ah->chip_fullsleep != true) && + (ah->curchan != NULL) && + (chan->channel != ah->curchan->channel) && + (allow_fbs || + ((chan->channelFlags & CHANNEL_ALL) == + (ah->curchan->channelFlags & CHANNEL_ALL)))) { + if (ath9k_hw_channel_change(ah, chan)) { + ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah, true); + if (AR_SREV_9271(ah)) + ar9002_hw_load_ani_reg(ah, chan); + return 0; + } + } saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) @@ -1711,9 +1625,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (r) return r; - if (mci) - ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep); - /* * Some AR91xx SoC devices frequently fail to accept TSF writes * right after the chip reset. When that happens, write a new @@ -1831,9 +1742,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_loadnf(ah, chan); ath9k_hw_start_nfcal(ah, true); - if (mci && ar9003_mci_end_reset(ah, chan, caldata)) - return -EIO; - ENABLE_REGWRITE_BUFFER(ah); ath9k_hw_restore_chainmask(ah); @@ -1848,14 +1756,14 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 mask; mask = REG_READ(ah, AR_CFG); if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { - ath_dbg(common, RESET, "CFG Byte Swap Set 0x%x\n", - mask); + ath_dbg(common, ATH_DBG_RESET, + "CFG Byte Swap Set 0x%x\n", mask); } else { mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; REG_WRITE(ah, AR_CFG, mask); - ath_dbg(common, RESET, "Setting CFG 0x%x\n", - REG_READ(ah, AR_CFG)); + ath_dbg(common, ATH_DBG_RESET, + "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { if (common->bus_ops->ath_bus_type == ATH_USB) { @@ -1873,12 +1781,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, #endif } - if (ath9k_hw_btcoex_is_enabled(ah)) + if (ah->btcoex_hw.enabled) ath9k_hw_btcoex_enable(ah); - if (mci) - ar9003_mci_check_bt(ah); - if (AR_SREV_9300_20_OR_LATER(ah)) { ar9003_hw_bb_watchdog_config(ah); @@ -1928,15 +1833,15 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); /* Shutdown chip. Active low */ - if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) { + if (!AR_SREV_5416(ah) && + !AR_SREV_9271(ah) && !AR_SREV_9462_10(ah)) { REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); udelay(2); } } /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ - if (AR_SREV_9300_20_OR_LATER(ah)) - REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); + REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); } /* @@ -2003,7 +1908,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) if (setChip) { if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { + if (ath9k_hw_set_reset_reg(ah, + ATH9K_RESET_POWER_ON) != true) { return false; } if (!AR_SREV_9300_20_OR_LATER(ah)) @@ -2052,29 +1958,18 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) if (ah->power_mode == mode) return status; - ath_dbg(common, RESET, "%s -> %s\n", + ath_dbg(common, ATH_DBG_RESET, "%s -> %s\n", modes[ah->power_mode], modes[mode]); switch (mode) { case ATH9K_PM_AWAKE: status = ath9k_hw_set_power_awake(ah, setChip); - - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) - REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); - break; case ATH9K_PM_FULL_SLEEP: - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) - ar9003_mci_set_full_sleep(ah); - ath9k_set_power_sleep(ah, setChip); ah->chip_fullsleep = true; break; case ATH9K_PM_NETWORK_SLEEP: - - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) - REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); - ath9k_set_power_network_sleep(ah, setChip); break; default: @@ -2124,8 +2019,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; default: - ath_dbg(ath9k_hw_common(ah), BEACON, - "%s: unsupported opmode: %d\n", __func__, ah->opmode); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BEACON, + "%s: unsupported opmode: %d\n", + __func__, ah->opmode); return; break; } @@ -2176,10 +2072,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, else nextTbtt = bs->bs_nexttbtt; - ath_dbg(common, BEACON, "next DTIM %d\n", bs->bs_nextdtim); - ath_dbg(common, BEACON, "next beacon %d\n", nextTbtt); - ath_dbg(common, BEACON, "beacon period %d\n", beaconintval); - ath_dbg(common, BEACON, "DTIM period %d\n", dtimperiod); + ath_dbg(common, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); + ath_dbg(common, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); + ath_dbg(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); + ath_dbg(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); ENABLE_REGWRITE_BUFFER(ah); @@ -2226,35 +2122,12 @@ static u8 fixup_chainmask(u8 chip_chainmask, u8 eeprom_chainmask) return chip_chainmask; } -/** - * ath9k_hw_dfs_tested - checks if DFS has been tested with used chipset - * @ah: the atheros hardware data structure - * - * We enable DFS support upstream on chipsets which have passed a series - * of tests. The testing requirements are going to be documented. Desired - * test requirements are documented at: - * - * http://wireless.kernel.org/en/users/Drivers/ath9k/dfs - * - * Once a new chipset gets properly tested an individual commit can be used - * to document the testing for DFS for that chipset. - */ -static bool ath9k_hw_dfs_tested(struct ath_hw *ah) -{ - - switch (ah->hw_version.macVersion) { - /* AR9580 will likely be our first target to get testing on */ - case AR_SREV_VERSION_9580: - default: - return false; - } -} - int ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; unsigned int chip_chainmask; u16 eeval; @@ -2270,8 +2143,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) regulatory->current_rd += 5; else if (regulatory->current_rd == 0x41) regulatory->current_rd = 0x43; - ath_dbg(common, REGULATORY, "regdomain mapped to 0x%x\n", - regulatory->current_rd); + ath_dbg(common, ATH_DBG_REGULATORY, + "regdomain mapped to 0x%x\n", regulatory->current_rd); } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); @@ -2289,8 +2162,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah)) chip_chainmask = 1; - else if (AR_SREV_9462(ah)) - chip_chainmask = 3; else if (!AR_SREV_9280_20_OR_LATER(ah)) chip_chainmask = 7; else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah)) @@ -2347,10 +2218,12 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->num_gpio_pins = AR_NUM_GPIO; - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) + if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_CST; pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; - else + } else { pCap->rts_aggr_limit = (8 * 1024); + } #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); @@ -2373,6 +2246,28 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; + if (common->btcoex_enabled) { + if (AR_SREV_9300_20_OR_LATER(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; + btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; + + if (AR_SREV_9285(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btpriority_gpio = + ATH_BTPRIORITY_GPIO_9285; + } else { + btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + } + } + } else { + btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; + } + if (AR_SREV_9300_20_OR_LATER(ah)) { pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK; if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah)) @@ -2436,9 +2331,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->pcie_lcr_offset = 0x80; } - if (ath9k_hw_dfs_tested(ah)) - pCap->hw_caps |= ATH9K_HW_CAP_DFS; - tx_chainmask = pCap->tx_chainmask; rx_chainmask = pCap->rx_chainmask; while (tx_chainmask || rx_chainmask) { @@ -2453,20 +2345,11 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) { ah->enabled_cals |= TX_IQ_CAL; - if (AR_SREV_9485_OR_LATER(ah)) + if (!AR_SREV_9330(ah)) ah->enabled_cals |= TX_IQ_ON_AGC_CAL; } - - if (AR_SREV_9462(ah)) { - - if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE)) - pCap->hw_caps |= ATH9K_HW_CAP_MCI; - - if (AR_SREV_9462_20(ah)) - pCap->hw_caps |= ATH9K_HW_CAP_RTT; - - } - + if (AR_SREV_9462(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI; return 0; } @@ -2592,6 +2475,12 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) } EXPORT_SYMBOL(ath9k_hw_set_gpio); +u32 ath9k_hw_getdefantenna(struct ath_hw *ah) +{ + return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; +} +EXPORT_SYMBOL(ath9k_hw_getdefantenna); + void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) { REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); @@ -2649,7 +2538,6 @@ bool ath9k_hw_phy_disable(struct ath_hw *ah) return false; ath9k_hw_init_pll(ah, NULL); - ah->htc_reset_init = true; return true; } EXPORT_SYMBOL(ath9k_hw_phy_disable); @@ -2679,8 +2567,7 @@ static int get_antenna_gain(struct ath_hw *ah, struct ath9k_channel *chan) return ah->eep_ops->get_eeprom(ah, gain_param); } -void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, - bool test) +void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_regulatory *reg = ath9k_hw_regulatory(ah); struct ieee80211_channel *channel; @@ -2701,7 +2588,7 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, ah->eep_ops->set_txpower(ah, chan, ath9k_regd_get_ctl(reg, chan), - ant_reduction, new_pwr, test); + ant_reduction, new_pwr, false); } void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) @@ -2714,7 +2601,7 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) if (test) channel->max_power = MAX_RATE_POWER / 2; - ath9k_hw_apply_txpower(ah, chan, test); + ath9k_hw_apply_txpower(ah, chan); if (test) channel->max_power = DIV_ROUND_UP(reg->max_power_level, 2); @@ -2777,7 +2664,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) { if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0, AH_TSF_WRITE_TIMEOUT)) - ath_dbg(ath9k_hw_common(ah), RESET, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); @@ -2902,7 +2789,7 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, timer_next = tsf + trig_timeout; - ath_dbg(ath9k_hw_common(ah), HWTIMER, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER, "current tsf %x period %x timer_next %x\n", tsf, timer_period, timer_next); @@ -2991,8 +2878,8 @@ void ath_gen_timer_isr(struct ath_hw *ah) index = rightmost_index(timer_table, &thresh_mask); timer = timer_table->timers[index]; BUG_ON(!timer); - ath_dbg(common, HWTIMER, "TSF overflow for Gen timer %d\n", - index); + ath_dbg(common, ATH_DBG_HWTIMER, + "TSF overflow for Gen timer %d\n", index); timer->overflow(timer->arg); } @@ -3000,7 +2887,7 @@ void ath_gen_timer_isr(struct ath_hw *ah) index = rightmost_index(timer_table, &trigger_mask); timer = timer_table->timers[index]; BUG_ON(!timer); - ath_dbg(common, HWTIMER, + ath_dbg(common, ATH_DBG_HWTIMER, "Gen timer[%d] trigger\n", index); timer->trigger(timer->arg); } @@ -3011,6 +2898,12 @@ EXPORT_SYMBOL(ath_gen_timer_isr); /* HTC */ /********/ +void ath9k_hw_htc_resetinit(struct ath_hw *ah) +{ + ah->htc_reset_init = true; +} +EXPORT_SYMBOL(ath9k_hw_htc_resetinit); + static struct { u32 version; const char * name; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f49be96a..947895c4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -127,16 +127,6 @@ #define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4 #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 -#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA 0x16 -#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK 0x17 -#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA 0x18 -#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK 0x19 -#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX 0x14 -#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX 0x13 -#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX 9 -#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX 8 -#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE 0x1d -#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA 0x1e #define AR_GPIOD_MASK 0x00001FFF #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) @@ -181,8 +171,8 @@ #define PAPRD_IDEAL_AGC2_PWR_RANGE 0xe0 enum ath_hw_txq_subtype { - ATH_TXQ_AC_BE = 0, - ATH_TXQ_AC_BK = 1, + ATH_TXQ_AC_BK = 0, + ATH_TXQ_AC_BE = 1, ATH_TXQ_AC_VI = 2, ATH_TXQ_AC_VO = 3, }; @@ -197,21 +187,21 @@ enum ath_ini_subsys { enum ath9k_hw_caps { ATH9K_HW_CAP_HT = BIT(0), ATH9K_HW_CAP_RFSILENT = BIT(1), - ATH9K_HW_CAP_AUTOSLEEP = BIT(2), - ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(3), - ATH9K_HW_CAP_EDMA = BIT(4), - ATH9K_HW_CAP_RAC_SUPPORTED = BIT(5), - ATH9K_HW_CAP_LDPC = BIT(6), - ATH9K_HW_CAP_FASTCLOCK = BIT(7), - ATH9K_HW_CAP_SGI_20 = BIT(8), - ATH9K_HW_CAP_PAPRD = BIT(9), - ATH9K_HW_CAP_ANT_DIV_COMB = BIT(10), - ATH9K_HW_CAP_2GHZ = BIT(11), - ATH9K_HW_CAP_5GHZ = BIT(12), - ATH9K_HW_CAP_APM = BIT(13), - ATH9K_HW_CAP_RTT = BIT(14), - ATH9K_HW_CAP_MCI = BIT(15), - ATH9K_HW_CAP_DFS = BIT(16), + ATH9K_HW_CAP_CST = BIT(2), + ATH9K_HW_CAP_AUTOSLEEP = BIT(4), + ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), + ATH9K_HW_CAP_EDMA = BIT(6), + ATH9K_HW_CAP_RAC_SUPPORTED = BIT(7), + ATH9K_HW_CAP_LDPC = BIT(8), + ATH9K_HW_CAP_FASTCLOCK = BIT(9), + ATH9K_HW_CAP_SGI_20 = BIT(10), + ATH9K_HW_CAP_PAPRD = BIT(11), + ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12), + ATH9K_HW_CAP_2GHZ = BIT(13), + ATH9K_HW_CAP_5GHZ = BIT(14), + ATH9K_HW_CAP_APM = BIT(15), + ATH9K_HW_CAP_RTT = BIT(16), + ATH9K_HW_CAP_MCI = BIT(17), }; struct ath9k_hw_capabilities { @@ -277,7 +267,6 @@ enum ath9k_int { ATH9K_INT_TX = 0x00000040, ATH9K_INT_TXDESC = 0x00000080, ATH9K_INT_TIM_TIMER = 0x00000100, - ATH9K_INT_MCI = 0x00000200, ATH9K_INT_BB_WATCHDOG = 0x00000400, ATH9K_INT_TXURN = 0x00000800, ATH9K_INT_MIB = 0x00001000, @@ -430,6 +419,16 @@ enum ath9k_rx_qtype { ATH9K_RX_QUEUE_MAX, }; +enum ath_mci_gpm_coex_profile_type { + MCI_GPM_COEX_PROFILE_UNKNOWN, + MCI_GPM_COEX_PROFILE_RFCOMM, + MCI_GPM_COEX_PROFILE_A2DP, + MCI_GPM_COEX_PROFILE_HID, + MCI_GPM_COEX_PROFILE_BNEP, + MCI_GPM_COEX_PROFILE_VOICE, + MCI_GPM_COEX_PROFILE_MAX +}; + struct ath9k_beacon_state { u32 bs_nexttbtt; u32 bs_nextdtim; @@ -783,6 +782,7 @@ struct ath_hw { u32 *analogBank6Data; u32 *analogBank6TPCData; u32 *analogBank7Data; + u32 *addac5416_21; u32 *bank6Temp; u8 txpower_limit; @@ -799,9 +799,8 @@ struct ath_hw { int firpwr[5]; enum ath9k_ani_cmd ani_function; -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; -#endif u32 intr_txqs; u8 txchainmask; @@ -829,14 +828,19 @@ struct ath_hw { struct ar5416IniArray iniAddac; struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdesLowPower; - struct ar5416IniArray iniModesFastClock; - struct ar5416IniArray iniAdditional; + struct ar5416IniArray iniModesAdditional; + struct ar5416IniArray iniModesAdditional_40M; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; + struct ar5416IniArray iniModes_9271_1_0_only; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; struct ar5416IniArray ini_japan2484; + struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271; + struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271; struct ar5416IniArray iniModes_9271_ANI_reg; + struct ar5416IniArray iniModes_high_power_tx_gain_9271; + struct ar5416IniArray iniModes_normal_power_tx_gain_9271; struct ar5416IniArray ini_radio_post_sys2ant; struct ar5416IniArray ini_BTCOEX_MAX_TXPWR; @@ -854,7 +858,7 @@ struct ath_hw { u32 ts_paddr_start; u32 ts_paddr_end; u16 ts_tail; - u16 ts_size; + u8 ts_size; u32 bb_watchdog_last_status; u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */ @@ -921,7 +925,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_deinit(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, - struct ath9k_hw_cal_data *caldata, bool fastcc); + struct ath9k_hw_cal_data *caldata, bool bChannelChange); int ath9k_hw_fill_cap_info(struct ath_hw *ah); u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan); @@ -931,6 +935,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, u32 ah_signal_type); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); +u32 ath9k_hw_getdefantenna(struct ath_hw *ah); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); /* General Operation */ @@ -951,6 +956,7 @@ bool ath9k_hw_disable(struct ath_hw *ah); void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test); void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); +void ath9k_hw_setbssidmask(struct ath_hw *ah); void ath9k_hw_write_associd(struct ath_hw *ah); u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); @@ -984,16 +990,19 @@ void ath_gen_timer_isr(struct ath_hw *hw); void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); +/* HTC */ +void ath9k_hw_htc_resetinit(struct ath_hw *ah); + /* PHY */ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, u32 *coef_mantissa, u32 *coef_exponent); -void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, - bool test); +void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan); /* * Code Specific to AR5008, AR9001 or AR9002, * we stuff these here to avoid callbacks for AR9003. */ +void ar9002_hw_cck_chan14_spread(struct ath_hw *ah); int ar9002_hw_rf_claim(struct ath_hw *ah); void ar9002_hw_enable_async_fifo(struct ath_hw *ah); @@ -1041,32 +1050,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT -static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) -{ - return ah->btcoex_hw.enabled; -} -void ath9k_hw_btcoex_enable(struct ath_hw *ah); -static inline enum ath_btcoex_scheme -ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) -{ - return ah->btcoex_hw.scheme; -} -#else -static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) -{ - return false; -} -static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah) -{ -} -static inline enum ath_btcoex_scheme -ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) -{ - return ATH_BTCOEX_CFG_NONE; -} -#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ - #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c old mode 100644 new mode 100755 index 30b039fb..39b5faf5 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -172,7 +172,7 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; - if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; spin_lock_irqsave(&sc->sc_serial_rw, flags); iowrite32(val, sc->mem + reg_offset); @@ -188,7 +188,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) struct ath_softc *sc = (struct ath_softc *) common->priv; u32 val; - if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; spin_lock_irqsave(&sc->sc_serial_rw, flags); val = ioread32(sc->mem + reg_offset); @@ -219,7 +219,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl unsigned long uninitialized_var(flags); u32 val; - if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { spin_lock_irqsave(&sc->sc_serial_rw, flags); val = __ath9k_reg_rmw(sc, reg_offset, set, clr); spin_unlock_irqrestore(&sc->sc_serial_rw, flags); @@ -258,8 +258,6 @@ static void setup_ht_cap(struct ath_softc *sc, if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) max_streams = 1; - else if (AR_SREV_9462(ah)) - max_streams = 2; else if (AR_SREV_9300_20_OR_LATER(ah)) max_streams = 3; else @@ -276,7 +274,8 @@ static void setup_ht_cap(struct ath_softc *sc, tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", + ath_dbg(common, ATH_DBG_CONFIG, + "TX streams %d, RX streams: %d\n", tx_streams, rx_streams); if (tx_streams != rx_streams) { @@ -296,22 +295,9 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_regulatory *reg = ath9k_hw_regulatory(ah); - int ret; - - ret = ath_reg_notifier_apply(wiphy, request, reg); - - /* Set tx power */ - if (ah->curchan) { - sc->config.txpowlimit = 2 * ah->curchan->chan->max_power; - ath9k_ps_wakeup(sc); - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); - sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; - ath9k_ps_restore(sc); - } + struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); - return ret; + return ath_reg_notifier_apply(wiphy, request, reg); } /* @@ -328,7 +314,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct ath_buf *bf; int i, bsize, error, desc_len; - ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n", + ath_dbg(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", name, nbuf, ndesc); INIT_LIST_HEAD(head); @@ -374,7 +360,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, goto fail; } ds = (u8 *) dd->dd_desc; - ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + ath_dbg(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); @@ -419,6 +405,36 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, return error; } +static int ath9k_init_btcoex(struct ath_softc *sc) +{ + struct ath_txq *txq; + int r; + + switch (sc->sc_ah->btcoex_hw.scheme) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_2WIRE: + ath9k_hw_btcoex_init_2wire(sc->sc_ah); + break; + case ATH_BTCOEX_CFG_3WIRE: + ath9k_hw_btcoex_init_3wire(sc->sc_ah); + r = ath_init_btcoex_timer(sc); + if (r) + return -1; + txq = sc->tx.txq_map[WME_AC_BE]; + ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; + INIT_LIST_HEAD(&sc->btcoex.mci.info); + break; + default: + WARN_ON(1); + break; + } + + return 0; +} + static int ath9k_init_queues(struct ath_softc *sc) { int i = 0; @@ -484,11 +500,19 @@ static void ath9k_init_misc(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; - setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); sc->config.txpowlimit = ATH_TXPOWER_MAX; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; + } + + sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); + memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + sc->beacon.slottime = ATH9K_SLOT_TIME_9; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) @@ -547,10 +571,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, mutex_init(&sc->mutex); #ifdef CONFIG_ATH9K_DEBUGFS spin_lock_init(&sc->nodes_lock); - INIT_LIST_HEAD(&sc->nodes); -#endif -#ifdef CONFIG_ATH9K_MAC_DEBUG spin_lock_init(&sc->debug.samp_lock); + INIT_LIST_HEAD(&sc->nodes); #endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, @@ -621,10 +643,8 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) static void ath9k_init_txpower_limits(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_channel *curchan = ah->curchan; - ah->txchainmask = common->tx_chainmask; if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) @@ -681,10 +701,11 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; - hw->max_listen_interval = 1; + hw->max_listen_interval = 10; hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); + hw->extra_tx_headroom = 4; hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; @@ -753,11 +774,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, ARRAY_SIZE(ath9k_tpt_blink)); #endif - INIT_WORK(&sc->hw_reset_work, ath_reset_work); - INIT_WORK(&sc->hw_check_work, ath_hw_check); - INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); - INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); - /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) @@ -776,6 +792,10 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, goto error_world; } + INIT_WORK(&sc->hw_reset_work, ath_reset_work); + INIT_WORK(&sc->hw_check_work, ath_hw_check); + INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); + INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); @@ -811,7 +831,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc) if (sc->sbands[IEEE80211_BAND_5GHZ].channels) kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels); - ath9k_deinit_btcoex(sc); + if ((sc->btcoex.no_stomp_timer) && + sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index f7bd2532..21333058 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -21,7 +21,7 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) { - ath_dbg(ath9k_hw_common(ah), INTERRUPT, + ath_dbg(ath9k_hw_common(ah), ATH_DBG_INTERRUPT, "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", ah->txok_interrupt_mask, ah->txerr_interrupt_mask, ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, @@ -57,7 +57,8 @@ EXPORT_SYMBOL(ath9k_hw_puttxbuf); void ath9k_hw_txstart(struct ath_hw *ah, u32 q) { - ath_dbg(ath9k_hw_common(ah), QUEUE, "Enable TXE on queue: %u\n", q); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_QUEUE, + "Enable TXE on queue: %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); } EXPORT_SYMBOL(ath9k_hw_txstart); @@ -185,6 +186,13 @@ bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q) } EXPORT_SYMBOL(ath9k_hw_stop_dma_queue); +void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) +{ + *txqs &= ah->intr_txqs; + ah->intr_txqs &= ~(*txqs); +} +EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs); + bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo) { @@ -194,12 +202,12 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, QUEUE, + ath_dbg(common, ATH_DBG_QUEUE, "Set TXQ properties, inactive queue: %u\n", q); return false; } - ath_dbg(common, QUEUE, "Set queue properties for: %u\n", q); + ath_dbg(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); qi->tqi_ver = qinfo->tqi_ver; qi->tqi_subtype = qinfo->tqi_subtype; @@ -258,7 +266,7 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, QUEUE, + ath_dbg(common, ATH_DBG_QUEUE, "Get TXQ properties, inactive queue: %u\n", q); return false; } @@ -303,21 +311,14 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, q = ATH9K_NUM_TX_QUEUES - 3; break; case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) - if (ah->txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == ATH9K_NUM_TX_QUEUES) { - ath_err(common, "No available TX queue\n"); - return -1; - } + q = qinfo->tqi_subtype; break; default: ath_err(common, "Invalid TX queue type: %u\n", type); return -1; } - ath_dbg(common, QUEUE, "Setup TX queue: %u\n", q); + ath_dbg(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); qi = &ah->txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { @@ -333,15 +334,6 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, } EXPORT_SYMBOL(ath9k_hw_setuptxqueue); -static void ath9k_hw_clear_queue_interrupts(struct ath_hw *ah, u32 q) -{ - ah->txok_interrupt_mask &= ~(1 << q); - ah->txerr_interrupt_mask &= ~(1 << q); - ah->txdesc_interrupt_mask &= ~(1 << q); - ah->txeol_interrupt_mask &= ~(1 << q); - ah->txurn_interrupt_mask &= ~(1 << q); -} - bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { struct ath_common *common = ath9k_hw_common(ah); @@ -349,14 +341,19 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, QUEUE, "Release TXQ, inactive queue: %u\n", q); + ath_dbg(common, ATH_DBG_QUEUE, + "Release TXQ, inactive queue: %u\n", q); return false; } - ath_dbg(common, QUEUE, "Release TX queue: %u\n", q); + ath_dbg(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ath9k_hw_clear_queue_interrupts(ah, q); + ah->txok_interrupt_mask &= ~(1 << q); + ah->txerr_interrupt_mask &= ~(1 << q); + ah->txdesc_interrupt_mask &= ~(1 << q); + ah->txeol_interrupt_mask &= ~(1 << q); + ah->txurn_interrupt_mask &= ~(1 << q); ath9k_hw_set_txq_interrupts(ah, qi); return true; @@ -372,11 +369,12 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - ath_dbg(common, QUEUE, "Reset TXQ, inactive queue: %u\n", q); + ath_dbg(common, ATH_DBG_QUEUE, + "Reset TXQ, inactive queue: %u\n", q); return true; } - ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q); + ath_dbg(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { if (chan && IS_CHAN_B(chan)) @@ -508,17 +506,26 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) if (AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN); - ath9k_hw_clear_queue_interrupts(ah, q); - if (qi->tqi_qflags & TXQ_FLAG_TXINT_ENABLE) { + if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) ah->txok_interrupt_mask |= 1 << q; + else + ah->txok_interrupt_mask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) ah->txerr_interrupt_mask |= 1 << q; - } + else + ah->txerr_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) ah->txdesc_interrupt_mask |= 1 << q; + else + ah->txdesc_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) ah->txeol_interrupt_mask |= 1 << q; + else + ah->txeol_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) ah->txurn_interrupt_mask |= 1 << q; + else + ah->txurn_interrupt_mask &= ~(1 << q); ath9k_hw_set_txq_interrupts(ah, qi); return true; @@ -607,11 +614,10 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; + if (ads.ds_rxstatus8 & AR_KeyMiss) + rs->rs_status |= ATH9K_RXERR_KEYMISS; } - if (ads.ds_rxstatus8 & AR_KeyMiss) - rs->rs_status |= ATH9K_RXERR_KEYMISS; - return 0; } EXPORT_SYMBOL(ath9k_hw_rxprocdesc); @@ -734,10 +740,7 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah) qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; - - if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) - qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE; - + /* NB: don't enable any interrupts */ return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } EXPORT_SYMBOL(ath9k_hw_beaconq_setup); @@ -750,10 +753,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) return true; host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); - - if (((host_isr & AR_INTR_MAC_IRQ) || - (host_isr & AR_INTR_ASYNC_MASK_MCI)) && - (host_isr != AR_INTR_SPURIOUS)) + if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS)) return true; host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); @@ -774,7 +774,7 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) else atomic_dec(&ah->intr_ref_cnt); - ath_dbg(common, INTERRUPT, "disable IER\n"); + ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { @@ -791,13 +791,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); u32 sync_default = AR_INTR_SYNC_DEFAULT; - u32 async_mask; if (!(ah->imask & ATH9K_INT_GLOBAL)) return; if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { - ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", + ath_dbg(common, ATH_DBG_INTERRUPT, + "Do not enable IER ref count %d\n", atomic_read(&ah->intr_ref_cnt)); return; } @@ -805,21 +805,18 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) if (AR_SREV_9340(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; - async_mask = AR_INTR_MAC_IRQ; - - if (ah->imask & ATH9K_INT_MCI) - async_mask |= AR_INTR_ASYNC_MASK_MCI; - - ath_dbg(common, INTERRUPT, "enable IER\n"); + ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask); - REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask); + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, + AR_INTR_MAC_IRQ); + REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); } - ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); } EXPORT_SYMBOL(ath9k_hw_enable_interrupts); @@ -834,7 +831,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) if (!(ints & ATH9K_INT_GLOBAL)) ath9k_hw_disable_interrupts(ah); - ath_dbg(common, INTERRUPT, "New interrupt mask 0x%x\n", ints); + ath_dbg(common, ATH_DBG_INTERRUPT, "New interrupt mask 0x%x\n", ints); mask = ints & ATH9K_INT_COMMON; mask2 = 0; @@ -897,7 +894,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) mask2 |= AR_IMR_S2_CST; } - ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask); + ath_dbg(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 21c95560..11dbd147 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -583,7 +583,8 @@ enum ath9k_tx_queue { #define ATH9K_WME_UPSD 4 enum ath9k_tx_queue_flags { - TXQ_FLAG_TXINT_ENABLE = 0x0001, + TXQ_FLAG_TXOKINT_ENABLE = 0x0001, + TXQ_FLAG_TXERRINT_ENABLE = 0x0001, TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, TXQ_FLAG_TXURNINT_ENABLE = 0x0008, @@ -713,6 +714,7 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q); void ath9k_hw_abort_tx_dma(struct ath_hw *ah); +void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo); bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c old mode 100644 new mode 100755 index 7e7bd157..608f8bf4 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -118,7 +118,7 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) + if (sc->ps_idle) mode = ATH9K_PM_FULL_SLEEP; else if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | @@ -289,7 +289,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath_start_ani(common); } - if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { + if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) { struct ath_hw_antcomb_conf div_ant_conf; u8 lna_conf; @@ -335,11 +335,17 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, hchan = ah->curchan; } + if (fastcc && !ath9k_hw_check_alive(ah)) + fastcc = false; + if (!ath_prepare_reset(sc, retry_tx, flush)) fastcc = false; - ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", - hchan->channel, IS_CHAN_HT40(hchan), fastcc); + ath_dbg(common, ATH_DBG_CONFIG, + "Reset to %u MHz, HT40: %d fastcc: %d\n", + hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS | + CHANNEL_HT40PLUS)), + fastcc); r = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (r) { @@ -370,8 +376,12 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (sc->sc_flags & SC_OP_INVALID) return -EIO; + ath9k_ps_wakeup(sc); + r = ath_reset_internal(sc, hchan, false); + ath9k_ps_restore(sc); + return r; } @@ -421,7 +431,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int txctl.paprd = BIT(chain); if (ath_tx_start(hw, skb, &txctl) != 0) { - ath_dbg(common, CALIBRATE, "PAPRD TX failed\n"); + ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD TX failed\n"); dev_kfree_skb_any(skb); return false; } @@ -430,7 +440,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); if (!time_left) - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Timeout waiting for paprd training on TX chain %d\n", chain); @@ -479,27 +489,27 @@ void ath_paprd_calibrate(struct work_struct *work) chain_ok = 0; - ath_dbg(common, CALIBRATE, - "Sending PAPRD frame for thermal measurement on chain %d\n", - chain); + ath_dbg(common, ATH_DBG_CALIBRATE, + "Sending PAPRD frame for thermal measurement " + "on chain %d\n", chain); if (!ath_paprd_send_frame(sc, skb, chain)) goto fail_paprd; ar9003_paprd_setup_gain_table(ah, chain); - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "Sending PAPRD training frame on chain %d\n", chain); if (!ath_paprd_send_frame(sc, skb, chain)) goto fail_paprd; if (!ar9003_paprd_is_done(ah)) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD not yet done on chain %d\n", chain); break; } if (ar9003_paprd_create_curve(ah, caldata, chain)) { - ath_dbg(common, CALIBRATE, + ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD create curve failed on chain %d\n", chain); break; @@ -554,6 +564,7 @@ void ath_ani_calibrate(unsigned long data) /* Long calibration runs independently of short calibration. */ if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) { longcal = true; + ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); common->ani.longcal_timer = timestamp; } @@ -561,6 +572,8 @@ void ath_ani_calibrate(unsigned long data) if (!common->ani.caldone) { if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; + ath_dbg(common, ATH_DBG_ANI, + "shortcal @%lu\n", jiffies); common->ani.shortcal_timer = timestamp; common->ani.resetcal_timer = timestamp; } @@ -574,9 +587,8 @@ void ath_ani_calibrate(unsigned long data) } /* Verify whether we must check ANI */ - if (sc->sc_ah->config.enable_ani - && (timestamp - common->ani.checkani_timer) >= - ah->config.ani_poll_interval) { + if ((timestamp - common->ani.checkani_timer) >= + ah->config.ani_poll_interval) { aniflag = true; common->ani.checkani_timer = timestamp; } @@ -596,12 +608,6 @@ void ath_ani_calibrate(unsigned long data) ah->rxchainmask, longcal); } - ath_dbg(common, ANI, - "Calibration @%lu finished: %s %s %s, caldone: %s\n", - jiffies, - longcal ? "long" : "", shortcal ? "short" : "", - aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); - ath9k_ps_restore(sc); set_timer: @@ -637,11 +643,10 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, spin_lock(&sc->nodes_lock); list_add(&an->list, &sc->nodes); spin_unlock(&sc->nodes_lock); -#endif an->sta = sta; an->vif = vif; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { +#endif + if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); @@ -660,7 +665,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) an->sta = NULL; #endif - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_node_cleanup(sc, an); } @@ -709,7 +714,8 @@ void ath9k_tasklet(unsigned long data) * TSF sync does not look correct; remain awake to sync with * the next Beacon. */ - ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n"); + ath_dbg(common, ATH_DBG_PS, + "TSFOOR - Sync with next Beacon\n"); sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; } @@ -735,7 +741,9 @@ void ath9k_tasklet(unsigned long data) ath_tx_tasklet(sc); } - ath9k_btcoex_handle_interrupt(sc, status); + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + if (status & ATH9K_INT_GENTIMER) + ath_gen_timer_isr(sc->sc_ah); out: /* re-enable hardware interrupt */ @@ -759,8 +767,7 @@ irqreturn_t ath_isr(int irq, void *dev) ATH9K_INT_BMISS | \ ATH9K_INT_CST | \ ATH9K_INT_TSFOOR | \ - ATH9K_INT_GENTIMER | \ - ATH9K_INT_MCI) + ATH9K_INT_GENTIMER) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; @@ -878,6 +885,82 @@ irqreturn_t ath_isr(int irq, void *dev) #undef SCHED_INTR } +static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_channel *channel = hw->conf.channel; + int r; + + ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_pcu_lock); + atomic_set(&ah->intr_ref_cnt, -1); + + ath9k_hw_configpcipowersave(ah, false); + + if (!ah->curchan) + ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); + + r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); + if (r) { + ath_err(common, + "Unable to reset channel (%u MHz), reset status %d\n", + channel->center_freq, r); + } + + ath_complete_reset(sc, true); + + /* Enable LED */ + ath9k_hw_cfg_output(ah, ah->led_pin, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, ah->led_pin, 0); + + spin_unlock_bh(&sc->sc_pcu_lock); + + ath9k_ps_restore(sc); +} + +void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) +{ + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_channel *channel = hw->conf.channel; + int r; + + ath9k_ps_wakeup(sc); + + ath_cancel_work(sc); + + spin_lock_bh(&sc->sc_pcu_lock); + + /* + * Keep the LED on when the radio is disabled + * during idle unassociated state. + */ + if (!sc->ps_idle) { + ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_cfg_gpio_input(ah, ah->led_pin); + } + + ath_prepare_reset(sc, false, true); + + if (!ah->curchan) + ah->curchan = ath9k_cmn_get_curchannel(hw, ah); + + r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); + if (r) { + ath_err(ath9k_hw_common(sc->sc_ah), + "Unable to reset channel (%u MHz), reset status %d\n", + channel->center_freq, r); + } + + ath9k_hw_phy_disable(ah); + + ath9k_hw_configpcipowersave(ah, true); + + spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); +} + static int ath_reset(struct ath_softc *sc, bool retry_tx) { int r; @@ -924,8 +1007,8 @@ void ath_hw_check(struct work_struct *work) busy = ath_update_survey_stats(sc); spin_unlock_irqrestore(&common->cc_lock, flags); - ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n", - busy, sc->hw_busy_count + 1); + ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " + "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); if (busy >= 99) { if (++sc->hw_busy_count >= 3) { RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); @@ -948,7 +1031,8 @@ static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) count++; if (count == 3) { /* Rx is hung for more than 500ms. Reset it */ - ath_dbg(common, RESET, "Possible RX hang, resetting\n"); + ath_dbg(common, ATH_DBG_RESET, + "Possible RX hang, resetting"); RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); count = 0; @@ -997,13 +1081,17 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath9k_channel *init_channel; int r; - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Starting driver with initial channel: %d MHz\n", curchan->center_freq); ath9k_ps_wakeup(sc); + mutex_lock(&sc->mutex); + /* setup initial channel */ + sc->chan_idx = curchan->hw_value; + init_channel = ath9k_cmn_get_curchannel(hw, ah); /* Reset SERDES registers */ @@ -1017,9 +1105,6 @@ static int ath9k_start(struct ieee80211_hw *hw) * and then setup of the interrupt mask. */ spin_lock_bh(&sc->sc_pcu_lock); - - atomic_set(&ah->intr_ref_cnt, -1); - r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (r) { ath_err(common, @@ -1046,33 +1131,30 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) ah->imask |= ATH9K_INT_CST; - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) - ah->imask |= ATH9K_INT_MCI; - sc->sc_flags &= ~SC_OP_INVALID; sc->sc_ah->is_monitoring = false; + /* Disable BMISS interrupt when we're not associated */ + ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + if (!ath_complete_reset(sc, false)) { r = -EIO; spin_unlock_bh(&sc->sc_pcu_lock); goto mutex_unlock; } - if (ah->led_pin >= 0) { - ath9k_hw_cfg_output(ah, ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ah->led_pin, 0); - } - - /* - * Reset key cache to sane defaults (all entries cleared) instead of - * semi-random values after suspend/resume. - */ - ath9k_cmn_init_crypto(sc->sc_ah); - spin_unlock_bh(&sc->sc_pcu_lock); - ath9k_start_btcoex(sc); + if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && + !ah->btcoex_hw.enabled) { + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + ath9k_hw_btcoex_enable(ah); + + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath9k_btcoex_timer_resume(sc); + } if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) common->bus_ops->extn_synch_en(common); @@ -1100,19 +1182,12 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (ieee80211_is_data(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control) && !ieee80211_has_pm(hdr->frame_control)) { - ath_dbg(common, PS, + ath_dbg(common, ATH_DBG_PS, "Add PM=1 for a TX frame while in PS mode\n"); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); } } - /* - * Cannot tx while the hardware is in full sleep, it first needs a full - * chip reset to recover from that - */ - if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) - goto exit; - if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { /* * We are using PS-Poll and mac80211 can request TX while in @@ -1123,11 +1198,12 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) ath9k_hw_setrxabort(sc->sc_ah, 0); if (ieee80211_is_pspoll(hdr->frame_control)) { - ath_dbg(common, PS, + ath_dbg(common, ATH_DBG_PS, "Sending PS-Poll to pick a buffered frame\n"); sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA; } else { - ath_dbg(common, PS, "Wake up to complete TX\n"); + ath_dbg(common, ATH_DBG_PS, + "Wake up to complete TX\n"); sc->ps_flags |= PS_WAIT_FOR_TX_ACK; } /* @@ -1141,10 +1217,10 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) memset(&txctl, 0, sizeof(struct ath_tx_control)); txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; - ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb); + ath_dbg(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); if (ath_tx_start(hw, skb, &txctl) != 0) { - ath_dbg(common, XMIT, "TX failed\n"); + ath_dbg(common, ATH_DBG_XMIT, "TX failed\n"); goto exit; } @@ -1158,14 +1234,13 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - bool prev_idle; mutex_lock(&sc->mutex); ath_cancel_work(sc); if (sc->sc_flags & SC_OP_INVALID) { - ath_dbg(common, ANY, "Device not present\n"); + ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; } @@ -1173,7 +1248,12 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* Ensure HW is awake when we try to shut it down. */ ath9k_ps_wakeup(sc); - ath9k_stop_btcoex(sc); + if (ah->btcoex_hw.enabled) { + ath9k_hw_btcoex_disable(ah); + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath9k_btcoex_timer_pause(sc); + ath_mci_flush_profile(&sc->btcoex.mci); + } spin_lock_bh(&sc->sc_pcu_lock); @@ -1184,49 +1264,39 @@ static void ath9k_stop(struct ieee80211_hw *hw) * before setting the invalid flag. */ ath9k_hw_disable_interrupts(ah); - spin_unlock_bh(&sc->sc_pcu_lock); - - /* we can now sync irq and kill any running tasklets, since we already - * disabled interrupts and not holding a spin lock */ - synchronize_irq(sc->irq); - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - - prev_idle = sc->ps_idle; - sc->ps_idle = true; - - spin_lock_bh(&sc->sc_pcu_lock); - - if (ah->led_pin >= 0) { - ath9k_hw_set_gpio(ah, ah->led_pin, 1); - ath9k_hw_cfg_gpio_input(ah, ah->led_pin); - } - - ath_prepare_reset(sc, false, true); + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_drain_all_txq(sc, false); + ath_stoprecv(sc); + ath9k_hw_phy_disable(ah); + } else + sc->rx.rxlink = NULL; if (sc->rx.frag) { dev_kfree_skb_any(sc->rx.frag); sc->rx.frag = NULL; } - if (!ah->curchan) - ah->curchan = ath9k_cmn_get_curchannel(hw, ah); - - ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); - ath9k_hw_phy_disable(ah); - - ath9k_hw_configpcipowersave(ah, true); + /* disable HAL and put h/w to sleep */ + ath9k_hw_disable(ah); spin_unlock_bh(&sc->sc_pcu_lock); + /* we can now sync irq and kill any running tasklets, since we already + * disabled interrupts and not holding a spin lock */ + synchronize_irq(sc->irq); + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); + ath9k_ps_restore(sc); + sc->ps_idle = true; + ath_radio_disable(sc, hw); + sc->sc_flags |= SC_OP_INVALID; - sc->ps_idle = prev_idle; mutex_unlock(&sc->mutex); - ath_dbg(common, CONFIG, "Driver halt\n"); + ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n"); } bool ath9k_uses_beacons(int type) @@ -1279,6 +1349,7 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) iter_data->nwds++; break; default: + iter_data->nothers++; break; } } @@ -1432,7 +1503,17 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } } - ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); + if ((ah->opmode == NL80211_IFTYPE_ADHOC) || + ((vif->type == NL80211_IFTYPE_ADHOC) && + sc->nvifs > 0)) { + ath_err(common, "Cannot create ADHOC interface when other" + " interfaces already exist.\n"); + ret = -EINVAL; + goto out; + } + + ath_dbg(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d\n", vif->type); sc->nvifs++; @@ -1452,7 +1533,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, struct ath_common *common = ath9k_hw_common(sc->sc_ah); int ret = 0; - ath_dbg(common, CONFIG, "Change Interface\n"); + ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); @@ -1495,7 +1576,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - ath_dbg(common, CONFIG, "Detach Interface\n"); + ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); @@ -1552,21 +1633,25 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; - bool reset_channel = false; + bool disable_radio = false; - ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); + /* + * Leave this as the first check because we need to turn on the + * radio if it was disabled before prior to processing the rest + * of the changes. Likewise we must only disable the radio towards + * the end. + */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); - if (sc->ps_idle) - ath_cancel_work(sc); - else - /* - * The chip needs a reset to properly wake up from - * full sleep - */ - reset_channel = ah->chip_fullsleep; + if (!sc->ps_idle) { + ath_radio_enable(sc, hw); + ath_dbg(common, ATH_DBG_CONFIG, + "not-idle: enabling radio\n"); + } else { + disable_radio = true; + } } /* @@ -1587,16 +1672,19 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (conf->flags & IEEE80211_CONF_MONITOR) { - ath_dbg(common, CONFIG, "Monitor mode is enabled\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "Monitor mode is enabled\n"); sc->sc_ah->is_monitoring = true; } else { - ath_dbg(common, CONFIG, "Monitor mode is disabled\n"); + ath_dbg(common, ATH_DBG_CONFIG, + "Monitor mode is disabled\n"); sc->sc_ah->is_monitoring = false; } } - if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; + struct ath9k_channel old_chan; int pos = curchan->hw_value; int old_pos = -1; unsigned long flags; @@ -1609,7 +1697,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) else sc->sc_flags &= ~SC_OP_OFFCHANNEL; - ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n", + ath_dbg(common, ATH_DBG_CONFIG, + "Set channel: %d MHz type: %d\n", curchan->center_freq, conf->channel_type); /* update survey stats for the old channel before switching */ @@ -1617,6 +1706,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_update_survey_stats(sc); spin_unlock_irqrestore(&common->cc_lock, flags); + /* + * Preserve the current channel values, before updating + * the same channel + */ + if (old_pos == pos) { + memcpy(&old_chan, &sc->sc_ah->channels[pos], + sizeof(struct ath9k_channel)); + ah->curchan = &old_chan; + } + ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], curchan, conf->channel_type); @@ -1656,14 +1755,21 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_POWER) { - ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); + ath_dbg(common, ATH_DBG_CONFIG, + "Set power: %d\n", conf->power_level); sc->config.txpowlimit = 2 * conf->power_level; + ath9k_ps_wakeup(sc); ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); + ath9k_ps_restore(sc); + } + + if (disable_radio) { + ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); + ath_radio_disable(sc, hw); } mutex_unlock(&sc->mutex); - ath9k_ps_restore(sc); return 0; } @@ -1696,8 +1802,8 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_setrxfilter(sc->sc_ah, rfilt); ath9k_ps_restore(sc); - ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, "Set HW RX filter: 0x%x\n", - rfilt); + ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, + "Set HW RX filter: 0x%x\n", rfilt); } static int ath9k_sta_add(struct ieee80211_hw *hw, @@ -1758,9 +1864,6 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an = (struct ath_node *) sta->drv_priv; - if (!sta->ht_cap.ht_supported) - return; - switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; @@ -1798,7 +1901,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, qi.tqi_cwmax = params->cw_max; qi.tqi_burstTime = params->txop; - ath_dbg(common, CONFIG, + ath_dbg(common, ATH_DBG_CONFIG, "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", queue, txq->axq_qnum, params->aifs, params->cw_min, params->cw_max, params->txop); @@ -1830,8 +1933,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, if (ath9k_modparam_nohwcrypt) return -ENOSPC; - if ((vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT) && + if (vif->type == NL80211_IFTYPE_ADHOC && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { @@ -1847,7 +1949,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ath_dbg(common, CONFIG, "Set HW Key\n"); + ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); switch (cmd) { case SET_KEY: @@ -1899,8 +2001,9 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); - ath_dbg(common, CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, common->curbssid); ath_beacon_config(sc, vif); /* * Request a re-configuration of Beacon related timers @@ -1931,7 +2034,8 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) /* Reconfigure bss info */ if (avp->primary_sta_vif && !bss_conf->assoc) { - ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n", + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info DISASSOC %d, bssid %pM\n", common->curaid, common->curbssid); sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); avp->primary_sta_vif = false; @@ -1970,10 +2074,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - if (changed & BSS_CHANGED_ASSOC) { + if (changed & BSS_CHANGED_BSSID) { ath9k_config_bss(sc, vif); - ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n", + ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", common->curbssid, common->curaid); } @@ -2050,6 +2154,25 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_beacon_config(sc, vif); } + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + sc->sc_flags |= SC_OP_PREAMBLE_SHORT; + else + sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", + bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && + hw->conf.channel->band != IEEE80211_BAND_5GHZ) + sc->sc_flags |= SC_OP_PROTECT_ENABLE; + else + sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; + } + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); } @@ -2107,10 +2230,15 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: + if (!(sc->sc_flags & SC_OP_RXAGGR)) + ret = -ENOTSUPP; break; case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: + if (!(sc->sc_flags & SC_OP_TXAGGR)) + return -EOPNOTSUPP; + ath9k_ps_wakeup(sc); ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (!ret) @@ -2202,17 +2330,20 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) cancel_delayed_work_sync(&sc->tx_complete_work); if (ah->ah_flags & AH_UNPLUGGED) { - ath_dbg(common, ANY, "Device has been unplugged!\n"); + ath_dbg(common, ATH_DBG_ANY, "Device has been unplugged!\n"); mutex_unlock(&sc->mutex); return; } if (sc->sc_flags & SC_OP_INVALID) { - ath_dbg(common, ANY, "Device not present\n"); + ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; } + if (drop) + timeout = 1; + for (j = 0; j < timeout; j++) { bool npend = false; @@ -2230,22 +2361,21 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) } if (!npend) - break; + goto out; } - if (drop) { - ath9k_ps_wakeup(sc); - spin_lock_bh(&sc->sc_pcu_lock); - drain_txq = ath_drain_all_txq(sc, false); - spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_pcu_lock); + drain_txq = ath_drain_all_txq(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); - if (!drain_txq) - ath_reset(sc, false); + if (!drain_txq) + ath_reset(sc, false); - ath9k_ps_restore(sc); - ieee80211_wake_queues(hw); - } + ath9k_ps_restore(sc); + ieee80211_wake_queues(hw); +out: ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); mutex_unlock(&sc->mutex); } @@ -2273,7 +2403,6 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) struct ath_vif *avp; struct ath_buf *bf; struct ath_tx_status ts; - bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int status; vif = sc->beacon.bslot[0]; @@ -2284,7 +2413,7 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) if (!avp->is_bslot_active) return 0; - if (!sc->beacon.tx_processed && !edma) { + if (!sc->beacon.tx_processed) { tasklet_disable(&sc->bcon_tasklet); bf = avp->av_bcbuf; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 29fe52d6..0fbb141b 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -14,13 +14,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include - #include "ath9k.h" #include "mci.h" -static const u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 }; +u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 }; static struct ath_mci_profile_info* ath_mci_find_profile(struct ath_mci_profile *mci, @@ -42,18 +39,24 @@ static bool ath_mci_add_profile(struct ath_common *common, struct ath_mci_profile_info *entry; if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) && - (info->type == MCI_GPM_COEX_PROFILE_VOICE)) + (info->type == MCI_GPM_COEX_PROFILE_VOICE)) { + ath_dbg(common, ATH_DBG_MCI, + "Too many SCO profile, failed to add new profile\n"); return false; + } if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) && - (info->type != MCI_GPM_COEX_PROFILE_VOICE)) + (info->type != MCI_GPM_COEX_PROFILE_VOICE)) { + ath_dbg(common, ATH_DBG_MCI, + "Too many ACL profile, failed to add new profile\n"); return false; + } entry = ath_mci_find_profile(mci, info); - if (entry) { + if (entry) memcpy(entry, info, 10); - } else { + else { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return false; @@ -62,7 +65,6 @@ static bool ath_mci_add_profile(struct ath_common *common, INC_PROF(mci, info); list_add_tail(&info->list, &mci->info); } - return true; } @@ -74,9 +76,11 @@ static void ath_mci_del_profile(struct ath_common *common, entry = ath_mci_find_profile(mci, info); - if (!entry) + if (!entry) { + ath_dbg(common, ATH_DBG_MCI, + "Profile to be deleted not found\n"); return; - + } DEC_PROF(mci, entry); list_del(&entry->list); kfree(entry); @@ -125,30 +129,30 @@ static void ath_mci_update_scheme(struct ath_softc *sc) list); if (mci->num_sco && info->T == 12) { mci->aggr_limit = 8; - ath_dbg(common, MCI, + ath_dbg(common, ATH_DBG_MCI, "Single SCO, aggregation limit 2 ms\n"); } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) && !info->master) { btcoex->btcoex_period = 60; - ath_dbg(common, MCI, + ath_dbg(common, ATH_DBG_MCI, "Single slave PAN/FTP, bt period 60 ms\n"); } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) && (info->T > 0 && info->T < 50) && (info->A > 1 || info->W > 1)) { btcoex->duty_cycle = 30; mci->aggr_limit = 8; - ath_dbg(common, MCI, + ath_dbg(common, ATH_DBG_MCI, "Multiple attempt/timeout single HID " "aggregation limit 2 ms dutycycle 30%%\n"); } } else if ((num_profile == 2) && (mci->num_hid == 2)) { btcoex->duty_cycle = 30; mci->aggr_limit = 8; - ath_dbg(common, MCI, + ath_dbg(common, ATH_DBG_MCI, "Two HIDs aggregation limit 2 ms dutycycle 30%%\n"); } else if (num_profile > 3) { mci->aggr_limit = 6; - ath_dbg(common, MCI, + ath_dbg(common, ATH_DBG_MCI, "Three or more profiles aggregation limit 1.5 ms\n"); } @@ -171,44 +175,14 @@ static void ath_mci_update_scheme(struct ath_softc *sc) btcoex->btcoex_period *= 1000; btcoex->btcoex_no_stomp = btcoex->btcoex_period * - (100 - btcoex->duty_cycle) / 100; + (100 - btcoex->duty_cycle) / 100; ath9k_hw_btcoex_enable(sc->sc_ah); ath9k_btcoex_timer_resume(sc); } -static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 payload[4] = {0, 0, 0, 0}; - - switch (opcode) { - case MCI_GPM_BT_CAL_REQ: - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { - ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); - } else { - ath_dbg(common, MCI, "MCI State mismatch: %d\n", - ar9003_mci_state(ah, MCI_STATE_BT, NULL)); - } - break; - case MCI_GPM_BT_CAL_DONE: - ar9003_mci_state(ah, MCI_STATE_BT, NULL); - break; - case MCI_GPM_BT_CAL_GRANT: - MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); - ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload, - 16, false, true); - break; - default: - ath_dbg(common, MCI, "Unknown GPM CAL message\n"); - break; - } -} - -static void ath_mci_process_profile(struct ath_softc *sc, - struct ath_mci_profile_info *info) +void ath_mci_process_profile(struct ath_softc *sc, + struct ath_mci_profile_info *info) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; @@ -222,7 +196,6 @@ static void ath_mci_process_profile(struct ath_softc *sc, btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; mci->aggr_limit = mci->num_sco ? 6 : 0; - if (NUM_PROF(mci)) { btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)]; @@ -235,27 +208,36 @@ static void ath_mci_process_profile(struct ath_softc *sc, ath_mci_update_scheme(sc); } -static void ath_mci_process_status(struct ath_softc *sc, - struct ath_mci_profile_status *status) +void ath_mci_process_status(struct ath_softc *sc, + struct ath_mci_profile_status *status) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; struct ath_mci_profile_info info; int i = 0, old_num_mgmt = mci->num_mgmt; /* Link status type are not handled */ - if (status->is_link) + if (status->is_link) { + ath_dbg(common, ATH_DBG_MCI, + "Skip link type status update\n"); return; + } memset(&info, 0, sizeof(struct ath_mci_profile_info)); info.conn_handle = status->conn_handle; - if (ath_mci_find_profile(mci, &info)) + if (ath_mci_find_profile(mci, &info)) { + ath_dbg(common, ATH_DBG_MCI, + "Skip non link state update for existing profile %d\n", + status->conn_handle); return; - - if (status->conn_handle >= ATH_MCI_MAX_PROFILE) + } + if (status->conn_handle >= ATH_MCI_MAX_PROFILE) { + ath_dbg(common, ATH_DBG_MCI, + "Ignore too many non-link update\n"); return; - + } if (status->is_critical) __set_bit(status->conn_handle, mci->status); else @@ -270,271 +252,3 @@ static void ath_mci_process_status(struct ath_softc *sc, if (old_num_mgmt != mci->num_mgmt) ath_mci_update_scheme(sc); } - -static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_mci_profile_info profile_info; - struct ath_mci_profile_status profile_status; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u32 version; - u8 major; - u8 minor; - u32 seq_num; - - switch (opcode) { - case MCI_GPM_COEX_VERSION_QUERY: - version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION, - NULL); - break; - case MCI_GPM_COEX_VERSION_RESPONSE: - major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION); - minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION); - version = (major << 8) + minor; - version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION, - &version); - break; - case MCI_GPM_COEX_STATUS_QUERY: - ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL); - break; - case MCI_GPM_COEX_BT_PROFILE_INFO: - memcpy(&profile_info, - (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10); - - if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) || - (profile_info.type >= MCI_GPM_COEX_PROFILE_MAX)) { - ath_dbg(common, MCI, - "Illegal profile type = %d, state = %d\n", - profile_info.type, - profile_info.start); - break; - } - - ath_mci_process_profile(sc, &profile_info); - break; - case MCI_GPM_COEX_BT_STATUS_UPDATE: - profile_status.is_link = *(rx_payload + - MCI_GPM_COEX_B_STATUS_TYPE); - profile_status.conn_handle = *(rx_payload + - MCI_GPM_COEX_B_STATUS_LINKID); - profile_status.is_critical = *(rx_payload + - MCI_GPM_COEX_B_STATUS_STATE); - - seq_num = *((u32 *)(rx_payload + 12)); - ath_dbg(common, MCI, - "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n", - profile_status.is_link, profile_status.conn_handle, - profile_status.is_critical, seq_num); - - ath_mci_process_status(sc, &profile_status); - break; - default: - ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode); - break; - } -} - -int ath_mci_setup(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_mci_coex *mci = &sc->mci_coex; - struct ath_mci_buf *buf = &mci->sched_buf; - - buf->bf_addr = dma_alloc_coherent(sc->dev, - ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, - &buf->bf_paddr, GFP_KERNEL); - - if (buf->bf_addr == NULL) { - ath_dbg(common, FATAL, "MCI buffer alloc failed\n"); - return -ENOMEM; - } - - memset(buf->bf_addr, MCI_GPM_RSVD_PATTERN, - ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE); - - mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE; - - mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE; - mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + mci->sched_buf.bf_len; - mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len; - - ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr, - mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4), - mci->sched_buf.bf_paddr); - - ath_dbg(common, MCI, "MCI Initialized\n"); - - return 0; -} - -void ath_mci_cleanup(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_hw *ah = sc->sc_ah; - struct ath_mci_coex *mci = &sc->mci_coex; - struct ath_mci_buf *buf = &mci->sched_buf; - - if (buf->bf_addr) - dma_free_coherent(sc->dev, - ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, - buf->bf_addr, buf->bf_paddr); - - ar9003_mci_cleanup(ah); - - ath_dbg(common, MCI, "MCI De-Initialized\n"); -} - -void ath_mci_intr(struct ath_softc *sc) -{ - struct ath_mci_coex *mci = &sc->mci_coex; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 mci_int, mci_int_rxmsg; - u32 offset, subtype, opcode; - u32 *pgpm; - u32 more_data = MCI_GPM_MORE; - bool skip_gpm = false; - - ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg); - - if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) { - ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL); - return; - } - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) { - u32 payload[4] = { 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffff00}; - - /* - * The following REMOTE_RESET and SYS_WAKING used to sent - * only when BT wake up. Now they are always sent, as a - * recovery method to reset BT MCI's RX alignment. - */ - ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, - payload, 16, true, false); - ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0, - NULL, 0, true, false); - - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE; - ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL); - - /* - * always do this for recovery and 2G/5G toggling and LNA_TRANS - */ - ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL); - } - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) { - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING; - - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) { - if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) != - MCI_BT_SLEEP) - ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, - NULL); - } - } - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) { - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING; - - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { - if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) != - MCI_BT_AWAKE) - ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP, - NULL); - } - } - - if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || - (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) { - ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL); - skip_gpm = true; - } - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; - offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET, - NULL); - } - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; - - while (more_data == MCI_GPM_MORE) { - - pgpm = mci->gpm_buf.bf_addr; - offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, - &more_data); - - if (offset == MCI_GPM_INVALID) - break; - - pgpm += (offset >> 2); - - /* - * The first dword is timer. - * The real data starts from 2nd dword. - */ - subtype = MCI_GPM_TYPE(pgpm); - opcode = MCI_GPM_OPCODE(pgpm); - - if (skip_gpm) - goto recycle; - - if (MCI_GPM_IS_CAL_TYPE(subtype)) { - ath_mci_cal_msg(sc, subtype, (u8 *)pgpm); - } else { - switch (subtype) { - case MCI_GPM_COEX_AGENT: - ath_mci_msg(sc, opcode, (u8 *)pgpm); - break; - default: - break; - } - } - recycle: - MCI_GPM_RECYCLE(pgpm); - } - } - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) { - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL) - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL; - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO; - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) { - int value_dbm = ar9003_mci_state(ah, - MCI_STATE_CONT_RSSI_POWER, NULL); - - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO; - - if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL)) - ath_dbg(common, MCI, - "MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n", - ar9003_mci_state(ah, - MCI_STATE_CONT_PRIORITY, NULL), - value_dbm); - else - ath_dbg(common, MCI, - "MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n", - ar9003_mci_state(ah, - MCI_STATE_CONT_PRIORITY, NULL), - value_dbm); - } - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK; - - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST; - } - - if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || - (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) - mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | - AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); -} diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index c841444f..9590c618 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -17,11 +17,6 @@ #ifndef MCI_H #define MCI_H -#include "ar9003_mci.h" - -#define ATH_MCI_SCHED_BUF_SIZE (16 * 16) /* 16 entries, 4 dword each */ -#define ATH_MCI_GPM_MAX_ENTRY 16 -#define ATH_MCI_GPM_BUF_SIZE (ATH_MCI_GPM_MAX_ENTRY * 16) #define ATH_MCI_DEF_BT_PERIOD 40 #define ATH_MCI_BDR_DUTY_CYCLE 20 #define ATH_MCI_MAX_DUTY_CYCLE 90 @@ -115,19 +110,9 @@ struct ath_mci_profile { u8 num_bdr; }; -struct ath_mci_buf { - void *bf_addr; /* virtual addr of desc */ - dma_addr_t bf_paddr; /* physical addr of buffer */ - u32 bf_len; /* len of data */ -}; - -struct ath_mci_coex { - struct ath_mci_buf sched_buf; - struct ath_mci_buf gpm_buf; -}; - void ath_mci_flush_profile(struct ath_mci_profile *mci); -int ath_mci_setup(struct ath_softc *sc); -void ath_mci_cleanup(struct ath_softc *sc); -void ath_mci_intr(struct ath_softc *sc); +void ath_mci_process_profile(struct ath_softc *sc, + struct ath_mci_profile_info *info); +void ath_mci_process_status(struct ath_softc *sc, + struct ath_mci_profile_status *status); #endif diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c old mode 100644 new mode 100755 index e8a13b8a..3374d09c --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -122,9 +122,8 @@ static void ath_pci_aspm_init(struct ath_common *common) if (!parent) return; - if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && - (AR_SREV_9285(ah))) { - /* Bluetooth coexistance requires disabling ASPM for AR9285. */ + if (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) { + /* Bluetooth coexistance requires disabling ASPM. */ pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm); aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm); @@ -150,31 +149,6 @@ static void ath_pci_aspm_init(struct ath_common *common) } } -static void ath_pci_aspm_init(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct ath_hw *ah = sc->sc_ah; - struct pci_dev *pdev = to_pci_dev(sc->dev); - struct pci_dev *parent; - int pos; - u8 aspm; - - if (!pci_is_pcie(pdev)) - return; - - parent = pdev->bus->self; - if (WARN_ON(!parent)) - return; - - pos = pci_pcie_cap(parent); - pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm); - if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { - ah->aspm_enabled = true; - /* Initialize PCIe PM and SERDES registers. */ - ath9k_hw_configpcipowersave(ah, 0, 0); - } -} - static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, @@ -334,11 +308,12 @@ static int ath_pci_suspend(struct device *device) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + /* The device has to be moved to FULLSLEEP forcibly. * Otherwise the chip never moved to full sleep, * when no interface is up. */ - ath9k_hw_disable(sc->sc_ah); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); return 0; @@ -347,6 +322,8 @@ static int ath_pci_suspend(struct device *device) static int ath_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; u32 val; /* @@ -358,17 +335,29 @@ static int ath_pci_resume(struct device *device) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + ath9k_ps_wakeup(sc); + /* Enable LED */ + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); + + /* + * Reset key cache to sane defaults (all entries cleared) instead of + * semi-random values after suspend/resume. + */ + ath9k_cmn_init_crypto(sc->sc_ah); + ath9k_ps_restore(sc); + + sc->ps_idle = true; + ath_radio_disable(sc, hw); + return 0; } -static const struct dev_pm_ops ath9k_pm_ops = { - .suspend = ath_pci_suspend, - .resume = ath_pci_resume, - .freeze = ath_pci_suspend, - .thaw = ath_pci_resume, - .poweroff = ath_pci_suspend, - .restore = ath_pci_resume, -}; +compat_pci_suspend(ath_pci_suspend) +compat_pci_resume(ath_pci_resume) + +static SIMPLE_DEV_PM_OPS(ath9k_pm_ops, ath_pci_suspend, ath_pci_resume); #define ATH9K_PM_OPS (&ath9k_pm_ops) @@ -386,7 +375,12 @@ static struct pci_driver ath_pci_driver = { .id_table = ath_pci_id_table, .probe = ath_pci_probe, .remove = ath_pci_remove, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) .driver.pm = ATH9K_PM_OPS, +#elif defined(CONFIG_PM) + .suspend = ath_pci_suspend_compat, + .resume = ath_pci_resume_compat, +#endif }; int ath_pci_init(void) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 08bb4553..888abc2b 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -567,8 +567,10 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, - struct ath_rateset *rateset, u32 capflag) + u8 *mcs_set, u32 capflag) { + struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; + u8 i, j, hi = 0; /* Use intersection of working rates and valid rates */ @@ -692,7 +694,7 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, return rate; /* This should not happen */ - WARN_ON_ONCE(1); + WARN_ON(1); rate = ath_rc_priv->valid_rate_index[0]; @@ -748,8 +750,7 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, * If 802.11g protection is enabled, determine whether to use RTS/CTS or * just CTS. Note that this is only done for OFDM/HT unicast frames. */ - if ((tx_info->control.vif && - tx_info->control.vif->bss_conf.use_cts_prot) && + if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) && (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM || WLAN_RC_PHY_HT(rate_table->info[rix].phy))) { rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; @@ -1198,7 +1199,7 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, return &ar5416_11na_ratetable; return &ar5416_11a_ratetable; default: - ath_dbg(common, CONFIG, "Invalid band\n"); + ath_dbg(common, ATH_DBG_CONFIG, "Invalid band\n"); return NULL; } } @@ -1211,7 +1212,7 @@ static void ath_rc_init(struct ath_softc *sc, { struct ath_rateset *rateset = &ath_rc_priv->neg_rates; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_rateset *ht_mcs = &ath_rc_priv->neg_ht_rates; + u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; /* Initial rate table size. Will change depending @@ -1227,7 +1228,7 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_init_valid_rate_idx(ath_rc_priv); for (i = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < RATE_TABLE_SIZE; j++) + for (j = 0; j < MAX_TX_RATE_PHY; j++) ath_rc_priv->valid_phy_rateidx[i][j] = 0; ath_rc_priv->valid_phy_ratecnt[i] = 0; } @@ -1270,12 +1271,11 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); - ath_rc_priv->rate_max_phy = (k > 4) ? - ath_rc_priv->valid_rate_index[k-4] : - ath_rc_priv->valid_rate_index[k-1]; + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; ath_rc_priv->rate_table = rate_table; - ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n", + ath_dbg(common, ATH_DBG_CONFIG, + "RC Initialized with capabilities: 0x%x\n", ath_rc_priv->ht_cap); } @@ -1299,13 +1299,12 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, return caps; } -static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta, +static bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) { - struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid; - if (!sta->ht_cap.ht_supported) + if (!(sc->sc_flags & SC_OP_TXAGGR)) return false; txtid = ATH_AN_2_TID(an, tidno); @@ -1346,7 +1345,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, fc = hdr->frame_control; for (i = 0; i < sc->hw->max_rates; i++) { struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; - if (rate->idx < 0 || !rate->count) + if (!rate->count) break; final_ts_idx = i; @@ -1376,11 +1375,13 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, if (ieee80211_is_data_qos(fc) && skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { u8 *qc, tid; + struct ath_node *an; qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; + an = (struct ath_node *)sta->drv_priv; - if(ath_tx_aggr_check(sc, sta, tid)) + if(ath_tx_aggr_check(sc, an, tid)) ieee80211_start_tx_ba_session(sta, tid, 0); } } @@ -1471,7 +1472,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, oper_cw40, oper_sgi); ath_rc_init(sc, priv_sta, sband, sta, rate_table); - ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, + ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, "Operating HT Bandwidth changed to: %d\n", sc->hw->conf.channel_type); } @@ -1480,6 +1481,12 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, #ifdef CONFIG_ATH9K_DEBUGFS +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1547,7 +1554,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, static const struct file_operations fops_rcstat = { .read = read_file_rcstat, - .open = simple_open, + .open = ath9k_debugfs_open, .owner = THIS_MODULE }; diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h old mode 100644 new mode 100755 index 12cf1225..e8e1901b --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -25,6 +25,8 @@ struct ath_softc; #define ATH_RATE_MAX 30 #define RATE_TABLE_SIZE 72 +#define MAX_TX_RATE_PHY 48 + #define RC_INVALID 0x0000 #define RC_LEGACY 0x0001 diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c old mode 100644 new mode 100755 index 2e6583d3..64546771 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -174,17 +174,22 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc, enum ath9k_rx_qtype qtype, int size) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_buf *bf, *tbf; + u32 nbuf = 0; if (list_empty(&sc->rx.rxbuf)) { - ath_dbg(common, QUEUE, "No free rx buf available\n"); + ath_dbg(common, ATH_DBG_QUEUE, "No free rx buf available\n"); return; } - list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) + while (!list_empty(&sc->rx.rxbuf)) { + nbuf++; + if (!ath_rx_edma_buf_link(sc, qtype)) break; + if (nbuf >= size) + break; + } } static void ath_rx_remove_buffer(struct ath_softc *sc, @@ -232,6 +237,7 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc) static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) { skb_queue_head_init(&rx_edma->rx_fifo); + skb_queue_head_init(&rx_edma->rx_buffers); rx_edma->rx_fifo_hwsize = size; } @@ -336,7 +342,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { return ath_rx_edma_init(sc, nbufs); } else { - ath_dbg(common, CONFIG, "cachelsz %u rxbufsize %u\n", + ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", common->cachelsz, common->rx_bufsize); /* Initialize rx descriptors */ @@ -474,6 +480,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) return rfilt; +#undef RX_FILTER_PRESERVE } int ath_startrecv(struct ath_softc *sc) @@ -591,7 +598,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (sc->ps_flags & PS_BEACON_SYNC) { sc->ps_flags &= ~PS_BEACON_SYNC; - ath_dbg(common, PS, + ath_dbg(common, ATH_DBG_PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); ath_set_beacon(sc); } @@ -604,7 +611,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * a backup trigger for returning into NETWORK SLEEP state, * so we are waiting for it as well. */ - ath_dbg(common, PS, + ath_dbg(common, ATH_DBG_PS, "Received DTIM beacon indicating buffered broadcast/multicast frame(s)\n"); sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON; return; @@ -617,7 +624,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * been delivered. */ sc->ps_flags &= ~PS_WAIT_FOR_CAB; - ath_dbg(common, PS, "PS wait for CAB frames timed out\n"); + ath_dbg(common, ATH_DBG_PS, + "PS wait for CAB frames timed out\n"); } } @@ -642,13 +650,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) * point. */ sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON); - ath_dbg(common, PS, + ath_dbg(common, ATH_DBG_PS, "All PS CAB frames received, back to sleep\n"); } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA; - ath_dbg(common, PS, + ath_dbg(common, ATH_DBG_PS, "Going back to sleep after having received PS-Poll data (0x%lx)\n", sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | @@ -658,9 +666,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) } static bool ath_edma_get_buffers(struct ath_softc *sc, - enum ath9k_rx_qtype qtype, - struct ath_rx_status *rs, - struct ath_buf **dest) + enum ath9k_rx_qtype qtype) { struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; struct ath_hw *ah = sc->sc_ah; @@ -679,7 +685,7 @@ static bool ath_edma_get_buffers(struct ath_softc *sc, dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, common->rx_bufsize, DMA_FROM_DEVICE); - ret = ath9k_hw_process_rxdesc_edma(ah, rs, skb->data); + ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data); if (ret == -EINPROGRESS) { /*let device gain the buffer again*/ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, @@ -692,21 +698,20 @@ static bool ath_edma_get_buffers(struct ath_softc *sc, /* corrupt descriptor, skip this one and the following one */ list_add_tail(&bf->list, &sc->rx.rxbuf); ath_rx_edma_buf_link(sc, qtype); - skb = skb_peek(&rx_edma->rx_fifo); - if (skb) { - bf = SKB_CB_ATHBUF(skb); - BUG_ON(!bf); + if (!skb) + return true; - __skb_unlink(skb, &rx_edma->rx_fifo); - list_add_tail(&bf->list, &sc->rx.rxbuf); - ath_rx_edma_buf_link(sc, qtype); - } + bf = SKB_CB_ATHBUF(skb); + BUG_ON(!bf); - bf = NULL; + __skb_unlink(skb, &rx_edma->rx_fifo); + list_add_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_edma_buf_link(sc, qtype); + return true; } + skb_queue_tail(&rx_edma->rx_buffers, skb); - *dest = bf; return true; } @@ -714,15 +719,18 @@ static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc, struct ath_rx_status *rs, enum ath9k_rx_qtype qtype) { - struct ath_buf *bf = NULL; + struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; + struct sk_buff *skb; + struct ath_buf *bf; - while (ath_edma_get_buffers(sc, qtype, rs, &bf)) { - if (!bf) - continue; + while (ath_edma_get_buffers(sc, qtype)); + skb = __skb_dequeue(&rx_edma->rx_buffers); + if (!skb) + return NULL; - return bf; - } - return NULL; + bf = SKB_CB_ATHBUF(skb); + ath9k_hw_process_rxdesc_edma(sc->sc_ah, rs, skb->data); + return bf; } static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, @@ -826,15 +834,6 @@ static bool ath9k_rx_accept(struct ath_common *common, (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | ATH9K_RXERR_KEYMISS)); - /* - * Key miss events are only relevant for pairwise keys where the - * descriptor does contain a valid key index. This has been observed - * mostly with CCMP encryption. - */ - if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || - !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) - rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; - if (!rx_stats->rs_datalen) return false; /* @@ -944,7 +943,7 @@ static int ath9k_process_rate(struct ath_common *common, * No valid hardware bitrate found -- we should not get here * because hardware has already validated this frame as OK. */ - ath_dbg(common, ANY, + ath_dbg(common, ATH_DBG_ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", rx_stats->rs_rate); @@ -959,7 +958,6 @@ static void ath9k_process_rssi(struct ath_common *common, struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; - int rssi = rx_stats->rs_rssi; if (!rx_stats->is_mybeacon || ((ah->opmode != NL80211_IFTYPE_STATION) && @@ -971,12 +969,13 @@ static void ath9k_process_rssi(struct ath_common *common, last_rssi = sc->last_rssi; if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); - if (rssi < 0) - rssi = 0; + rx_stats->rs_rssi = ATH_EP_RND(last_rssi, + ATH_RSSI_EP_MULTIPLIER); + if (rx_stats->rs_rssi < 0) + rx_stats->rs_rssi = 0; /* Update Beacon RSSI, this is used by ANI. */ - ah->stats.avgbrssi = rssi; + ah->stats.avgbrssi = rx_stats->rs_rssi; } /* @@ -993,6 +992,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, { struct ath_hw *ah = common->ah; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. @@ -1014,8 +1015,6 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_MPDU; - if (rx_stats->rs_moreaggr) - rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; return 0; } @@ -1835,7 +1834,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); rxs = IEEE80211_SKB_RXCB(hdr_skb); if (ieee80211_is_beacon(hdr->frame_control) && - !is_zero_ether_addr(common->curbssid) && !compare_ether_addr(hdr->addr3, common->curbssid)) rs.is_mybeacon = true; else @@ -1850,7 +1848,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (sc->sc_flags & SC_OP_RXFLUSH) goto requeue_drop_frag; - memset(rxs, 0, sizeof(struct ieee80211_rx_status)); + retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, + rxs, &decrypt_error); + if (retval) + goto requeue_drop_frag; rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; if (rs.rs_tstamp > tsf_lower && @@ -1861,11 +1862,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) rxs->mactime += 0x100000000ULL; - retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, - rxs, &decrypt_error); - if (retval) - goto requeue_drop_frag; - /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC); @@ -1924,33 +1920,28 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (sc->rx.frag) { int space = skb->len - skb_tailroom(hdr_skb); + sc->rx.frag = NULL; + if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { dev_kfree_skb(skb); goto requeue_drop_frag; } - sc->rx.frag = NULL; - skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len), skb->len); dev_kfree_skb_any(skb); skb = hdr_skb; } - - if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { - - /* - * change the default rx antenna if rx diversity - * chooses the other antenna 3 times in a row. - */ - if (sc->rx.defant != rs.rs_antenna) { - if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, rs.rs_antenna); - } else { - sc->rx.rxotherant = 0; - } - + /* + * change the default rx antenna if rx diversity chooses the + * other antenna 3 times in a row. + */ + if (sc->rx.defant != rs.rs_antenna) { + if (++sc->rx.rxotherant >= 3) + ath_setdefantenna(sc, rs.rs_antenna); + } else { + sc->rx.rxotherant = 0; } if (rxs->flag & RX_FLAG_MMIC_STRIPPED) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 458f81b4..45910975 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -797,6 +797,7 @@ #define AR_SREV_VERSION_9580 0x1C0 #define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ #define AR_SREV_VERSION_9462 0x280 +#define AR_SREV_REVISION_9462_10 0 #define AR_SREV_REVISION_9462_20 2 #define AR_SREV_5416(_ah) \ @@ -897,6 +898,10 @@ #define AR_SREV_9462(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462)) +#define AR_SREV_9462_10(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_10)) + #define AR_SREV_9462_20(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20)) @@ -1001,8 +1006,6 @@ enum { #define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_MASK_GPIO_S 18 -#define AR_INTR_ASYNC_MASK_MCI 0x00000080 -#define AR_INTR_ASYNC_MASK_MCI_S 7 #define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 @@ -1010,14 +1013,6 @@ enum { #define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) #define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) -#define AR_INTR_ASYNC_CAUSE_MCI 0x00000080 -#define AR_INTR_ASYNC_USED (AR_INTR_MAC_IRQ | \ - AR_INTR_ASYNC_CAUSE_MCI) - -/* Asynchronous Interrupt Enable Register */ -#define AR_INTR_ASYNC_ENABLE_MCI 0x00000080 -#define AR_INTR_ASYNC_ENABLE_MCI_S 7 - #define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 @@ -1151,7 +1146,6 @@ enum { #define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 -#define AR_ENT_OTP_49GHZ_DISABLE 0x00100000 #define AR_ENT_OTP_MIN_PKT_SIZE_DISABLE 0x00800000 #define AR_CH0_BB_DPLL1 0x16180 @@ -1275,8 +1269,6 @@ enum { #define AR_RTC_INTR_MASK \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) -#define AR_RTC_KEEP_AWAKE 0x7034 - /* RTC_DERIVED_* - only for AR9100 */ #define AR_RTC_DERIVED_CLK \ @@ -1563,8 +1555,6 @@ enum { #define AR_DIAG_FRAME_NV0 0x00020000 #define AR_DIAG_OBS_PT_SEL1 0x000C0000 #define AR_DIAG_OBS_PT_SEL1_S 18 -#define AR_DIAG_OBS_PT_SEL2 0x08000000 -#define AR_DIAG_OBS_PT_SEL2_S 27 #define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */ #define AR_DIAG_IGNORE_VIRT_CS 0x00200000 #define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000 @@ -1939,277 +1929,37 @@ enum { #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 /* MCI Registers */ - -#define AR_MCI_COMMAND0 0x1800 -#define AR_MCI_COMMAND0_HEADER 0xFF -#define AR_MCI_COMMAND0_HEADER_S 0 -#define AR_MCI_COMMAND0_LEN 0x1f00 -#define AR_MCI_COMMAND0_LEN_S 8 -#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP 0x2000 -#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S 13 - -#define AR_MCI_COMMAND1 0x1804 - -#define AR_MCI_COMMAND2 0x1808 -#define AR_MCI_COMMAND2_RESET_TX 0x01 -#define AR_MCI_COMMAND2_RESET_TX_S 0 -#define AR_MCI_COMMAND2_RESET_RX 0x02 -#define AR_MCI_COMMAND2_RESET_RX_S 1 -#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES 0x3FC -#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S 2 -#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP 0x400 -#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S 10 - -#define AR_MCI_RX_CTRL 0x180c - -#define AR_MCI_TX_CTRL 0x1810 -/* 0 = no division, 1 = divide by 2, 2 = divide by 4, 3 = divide by 8 */ -#define AR_MCI_TX_CTRL_CLK_DIV 0x03 -#define AR_MCI_TX_CTRL_CLK_DIV_S 0 -#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE 0x04 -#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S 2 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ 0xFFFFF8 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S 3 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM 0xF000000 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S 24 - -#define AR_MCI_MSG_ATTRIBUTES_TABLE 0x1814 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM 0xFFFF -#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S 0 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR 0xFFFF0000 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S 16 - -#define AR_MCI_SCHD_TABLE_0 0x1818 -#define AR_MCI_SCHD_TABLE_1 0x181c -#define AR_MCI_GPM_0 0x1820 -#define AR_MCI_GPM_1 0x1824 -#define AR_MCI_GPM_WRITE_PTR 0xFFFF0000 -#define AR_MCI_GPM_WRITE_PTR_S 16 -#define AR_MCI_GPM_BUF_LEN 0x0000FFFF -#define AR_MCI_GPM_BUF_LEN_S 0 - -#define AR_MCI_INTERRUPT_RAW 0x1828 -#define AR_MCI_INTERRUPT_EN 0x182c -#define AR_MCI_INTERRUPT_SW_MSG_DONE 0x00000001 -#define AR_MCI_INTERRUPT_SW_MSG_DONE_S 0 -#define AR_MCI_INTERRUPT_CPU_INT_MSG 0x00000002 -#define AR_MCI_INTERRUPT_CPU_INT_MSG_S 1 -#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL 0x00000004 -#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S 2 -#define AR_MCI_INTERRUPT_RX_INVALID_HDR 0x00000008 -#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S 3 -#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL 0x00000010 -#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S 4 -#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL 0x00000020 -#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S 5 -#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL 0x00000080 -#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S 7 -#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL 0x00000100 -#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S 8 -#define AR_MCI_INTERRUPT_RX_MSG 0x00000200 -#define AR_MCI_INTERRUPT_RX_MSG_S 9 -#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE 0x00000400 -#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S 10 -#define AR_MCI_INTERRUPT_BT_PRI 0x07fff800 -#define AR_MCI_INTERRUPT_BT_PRI_S 11 -#define AR_MCI_INTERRUPT_BT_PRI_THRESH 0x08000000 -#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S 27 -#define AR_MCI_INTERRUPT_BT_FREQ 0x10000000 -#define AR_MCI_INTERRUPT_BT_FREQ_S 28 -#define AR_MCI_INTERRUPT_BT_STOMP 0x20000000 -#define AR_MCI_INTERRUPT_BT_STOMP_S 29 -#define AR_MCI_INTERRUPT_BB_AIC_IRQ 0x40000000 -#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S 30 -#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT 0x80000000 -#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S 31 - -#define AR_MCI_INTERRUPT_DEFAULT (AR_MCI_INTERRUPT_SW_MSG_DONE | \ - AR_MCI_INTERRUPT_RX_INVALID_HDR | \ - AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_MSG | \ - AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \ - AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT) - -#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_SW_MSG_FAIL) - -#define AR_MCI_REMOTE_CPU_INT 0x1830 -#define AR_MCI_REMOTE_CPU_INT_EN 0x1834 -#define AR_MCI_INTERRUPT_RX_MSG_RAW 0x1838 -#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 -#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 -#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 -#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ +#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 +#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 +#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 +#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \ AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ AR_MCI_INTERRUPT_RX_MSG_CONT_RST) -#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM | \ - AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \ - AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ - AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \ - AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \ - AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_RST | \ - AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) - -#define AR_MCI_CPU_INT 0x1840 - -#define AR_MCI_RX_STATUS 0x1844 -#define AR_MCI_RX_LAST_SCHD_MSG_INDEX 0x00000F00 -#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S 8 -#define AR_MCI_RX_REMOTE_SLEEP 0x00001000 -#define AR_MCI_RX_REMOTE_SLEEP_S 12 -#define AR_MCI_RX_MCI_CLK_REQ 0x00002000 -#define AR_MCI_RX_MCI_CLK_REQ_S 13 - -#define AR_MCI_CONT_STATUS 0x1848 -#define AR_MCI_CONT_RSSI_POWER 0x000000FF -#define AR_MCI_CONT_RSSI_POWER_S 0 -#define AR_MCI_CONT_RRIORITY 0x0000FF00 -#define AR_MCI_CONT_RRIORITY_S 8 -#define AR_MCI_CONT_TXRX 0x00010000 -#define AR_MCI_CONT_TXRX_S 16 - -#define AR_MCI_BT_PRI0 0x184c -#define AR_MCI_BT_PRI1 0x1850 -#define AR_MCI_BT_PRI2 0x1854 -#define AR_MCI_BT_PRI3 0x1858 -#define AR_MCI_BT_PRI 0x185c -#define AR_MCI_WL_FREQ0 0x1860 -#define AR_MCI_WL_FREQ1 0x1864 -#define AR_MCI_WL_FREQ2 0x1868 -#define AR_MCI_GAIN 0x186c -#define AR_MCI_WBTIMER1 0x1870 -#define AR_MCI_WBTIMER2 0x1874 -#define AR_MCI_WBTIMER3 0x1878 -#define AR_MCI_WBTIMER4 0x187c -#define AR_MCI_MAXGAIN 0x1880 -#define AR_MCI_HW_SCHD_TBL_CTL 0x1884 -#define AR_MCI_HW_SCHD_TBL_D0 0x1888 -#define AR_MCI_HW_SCHD_TBL_D1 0x188c -#define AR_MCI_HW_SCHD_TBL_D2 0x1890 -#define AR_MCI_HW_SCHD_TBL_D3 0x1894 -#define AR_MCI_TX_PAYLOAD0 0x1898 -#define AR_MCI_TX_PAYLOAD1 0x189c -#define AR_MCI_TX_PAYLOAD2 0x18a0 -#define AR_MCI_TX_PAYLOAD3 0x18a4 -#define AR_BTCOEX_WBTIMER 0x18a8 - -#define AR_BTCOEX_CTRL 0x18ac -#define AR_BTCOEX_CTRL_AR9462_MODE 0x00000001 -#define AR_BTCOEX_CTRL_AR9462_MODE_S 0 -#define AR_BTCOEX_CTRL_WBTIMER_EN 0x00000002 -#define AR_BTCOEX_CTRL_WBTIMER_EN_S 1 -#define AR_BTCOEX_CTRL_MCI_MODE_EN 0x00000004 -#define AR_BTCOEX_CTRL_MCI_MODE_EN_S 2 -#define AR_BTCOEX_CTRL_LNA_SHARED 0x00000008 -#define AR_BTCOEX_CTRL_LNA_SHARED_S 3 -#define AR_BTCOEX_CTRL_PA_SHARED 0x00000010 -#define AR_BTCOEX_CTRL_PA_SHARED_S 4 -#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN 0x00000020 -#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S 5 -#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN 0x00000040 -#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S 6 -#define AR_BTCOEX_CTRL_NUM_ANTENNAS 0x00000180 -#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S 7 -#define AR_BTCOEX_CTRL_RX_CHAIN_MASK 0x00000E00 -#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S 9 -#define AR_BTCOEX_CTRL_AGGR_THRESH 0x00007000 -#define AR_BTCOEX_CTRL_AGGR_THRESH_S 12 -#define AR_BTCOEX_CTRL_1_CHAIN_BCN 0x00080000 -#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S 19 -#define AR_BTCOEX_CTRL_1_CHAIN_ACK 0x00100000 -#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S 20 -#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN 0x1FE00000 -#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S 28 -#define AR_BTCOEX_CTRL_REDUCE_TXPWR 0x20000000 -#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S 29 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_10 0x40000000 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S 30 -#define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000 -#define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31 - -#define AR_BTCOEX_WL_WEIGHTS0 0x18b0 -#define AR_BTCOEX_WL_WEIGHTS1 0x18b4 -#define AR_BTCOEX_WL_WEIGHTS2 0x18b8 -#define AR_BTCOEX_WL_WEIGHTS3 0x18bc -#define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) -#define AR_BTCOEX_WL_LNA 0x1940 -#define AR_BTCOEX_RFGAIN_CTRL 0x1944 - -#define AR_BTCOEX_CTRL2 0x1948 -#define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800 -#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S 11 -#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK 0x00380000 -#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S 19 -#define AR_BTCOEX_CTRL2_RX_DEWEIGHT 0x00400000 -#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S 22 -#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL 0x00800000 -#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S 23 -#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL 0x01000000 -#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S 24 -#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE 0x02000000 -#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S 25 - -#define AR_BTCOEX_CTRL_SPDT_ENABLE 0x00000001 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_S 0 -#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL 0x00000002 -#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S 1 -#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT 0x00000004 -#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2 -#define AR_GLB_WLAN_UART_INTF_EN 0x00020000 -#define AR_GLB_WLAN_UART_INTF_EN_S 17 -#define AR_GLB_DS_JTAG_DISABLE 0x00040000 -#define AR_GLB_DS_JTAG_DISABLE_S 18 - -#define AR_BTCOEX_RC 0x194c -#define AR_BTCOEX_MAX_RFGAIN(_x) (0x1950 + ((_x) << 2)) -#define AR_BTCOEX_DBG 0x1a50 -#define AR_MCI_LAST_HW_MSG_HDR 0x1a54 -#define AR_MCI_LAST_HW_MSG_BDY 0x1a58 - -#define AR_MCI_SCHD_TABLE_2 0x1a5c -#define AR_MCI_SCHD_TABLE_2_MEM_BASED 0x00000001 -#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0 -#define AR_MCI_SCHD_TABLE_2_HW_BASED 0x00000002 -#define AR_MCI_SCHD_TABLE_2_HW_BASED_S 1 - -#define AR_BTCOEX_CTRL3 0x1a60 -#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff -#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0 - #endif diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 65c8894c..35422fc1 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -187,7 +187,7 @@ void ath9k_fatal_work(struct work_struct *work) fatal_work); struct ath_common *common = ath9k_hw_common(priv->ah); - ath_dbg(common, FATAL, "FATAL Event received, resetting device\n"); + ath_dbg(common, ATH_DBG_FATAL, "FATAL Event received, resetting device\n"); ath9k_htc_reset(priv); } @@ -330,7 +330,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout); if (!time_left) { - ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", + ath_dbg(common, ATH_DBG_WMI, + "Timeout waiting for WMI command: %s\n", wmi_cmd_to_name(cmd_id)); mutex_unlock(&wmi->op_mutex); return -ETIMEDOUT; @@ -341,7 +342,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, return 0; out: - ath_dbg(common, WMI, "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id)); + ath_dbg(common, ATH_DBG_WMI, + "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id)); mutex_unlock(&wmi->op_mutex); kfree_skb(skb); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c old mode 100644 new mode 100755 index 1a5f275f..8f68e760 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -53,7 +53,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, int tx_flags, struct ath_txq *txq); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, - struct ath_tx_status *ts, int txok); + struct ath_tx_status *ts, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head, bool internal); static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, @@ -104,32 +104,6 @@ static int ath_max_4ms_framelen[4][32] = { /* Aggregation logic */ /*********************/ -static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) - __acquires(&txq->axq_lock) -{ - spin_lock_bh(&txq->axq_lock); -} - -static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq) - __releases(&txq->axq_lock) -{ - spin_unlock_bh(&txq->axq_lock); -} - -static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) - __releases(&txq->axq_lock) -{ - struct sk_buff_head q; - struct sk_buff *skb; - - __skb_queue_head_init(&q); - skb_queue_splice_init(&txq->complete_q, &q); - spin_unlock_bh(&txq->axq_lock); - - while ((skb = __skb_dequeue(&q))) - ieee80211_tx_status(sc->hw, skb); -} - static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) { struct ath_atx_ac *ac = tid->ac; @@ -156,7 +130,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) WARN_ON(!tid->paused); - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); tid->paused = false; if (skb_queue_empty(&tid->buf_q)) @@ -165,7 +139,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ath_tx_queue_tid(txq, tid); ath_txq_schedule(sc, txq); unlock: - ath_txq_unlock_complete(sc, txq); + spin_unlock_bh(&txq->axq_lock); } static struct ath_frame_info *get_frame_info(struct sk_buff *skb) @@ -176,12 +150,6 @@ static struct ath_frame_info *get_frame_info(struct sk_buff *skb) return (struct ath_frame_info *) &tx_info->rate_driver_data[0]; } -static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno) -{ - ieee80211_send_bar(tid->an->vif, tid->an->sta->addr, tid->tidno, - seqno << IEEE80211_SEQ_SEQ_SHIFT); -} - static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -190,44 +158,28 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) struct list_head bf_head; struct ath_tx_status ts; struct ath_frame_info *fi; - bool sendbar = false; INIT_LIST_HEAD(&bf_head); memset(&ts, 0, sizeof(ts)); + spin_lock_bh(&txq->axq_lock); while ((skb = __skb_dequeue(&tid->buf_q))) { fi = get_frame_info(skb); bf = fi->bf; - if (!bf) { - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { - ieee80211_free_txskb(sc->hw, skb); - continue; - } - } - - if (fi->retries) { + spin_unlock_bh(&txq->axq_lock); + if (bf && fi->retries) { list_add_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, tid, bf->bf_state.seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); - sendbar = true; + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1); } else { ath_tx_send_normal(sc, txq, NULL, skb); } + spin_lock_bh(&txq->axq_lock); } - if (tid->baw_head == tid->baw_tail) { - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_CLEANUP; - } - - if (sendbar) { - ath_txq_unlock(sc, txq); - ath_send_bar(tid, tid->seq_start); - ath_txq_lock(sc, txq); - } + spin_unlock_bh(&txq->axq_lock); } static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, @@ -243,8 +195,6 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) { INCR(tid->seq_start, IEEE80211_SEQ_MAX); INCR(tid->baw_head, ATH_TID_MAX_BUFS); - if (tid->bar_index >= 0) - tid->bar_index--; } } @@ -288,7 +238,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, bf = fi->bf; if (!bf) { + spin_unlock(&txq->axq_lock); ath_tx_complete(sc, skb, ATH_TX_ERROR, txq); + spin_lock(&txq->axq_lock); continue; } @@ -297,26 +249,24 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, if (fi->retries) ath_tx_update_baw(sc, tid, bf->bf_state.seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); + spin_unlock(&txq->axq_lock); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); + spin_lock(&txq->axq_lock); } tid->seq_next = tid->seq_start; tid->baw_tail = tid->baw_head; - tid->bar_index = -1; } static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, - struct sk_buff *skb, int count) + struct sk_buff *skb) { struct ath_frame_info *fi = get_frame_info(skb); struct ath_buf *bf = fi->bf; struct ieee80211_hdr *hdr; - int prev = fi->retries; TX_STAT_INC(txq->axq_qnum, a_retries); - fi->retries += count; - - if (prev > 0) + if (fi->retries++ > 0) return; hdr = (struct ieee80211_hdr *)skb->data; @@ -416,7 +366,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; struct list_head bf_head; struct sk_buff_head bf_pending; - u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first; + u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; bool rc_update = true, isba; @@ -425,8 +375,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, int nframes; u8 tidno; bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH); - int i, retries; - int bar_index = -1; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -435,10 +383,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, memcpy(rates, tx_info->control.rates, sizeof(rates)); - retries = ts->ts_longretry + 1; - for (i = 0; i < ts->ts_rateindex; i++) - retries += rates[i].count; - rcu_read_lock(); sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); @@ -452,7 +396,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (!bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, + 0, 0); bf = bf_next; } @@ -462,18 +407,13 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, an = (struct ath_node *)sta->drv_priv; tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(an, tidno); - seq_first = tid->seq_start; - isba = ts->ts_flags & ATH9K_TX_BA; /* * The hardware occasionally sends a tx status for the wrong TID. * In this case, the BA status cannot be considered valid and all * subframes need to be retransmitted - * - * Only BlockAcks have a TID and therefore normal Acks cannot be - * checked */ - if (isba && tidno != ts->tid) + if (tidno != ts->tid) txok = false; isaggr = bf_isaggr(bf); @@ -516,25 +456,25 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } else if (!isaggr && txok) { /* transmit completion */ acked_cnt++; - } else if ((tid->state & AGGR_CLEANUP) || !retry) { - /* - * cleanup in progress, just fail - * the un-acked sub-frames - */ - txfail = 1; - } else if (flush) { - txpending = 1; - } else if (fi->retries < ATH_MAX_SW_RETRIES) { - if (txok || !an->sleeping) - ath_tx_set_retry(sc, txq, bf->bf_mpdu, - retries); - - txpending = 1; } else { - txfail = 1; - txfail_cnt++; - bar_index = max_t(int, bar_index, - ATH_BA_INDEX(seq_first, seqno)); + if ((tid->state & AGGR_CLEANUP) || !retry) { + /* + * cleanup in progress, just fail + * the un-acked sub-frames + */ + txfail = 1; + } else if (flush) { + txpending = 1; + } else if (fi->retries < ATH_MAX_SW_RETRIES) { + if (txok || !an->sleeping) + ath_tx_set_retry(sc, txq, bf->bf_mpdu); + + txpending = 1; + } else { + txfail = 1; + sendbar = 1; + txfail_cnt++; + } } /* @@ -551,7 +491,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * complete the acked-ones/xretried ones; update * block-ack window */ + spin_lock_bh(&txq->axq_lock); ath_tx_update_baw(sc, tid, seqno); + spin_unlock_bh(&txq->axq_lock); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); @@ -560,30 +502,33 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, - !txfail); + !txfail, sendbar); } else { /* retry the un-acked ones */ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && - bf->bf_next == NULL && bf_last->bf_stale) { - struct ath_buf *tbf; - - tbf = ath_clone_txbuf(sc, bf_last); - /* - * Update tx baw and complete the - * frame with failed status if we - * run out of tx buf. - */ - if (!tbf) { - ath_tx_update_baw(sc, tid, seqno); - - ath_tx_complete_buf(sc, bf, txq, - &bf_head, ts, 0); - bar_index = max_t(int, bar_index, - ATH_BA_INDEX(seq_first, seqno)); - break; + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { + if (bf->bf_next == NULL && bf_last->bf_stale) { + struct ath_buf *tbf; + + tbf = ath_clone_txbuf(sc, bf_last); + /* + * Update tx baw and complete the + * frame with failed status if we + * run out of tx buf. + */ + if (!tbf) { + spin_lock_bh(&txq->axq_lock); + ath_tx_update_baw(sc, tid, seqno); + spin_unlock_bh(&txq->axq_lock); + + ath_tx_complete_buf(sc, bf, txq, + &bf_head, + ts, 0, + !flush); + break; + } + + fi->bf = tbf; } - - fi->bf = tbf; } /* @@ -601,6 +546,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (an->sleeping) ieee80211_sta_set_buffered(sta, tid->tidno, true); + spin_lock_bh(&txq->axq_lock); skb_queue_splice(&bf_pending, &tid->buf_q); if (!an->sleeping) { ath_tx_queue_tid(txq, tid); @@ -608,22 +554,18 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (ts->ts_status & ATH9K_TXERR_FILT) tid->ac->clear_ps_filter = true; } + spin_unlock_bh(&txq->axq_lock); } - if (bar_index >= 0) { - u16 bar_seq = ATH_BA_INDEX2SEQ(seq_first, bar_index); - - if (BAW_WITHIN(tid->seq_start, tid->baw_size, bar_seq)) - tid->bar_index = ATH_BA_INDEX(tid->seq_start, bar_seq); + if (tid->state & AGGR_CLEANUP) { + ath_tx_flush_tid(sc, tid); - ath_txq_unlock(sc, txq); - ath_send_bar(tid, ATH_BA_INDEX2SEQ(seq_first, bar_index + 1)); - ath_txq_lock(sc, txq); + if (tid->baw_head == tid->baw_tail) { + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->state &= ~AGGR_CLEANUP; + } } - if (tid->state & AGGR_CLEANUP) - ath_tx_flush_tid(sc, tid); - rcu_read_unlock(); if (needreset) { @@ -660,8 +602,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; + struct ath_mci_profile *mci = &sc->btcoex.mci; u32 max_4ms_framelen, frmlen; - u16 aggr_limit, bt_aggr_limit, legacy = 0; + u16 aggr_limit, legacy = 0; int i; skb = bf->bf_mpdu; @@ -676,26 +619,24 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; for (i = 0; i < 4; i++) { - int modeidx; - - if (!rates[i].count) - continue; - - if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) { - legacy = 1; - break; - } + if (rates[i].count) { + int modeidx; + if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) { + legacy = 1; + break; + } - if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - modeidx = MCS_HT40; - else - modeidx = MCS_HT20; + if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + modeidx = MCS_HT40; + else + modeidx = MCS_HT20; - if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) - modeidx++; + if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) + modeidx++; - frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; - max_4ms_framelen = min(max_4ms_framelen, frmlen); + frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; + max_4ms_framelen = min(max_4ms_framelen, frmlen); + } } /* @@ -706,14 +647,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) return 0; - aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); - - /* - * Override the default aggregation limit for BTCOEX. - */ - bt_aggr_limit = ath9k_btcoex_aggr_limit(sc, max_4ms_framelen); - if (bt_aggr_limit) - aggr_limit = bt_aggr_limit; + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit) + aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4; + else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED) + aggr_limit = min((max_4ms_framelen * 3) / 8, + (u32)ATH_AMPDU_LIMIT_MAX); + else + aggr_limit = min(max_4ms_framelen, + (u32)ATH_AMPDU_LIMIT_MAX); /* * h/w can accept aggregates up to 16 bit lengths (65535). @@ -834,6 +775,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; seqno = bf->bf_state.seqno; + if (!bf_first) + bf_first = bf; /* do not step over block-ack window */ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { @@ -841,21 +784,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, break; } - if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { - struct ath_tx_status ts = {}; - struct list_head bf_head; - - INIT_LIST_HEAD(&bf_head); - list_add(&bf->list, &bf_head); - __skb_unlink(skb, &tid->buf_q); - ath_tx_update_baw(sc, tid, seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); - continue; - } - - if (!bf_first) - bf_first = bf; - if (!rl) { aggr_limit = ath_lookup_rate(sc, bf, tid); rl = 1; @@ -964,7 +892,16 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, /* set dur_update_en for l-sig computation except for PS-Poll frames */ info->dur_update = !ieee80211_is_pspoll(hdr->frame_control); - info->rtscts_rate = fi->rtscts_rate; + + /* + * We check if Short Preamble is needed for the CTS rate by + * checking the BSS's global flag. + * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. + */ + rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); + info->rtscts_rate = rate->hw_value; + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) + info->rtscts_rate |= rate->hw_value_short; for (i = 0; i < 4; i++) { bool is_40, is_sgi, is_sp; @@ -1190,7 +1127,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, txtid->state |= AGGR_ADDBA_PROGRESS; txtid->paused = true; *ssn = txtid->seq_start = txtid->seq_next; - txtid->bar_index = -1; memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); txtid->baw_head = txtid->baw_tail = 0; @@ -1212,7 +1148,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) return; } - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); txtid->paused = true; /* @@ -1225,9 +1161,9 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) txtid->state |= AGGR_CLEANUP; else txtid->state &= ~AGGR_ADDBA_COMPLETE; + spin_unlock_bh(&txq->axq_lock); ath_tx_flush_tid(sc, txtid); - ath_txq_unlock_complete(sc, txq); } void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, @@ -1242,15 +1178,13 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, for (tidno = 0, tid = &an->tid[tidno]; tidno < WME_NUM_TID; tidno++, tid++) { + if (!tid->sched) + continue; + ac = tid->ac; txq = ac->txq; - ath_txq_lock(sc, txq); - - if (!tid->sched) { - ath_txq_unlock(sc, txq); - continue; - } + spin_lock_bh(&txq->axq_lock); buffered = !skb_queue_empty(&tid->buf_q); @@ -1262,7 +1196,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, list_del(&ac->list); } - ath_txq_unlock(sc, txq); + spin_unlock_bh(&txq->axq_lock); ieee80211_sta_set_buffered(sta, tidno, buffered); } @@ -1281,7 +1215,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) ac = tid->ac; txq = ac->txq; - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); ac->clear_ps_filter = true; if (!skb_queue_empty(&tid->buf_q) && !tid->paused) { @@ -1289,7 +1223,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) ath_txq_schedule(sc, txq); } - ath_txq_unlock_complete(sc, txq); + spin_unlock_bh(&txq->axq_lock); } } @@ -1300,11 +1234,14 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid an = (struct ath_node *)sta->drv_priv; - txtid = ATH_AN_2_TID(an, tid); - txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; - txtid->state |= AGGR_ADDBA_COMPLETE; - txtid->state &= ~AGGR_ADDBA_PROGRESS; - ath_tx_resume_tid(sc, txtid); + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->baw_size = + IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; + ath_tx_resume_tid(sc, txtid); + } } /********************/ @@ -1363,7 +1300,8 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) * based intr on the EOSP frames. */ if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE; + qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE | + TXQ_FLAG_TXERRINT_ENABLE; } else { if (qtype == ATH9K_TX_QUEUE_UAPSD) qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; @@ -1385,7 +1323,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_qnum = axq_qnum; txq->mac80211_qnum = -1; txq->axq_link = NULL; - __skb_queue_head_init(&txq->complete_q); INIT_LIST_HEAD(&txq->axq_q); INIT_LIST_HEAD(&txq->axq_acq); spin_lock_init(&txq->axq_lock); @@ -1468,6 +1405,8 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf) static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, struct list_head *list, bool retry_tx) + __releases(txq->axq_lock) + __acquires(txq->axq_lock) { struct ath_buf *bf, *lastbf; struct list_head bf_head; @@ -1494,11 +1433,13 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, if (bf_is_ampdu_not_probing(bf)) txq->axq_ampdu_depth--; + spin_unlock_bh(&txq->axq_lock); if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0, retry_tx); else - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); + spin_lock_bh(&txq->axq_lock); } } @@ -1510,8 +1451,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, */ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) { - ath_txq_lock(sc, txq); - + spin_lock_bh(&txq->axq_lock); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { int idx = txq->txq_tailidx; @@ -1529,10 +1469,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx); /* flush any pending frames if aggregation is enabled */ - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx) + if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx) ath_txq_drain_pending_buffers(sc, txq); - ath_txq_unlock_complete(sc, txq); + spin_unlock_bh(&txq->axq_lock); } bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) @@ -1626,9 +1566,11 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) break; } - if (!list_empty(&ac->tid_q) && !ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); + if (!list_empty(&ac->tid_q)) { + if (!ac->sched) { + ac->sched = true; + list_add_tail(&ac->list, &txq->axq_acq); + } } if (ac == last_ac || @@ -1666,8 +1608,8 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, bf = list_first_entry(head, struct ath_buf, list); bf_last = list_entry(head->prev, struct ath_buf, list); - ath_dbg(common, QUEUE, "qnum: %d, txq depth: %d\n", - txq->axq_qnum, txq->axq_depth); + ath_dbg(common, ATH_DBG_QUEUE, + "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) { list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]); @@ -1678,7 +1620,8 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, if (txq->axq_link) { ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr); - ath_dbg(common, XMIT, "link[%u] (%p)=%llx (%p)\n", + ath_dbg(common, ATH_DBG_XMIT, + "link[%u] (%p)=%llx (%p)\n", txq->axq_qnum, txq->axq_link, ito64(bf->bf_daddr), bf->bf_desc); } else if (!edma) @@ -1690,7 +1633,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, if (puttxbuf) { TX_STAT_INC(txq->axq_qnum, puttxbuf); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n", + ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } @@ -1762,12 +1705,20 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf; bf = fi->bf; + if (!bf) + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + + if (!bf) + return; INIT_LIST_HEAD(&bf_head); list_add_tail(&bf->list, &bf_head); bf->bf_state.bf_type = 0; - bf->bf_next = NULL; + /* update starting sequence number for subsequent ADDBA request */ + if (tid) + INCR(tid->seq_start, IEEE80211_SEQ_MAX); + bf->bf_lastbf = bf; ath_tx_fill_desc(sc, bf, txq, fi->framelen); ath_tx_txqaddbuf(sc, txq, &bf_head, false); @@ -1841,28 +1792,20 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_frame_info *fi = get_frame_info(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_buf *bf; - int fragno; u16 seqno; bf = ath_tx_get_buffer(sc); if (!bf) { - ath_dbg(common, XMIT, "TX buffers are full\n"); - return NULL; + ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n"); + goto error; } ATH_TXBUF_RESET(bf); if (tid) { - fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; seqno = tid->seq_next; hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); - - if (fragno) - hdr->seq_ctrl |= cpu_to_le16(fragno); - - if (!ieee80211_has_morefrags(hdr->frame_control)) - INCR(tid->seq_next, IEEE80211_SEQ_MAX); - + INCR(tid->seq_next, IEEE80211_SEQ_MAX); bf->bf_state.seqno = seqno; } @@ -1894,7 +1837,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, struct ath_buf *bf; u8 tidno; - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an && + spin_lock_bh(&txctl->txq->axq_lock); + if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; @@ -1911,13 +1855,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, ath_tx_send_ampdu(sc, tid, skb, txctl); } else { bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); - if (!bf) { - if (txctl->paprd) - dev_kfree_skb_any(skb); - else - ieee80211_free_txskb(sc->hw, skb); - return; - } + if (!bf) + goto out; bf->bf_state.bfs_paprd = txctl->paprd; @@ -1926,6 +1865,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, ath_tx_send_normal(sc, txctl->txq, tid, skb); } + +out: + spin_unlock_bh(&txctl->txq->axq_lock); } /* Upon failure caller should free skb */ @@ -1986,18 +1928,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, */ q = skb_get_queue_mapping(skb); - - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); if (txq == sc->tx.txq_map[q] && ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { ieee80211_stop_queue(sc->hw, q); - txq->stopped = true; + txq->stopped = 1; } + spin_unlock_bh(&txq->axq_lock); ath_tx_start_dma(sc, skb, txctl); - - ath_txq_unlock(sc, txq); - return 0; } @@ -2008,12 +1947,16 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, int tx_flags, struct ath_txq *txq) { + struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; int q, padpos, padsize; - ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); + ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); + + if (tx_flags & ATH_TX_BAR) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (!(tx_flags & ATH_TX_ERROR)) /* Frame was ACKed */ @@ -2030,9 +1973,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, skb_pull(skb, padsize); } - if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { + if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) { sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; - ath_dbg(common, PS, + ath_dbg(common, ATH_DBG_PS, "Going back to sleep after having received TX status (0x%lx)\n", sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | @@ -2042,27 +1985,32 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, q = skb_get_queue_mapping(skb); if (txq == sc->tx.txq_map[q]) { + spin_lock_bh(&txq->axq_lock); if (WARN_ON(--txq->pending_frames < 0)) txq->pending_frames = 0; if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { ieee80211_wake_queue(sc->hw, q); - txq->stopped = false; + txq->stopped = 0; } + spin_unlock_bh(&txq->axq_lock); } - __skb_queue_tail(&txq->complete_q, skb); + ieee80211_tx_status(hw, skb); } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, - struct ath_tx_status *ts, int txok) + struct ath_tx_status *ts, int txok, int sendbar) { struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); unsigned long flags; int tx_flags = 0; + if (sendbar) + tx_flags = ATH_TX_BAR; + if (!txok) tx_flags |= ATH_TX_ERROR; @@ -2154,6 +2102,8 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_tx_status *ts, struct ath_buf *bf, struct list_head *bf_head) + __releases(txq->axq_lock) + __acquires(txq->axq_lock) { int txok; @@ -2163,13 +2113,17 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, if (bf_is_ampdu_not_probing(bf)) txq->axq_ampdu_depth--; + spin_unlock_bh(&txq->axq_lock); + if (!bf_isampdu(bf)) { ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); - ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); + ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0); } else ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + spin_lock_bh(&txq->axq_lock); + + if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); } @@ -2183,18 +2137,18 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct ath_tx_status ts; int status; - ath_dbg(common, QUEUE, "tx queue %d (%x), link %p\n", + ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); for (;;) { if (work_pending(&sc->hw_reset_work)) break; if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); break; } @@ -2246,7 +2200,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); } - ath_txq_unlock_complete(sc, txq); + spin_unlock_bh(&txq->axq_lock); } static void ath_tx_complete_poll_work(struct work_struct *work) @@ -2263,21 +2217,21 @@ static void ath_tx_complete_poll_work(struct work_struct *work) for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) { txq = &sc->tx.txq[i]; - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); if (txq->axq_depth) { if (txq->axq_tx_inprogress) { needreset = true; - ath_txq_unlock(sc, txq); + spin_unlock_bh(&txq->axq_lock); break; } else { txq->axq_tx_inprogress = true; } } - ath_txq_unlock_complete(sc, txq); + spin_unlock_bh(&txq->axq_lock); } if (needreset) { - ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, + ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, "tx hung, resetting the chip\n"); RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); @@ -2291,9 +2245,10 @@ static void ath_tx_complete_poll_work(struct work_struct *work) void ath_tx_tasklet(struct ath_softc *sc) { - struct ath_hw *ah = sc->sc_ah; - u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs; int i; + u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); + + ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) @@ -2319,23 +2274,21 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) if (status == -EINPROGRESS) break; if (status == -EIO) { - ath_dbg(common, XMIT, "Error processing tx status\n"); + ath_dbg(common, ATH_DBG_XMIT, + "Error processing tx status\n"); break; } - /* Process beacon completions separately */ - if (ts.qid == sc->beacon.beaconq) { - sc->beacon.tx_processed = true; - sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); + /* Skip beacon completions */ + if (ts.qid == sc->beacon.beaconq) continue; - } txq = &sc->tx.txq[ts.qid]; - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { - ath_txq_unlock(sc, txq); + spin_unlock_bh(&txq->axq_lock); return; } @@ -2361,7 +2314,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) } ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); - ath_txq_unlock_complete(sc, txq); + spin_unlock_bh(&txq->axq_lock); } } @@ -2500,7 +2453,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) ac = tid->ac; txq = ac->txq; - ath_txq_lock(sc, txq); + spin_lock_bh(&txq->axq_lock); if (tid->sched) { list_del(&tid->list); @@ -2516,6 +2469,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) tid->state &= ~AGGR_ADDBA_COMPLETE; tid->state &= ~AGGR_CLEANUP; - ath_txq_unlock(sc, txq); + spin_unlock_bh(&txq->axq_lock); } } diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 0cea20e3..6cfbb419 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -559,7 +559,6 @@ int carl9170_set_hwretry_limit(struct ar9170 *ar, const u32 max_retry); int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac, const u8 ktype, const u8 keyidx, const u8 *keydata, const int keylen); int carl9170_disable_key(struct ar9170 *ar, const u8 id); -int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel); /* RX */ void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len); @@ -594,6 +593,7 @@ int carl9170_get_noisefloor(struct ar9170 *ar); /* FW */ int carl9170_parse_firmware(struct ar9170 *ar); +int carl9170_fw_fix_eeprom(struct ar9170 *ar); extern struct ieee80211_rate __carl9170_ratetable[]; extern int modparam_noht; diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c index 93fe6003..de57f90e 100644 --- a/drivers/net/wireless/ath/carl9170/debug.c +++ b/drivers/net/wireless/ath/carl9170/debug.c @@ -48,10 +48,15 @@ #define ADD(buf, off, max, fmt, args...) \ off += snprintf(&buf[off], max - off, fmt, ##args); +static int carl9170_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} struct carl9170_debugfs_fops { unsigned int read_bufsize; - umode_t attr; + mode_t attr; char *(*read)(struct ar9170 *ar, char *buf, size_t bufsize, ssize_t *len); ssize_t (*write)(struct ar9170 *aru, const char *buf, size_t size); @@ -173,7 +178,7 @@ static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\ .attr = _attr, \ .req_dev_state = _dstate, \ .fops = { \ - .open = simple_open, \ + .open = carl9170_debugfs_open, \ .read = carl9170_debugfs_read, \ .write = carl9170_debugfs_write, \ .owner = THIS_MODULE \ diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index cffde8d9..cba9d043 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -146,15 +146,13 @@ static bool valid_cpu_addr(const u32 address) return false; } -static int carl9170_fw_checksum(struct ar9170 *ar, const __u8 *data, - size_t len) +static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) { const struct carl9170fw_otus_desc *otus_desc; - const struct carl9170fw_last_desc *last_desc; const struct carl9170fw_chk_desc *chk_desc; - unsigned long fin, diff; - unsigned int dsc_len; - u32 crc32; + const struct carl9170fw_last_desc *last_desc; + const struct carl9170fw_txsq_desc *txsq_desc; + u16 if_comb_types; last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC, sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER); @@ -172,68 +170,36 @@ static int carl9170_fw_checksum(struct ar9170 *ar, const __u8 *data, chk_desc = carl9170_fw_find_desc(ar, CHK_MAGIC, sizeof(*chk_desc), CARL9170FW_CHK_DESC_CUR_VER); - if (!chk_desc) { - dev_warn(&ar->udev->dev, "Unprotected firmware image.\n"); - return 0; - } + if (chk_desc) { + unsigned long fin, diff; + unsigned int dsc_len; + u32 crc32; - dsc_len = min_t(unsigned int, len, + dsc_len = min_t(unsigned int, len, (unsigned long)chk_desc - (unsigned long)otus_desc); - fin = (unsigned long) last_desc + sizeof(*last_desc); - diff = fin - (unsigned long) otus_desc; + fin = (unsigned long) last_desc + sizeof(*last_desc); + diff = fin - (unsigned long) otus_desc; - if (diff < len) - len -= diff; + if (diff < len) + len -= diff; - if (len < 256) - return -EIO; + if (len < 256) + return -EIO; - crc32 = crc32_le(~0, data, len); - if (cpu_to_le32(crc32) != chk_desc->fw_crc32) { - dev_err(&ar->udev->dev, "fw checksum test failed.\n"); - return -ENOEXEC; - } - - crc32 = crc32_le(crc32, (void *)otus_desc, dsc_len); - if (cpu_to_le32(crc32) != chk_desc->hdr_crc32) { - dev_err(&ar->udev->dev, "descriptor check failed.\n"); - return -EINVAL; - } - return 0; -} - -static int carl9170_fw_tx_sequence(struct ar9170 *ar) -{ - const struct carl9170fw_txsq_desc *txsq_desc; + crc32 = crc32_le(~0, data, len); + if (cpu_to_le32(crc32) != chk_desc->fw_crc32) { + dev_err(&ar->udev->dev, "fw checksum test failed.\n"); + return -ENOEXEC; + } - txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC, sizeof(*txsq_desc), - CARL9170FW_TXSQ_DESC_CUR_VER); - if (txsq_desc) { - ar->fw.tx_seq_table = le32_to_cpu(txsq_desc->seq_table_addr); - if (!valid_cpu_addr(ar->fw.tx_seq_table)) + crc32 = crc32_le(crc32, (void *)otus_desc, dsc_len); + if (cpu_to_le32(crc32) != chk_desc->hdr_crc32) { + dev_err(&ar->udev->dev, "descriptor check failed.\n"); return -EINVAL; + } } else { - ar->fw.tx_seq_table = 0; - } - - return 0; -} - -static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) -{ - const struct carl9170fw_otus_desc *otus_desc; - int err; - u16 if_comb_types; - - err = carl9170_fw_checksum(ar, data, len); - if (err) - return err; - - otus_desc = carl9170_fw_find_desc(ar, OTUS_MAGIC, - sizeof(*otus_desc), CARL9170FW_OTUS_DESC_CUR_VER); - if (!otus_desc) { - return -ENODATA; + dev_warn(&ar->udev->dev, "Unprotected firmware image.\n"); } #define SUPP(feat) \ @@ -355,8 +321,19 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) ar->hw->wiphy->interface_modes |= if_comb_types; + txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC, + sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER); + + if (txsq_desc) { + ar->fw.tx_seq_table = le32_to_cpu(txsq_desc->seq_table_addr); + if (!valid_cpu_addr(ar->fw.tx_seq_table)) + return -EINVAL; + } else { + ar->fw.tx_seq_table = 0; + } + #undef SUPPORTED - return carl9170_fw_tx_sequence(ar); + return 0; } static struct carl9170fw_desc_head * @@ -389,6 +366,39 @@ carl9170_find_fw_desc(struct ar9170 *ar, const __u8 *fw_data, const size_t len) return (void *)&fw_data[scan - found]; } +int carl9170_fw_fix_eeprom(struct ar9170 *ar) +{ + const struct carl9170fw_fix_desc *fix_desc = NULL; + unsigned int i, n, off; + u32 *data = (void *)&ar->eeprom; + + fix_desc = carl9170_fw_find_desc(ar, FIX_MAGIC, + sizeof(*fix_desc), CARL9170FW_FIX_DESC_CUR_VER); + + if (!fix_desc) + return 0; + + n = (le16_to_cpu(fix_desc->head.length) - sizeof(*fix_desc)) / + sizeof(struct carl9170fw_fix_entry); + + for (i = 0; i < n; i++) { + off = le32_to_cpu(fix_desc->data[i].address) - + AR9170_EEPROM_START; + + if (off >= sizeof(struct ar9170_eeprom) || (off & 3)) { + dev_err(&ar->udev->dev, "Skip invalid entry %d\n", i); + continue; + } + + data[off / sizeof(*data)] &= + le32_to_cpu(fix_desc->data[i].mask); + data[off / sizeof(*data)] |= + le32_to_cpu(fix_desc->data[i].value); + } + + return 0; +} + int carl9170_parse_firmware(struct ar9170 *ar) { const struct carl9170fw_desc_head *fw_desc = NULL; diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index 53415bfd..dfda9197 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -485,38 +485,3 @@ int carl9170_disable_key(struct ar9170 *ar, const u8 id) return carl9170_exec_cmd(ar, CARL9170_CMD_DKEY, sizeof(key), (u8 *)&key, 0, NULL); } - -int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel) -{ - unsigned int power, chains; - - if (ar->eeprom.tx_mask != 1) - chains = AR9170_TX_PHY_TXCHAIN_2; - else - chains = AR9170_TX_PHY_TXCHAIN_1; - - switch (channel->band) { - case IEEE80211_BAND_2GHZ: - power = ar->power_2G_ofdm[0] & 0x3f; - break; - case IEEE80211_BAND_5GHZ: - power = ar->power_5G_leg[0] & 0x3f; - break; - default: - BUG_ON(1); - } - - power = min_t(unsigned int, power, ar->hw->conf.power_level * 2); - - carl9170_regwrite_begin(ar); - carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, - 0x3c1e | power << 20 | chains << 26); - carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC, - power << 5 | chains << 11 | - power << 21 | chains << 27); - carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC, - power << 5 | chains << 11 | - power << 21 | chains << 27); - carl9170_regwrite_finish(); - return carl9170_regwrite_result(); -} diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 8d2523b3..e24a4b7b 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -48,7 +48,7 @@ #include "carl9170.h" #include "cmd.h" -static bool modparam_nohwcrypt; +static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload."); @@ -446,7 +446,7 @@ static void carl9170_op_stop(struct ieee80211_hw *hw) mutex_lock(&ar->mutex); if (IS_ACCEPTING_CMD(ar)) { - RCU_INIT_POINTER(ar->beacon_iter, NULL); + rcu_assign_pointer(ar->beacon_iter, NULL); carl9170_led_set_state(ar, 0); @@ -678,7 +678,7 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, vif_priv->active = false; bitmap_release_region(&ar->vif_bitmap, vif_id, 0); ar->vifs--; - RCU_INIT_POINTER(ar->vif_priv[vif_id].vif, NULL); + rcu_assign_pointer(ar->vif_priv[vif_id].vif, NULL); list_del_rcu(&vif_priv->list); mutex_unlock(&ar->mutex); synchronize_rcu(); @@ -716,7 +716,7 @@ static void carl9170_op_remove_interface(struct ieee80211_hw *hw, WARN_ON(vif_priv->enable_beacon); vif_priv->enable_beacon = false; list_del_rcu(&vif_priv->list); - RCU_INIT_POINTER(ar->vif_priv[id].vif, NULL); + rcu_assign_pointer(ar->vif_priv[id].vif, NULL); if (vif == main_vif) { rcu_read_unlock(); @@ -853,6 +853,11 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } + if (changed & IEEE80211_CONF_CHANGE_POWER) { + /* TODO */ + err = 0; + } + if (changed & IEEE80211_CONF_CHANGE_SMPS) { /* TODO */ err = 0; @@ -886,28 +891,40 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } - if (changed & IEEE80211_CONF_CHANGE_POWER) { - err = carl9170_set_mac_tpc(ar, ar->hw->conf.channel); - if (err) - goto out; - } - out: mutex_unlock(&ar->mutex); return err; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) static u64 carl9170_op_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list) +#else +static u64 carl9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, + struct dev_addr_list *ha) +#endif { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) struct netdev_hw_addr *ha; +#else + int i; +#endif u64 mchash; /* always get broadcast frames */ mchash = 1ULL << (0xff >> 2); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) netdev_hw_addr_list_for_each(ha, mc_list) mchash |= 1ULL << (ha->addr[5] >> 2); +#else + for (i = 0; i < mc_count; i++) { + if (WARN_ON(!ha)) + break; + mchash |= 1ULL << (ha->dmi_addr[5] >> 2); + ha = ha->next; + } +#endif return mchash; } @@ -1259,7 +1276,7 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, } for (i = 0; i < CARL9170_NUM_TID; i++) - RCU_INIT_POINTER(sta_info->agg[i], NULL); + rcu_assign_pointer(sta_info->agg[i], NULL); sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); sta_info->ht_sta = true; @@ -1286,7 +1303,7 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, struct carl9170_sta_tid *tid_info; tid_info = rcu_dereference(sta_info->agg[i]); - RCU_INIT_POINTER(sta_info->agg[i], NULL); + rcu_assign_pointer(sta_info->agg[i], NULL); if (!tid_info) continue; @@ -1399,7 +1416,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, spin_unlock_bh(&ar->tx_ampdu_list_lock); } - RCU_INIT_POINTER(sta_info->agg[tid], NULL); + rcu_assign_pointer(sta_info->agg[tid], NULL); rcu_read_unlock(); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -1797,9 +1814,6 @@ void *carl9170_alloc(size_t priv_size) ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - - /* As IBSS Encryption is software-based, IBSS RSN is supported. */ - hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; return ar; err_nomem: @@ -1935,6 +1949,10 @@ int carl9170_register(struct ar9170 *ar) if (err) return err; + err = carl9170_fw_fix_eeprom(ar); + if (err) + return err; + err = carl9170_parse_eeprom(ar); if (err) return err; diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index b72c09cf..472efc7e 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -1426,15 +1426,15 @@ static void carl9170_calc_ctl(struct ar9170 *ar, u32 freq, enum carl9170_bw bw) #undef EDGES } -static void carl9170_set_power_cal(struct ar9170 *ar, u32 freq, - enum carl9170_bw bw) +static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq, + enum carl9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; struct ar9170_calibration_target_power_ht *ctph; u8 *ctpres; int ntargets; int idx, i, n; - u8 f; + u8 ackpower, ackchains, f; u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; if (freq < 3000) @@ -1523,6 +1523,32 @@ static void carl9170_set_power_cal(struct ar9170 *ar, u32 freq, /* calc. conformance test limits and apply to ar->power*[] */ carl9170_calc_ctl(ar, freq, bw); + + /* set ACK/CTS TX power */ + carl9170_regwrite_begin(ar); + + if (ar->eeprom.tx_mask != 1) + ackchains = AR9170_TX_PHY_TXCHAIN_2; + else + ackchains = AR9170_TX_PHY_TXCHAIN_1; + + if (freq < 3000) + ackpower = ar->power_2G_ofdm[0] & 0x3f; + else + ackpower = ar->power_5G_leg[0] & 0x3f; + + carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, + 0x3c1e | ackpower << 20 | ackchains << 26); + carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC, + ackpower << 5 | ackchains << 11 | + ackpower << 21 | ackchains << 27); + + carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC, + ackpower << 5 | ackchains << 11 | + ackpower << 21 | ackchains << 27); + + carl9170_regwrite_finish(); + return carl9170_regwrite_result(); } int carl9170_get_noisefloor(struct ar9170 *ar) @@ -1686,9 +1712,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, if (err) return err; - carl9170_set_power_cal(ar, channel->center_freq, bw); - - err = carl9170_set_mac_tpc(ar, channel); + err = carl9170_set_power_cal(ar, channel->center_freq, bw); if (err) return err; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index aed30517..59472e16 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -314,7 +314,7 @@ static void carl9170_tx_release(struct kref *ref) * feedback either [CTL_REQ_TX_STATUS not set] */ - ieee80211_free_txskb(ar->hw, skb); + dev_kfree_skb_any(skb); return; } else { /* @@ -719,8 +719,6 @@ static void carl9170_tx_rate_tpc_chains(struct ar9170 *ar, else *chains = AR9170_TX_PHY_TXCHAIN_2; } - - *tpc = min_t(unsigned int, *tpc, ar->hw->conf.power_level * 2); } static __le32 carl9170_tx_physet(struct ar9170 *ar, @@ -1236,7 +1234,6 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_sta *sta; struct carl9170_sta_info *sta_info; - struct ieee80211_tx_info *tx_info; rcu_read_lock(); sta = __carl9170_get_tx_sta(ar, skb); @@ -1244,18 +1241,16 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) goto out_rcu; sta_info = (void *) sta->drv_priv; - tx_info = IEEE80211_SKB_CB(skb); + if (unlikely(sta_info->sleeping)) { + struct ieee80211_tx_info *tx_info; - if (unlikely(sta_info->sleeping) && - !(tx_info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER | - IEEE80211_TX_CTL_CLEAR_PS_FILT))) { rcu_read_unlock(); + tx_info = IEEE80211_SKB_CB(skb); if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) atomic_dec(&ar->tx_ampdu_upload); tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - carl9170_release_dev_space(ar, skb); carl9170_tx_status(ar, skb, false); return true; } @@ -1437,7 +1432,7 @@ void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) err_free: ar->tx_dropped++; - ieee80211_free_txskb(ar->hw, skb); + dev_kfree_skb_any(skb); } void carl9170_tx_scheduler(struct ar9170 *ar) diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 89821e48..333b69ef 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -1161,4 +1161,15 @@ static struct usb_driver carl9170_driver = { #endif /* CONFIG_PM */ }; -module_usb_driver(carl9170_driver); +static int __init carl9170_usb_init(void) +{ + return usb_register(&carl9170_driver); +} + +static void __exit carl9170_usb_exit(void) +{ + usb_deregister(&carl9170_driver); +} + +module_init(carl9170_usb_init); +module_exit(carl9170_usb_exit); diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c old mode 100644 new mode 100755 diff --git a/drivers/power/msm_battery.c b/drivers/power/msm_battery.c index 801d01e0..df0297cd 100644 --- a/drivers/power/msm_battery.c +++ b/drivers/power/msm_battery.c @@ -68,9 +68,9 @@ #define MSM_BATT_POLLING_TIME (10 * HZ) -#define BATTERY_HIGH 4200 -#define BATTERY_LOW 3500 -#define BATTERY_ULTRA_LOW 3400 +#define BATTERY_HIGH 4300 +#define BATTERY_LOW 3400 +#define BATTERY_ULTRA_LOW 3200 #define TEMPERATURE_HOT 350 #define TEMPERATURE_COLD 50 diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index d7be4960..2fca70ce 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -82,14 +82,6 @@ source "drivers/staging/iio/Kconfig" source "drivers/staging/snappy/Kconfig" -source "drivers/staging/zram/Kconfig" - -source "drivers/staging/zcache/Kconfig" - -source "drivers/staging/qcache/Kconfig" - -source "drivers/staging/zsmalloc/Kconfig" - source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h25/Kconfig" @@ -100,6 +92,8 @@ source "drivers/staging/crystalhd/Kconfig" source "drivers/staging/cxt1e1/Kconfig" +source "drivers/staging/zcache/Kconfig" + source "drivers/staging/xgifb/Kconfig" source "drivers/staging/tidspbridge/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 150a7ce8..ab64895f 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -34,10 +34,7 @@ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_SNAPPY_COMPRESS) += snappy/ obj-$(CONFIG_SNAPPY_DECOMPRESS) += snappy/ -obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_ZCACHE) += zcache/ -obj-$(CONFIG_QCACHE) += qcache/ -obj-$(CONFIG_ZSMALLOC) += zsmalloc/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ obj-$(CONFIG_FB_SM7XX) += sm7xx/ diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 901066bc..a38faeda 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -34,10 +34,12 @@ #include #include #include +#include #include "binder.h" +#include "binder_trace.h" -static DEFINE_MUTEX(binder_lock); +static DEFINE_MUTEX(binder_main_lock); static DEFINE_MUTEX(binder_deferred_lock); static DEFINE_MUTEX(binder_mmap_lock); @@ -500,6 +502,19 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) return -EBADF; } +static inline void binder_lock(const char *tag) +{ + trace_binder_lock(tag); + mutex_lock(&binder_main_lock); + trace_binder_locked(tag); +} + +static inline void binder_unlock(const char *tag) +{ + trace_binder_unlock(tag); + mutex_unlock(&binder_main_lock); +} + static void binder_set_nice(long nice) { long min_nice; @@ -626,6 +641,8 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, if (end <= start) return 0; + trace_binder_update_page_range(proc, allocate, start, end); + if (vma) mm = NULL; else @@ -1211,8 +1228,9 @@ static int binder_inc_ref(struct binder_ref *ref, int strong, } -static int binder_dec_ref(struct binder_ref *ref, int strong) +static int binder_dec_ref(struct binder_ref **ptr_to_ref, int strong) { + struct binder_ref *ref = *ptr_to_ref; if (strong) { if (ref->strong == 0) { binder_user_error("binder: %d invalid dec strong, " @@ -1238,8 +1256,10 @@ static int binder_dec_ref(struct binder_ref *ref, int strong) } ref->weak--; } - if (ref->strong == 0 && ref->weak == 0) + if (ref->strong == 0 && ref->weak == 0) { binder_delete_ref(ref); + *ptr_to_ref = NULL; + } return 0; } @@ -1378,7 +1398,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d (node %d)\n", ref->debug_id, ref->desc, ref->node->debug_id); - binder_dec_ref(ref, fp->type == BINDER_TYPE_HANDLE); + binder_dec_ref(&ref, fp->type == BINDER_TYPE_HANDLE); } break; case BINDER_TYPE_FD: @@ -1404,6 +1424,7 @@ static void binder_transaction(struct binder_proc *proc, struct binder_transaction *t; struct binder_work *tcomplete; size_t *offp, *off_end; + size_t off_min; struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; @@ -1489,6 +1510,10 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_DEAD_REPLY; goto err_dead_binder; } + if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { + return_error = BR_FAILED_REPLY; + goto err_invalid_target_handle; + } if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; @@ -1565,6 +1590,9 @@ static void binder_transaction(struct binder_proc *proc, t->code = tr->code; t->flags = tr->flags; t->priority = task_nice(current); + + trace_binder_transaction(reply, t, target_node); + t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); if (t->buffer == NULL) { @@ -1575,6 +1603,7 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; + trace_binder_transaction_alloc_buf(t->buffer); if (target_node) binder_inc_node(target_node, 1, 0, NULL); @@ -1600,18 +1629,23 @@ static void binder_transaction(struct binder_proc *proc, goto err_bad_offset; } off_end = (void *)offp + tr->offsets_size; + off_min = 0; for (; offp < off_end; offp++) { struct flat_binder_object *fp; if (*offp > t->buffer->data_size - sizeof(*fp) || + *offp < off_min || t->buffer->data_size < sizeof(*fp) || - !IS_ALIGNED(*offp, sizeof(void *))) { - binder_user_error("binder: %d:%d got transaction with " - "invalid offset, %zd\n", - proc->pid, thread->pid, *offp); + !IS_ALIGNED(*offp, sizeof(u32))) { + binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n", + proc->pid, thread->pid, (u64)*offp, + (u64)off_min, + (u64)(t->buffer->data_size - + sizeof(*fp))); return_error = BR_FAILED_REPLY; goto err_bad_offset; } fp = (struct flat_binder_object *)(t->buffer->data + *offp); + off_min = *offp + sizeof(struct flat_binder_object); switch (fp->type) { case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { @@ -1634,6 +1668,10 @@ static void binder_transaction(struct binder_proc *proc, fp->cookie, node->cookie); goto err_binder_get_ref_for_node_failed; } + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + return_error = BR_FAILED_REPLY; + goto err_binder_get_ref_for_node_failed; + } ref = binder_get_ref_for_node(target_proc, node); if (ref == NULL) { return_error = BR_FAILED_REPLY; @@ -1647,6 +1685,7 @@ static void binder_transaction(struct binder_proc *proc, binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo); + trace_binder_transaction_node_to_ref(t, node, ref); binder_debug(BINDER_DEBUG_TRANSACTION, " node %d u%p -> ref %d desc %d\n", node->debug_id, node->ptr, ref->debug_id, @@ -1663,6 +1702,10 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_binder_get_ref_failed; } + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + return_error = BR_FAILED_REPLY; + goto err_binder_get_ref_failed; + } if (ref->node->proc == target_proc) { if (fp->type == BINDER_TYPE_HANDLE) fp->type = BINDER_TYPE_BINDER; @@ -1671,6 +1714,7 @@ static void binder_transaction(struct binder_proc *proc, fp->binder = ref->node->ptr; fp->cookie = ref->node->cookie; binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); + trace_binder_transaction_ref_to_node(t, ref); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> node %d u%p\n", ref->debug_id, ref->desc, ref->node->debug_id, @@ -1684,6 +1728,8 @@ static void binder_transaction(struct binder_proc *proc, } fp->handle = new_ref->desc; binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); + trace_binder_transaction_ref_to_ref(t, ref, + new_ref); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> ref %d desc %d (node %d)\n", ref->debug_id, ref->desc, new_ref->debug_id, @@ -1716,6 +1762,11 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_fget_failed; } + if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) { + fput(file); + return_error = BR_FAILED_REPLY; + goto err_get_unused_fd_failed; + } target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); if (target_fd < 0) { fput(file); @@ -1723,6 +1774,7 @@ static void binder_transaction(struct binder_proc *proc, goto err_get_unused_fd_failed; } task_fd_install(target_proc, target_fd, file); + trace_binder_transaction_fd(t, fp->handle, target_fd); binder_debug(BINDER_DEBUG_TRANSACTION, " fd %ld -> %d\n", fp->handle, target_fd); /* TODO: fput? */ @@ -1771,6 +1823,7 @@ static void binder_transaction(struct binder_proc *proc, err_bad_object_type: err_bad_offset: err_copy_data_failed: + trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); t->buffer->transaction = NULL; binder_free_buf(target_proc, t->buffer); @@ -1816,6 +1869,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, if (get_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); + trace_binder_command(cmd); if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { binder_stats.bc[_IOC_NR(cmd)]++; proc->stats.bc[_IOC_NR(cmd)]++; @@ -1864,18 +1918,24 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, break; case BC_RELEASE: debug_string = "Release"; - binder_dec_ref(ref, 1); + binder_dec_ref(&ref, 1); break; case BC_DECREFS: default: debug_string = "DecRefs"; - binder_dec_ref(ref, 0); + binder_dec_ref(&ref, 0); break; } - binder_debug(BINDER_DEBUG_USER_REFS, - "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n", - proc->pid, thread->pid, debug_string, ref->debug_id, - ref->desc, ref->strong, ref->weak, ref->node->debug_id); + if (ref == NULL) { + binder_debug(BINDER_DEBUG_USER_REFS, + "binder: %d:%d %s ref deleted", + proc->pid, thread->pid, debug_string); + } else { + binder_debug(BINDER_DEBUG_USER_REFS, + "binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n", + proc->pid, thread->pid, debug_string, ref->debug_id, + ref->desc, ref->strong, ref->weak, ref->node->debug_id); + } break; } case BC_INCREFS_DONE: @@ -1987,6 +2047,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, else list_move_tail(buffer->target_node->async_todo.next, &thread->todo); } + trace_binder_transaction_buffer_release(buffer); binder_transaction_buffer_release(proc, buffer, NULL); binder_free_buf(proc, buffer); break; @@ -2196,6 +2257,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, uint32_t cmd) { + trace_binder_return(cmd); if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { binder_stats.br[_IOC_NR(cmd)]++; proc->stats.br[_IOC_NR(cmd)]++; @@ -2257,7 +2319,12 @@ static int binder_thread_read(struct binder_proc *proc, thread->looper |= BINDER_LOOPER_STATE_WAITING; if (wait_for_proc_work) proc->ready_threads++; - mutex_unlock(&binder_lock); + + binder_unlock(__func__); + + trace_binder_wait_for_work(wait_for_proc_work, + !!thread->transaction_stack, + !list_empty(&thread->todo)); if (wait_for_proc_work) { if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { @@ -2281,7 +2348,9 @@ static int binder_thread_read(struct binder_proc *proc, } else ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); } - mutex_lock(&binder_lock); + + binder_lock(__func__); + if (wait_for_proc_work) proc->ready_threads--; thread->looper &= ~BINDER_LOOPER_STATE_WAITING; @@ -2471,6 +2540,7 @@ static int binder_thread_read(struct binder_proc *proc, return -EFAULT; ptr += sizeof(tr); + trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_TRANSACTION, "binder: %d:%d %s %d %d:%d, cmd %d" @@ -2647,12 +2717,14 @@ static unsigned int binder_poll(struct file *filp, struct binder_thread *thread = NULL; int wait_for_proc_work; - mutex_lock(&binder_lock); + binder_lock(__func__); + thread = binder_get_thread(proc); wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo) && thread->return_error == BR_OK; - mutex_unlock(&binder_lock); + + binder_unlock(__func__); if (wait_for_proc_work) { if (binder_has_proc_work(proc, thread)) @@ -2680,11 +2752,13 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ + trace_binder_ioctl(cmd, arg); + ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) - return ret; + goto err_unlocked; - mutex_lock(&binder_lock); + binder_lock(__func__); thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; @@ -2709,6 +2783,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (bwr.write_size > 0) { ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); + trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; if (copy_to_user(ubuf, &bwr, sizeof(bwr))) @@ -2718,6 +2793,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } if (bwr.read_size > 0) { ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); + trace_binder_read_done(ret); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); if (ret < 0) { @@ -2749,6 +2825,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = -EBUSY; goto err; } + ret = security_binder_set_context_mgr(proc->tsk); + if (ret < 0) + goto err; if (binder_context_mgr_uid != -1) { if (binder_context_mgr_uid != current->cred->euid) { binder_debug(BINDER_DEBUG_TOP_ERRORS, @@ -2795,12 +2874,14 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) err: if (thread) thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; - mutex_unlock(&binder_lock); + binder_unlock(__func__); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) binder_debug(BINDER_DEBUG_TOP_ERRORS, "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); +err_unlocked: + trace_binder_ioctl_done(ret); return ret; } @@ -2946,13 +3027,16 @@ static int binder_open(struct inode *nodp, struct file *filp) INIT_LIST_HEAD(&proc->todo); init_waitqueue_head(&proc->wait); proc->default_priority = task_nice(current); - mutex_lock(&binder_lock); + + binder_lock(__func__); + binder_stats_created(BINDER_STAT_PROC); hlist_add_head(&proc->proc_node, &binder_procs); proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); filp->private_data = proc; - mutex_unlock(&binder_lock); + + binder_unlock(__func__); if (binder_debugfs_dir_entry_proc) { char strbuf[11]; @@ -3135,7 +3219,7 @@ static void binder_deferred_func(struct work_struct *work) int defer; do { - mutex_lock(&binder_lock); + binder_lock(__func__); mutex_lock(&binder_deferred_lock); if (!hlist_empty(&binder_deferred_list)) { proc = hlist_entry(binder_deferred_list.first, @@ -3162,7 +3246,7 @@ static void binder_deferred_func(struct work_struct *work) if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - mutex_unlock(&binder_lock); + binder_unlock(__func__); if (files) put_files_struct(files); } while (proc); @@ -3503,7 +3587,7 @@ static int binder_state_show(struct seq_file *m, void *unused) int do_lock = !binder_debug_no_lock; if (do_lock) - mutex_lock(&binder_lock); + binder_lock(__func__); seq_puts(m, "binder state:\n"); @@ -3515,7 +3599,7 @@ static int binder_state_show(struct seq_file *m, void *unused) hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc(m, proc, 1); if (do_lock) - mutex_unlock(&binder_lock); + binder_unlock(__func__); return 0; } @@ -3526,7 +3610,7 @@ static int binder_stats_show(struct seq_file *m, void *unused) int do_lock = !binder_debug_no_lock; if (do_lock) - mutex_lock(&binder_lock); + binder_lock(__func__); seq_puts(m, "binder stats:\n"); @@ -3535,7 +3619,7 @@ static int binder_stats_show(struct seq_file *m, void *unused) hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc_stats(m, proc); if (do_lock) - mutex_unlock(&binder_lock); + binder_unlock(__func__); return 0; } @@ -3546,27 +3630,39 @@ static int binder_transactions_show(struct seq_file *m, void *unused) int do_lock = !binder_debug_no_lock; if (do_lock) - mutex_lock(&binder_lock); + binder_lock(__func__); seq_puts(m, "binder transactions:\n"); hlist_for_each_entry(proc, pos, &binder_procs, proc_node) print_binder_proc(m, proc, 0); if (do_lock) - mutex_unlock(&binder_lock); + binder_unlock(__func__); return 0; } static int binder_proc_show(struct seq_file *m, void *unused) { - struct binder_proc *proc = m->private; - int do_lock = !binder_debug_no_lock; + struct binder_proc *itr; + struct binder_proc *proc = m->private; + struct hlist_node *pos; + int do_lock = !binder_debug_no_lock; + bool valid_proc = false; if (do_lock) - mutex_lock(&binder_lock); - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, proc, 1); + binder_lock(__func__); + + hlist_for_each_entry(itr, pos, &binder_procs, proc_node) { + if (itr == proc) { + valid_proc = true; + break; + } + } + if (valid_proc) { + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, proc, 1); + } if (do_lock) - mutex_unlock(&binder_lock); + binder_unlock(__func__); return 0; } @@ -3661,4 +3757,7 @@ static int __init binder_init(void) device_initcall(binder_init); +#define CREATE_TRACE_POINTS +#include + MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/android/binder_trace.h b/drivers/staging/android/binder_trace.h new file mode 100644 index 00000000..12ef1e93 --- /dev/null +++ b/drivers/staging/android/binder_trace.h @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2012 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. + * + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM binder + +#if !defined(_BINDER_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _BINDER_TRACE_H + +#include + +struct binder_buffer; +struct binder_node; +struct binder_proc; +struct binder_ref; +struct binder_thread; +struct binder_transaction; + +TRACE_EVENT(binder_ioctl, + TP_PROTO(unsigned int cmd, unsigned long arg), + TP_ARGS(cmd, arg), + + TP_STRUCT__entry( + __field(unsigned int, cmd) + __field(unsigned long, arg) + ), + TP_fast_assign( + __entry->cmd = cmd; + __entry->arg = arg; + ), + TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg) +); + +DECLARE_EVENT_CLASS(binder_lock_class, + TP_PROTO(const char *tag), + TP_ARGS(tag), + TP_STRUCT__entry( + __field(const char *, tag) + ), + TP_fast_assign( + __entry->tag = tag; + ), + TP_printk("tag=%s", __entry->tag) +); + +#define DEFINE_BINDER_LOCK_EVENT(name) \ +DEFINE_EVENT(binder_lock_class, name, \ + TP_PROTO(const char *func), \ + TP_ARGS(func)) + +DEFINE_BINDER_LOCK_EVENT(binder_lock); +DEFINE_BINDER_LOCK_EVENT(binder_locked); +DEFINE_BINDER_LOCK_EVENT(binder_unlock); + +DECLARE_EVENT_CLASS(binder_function_return_class, + TP_PROTO(int ret), + TP_ARGS(ret), + TP_STRUCT__entry( + __field(int, ret) + ), + TP_fast_assign( + __entry->ret = ret; + ), + TP_printk("ret=%d", __entry->ret) +); + +#define DEFINE_BINDER_FUNCTION_RETURN_EVENT(name) \ +DEFINE_EVENT(binder_function_return_class, name, \ + TP_PROTO(int ret), \ + TP_ARGS(ret)) + +DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done); +DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done); +DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done); + +TRACE_EVENT(binder_wait_for_work, + TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo), + TP_ARGS(proc_work, transaction_stack, thread_todo), + + TP_STRUCT__entry( + __field(bool, proc_work) + __field(bool, transaction_stack) + __field(bool, thread_todo) + ), + TP_fast_assign( + __entry->proc_work = proc_work; + __entry->transaction_stack = transaction_stack; + __entry->thread_todo = thread_todo; + ), + TP_printk("proc_work=%d transaction_stack=%d thread_todo=%d", + __entry->proc_work, __entry->transaction_stack, + __entry->thread_todo) +); + +TRACE_EVENT(binder_transaction, + TP_PROTO(bool reply, struct binder_transaction *t, + struct binder_node *target_node), + TP_ARGS(reply, t, target_node), + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, target_node) + __field(int, to_proc) + __field(int, to_thread) + __field(int, reply) + __field(unsigned int, code) + __field(unsigned int, flags) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->target_node = target_node ? target_node->debug_id : 0; + __entry->to_proc = t->to_proc->pid; + __entry->to_thread = t->to_thread ? t->to_thread->pid : 0; + __entry->reply = reply; + __entry->code = t->code; + __entry->flags = t->flags; + ), + TP_printk("transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x code=0x%x", + __entry->debug_id, __entry->target_node, + __entry->to_proc, __entry->to_thread, + __entry->reply, __entry->flags, __entry->code) +); + +TRACE_EVENT(binder_transaction_received, + TP_PROTO(struct binder_transaction *t), + TP_ARGS(t), + + TP_STRUCT__entry( + __field(int, debug_id) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + ), + TP_printk("transaction=%d", __entry->debug_id) +); + +TRACE_EVENT(binder_transaction_node_to_ref, + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref *ref), + TP_ARGS(t, node, ref), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, node_debug_id) + __field(void __user *, node_ptr) + __field(int, ref_debug_id) + __field(uint32_t, ref_desc) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->node_debug_id = node->debug_id; + __entry->node_ptr = node->ptr; + __entry->ref_debug_id = ref->debug_id; + __entry->ref_desc = ref->desc; + ), + TP_printk("transaction=%d node=%d src_ptr=0x%p ==> dest_ref=%d dest_desc=%d", + __entry->debug_id, __entry->node_debug_id, __entry->node_ptr, + __entry->ref_debug_id, __entry->ref_desc) +); + +TRACE_EVENT(binder_transaction_ref_to_node, + TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), + TP_ARGS(t, ref), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, ref_debug_id) + __field(uint32_t, ref_desc) + __field(int, node_debug_id) + __field(void __user *, node_ptr) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->ref_debug_id = ref->debug_id; + __entry->ref_desc = ref->desc; + __entry->node_debug_id = ref->node->debug_id; + __entry->node_ptr = ref->node->ptr; + ), + TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%p", + __entry->debug_id, __entry->node_debug_id, + __entry->ref_debug_id, __entry->ref_desc, __entry->node_ptr) +); + +TRACE_EVENT(binder_transaction_ref_to_ref, + TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, + struct binder_ref *dest_ref), + TP_ARGS(t, src_ref, dest_ref), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, node_debug_id) + __field(int, src_ref_debug_id) + __field(uint32_t, src_ref_desc) + __field(int, dest_ref_debug_id) + __field(uint32_t, dest_ref_desc) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->node_debug_id = src_ref->node->debug_id; + __entry->src_ref_debug_id = src_ref->debug_id; + __entry->src_ref_desc = src_ref->desc; + __entry->dest_ref_debug_id = dest_ref->debug_id; + __entry->dest_ref_desc = dest_ref->desc; + ), + TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ref=%d dest_desc=%d", + __entry->debug_id, __entry->node_debug_id, + __entry->src_ref_debug_id, __entry->src_ref_desc, + __entry->dest_ref_debug_id, __entry->dest_ref_desc) +); + +TRACE_EVENT(binder_transaction_fd, + TP_PROTO(struct binder_transaction *t, int src_fd, int dest_fd), + TP_ARGS(t, src_fd, dest_fd), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, src_fd) + __field(int, dest_fd) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->src_fd = src_fd; + __entry->dest_fd = dest_fd; + ), + TP_printk("transaction=%d src_fd=%d ==> dest_fd=%d", + __entry->debug_id, __entry->src_fd, __entry->dest_fd) +); + +DECLARE_EVENT_CLASS(binder_buffer_class, + TP_PROTO(struct binder_buffer *buf), + TP_ARGS(buf), + TP_STRUCT__entry( + __field(int, debug_id) + __field(size_t, data_size) + __field(size_t, offsets_size) + ), + TP_fast_assign( + __entry->debug_id = buf->debug_id; + __entry->data_size = buf->data_size; + __entry->offsets_size = buf->offsets_size; + ), + TP_printk("transaction=%d data_size=%zd offsets_size=%zd", + __entry->debug_id, __entry->data_size, __entry->offsets_size) +); + +DEFINE_EVENT(binder_buffer_class, binder_transaction_alloc_buf, + TP_PROTO(struct binder_buffer *buffer), + TP_ARGS(buffer)); + +DEFINE_EVENT(binder_buffer_class, binder_transaction_buffer_release, + TP_PROTO(struct binder_buffer *buffer), + TP_ARGS(buffer)); + +DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, + TP_PROTO(struct binder_buffer *buffer), + TP_ARGS(buffer)); + +TRACE_EVENT(binder_update_page_range, + TP_PROTO(struct binder_proc *proc, bool allocate, + void *start, void *end), + TP_ARGS(proc, allocate, start, end), + TP_STRUCT__entry( + __field(int, proc) + __field(bool, allocate) + __field(size_t, offset) + __field(size_t, size) + ), + TP_fast_assign( + __entry->proc = proc->pid; + __entry->allocate = allocate; + __entry->offset = start - proc->buffer; + __entry->size = end - start; + ), + TP_printk("proc=%d allocate=%d offset=%zu size=%zu", + __entry->proc, __entry->allocate, + __entry->offset, __entry->size) +); + +TRACE_EVENT(binder_command, + TP_PROTO(uint32_t cmd), + TP_ARGS(cmd), + TP_STRUCT__entry( + __field(uint32_t, cmd) + ), + TP_fast_assign( + __entry->cmd = cmd; + ), + TP_printk("cmd=0x%x %s", + __entry->cmd, + _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_command_strings) ? + binder_command_strings[_IOC_NR(__entry->cmd)] : + "unknown") +); + +TRACE_EVENT(binder_return, + TP_PROTO(uint32_t cmd), + TP_ARGS(cmd), + TP_STRUCT__entry( + __field(uint32_t, cmd) + ), + TP_fast_assign( + __entry->cmd = cmd; + ), + TP_printk("cmd=0x%x %s", + __entry->cmd, + _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_return_strings) ? + binder_return_strings[_IOC_NR(__entry->cmd)] : + "unknown") +); + +#endif /* _BINDER_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE binder_trace +#include "trace/define_trace.h" diff --git a/drivers/staging/qcache/Kconfig b/drivers/staging/qcache/Kconfig deleted file mode 100644 index 389341cf..00000000 --- a/drivers/staging/qcache/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config QCACHE - tristate "Dynamic compression of clean pagecache pages" - depends on CLEANCACHE - select LZO_COMPRESS - select LZO_DECOMPRESS - default n - help - Qcache is the backend for fmem diff --git a/drivers/staging/qcache/Makefile b/drivers/staging/qcache/Makefile deleted file mode 100644 index 4fdf05c1..00000000 --- a/drivers/staging/qcache/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -qcache-y := qcache-main.o tmem.o fmem.o - -obj-$(CONFIG_QCACHE) += qcache.o diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c deleted file mode 100644 index 0609f4af..00000000 --- a/drivers/staging/qcache/fmem.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#ifdef CONFIG_MEMORY_HOTPLUG -#include -#include -#endif -#include "tmem.h" -#include - -struct fmem_data fmem_data; -enum fmem_state fmem_state; -static spinlock_t fmem_state_lock; - -#ifdef CONFIG_MEMORY_HOTPLUG -static unsigned int section_powered_off[NR_MEM_SECTIONS]; -static unsigned int fmem_section_start, fmem_section_end; -#endif - -void *fmem_map_virtual_area(int cacheability) -{ - unsigned long addr; - const struct mem_type *type; - int ret; - - addr = (unsigned long) fmem_data.area->addr; - type = get_mem_type(cacheability); - ret = ioremap_pages(addr, fmem_data.phys, fmem_data.size, type); - if (ret) - return ERR_PTR(ret); - - fmem_data.virt = fmem_data.area->addr; - - return fmem_data.virt; -} - -void fmem_unmap_virtual_area(void) -{ - unmap_kernel_range((unsigned long)fmem_data.virt, fmem_data.size); - fmem_data.virt = NULL; -} - -static int fmem_probe(struct platform_device *pdev) -{ - struct fmem_platform_data *pdata = pdev->dev.platform_data; - - if (!pdata->phys) - pdata->phys = allocate_contiguous_ebi_nomap(pdata->size, - pdata->align); - -#ifdef CONFIG_MEMORY_HOTPLUG - fmem_section_start = pdata->phys >> PA_SECTION_SHIFT; - fmem_section_end = (pdata->phys - 1 + pdata->size) >> PA_SECTION_SHIFT; -#endif - fmem_data.phys = pdata->phys + pdata->reserved_size_low; - fmem_data.size = pdata->size - pdata->reserved_size_low - - pdata->reserved_size_high; - fmem_data.reserved_size_low = pdata->reserved_size_low; - fmem_data.reserved_size_high = pdata->reserved_size_high; - - if (!fmem_data.size) - return -ENODEV; - - fmem_data.area = get_vm_area(fmem_data.size, VM_IOREMAP); - if (!fmem_data.area) - return -ENOMEM; - - if (!fmem_map_virtual_area(MT_DEVICE_CACHED)) { - remove_vm_area(fmem_data.area->addr); - return -ENOMEM; - } - pr_info("fmem phys %lx virt %p size %lx\n", - fmem_data.phys, fmem_data.virt, fmem_data.size); - - spin_lock_init(&fmem_state_lock); - - return 0; -} - -static int fmem_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver fmem_driver = { - .probe = fmem_probe, - .remove = fmem_remove, - .driver = { .name = "fmem" } -}; - -#ifdef CONFIG_SYSFS -static ssize_t fmem_state_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - if (fmem_state == FMEM_T_STATE) - return snprintf(buf, 3, "t\n"); - else if (fmem_state == FMEM_C_STATE) - return snprintf(buf, 3, "c\n"); -#ifdef CONFIG_MEMORY_HOTPLUG - else if (fmem_state == FMEM_O_STATE) - return snprintf(buf, 3, "o\n"); -#endif - else if (fmem_state == FMEM_UNINITIALIZED) - return snprintf(buf, 15, "uninitialized\n"); - return snprintf(buf, 3, "?\n"); -} - -static ssize_t fmem_state_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - int ret = -EINVAL; - - if (!strncmp(buf, "t", 1)) - ret = fmem_set_state(FMEM_T_STATE); - else if (!strncmp(buf, "c", 1)) - ret = fmem_set_state(FMEM_C_STATE); -#ifdef CONFIG_MEMORY_HOTPLUG - else if (!strncmp(buf, "o", 1)) - ret = fmem_set_state(FMEM_O_STATE); -#endif - if (ret) - return ret; - return 1; -} - -static struct kobj_attribute fmem_state_attr = { - .attr = { .name = "state", .mode = 0644 }, - .show = fmem_state_show, - .store = fmem_state_store, -}; - -static struct attribute *fmem_attrs[] = { - &fmem_state_attr.attr, - NULL, -}; - -static struct attribute_group fmem_attr_group = { - .attrs = fmem_attrs, - .name = "fmem", -}; - -static int fmem_create_sysfs(void) -{ - int ret = 0; - - ret = sysfs_create_group(mm_kobj, &fmem_attr_group); - if (ret) - pr_err("fmem: can't create sysfs\n"); - return ret; -} - -#endif - -#ifdef CONFIG_MEMORY_HOTPLUG -bool fmem_is_disjoint(unsigned long start_pfn, unsigned long nr_pages) -{ - unsigned long fmem_start_pfn, fmem_end_pfn; - unsigned long unstable_end_pfn; - unsigned long highest_start_pfn, lowest_end_pfn; - - fmem_start_pfn = (fmem_data.phys - fmem_data.reserved_size_low) - >> PAGE_SHIFT; - fmem_end_pfn = (fmem_data.phys + fmem_data.size + - fmem_data.reserved_size_high - 1) >> PAGE_SHIFT; - unstable_end_pfn = start_pfn + nr_pages - 1; - - highest_start_pfn = max(fmem_start_pfn, start_pfn); - lowest_end_pfn = min(fmem_end_pfn, unstable_end_pfn); - - return lowest_end_pfn < highest_start_pfn; -} - -static int fmem_mem_going_offline_callback(void *arg) -{ - struct memory_notify *marg = arg; - - if (fmem_is_disjoint(marg->start_pfn, marg->nr_pages)) - return 0; - return fmem_set_state(FMEM_O_STATE); -} - -static void fmem_mem_online_callback(void *arg) -{ - struct memory_notify *marg = arg; - int i; - - section_powered_off[marg->start_pfn >> PFN_SECTION_SHIFT] = 0; - - if (fmem_state != FMEM_O_STATE) - return; - - for (i = fmem_section_start; i <= fmem_section_end; i++) { - if (section_powered_off[i]) - return; - } - - fmem_set_state(FMEM_T_STATE); -} - -static void fmem_mem_offline_callback(void *arg) -{ - struct memory_notify *marg = arg; - - section_powered_off[marg->start_pfn >> PFN_SECTION_SHIFT] = 1; -} - -static int fmem_memory_callback(struct notifier_block *self, - unsigned long action, void *arg) -{ - int ret = 0; - - if (fmem_state == FMEM_UNINITIALIZED) - return NOTIFY_OK; - - switch (action) { - case MEM_ONLINE: - fmem_mem_online_callback(arg); - break; - case MEM_GOING_OFFLINE: - ret = fmem_mem_going_offline_callback(arg); - break; - case MEM_OFFLINE: - fmem_mem_offline_callback(arg); - break; - case MEM_GOING_ONLINE: - case MEM_CANCEL_ONLINE: - case MEM_CANCEL_OFFLINE: - break; - } - if (ret) - ret = notifier_from_errno(ret); - else - ret = NOTIFY_OK; - return ret; -} -#endif - -static int __init fmem_init(void) -{ -#ifdef CONFIG_MEMORY_HOTPLUG - hotplug_memory_notifier(fmem_memory_callback, 0); -#endif - return platform_driver_register(&fmem_driver); -} - -static void __exit fmem_exit(void) -{ - platform_driver_unregister(&fmem_driver); -} - -struct fmem_data *fmem_get_info(void) -{ - return &fmem_data; -} -EXPORT_SYMBOL(fmem_get_info); - -void lock_fmem_state(void) -{ - spin_lock(&fmem_state_lock); -} - -void unlock_fmem_state(void) -{ - spin_unlock(&fmem_state_lock); -} - -int fmem_set_state(enum fmem_state new_state) -{ - int ret = 0; - int create_sysfs = 0; - - lock_fmem_state(); - if (fmem_state == new_state) - goto out; - - if (fmem_state == FMEM_UNINITIALIZED) { - if (new_state == FMEM_T_STATE) { - tmem_enable(); - create_sysfs = 1; - goto out_set; - } else { - ret = -EINVAL; - goto out; - } - } - -#ifdef CONFIG_MEMORY_HOTPLUG - if (fmem_state == FMEM_C_STATE && new_state == FMEM_O_STATE) { - ret = -EAGAIN; - goto out; - } - - if (fmem_state == FMEM_O_STATE && new_state == FMEM_C_STATE) { - pr_warn("attempting to use powered off memory as fmem\n"); - ret = -EAGAIN; - goto out; - } -#endif - - if (new_state == FMEM_T_STATE) { - void *v; - v = fmem_map_virtual_area(MT_DEVICE_CACHED); - if (IS_ERR_OR_NULL(v)) { - ret = PTR_ERR(v); - goto out; - } - tmem_enable(); - } else { - tmem_disable(); - fmem_unmap_virtual_area(); - } - -out_set: - fmem_state = new_state; -out: - unlock_fmem_state(); -#ifdef CONFIG_SYSFS - if (create_sysfs) - fmem_create_sysfs(); -#endif - return ret; -} -EXPORT_SYMBOL(fmem_set_state); - -arch_initcall(fmem_init); -module_exit(fmem_exit); diff --git a/drivers/staging/qcache/qcache-main.c b/drivers/staging/qcache/qcache-main.c deleted file mode 100644 index f416cfcb..00000000 --- a/drivers/staging/qcache/qcache-main.c +++ /dev/null @@ -1,1358 +0,0 @@ -/* - * Copyright (c) 2010,2011, Dan Magenheimer, Oracle Corp. - * Copyright (c) 2010,2011, Nitin Gupta - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. - * - * Qcache provides an in-kernel "host implementation" for transcendent memory - * and, thus indirectly, for cleancache and frontswap. Qcache includes a - * page-accessible memory [1] interface, utilizing lzo1x compression: - * 1) "compression buddies" ("zbud") is used for ephemeral pages - * Zbud allows pairs (and potentially, - * in the future, more than a pair of) compressed pages to be closely linked - * so that reclaiming can be done via the kernel's physical-page-oriented - * "shrinker" interface. - * - * [1] For a definition of page-accessible memory (aka PAM), see: - * http://marc.info/?l=linux-mm&m=127811271605009 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tmem.h" - -#if !defined(CONFIG_CLEANCACHE) -#error "qcache is useless without CONFIG_CLEANCACHE" -#endif -#include - -#define ZCACHE_GFP_MASK \ - (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC) - -#define MAX_POOLS_PER_CLIENT 16 - -#define MAX_CLIENTS 16 -#define LOCAL_CLIENT ((uint16_t)-1) - -MODULE_LICENSE("GPL"); - -struct zcache_client { - struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT]; - struct xv_pool *xvpool; - bool allocated; - atomic_t refcount; -}; - -struct qcache_info { - void *addr; - unsigned long *bitmap; - spinlock_t lock; - unsigned pages; -}; -static struct qcache_info qcache_info; -static unsigned long zcache_qc_allocated; -static unsigned long zcache_qc_freed; -static unsigned long zcache_qc_used; -static unsigned long zcache_qc_max_used; - -static struct zcache_client zcache_host; -static struct zcache_client zcache_clients[MAX_CLIENTS]; - -static inline uint16_t get_client_id_from_client(struct zcache_client *cli) -{ - BUG_ON(cli == NULL); - if (cli == &zcache_host) - return LOCAL_CLIENT; - return cli - &zcache_clients[0]; -} - -static inline bool is_local_client(struct zcache_client *cli) -{ - return cli == &zcache_host; -} - -/********** - * Compression buddies ("zbud") provides for packing two (or, possibly - * in the future, more) compressed ephemeral pages into a single "raw" - * (physical) page and tracking them with data structures so that - * the raw pages can be easily reclaimed. - * - * A zbud page ("zbpg") is an aligned page containing a list_head, - * a lock, and two "zbud headers". The remainder of the physical - * page is divided up into aligned 64-byte "chunks" which contain - * the compressed data for zero, one, or two zbuds. Each zbpg - * resides on: (1) an "unused list" if it has no zbuds; (2) a - * "buddied" list if it is fully populated with two zbuds; or - * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks - * the one unbuddied zbud uses. The data inside a zbpg cannot be - * read or written unless the zbpg's lock is held. - */ - -#define ZBH_SENTINEL 0x43214321 -#define ZBPG_SENTINEL 0xdeadbeef - -#define ZBUD_MAX_BUDS 2 - -struct zbud_hdr { - uint16_t client_id; - uint16_t pool_id; - struct tmem_oid oid; - uint32_t index; - uint16_t size; /* compressed size in bytes, zero means unused */ - DECL_SENTINEL -}; - -struct zbud_page { - struct list_head bud_list; - spinlock_t lock; - struct zbud_hdr buddy[ZBUD_MAX_BUDS]; - DECL_SENTINEL - /* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */ -}; - -#define CHUNK_SHIFT 6 -#define CHUNK_SIZE (1 << CHUNK_SHIFT) -#define CHUNK_MASK (~(CHUNK_SIZE-1)) -#define NCHUNKS (((PAGE_SIZE - sizeof(struct zbud_page)) & \ - CHUNK_MASK) >> CHUNK_SHIFT) -#define MAX_CHUNK (NCHUNKS-1) - -static struct { - struct list_head list; - unsigned count; -} zbud_unbuddied[NCHUNKS]; -/* list N contains pages with N chunks USED and NCHUNKS-N unused */ -/* element 0 is never used but optimizing that isn't worth it */ -static unsigned long zbud_cumul_chunk_counts[NCHUNKS]; - -struct list_head zbud_buddied_list; -static unsigned long zcache_zbud_buddied_count; - -/* protects the buddied list and all unbuddied lists */ -static DEFINE_SPINLOCK(zbud_budlists_spinlock); - -static atomic_t zcache_zbud_curr_raw_pages; -static atomic_t zcache_zbud_curr_zpages; -static unsigned long zcache_zbud_curr_zbytes; -static unsigned long zcache_zbud_cumul_zpages; -static unsigned long zcache_zbud_cumul_zbytes; -static unsigned long zcache_compress_poor; -static unsigned long zcache_mean_compress_poor; - -/* forward references */ -static void *zcache_get_free_page(void); - -static void *qcache_alloc(void) -{ - void *addr; - unsigned long flags; - int offset; - struct qcache_info *qc = &qcache_info; - - spin_lock_irqsave(&qc->lock, flags); - offset = bitmap_find_free_region(qc->bitmap, qc->pages, 0); - - if (offset < 0) { - spin_unlock_irqrestore(&qc->lock, flags); - return NULL; - } - - zcache_qc_allocated++; - zcache_qc_used++; - zcache_qc_max_used = max(zcache_qc_max_used, zcache_qc_used); - spin_unlock_irqrestore(&qc->lock, flags); - - addr = qc->addr + offset * PAGE_SIZE; - - return addr; -} - -static void qcache_free(void *addr) -{ - unsigned long flags; - int offset; - struct qcache_info *qc = &qcache_info; - - offset = (addr - qc->addr) / PAGE_SIZE; - - spin_lock_irqsave(&qc->lock, flags); - bitmap_release_region(qc->bitmap, offset, 0); - - zcache_qc_freed++; - zcache_qc_used--; - spin_unlock_irqrestore(&qc->lock, flags); -} - -/* - * zbud helper functions - */ - -static inline unsigned zbud_max_buddy_size(void) -{ - return MAX_CHUNK << CHUNK_SHIFT; -} - -static inline unsigned zbud_size_to_chunks(unsigned size) -{ - BUG_ON(size == 0 || size > zbud_max_buddy_size()); - return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT; -} - -static inline int zbud_budnum(struct zbud_hdr *zh) -{ - unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1); - struct zbud_page *zbpg = NULL; - unsigned budnum = -1U; - int i; - - for (i = 0; i < ZBUD_MAX_BUDS; i++) - if (offset == offsetof(typeof(*zbpg), buddy[i])) { - budnum = i; - break; - } - BUG_ON(budnum == -1U); - return budnum; -} - -static char *zbud_data(struct zbud_hdr *zh, unsigned size) -{ - struct zbud_page *zbpg; - char *p; - unsigned budnum; - - ASSERT_SENTINEL(zh, ZBH); - budnum = zbud_budnum(zh); - BUG_ON(size == 0 || size > zbud_max_buddy_size()); - zbpg = container_of(zh, struct zbud_page, buddy[budnum]); - p = (char *)zbpg; - if (budnum == 0) - p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) & - CHUNK_MASK); - else if (budnum == 1) - p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK); - return p; -} - -/* - * zbud raw page management - */ - -static struct zbud_page *zbud_alloc_raw_page(void) -{ - struct zbud_page *zbpg = NULL; - struct zbud_hdr *zh0, *zh1; - - zbpg = zcache_get_free_page(); - if (likely(zbpg != NULL)) { - INIT_LIST_HEAD(&zbpg->bud_list); - zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1]; - spin_lock_init(&zbpg->lock); - atomic_inc(&zcache_zbud_curr_raw_pages); - INIT_LIST_HEAD(&zbpg->bud_list); - SET_SENTINEL(zbpg, ZBPG); - zh0->size = 0; zh1->size = 0; - tmem_oid_set_invalid(&zh0->oid); - tmem_oid_set_invalid(&zh1->oid); - } - return zbpg; -} - -static void zbud_free_raw_page(struct zbud_page *zbpg) -{ - struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1]; - - ASSERT_SENTINEL(zbpg, ZBPG); - BUG_ON(!list_empty(&zbpg->bud_list)); - BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid)); - BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid)); - INVERT_SENTINEL(zbpg, ZBPG); - spin_unlock(&zbpg->lock); - qcache_free(zbpg); -} - -/* - * core zbud handling routines - */ - -static unsigned zbud_free(struct zbud_hdr *zh) -{ - unsigned size; - - ASSERT_SENTINEL(zh, ZBH); - BUG_ON(!tmem_oid_valid(&zh->oid)); - size = zh->size; - BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size()); - zh->size = 0; - tmem_oid_set_invalid(&zh->oid); - INVERT_SENTINEL(zh, ZBH); - zcache_zbud_curr_zbytes -= size; - atomic_dec(&zcache_zbud_curr_zpages); - return size; -} - -static void zbud_free_and_delist(struct zbud_hdr *zh) -{ - unsigned chunks; - struct zbud_hdr *zh_other; - unsigned budnum = zbud_budnum(zh), size; - struct zbud_page *zbpg = - container_of(zh, struct zbud_page, buddy[budnum]); - - spin_lock(&zbpg->lock); - if (list_empty(&zbpg->bud_list)) { - spin_unlock(&zbpg->lock); - return; - } - size = zbud_free(zh); - zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0]; - if (zh_other->size == 0) { /* was unbuddied: unlist and free */ - chunks = zbud_size_to_chunks(size) ; - spin_lock(&zbud_budlists_spinlock); - BUG_ON(list_empty(&zbud_unbuddied[chunks].list)); - list_del_init(&zbpg->bud_list); - zbud_unbuddied[chunks].count--; - spin_unlock(&zbud_budlists_spinlock); - zbud_free_raw_page(zbpg); - } else { /* was buddied: move remaining buddy to unbuddied list */ - chunks = zbud_size_to_chunks(zh_other->size) ; - spin_lock(&zbud_budlists_spinlock); - list_del_init(&zbpg->bud_list); - zcache_zbud_buddied_count--; - list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list); - zbud_unbuddied[chunks].count++; - spin_unlock(&zbud_budlists_spinlock); - spin_unlock(&zbpg->lock); - } -} - -static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id, - struct tmem_oid *oid, - uint32_t index, struct page *page, - void *cdata, unsigned size) -{ - struct zbud_hdr *zh0, *zh1, *zh = NULL; - struct zbud_page *zbpg = NULL, *ztmp; - unsigned nchunks; - char *to; - int i, found_good_buddy = 0; - - nchunks = zbud_size_to_chunks(size) ; - for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) { - spin_lock(&zbud_budlists_spinlock); - if (!list_empty(&zbud_unbuddied[i].list)) { - list_for_each_entry_safe(zbpg, ztmp, - &zbud_unbuddied[i].list, bud_list) { - if (spin_trylock(&zbpg->lock)) { - found_good_buddy = i; - goto found_unbuddied; - } - } - } - spin_unlock(&zbud_budlists_spinlock); - } - /* didn't find a good buddy, try allocating a new page */ - zbpg = zbud_alloc_raw_page(); - if (unlikely(zbpg == NULL)) - goto out; - /* ok, have a page, now compress the data before taking locks */ - spin_lock(&zbpg->lock); - spin_lock(&zbud_budlists_spinlock); - list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list); - zbud_unbuddied[nchunks].count++; - zh = &zbpg->buddy[0]; - goto init_zh; - -found_unbuddied: - zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1]; - BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0))); - if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */ - ASSERT_SENTINEL(zh0, ZBH); - zh = zh1; - } else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */ - ASSERT_SENTINEL(zh1, ZBH); - zh = zh0; - } else - BUG(); - list_del_init(&zbpg->bud_list); - zbud_unbuddied[found_good_buddy].count--; - list_add_tail(&zbpg->bud_list, &zbud_buddied_list); - zcache_zbud_buddied_count++; - -init_zh: - SET_SENTINEL(zh, ZBH); - zh->size = size; - zh->index = index; - zh->oid = *oid; - zh->pool_id = pool_id; - zh->client_id = client_id; - /* can wait to copy the data until the list locks are dropped */ - spin_unlock(&zbud_budlists_spinlock); - - to = zbud_data(zh, size); - memcpy(to, cdata, size); - spin_unlock(&zbpg->lock); - zbud_cumul_chunk_counts[nchunks]++; - atomic_inc(&zcache_zbud_curr_zpages); - zcache_zbud_cumul_zpages++; - zcache_zbud_curr_zbytes += size; - zcache_zbud_cumul_zbytes += size; -out: - return zh; -} - -static int zbud_decompress(struct page *page, struct zbud_hdr *zh) -{ - struct zbud_page *zbpg; - unsigned budnum = zbud_budnum(zh); - size_t out_len = PAGE_SIZE; - char *to_va, *from_va; - unsigned size; - int ret = 0; - - zbpg = container_of(zh, struct zbud_page, buddy[budnum]); - spin_lock(&zbpg->lock); - if (list_empty(&zbpg->bud_list)) { - ret = -EINVAL; - goto out; - } - ASSERT_SENTINEL(zh, ZBH); - BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size()); - to_va = kmap_atomic(page); - size = zh->size; - from_va = zbud_data(zh, size); - ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len); - BUG_ON(ret != LZO_E_OK); - BUG_ON(out_len != PAGE_SIZE); - kunmap_atomic(to_va); -out: - spin_unlock(&zbpg->lock); - return ret; -} - -static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, - uint16_t poolid); -static void zcache_put_pool(struct tmem_pool *pool); - -static void zbud_init(void) -{ - int i; - - INIT_LIST_HEAD(&zbud_buddied_list); - zcache_zbud_buddied_count = 0; - for (i = 0; i < NCHUNKS; i++) { - INIT_LIST_HEAD(&zbud_unbuddied[i].list); - zbud_unbuddied[i].count = 0; - } -} - -#ifdef CONFIG_SYSFS -/* - * These sysfs routines show a nice distribution of how many zbpg's are - * currently (and have ever been placed) in each unbuddied list. It's fun - * to watch but can probably go away before final merge. - */ -static int zbud_show_unbuddied_list_counts(char *buf) -{ - int i; - char *p = buf; - - for (i = 0; i < NCHUNKS; i++) - p += sprintf(p, "%u ", zbud_unbuddied[i].count); - return p - buf; -} - -static int zbud_show_cumul_chunk_counts(char *buf) -{ - unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0; - unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0; - unsigned long total_chunks_lte_42 = 0; - char *p = buf; - - for (i = 0; i < NCHUNKS; i++) { - p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]); - chunks += zbud_cumul_chunk_counts[i]; - total_chunks += zbud_cumul_chunk_counts[i]; - sum_total_chunks += i * zbud_cumul_chunk_counts[i]; - if (i == 21) - total_chunks_lte_21 = total_chunks; - if (i == 32) - total_chunks_lte_32 = total_chunks; - if (i == 42) - total_chunks_lte_42 = total_chunks; - } - p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n", - total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42, - chunks == 0 ? 0 : sum_total_chunks / chunks); - return p - buf; -} -#endif - -/* - * zcache core code starts here - */ - -/* useful stats not collected by cleancache or frontswap */ -static unsigned long zcache_flush_total; -static unsigned long zcache_flush_found; -static unsigned long zcache_flobj_total; -static unsigned long zcache_flobj_found; -static unsigned long zcache_failed_eph_puts; - -/* - * Tmem operations assume the poolid implies the invoking client. - * Zcache only has one client (the kernel itself): LOCAL_CLIENT. - * RAMster has each client numbered by cluster node, and a KVM version - * of zcache would have one client per guest and each client might - * have a poolid==N. - */ -static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid) -{ - struct tmem_pool *pool = NULL; - struct zcache_client *cli = NULL; - - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else { - if (cli_id >= MAX_CLIENTS) - goto out; - cli = &zcache_clients[cli_id]; - if (cli == NULL) - goto out; - atomic_inc(&cli->refcount); - } - if (poolid < MAX_POOLS_PER_CLIENT) { - pool = cli->tmem_pools[poolid]; - if (pool != NULL) - atomic_inc(&pool->refcount); - } -out: - return pool; -} - -static void zcache_put_pool(struct tmem_pool *pool) -{ - struct zcache_client *cli = NULL; - - if (pool == NULL) - BUG(); - cli = pool->client; - atomic_dec(&pool->refcount); - atomic_dec(&cli->refcount); -} - -int zcache_new_client(uint16_t cli_id) -{ - struct zcache_client *cli = NULL; - int ret = -1; - - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; - if (cli == NULL) - goto out; - if (cli->allocated) - goto out; - cli->allocated = 1; - ret = 0; -out: - return ret; -} - -/* counters for debugging */ -static unsigned long zcache_failed_get_free_pages; -static unsigned long zcache_failed_alloc; -static unsigned long zcache_put_to_flush; -static unsigned long zcache_aborted_preload; -static unsigned long zcache_aborted_shrink; - -/* - * Ensure that memory allocation requests in zcache don't result - * in direct reclaim requests via the shrinker, which would cause - * an infinite loop. Maybe a GFP flag would be better? - */ -static DEFINE_SPINLOCK(zcache_direct_reclaim_lock); - -/* - * for now, used named slabs so can easily track usage; later can - * either just use kmalloc, or perhaps add a slab-like allocator - * to more carefully manage total memory utilization - */ -static struct kmem_cache *zcache_objnode_cache; -static struct kmem_cache *zcache_obj_cache; -static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0); -static unsigned long zcache_curr_obj_count_max; -static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0); -static unsigned long zcache_curr_objnode_count_max; - -/* - * to avoid memory allocation recursion (e.g. due to direct reclaim), we - * preload all necessary data structures so the hostops callbacks never - * actually do a malloc - */ -struct zcache_preload { - void *page; - struct tmem_obj *obj; - int nr; - struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH]; -}; -static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, }; - -static int zcache_do_preload(struct tmem_pool *pool) -{ - struct zcache_preload *kp; - struct tmem_objnode *objnode; - struct tmem_obj *obj; - void *page; - int ret = -ENOMEM; - - if (unlikely(zcache_objnode_cache == NULL)) - goto out; - if (unlikely(zcache_obj_cache == NULL)) - goto out; - if (!spin_trylock(&zcache_direct_reclaim_lock)) { - zcache_aborted_preload++; - goto out; - } - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - while (kp->nr < ARRAY_SIZE(kp->objnodes)) { - preempt_enable_no_resched(); - objnode = kmem_cache_alloc(zcache_objnode_cache, - ZCACHE_GFP_MASK); - if (unlikely(objnode == NULL)) { - zcache_failed_alloc++; - goto unlock_out; - } - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - if (kp->nr < ARRAY_SIZE(kp->objnodes)) - kp->objnodes[kp->nr++] = objnode; - else - kmem_cache_free(zcache_objnode_cache, objnode); - } - preempt_enable_no_resched(); - obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK); - if (unlikely(obj == NULL)) { - zcache_failed_alloc++; - goto unlock_out; - } - page = qcache_alloc(); - if (unlikely(page == NULL)) { - zcache_failed_get_free_pages++; - kmem_cache_free(zcache_obj_cache, obj); - goto unlock_out; - } - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - if (kp->obj == NULL) - kp->obj = obj; - else - kmem_cache_free(zcache_obj_cache, obj); - if (kp->page == NULL) - kp->page = page; - else - qcache_free(page); - ret = 0; -unlock_out: - spin_unlock(&zcache_direct_reclaim_lock); -out: - return ret; -} - -static void *zcache_get_free_page(void) -{ - struct zcache_preload *kp; - void *page; - - kp = &__get_cpu_var(zcache_preloads); - page = kp->page; - BUG_ON(page == NULL); - kp->page = NULL; - return page; -} - -/* - * zcache implementation for tmem host ops - */ - -static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool) -{ - struct tmem_objnode *objnode = NULL; - unsigned long count; - struct zcache_preload *kp; - - kp = &__get_cpu_var(zcache_preloads); - if (kp->nr <= 0) - goto out; - objnode = kp->objnodes[kp->nr - 1]; - BUG_ON(objnode == NULL); - kp->objnodes[kp->nr - 1] = NULL; - kp->nr--; - count = atomic_inc_return(&zcache_curr_objnode_count); - if (count > zcache_curr_objnode_count_max) - zcache_curr_objnode_count_max = count; -out: - return objnode; -} - -static void zcache_objnode_free(struct tmem_objnode *objnode, - struct tmem_pool *pool) -{ - atomic_dec(&zcache_curr_objnode_count); - BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0); - kmem_cache_free(zcache_objnode_cache, objnode); -} - -static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool) -{ - struct tmem_obj *obj = NULL; - unsigned long count; - struct zcache_preload *kp; - - kp = &__get_cpu_var(zcache_preloads); - obj = kp->obj; - BUG_ON(obj == NULL); - kp->obj = NULL; - count = atomic_inc_return(&zcache_curr_obj_count); - if (count > zcache_curr_obj_count_max) - zcache_curr_obj_count_max = count; - return obj; -} - -static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool) -{ - atomic_dec(&zcache_curr_obj_count); - BUG_ON(atomic_read(&zcache_curr_obj_count) < 0); - kmem_cache_free(zcache_obj_cache, obj); -} - -static void zcache_flush_all_obj(void) -{ - struct tmem_pool *pool; - int pool_id; - struct zcache_preload *kp; - - kp = &__get_cpu_var(zcache_preloads); - - for (pool_id = 0; pool_id < MAX_POOLS_PER_CLIENT; pool_id++) { - pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id); - tmem_flush_pool(pool); - if (pool) - zcache_put_pool(pool); - } - if (kp->page) { - qcache_free(kp->page); - kp->page = NULL; - } - if (zcache_qc_used) - pr_warn("pages used not 0 after qcache flush all, is %ld\n", - zcache_qc_used); -} - -/* - * When zcache is disabled ("frozen"), pools can be created and destroyed, - * but all puts (and thus all other operations that require memory allocation) - * must fail. If zcache is unfrozen, accepts puts, then frozen again, - * data consistency requires all puts while frozen to be converted into - * flushes. - */ -static bool zcache_freeze; - -static void zcache_control(bool freeze) -{ - zcache_freeze = freeze; -} - -static struct tmem_hostops zcache_hostops = { - .obj_alloc = zcache_obj_alloc, - .obj_free = zcache_obj_free, - .objnode_alloc = zcache_objnode_alloc, - .objnode_free = zcache_objnode_free, - .flush_all_obj = zcache_flush_all_obj, - .control = zcache_control, -}; - -/* - * zcache implementations for PAM page descriptor ops - */ - -static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0); -static unsigned long zcache_curr_eph_pampd_count_max; - -/* forward reference */ -static int zcache_compress(struct page *from, void **out_va, size_t *out_len); - -static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph, - struct tmem_pool *pool, struct tmem_oid *oid, - uint32_t index) -{ - void *pampd = NULL, *cdata; - size_t clen; - int ret; - unsigned long count; - struct page *page = (struct page *)(data); - struct zcache_client *cli = pool->client; - uint16_t client_id = get_client_id_from_client(cli); - - ret = zcache_compress(page, &cdata, &clen); - if (ret == 0) - goto out; - if (clen == 0 || clen > zbud_max_buddy_size()) { - zcache_compress_poor++; - goto out; - } - pampd = (void *)zbud_create(client_id, pool->pool_id, oid, - index, page, cdata, clen); - if (pampd != NULL) { - count = atomic_inc_return(&zcache_curr_eph_pampd_count); - if (count > zcache_curr_eph_pampd_count_max) - zcache_curr_eph_pampd_count_max = count; - } -out: - return pampd; -} - -/* - * fill the pageframe corresponding to the struct page with the data - * from the passed pampd - */ -static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw, - void *pampd, struct tmem_pool *pool, - struct tmem_oid *oid, uint32_t index) -{ - BUG(); - return 0; -} - -/* - * fill the pageframe corresponding to the struct page with the data - * from the passed pampd - */ -static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw, - void *pampd, struct tmem_pool *pool, - struct tmem_oid *oid, uint32_t index) -{ - int ret = 0; - - zbud_decompress((struct page *)(data), pampd); - zbud_free_and_delist((struct zbud_hdr *)pampd); - atomic_dec(&zcache_curr_eph_pampd_count); - return ret; -} - -/* - * free the pampd and remove it from any zcache lists - * pampd must no longer be pointed to from any tmem data structures! - */ -static void zcache_pampd_free(void *pampd, struct tmem_pool *pool, - struct tmem_oid *oid, uint32_t index) -{ - zbud_free_and_delist((struct zbud_hdr *)pampd); - atomic_dec(&zcache_curr_eph_pampd_count); - BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0); -} - -static void zcache_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj) -{ -} - -static void zcache_pampd_new_obj(struct tmem_obj *obj) -{ -} - -static int zcache_pampd_replace_in_obj(void *pampd, struct tmem_obj *obj) -{ - return -1; -} - -static bool zcache_pampd_is_remote(void *pampd) -{ - return 0; -} - -static struct tmem_pamops zcache_pamops = { - .create = zcache_pampd_create, - .get_data = zcache_pampd_get_data, - .get_data_and_free = zcache_pampd_get_data_and_free, - .free = zcache_pampd_free, - .free_obj = zcache_pampd_free_obj, - .new_obj = zcache_pampd_new_obj, - .replace_in_obj = zcache_pampd_replace_in_obj, - .is_remote = zcache_pampd_is_remote, -}; - -/* - * zcache compression/decompression and related per-cpu stuff - */ - -#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS -#define LZO_DSTMEM_PAGE_ORDER 1 -static DEFINE_PER_CPU(unsigned char *, zcache_workmem); -static DEFINE_PER_CPU(unsigned char *, zcache_dstmem); - -static int zcache_compress(struct page *from, void **out_va, size_t *out_len) -{ - int ret = 0; - unsigned char *dmem = __get_cpu_var(zcache_dstmem); - unsigned char *wmem = __get_cpu_var(zcache_workmem); - char *from_va; - - BUG_ON(!irqs_disabled()); - if (unlikely(dmem == NULL || wmem == NULL)) - goto out; /* no buffer, so can't compress */ - from_va = kmap_atomic(from); - mb(); - ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem); - BUG_ON(ret != LZO_E_OK); - *out_va = dmem; - kunmap_atomic(from_va); - ret = 1; -out: - return ret; -} - -#ifdef CONFIG_SYSFS -#define ZCACHE_SYSFS_RO(_name) \ - static ssize_t zcache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return sprintf(buf, "%lu\n", zcache_##_name); \ - } \ - static struct kobj_attribute zcache_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = zcache_##_name##_show, \ - } - -#define ZCACHE_SYSFS_RO_ATOMIC(_name) \ - static ssize_t zcache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \ - } \ - static struct kobj_attribute zcache_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = zcache_##_name##_show, \ - } - -#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \ - static ssize_t zcache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return _func(buf); \ - } \ - static struct kobj_attribute zcache_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = zcache_##_name##_show, \ - } - -ZCACHE_SYSFS_RO(curr_obj_count_max); -ZCACHE_SYSFS_RO(curr_objnode_count_max); -ZCACHE_SYSFS_RO(flush_total); -ZCACHE_SYSFS_RO(flush_found); -ZCACHE_SYSFS_RO(flobj_total); -ZCACHE_SYSFS_RO(flobj_found); -ZCACHE_SYSFS_RO(failed_eph_puts); -ZCACHE_SYSFS_RO(zbud_curr_zbytes); -ZCACHE_SYSFS_RO(zbud_cumul_zpages); -ZCACHE_SYSFS_RO(zbud_cumul_zbytes); -ZCACHE_SYSFS_RO(zbud_buddied_count); -ZCACHE_SYSFS_RO(failed_get_free_pages); -ZCACHE_SYSFS_RO(failed_alloc); -ZCACHE_SYSFS_RO(put_to_flush); -ZCACHE_SYSFS_RO(aborted_preload); -ZCACHE_SYSFS_RO(aborted_shrink); -ZCACHE_SYSFS_RO(compress_poor); -ZCACHE_SYSFS_RO(mean_compress_poor); -ZCACHE_SYSFS_RO(qc_allocated); -ZCACHE_SYSFS_RO(qc_freed); -ZCACHE_SYSFS_RO(qc_used); -ZCACHE_SYSFS_RO(qc_max_used); -ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages); -ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages); -ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count); -ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count); -ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts, - zbud_show_unbuddied_list_counts); -ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts, - zbud_show_cumul_chunk_counts); - -static struct attribute *qcache_attrs[] = { - &zcache_curr_obj_count_attr.attr, - &zcache_curr_obj_count_max_attr.attr, - &zcache_curr_objnode_count_attr.attr, - &zcache_curr_objnode_count_max_attr.attr, - &zcache_flush_total_attr.attr, - &zcache_flobj_total_attr.attr, - &zcache_flush_found_attr.attr, - &zcache_flobj_found_attr.attr, - &zcache_failed_eph_puts_attr.attr, - &zcache_compress_poor_attr.attr, - &zcache_mean_compress_poor_attr.attr, - &zcache_zbud_curr_raw_pages_attr.attr, - &zcache_zbud_curr_zpages_attr.attr, - &zcache_zbud_curr_zbytes_attr.attr, - &zcache_zbud_cumul_zpages_attr.attr, - &zcache_zbud_cumul_zbytes_attr.attr, - &zcache_zbud_buddied_count_attr.attr, - &zcache_failed_get_free_pages_attr.attr, - &zcache_failed_alloc_attr.attr, - &zcache_put_to_flush_attr.attr, - &zcache_aborted_preload_attr.attr, - &zcache_aborted_shrink_attr.attr, - &zcache_zbud_unbuddied_list_counts_attr.attr, - &zcache_zbud_cumul_chunk_counts_attr.attr, - &zcache_qc_allocated_attr.attr, - &zcache_qc_freed_attr.attr, - &zcache_qc_used_attr.attr, - &zcache_qc_max_used_attr.attr, - NULL, -}; - -static struct attribute_group qcache_attr_group = { - .attrs = qcache_attrs, - .name = "qcache", -}; - -#endif /* CONFIG_SYSFS */ - -/* - * zcache shims between cleancache ops and tmem - */ - -static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp, - uint32_t index, struct page *page) -{ - struct tmem_pool *pool; - int ret = -1; - - BUG_ON(!irqs_disabled()); - pool = zcache_get_pool_by_id(cli_id, pool_id); - if (unlikely(pool == NULL)) - goto out; - if (!zcache_freeze && zcache_do_preload(pool) == 0) { - /* preload does preempt_disable on success */ - ret = tmem_put(pool, oidp, index, (char *)(page), - PAGE_SIZE, 0, is_ephemeral(pool)); - if (ret < 0) { - zcache_failed_eph_puts++; - } - zcache_put_pool(pool); - preempt_enable_no_resched(); - } else { - zcache_put_to_flush++; - if (atomic_read(&pool->obj_count) > 0) - /* the put fails whether the flush succeeds or not */ - (void)tmem_flush_page(pool, oidp, index); - zcache_put_pool(pool); - } -out: - return ret; -} - -static int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp, - uint32_t index, struct page *page) -{ - struct tmem_pool *pool; - int ret = -1; - unsigned long flags; - size_t size = PAGE_SIZE; - - local_irq_save(flags); - pool = zcache_get_pool_by_id(cli_id, pool_id); - if (likely(pool != NULL)) { - if (atomic_read(&pool->obj_count) > 0) - ret = tmem_get(pool, oidp, index, (char *)(page), - &size, 0, is_ephemeral(pool)); - zcache_put_pool(pool); - } - local_irq_restore(flags); - return ret; -} - -static int zcache_flush_page(int cli_id, int pool_id, - struct tmem_oid *oidp, uint32_t index) -{ - struct tmem_pool *pool; - int ret = -1; - unsigned long flags; - - local_irq_save(flags); - zcache_flush_total++; - pool = zcache_get_pool_by_id(cli_id, pool_id); - if (likely(pool != NULL)) { - if (atomic_read(&pool->obj_count) > 0) - ret = tmem_flush_page(pool, oidp, index); - zcache_put_pool(pool); - } - if (ret >= 0) - zcache_flush_found++; - local_irq_restore(flags); - return ret; -} - -static int zcache_flush_object(int cli_id, int pool_id, - struct tmem_oid *oidp) -{ - struct tmem_pool *pool; - int ret = -1; - unsigned long flags; - - local_irq_save(flags); - zcache_flobj_total++; - pool = zcache_get_pool_by_id(cli_id, pool_id); - if (likely(pool != NULL)) { - if (atomic_read(&pool->obj_count) > 0) - ret = tmem_flush_object(pool, oidp); - zcache_put_pool(pool); - } - if (ret >= 0) - zcache_flobj_found++; - local_irq_restore(flags); - return ret; -} - -static int zcache_destroy_pool(int cli_id, int pool_id) -{ - struct tmem_pool *pool = NULL; - struct zcache_client *cli = NULL; - int ret = -1; - - if (pool_id < 0) - goto out; - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; - if (cli == NULL) - goto out; - atomic_inc(&cli->refcount); - pool = cli->tmem_pools[pool_id]; - if (pool == NULL) - goto out; - cli->tmem_pools[pool_id] = NULL; - /* wait for pool activity on other cpus to quiesce */ - while (atomic_read(&pool->refcount) != 0) - ; - atomic_dec(&cli->refcount); - local_bh_disable(); - ret = tmem_destroy_pool(pool); - local_bh_enable(); - kfree(pool); - pr_info("qcache: destroyed pool id=%d, cli_id=%d\n", - pool_id, cli_id); -out: - return ret; -} - -static int zcache_new_pool(uint16_t cli_id, uint32_t flags) -{ - int poolid = -1; - struct tmem_pool *pool; - struct zcache_client *cli = NULL; - - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; - if (cli == NULL) - goto out; - atomic_inc(&cli->refcount); - pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL); - if (pool == NULL) { - pr_info("qcache: pool creation failed: out of memory\n"); - goto out; - } - - for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++) - if (cli->tmem_pools[poolid] == NULL) - break; - if (poolid >= MAX_POOLS_PER_CLIENT) { - pr_info("qcache: pool creation failed: max exceeded\n"); - kfree(pool); - poolid = -1; - goto out; - } - atomic_set(&pool->refcount, 0); - pool->client = cli; - pool->pool_id = poolid; - tmem_new_pool(pool, flags); - cli->tmem_pools[poolid] = pool; - pr_info("qcache: created %s tmem pool, id=%d, client=%d\n", - flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral", - poolid, cli_id); -out: - if (cli != NULL) - atomic_dec(&cli->refcount); - return poolid; -} - -/********** - * Two kernel functionalities currently can be layered on top of tmem. - * These are "cleancache" which is used as a second-chance cache for clean - * page cache pages; and "frontswap" which is used for swap pages - * to avoid writes to disk. A generic "shim" is provided here for each - * to translate in-kernel semantics to zcache semantics. - */ - -static void zcache_cleancache_put_page(int pool_id, - struct cleancache_filekey key, - pgoff_t index, struct page *page) -{ - u32 ind = (u32) index; - struct tmem_oid oid = *(struct tmem_oid *)&key; - - if (likely(ind == index)) - (void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index, page); -} - -static int zcache_cleancache_get_page(int pool_id, - struct cleancache_filekey key, - pgoff_t index, struct page *page) -{ - u32 ind = (u32) index; - struct tmem_oid oid = *(struct tmem_oid *)&key; - int ret = -1; - - if (likely(ind == index)) - ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index, page); - return ret; -} - -static void zcache_cleancache_flush_page(int pool_id, - struct cleancache_filekey key, - pgoff_t index) -{ - u32 ind = (u32) index; - struct tmem_oid oid = *(struct tmem_oid *)&key; - - if (likely(ind == index)) - (void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind); -} - -static void zcache_cleancache_flush_inode(int pool_id, - struct cleancache_filekey key) -{ - struct tmem_oid oid = *(struct tmem_oid *)&key; - - (void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid); -} - -static void zcache_cleancache_flush_fs(int pool_id) -{ - if (pool_id >= 0) - (void)zcache_destroy_pool(LOCAL_CLIENT, pool_id); -} - -static int zcache_cleancache_init_fs(size_t pagesize) -{ - BUG_ON(sizeof(struct cleancache_filekey) != - sizeof(struct tmem_oid)); - BUG_ON(pagesize != PAGE_SIZE); - return zcache_new_pool(LOCAL_CLIENT, 0); -} - -static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize) -{ - /* shared pools are unsupported and map to private */ - BUG_ON(sizeof(struct cleancache_filekey) != - sizeof(struct tmem_oid)); - BUG_ON(pagesize != PAGE_SIZE); - return zcache_new_pool(LOCAL_CLIENT, 0); -} - -static struct cleancache_ops zcache_cleancache_ops = { - .put_page = zcache_cleancache_put_page, - .get_page = zcache_cleancache_get_page, - .invalidate_page = zcache_cleancache_flush_page, - .invalidate_inode = zcache_cleancache_flush_inode, - .invalidate_fs = zcache_cleancache_flush_fs, - .init_shared_fs = zcache_cleancache_init_shared_fs, - .init_fs = zcache_cleancache_init_fs -}; - -struct cleancache_ops zcache_cleancache_register_ops(void) -{ - struct cleancache_ops old_ops = - cleancache_register_ops(&zcache_cleancache_ops); - - return old_ops; -} - -static int __init qcache_init(void) -{ - int ret = 0; - struct qcache_info *qc = &qcache_info; - struct fmem_data *fdp; - int bitmap_size; - unsigned int cpu; - struct cleancache_ops old_ops; - -#ifdef CONFIG_SYSFS - ret = sysfs_create_group(mm_kobj, &qcache_attr_group); - if (ret) { - pr_err("qcache: can't create sysfs\n"); - goto out; - } -#endif /* CONFIG_SYSFS */ - - fdp = fmem_get_info(); - qc->addr = fdp->virt; - qc->pages = fdp->size >> PAGE_SHIFT; - if (!qc->pages) - goto out; - - tmem_register_hostops(&zcache_hostops); - tmem_register_pamops(&zcache_pamops); - for_each_online_cpu(cpu) { - per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages( - GFP_KERNEL | __GFP_REPEAT, - LZO_DSTMEM_PAGE_ORDER), - per_cpu(zcache_workmem, cpu) = - kzalloc(LZO1X_MEM_COMPRESS, - GFP_KERNEL | __GFP_REPEAT); - } - zcache_objnode_cache = kmem_cache_create("zcache_objnode", - sizeof(struct tmem_objnode), 0, 0, NULL); - zcache_obj_cache = kmem_cache_create("zcache_obj", - sizeof(struct tmem_obj), 0, 0, NULL); - ret = zcache_new_client(LOCAL_CLIENT); - if (ret) { - pr_err("qcache: can't create client\n"); - goto out; - } - - zbud_init(); - old_ops = zcache_cleancache_register_ops(); - pr_info("qcache: cleancache enabled using kernel " - "transcendent memory and compression buddies\n"); - if (old_ops.init_fs != NULL) - pr_warning("qcache: cleancache_ops overridden"); - - - bitmap_size = BITS_TO_LONGS(qc->pages) * sizeof(long); - - qc->bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!qc->bitmap) { - pr_info("can't allocate qcache bitmap!\n"); - ret = -ENOMEM; - goto out; - } - spin_lock_init(&qc->lock); - - fmem_set_state(FMEM_T_STATE); - -out: - return ret; -} - -module_init(qcache_init) diff --git a/drivers/staging/qcache/tmem.c b/drivers/staging/qcache/tmem.c deleted file mode 100644 index 40f22460..00000000 --- a/drivers/staging/qcache/tmem.c +++ /dev/null @@ -1,833 +0,0 @@ -/* - * In-kernel transcendent memory (generic implementation) - * - * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp. - * Copyright (c) 2011, The Linux Foundation. All rights reserved. - * - * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented - * "handles" (triples containing a pool id, and object id, and an index), to - * pages in a page-accessible memory (PAM). Tmem references the PAM pages via - * an abstract "pampd" (PAM page-descriptor), which can be operated on by a - * set of functions (pamops). Each pampd contains some representation of - * PAGE_SIZE bytes worth of data. Tmem must support potentially millions of - * pages and must be able to insert, find, and delete these pages at a - * potential frequency of thousands per second concurrently across many CPUs, - * (and, if used with KVM, across many vcpus across many guests). - * Tmem is tracked with a hierarchy of data structures, organized by - * the elements in a handle-tuple: pool_id, object_id, and page index. - * One or more "clients" (e.g. guests) each provide one or more tmem_pools. - * Each pool, contains a hash table of rb_trees of tmem_objs. Each - * tmem_obj contains a radix-tree-like tree of pointers, with intermediate - * nodes called tmem_objnodes. Each leaf pointer in this tree points to - * a pampd, which is accessible only through a small set of callbacks - * registered by the PAM implementation (see tmem_register_pamops). Tmem - * does all memory allocation via a set of callbacks registered by the tmem - * host implementation (e.g. see tmem_register_hostops). - */ - -#include -#include -#include - -#include "tmem.h" - -/* data structure sentinels used for debugging... see tmem.h */ -#define POOL_SENTINEL 0x87658765 -#define OBJ_SENTINEL 0x12345678 -#define OBJNODE_SENTINEL 0xfedcba09 - -static bool tmem_enabled; - -static void lock_tmem_state(void) -{ - lock_fmem_state(); -} - -static void unlock_tmem_state(void) -{ - unlock_fmem_state(); -} - -/* - * A tmem host implementation must use this function to register callbacks - * for memory allocation. - */ -static struct tmem_hostops tmem_hostops; - -static void tmem_objnode_tree_init(void); - -void tmem_register_hostops(struct tmem_hostops *m) -{ - tmem_objnode_tree_init(); - tmem_hostops = *m; -} - -/* - * A tmem host implementation must use this function to register - * callbacks for a page-accessible memory (PAM) implementation - */ -static struct tmem_pamops tmem_pamops; - -void tmem_register_pamops(struct tmem_pamops *m) -{ - tmem_pamops = *m; -} - -/* - * Oid's are potentially very sparse and tmem_objs may have an indeterminately - * short life, being added and deleted at a relatively high frequency. - * So an rb_tree is an ideal data structure to manage tmem_objs. But because - * of the potentially huge number of tmem_objs, each pool manages a hashtable - * of rb_trees to reduce search, insert, delete, and rebalancing time. - * Each hashbucket also has a lock to manage concurrent access. - * - * The following routines manage tmem_objs. When any tmem_obj is accessed, - * the hashbucket lock must be held. - */ - -/* searches for object==oid in pool, returns locked object if found */ -static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb, - struct tmem_oid *oidp) -{ - struct rb_node *rbnode; - struct tmem_obj *obj; - - rbnode = hb->obj_rb_root.rb_node; - while (rbnode) { - BUG_ON(RB_EMPTY_NODE(rbnode)); - obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node); - switch (tmem_oid_compare(oidp, &obj->oid)) { - case 0: /* equal */ - goto out; - case -1: - rbnode = rbnode->rb_left; - break; - case 1: - rbnode = rbnode->rb_right; - break; - } - } - obj = NULL; -out: - return obj; -} - -static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *); - -/* free an object that has no more pampds in it */ -static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb) -{ - struct tmem_pool *pool; - - BUG_ON(obj == NULL); - ASSERT_SENTINEL(obj, OBJ); - BUG_ON(obj->pampd_count > 0); - pool = obj->pool; - BUG_ON(pool == NULL); - if (obj->objnode_tree_root != NULL) /* may be "stump" with no leaves */ - tmem_pampd_destroy_all_in_obj(obj); - BUG_ON(obj->objnode_tree_root != NULL); - BUG_ON((long)obj->objnode_count != 0); - atomic_dec(&pool->obj_count); - BUG_ON(atomic_read(&pool->obj_count) < 0); - INVERT_SENTINEL(obj, OBJ); - obj->pool = NULL; - tmem_oid_set_invalid(&obj->oid); - rb_erase(&obj->rb_tree_node, &hb->obj_rb_root); -} - -/* - * initialize, and insert an tmem_object_root (called only if find failed) - */ -static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb, - struct tmem_pool *pool, - struct tmem_oid *oidp) -{ - struct rb_root *root = &hb->obj_rb_root; - struct rb_node **new = &(root->rb_node), *parent = NULL; - struct tmem_obj *this; - - BUG_ON(pool == NULL); - atomic_inc(&pool->obj_count); - obj->objnode_tree_height = 0; - obj->objnode_tree_root = NULL; - obj->pool = pool; - obj->oid = *oidp; - obj->objnode_count = 0; - obj->pampd_count = 0; - (*tmem_pamops.new_obj)(obj); - SET_SENTINEL(obj, OBJ); - while (*new) { - BUG_ON(RB_EMPTY_NODE(*new)); - this = rb_entry(*new, struct tmem_obj, rb_tree_node); - parent = *new; - switch (tmem_oid_compare(oidp, &this->oid)) { - case 0: - BUG(); /* already present; should never happen! */ - break; - case -1: - new = &(*new)->rb_left; - break; - case 1: - new = &(*new)->rb_right; - break; - } - } - rb_link_node(&obj->rb_tree_node, parent, new); - rb_insert_color(&obj->rb_tree_node, root); -} - -/* - * Tmem is managed as a set of tmem_pools with certain attributes, such as - * "ephemeral" vs "persistent". These attributes apply to all tmem_objs - * and all pampds that belong to a tmem_pool. A tmem_pool is created - * or deleted relatively rarely (for example, when a filesystem is - * mounted or unmounted. - */ - -/* flush all data from a pool and, optionally, free it */ -static void tmem_pool_flush(struct tmem_pool *pool, bool destroy) -{ - struct rb_node *rbnode; - struct tmem_obj *obj; - struct tmem_hashbucket *hb = &pool->hashbucket[0]; - int i; - - BUG_ON(pool == NULL); - for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) { - spin_lock(&hb->lock); - rbnode = rb_first(&hb->obj_rb_root); - while (rbnode != NULL) { - obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node); - rbnode = rb_next(rbnode); - tmem_pampd_destroy_all_in_obj(obj); - tmem_obj_free(obj, hb); - (*tmem_hostops.obj_free)(obj, pool); - } - spin_unlock(&hb->lock); - } - if (destroy) - list_del(&pool->pool_list); -} - -/* - * A tmem_obj contains a radix-tree-like tree in which the intermediate - * nodes are called tmem_objnodes. (The kernel lib/radix-tree.c implementation - * is very specialized and tuned for specific uses and is not particularly - * suited for use from this code, though some code from the core algorithms has - * been reused, thus the copyright notices below). Each tmem_objnode contains - * a set of pointers which point to either a set of intermediate tmem_objnodes - * or a set of of pampds. - * - * Portions Copyright (C) 2001 Momchil Velikov - * Portions Copyright (C) 2001 Christoph Hellwig - * Portions Copyright (C) 2005 SGI, Christoph Lameter - */ - -struct tmem_objnode_tree_path { - struct tmem_objnode *objnode; - int offset; -}; - -/* objnode height_to_maxindex translation */ -static unsigned long tmem_objnode_tree_h2max[OBJNODE_TREE_MAX_PATH + 1]; - -static void tmem_objnode_tree_init(void) -{ - unsigned int ht, tmp; - - for (ht = 0; ht < ARRAY_SIZE(tmem_objnode_tree_h2max); ht++) { - tmp = ht * OBJNODE_TREE_MAP_SHIFT; - if (tmp >= OBJNODE_TREE_INDEX_BITS) - tmem_objnode_tree_h2max[ht] = ~0UL; - else - tmem_objnode_tree_h2max[ht] = - (~0UL >> (OBJNODE_TREE_INDEX_BITS - tmp - 1)) >> 1; - } -} - -static struct tmem_objnode *tmem_objnode_alloc(struct tmem_obj *obj) -{ - struct tmem_objnode *objnode; - - ASSERT_SENTINEL(obj, OBJ); - BUG_ON(obj->pool == NULL); - ASSERT_SENTINEL(obj->pool, POOL); - objnode = (*tmem_hostops.objnode_alloc)(obj->pool); - if (unlikely(objnode == NULL)) - goto out; - objnode->obj = obj; - SET_SENTINEL(objnode, OBJNODE); - memset(&objnode->slots, 0, sizeof(objnode->slots)); - objnode->slots_in_use = 0; - obj->objnode_count++; -out: - return objnode; -} - -static void tmem_objnode_free(struct tmem_objnode *objnode) -{ - struct tmem_pool *pool; - int i; - - BUG_ON(objnode == NULL); - for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++) - BUG_ON(objnode->slots[i] != NULL); - ASSERT_SENTINEL(objnode, OBJNODE); - INVERT_SENTINEL(objnode, OBJNODE); - BUG_ON(objnode->obj == NULL); - ASSERT_SENTINEL(objnode->obj, OBJ); - pool = objnode->obj->pool; - BUG_ON(pool == NULL); - ASSERT_SENTINEL(pool, POOL); - objnode->obj->objnode_count--; - objnode->obj = NULL; - (*tmem_hostops.objnode_free)(objnode, pool); -} - -/* - * lookup index in object and return associated pampd (or NULL if not found) - */ -static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) -{ - unsigned int height, shift; - struct tmem_objnode **slot = NULL; - - BUG_ON(obj == NULL); - ASSERT_SENTINEL(obj, OBJ); - BUG_ON(obj->pool == NULL); - ASSERT_SENTINEL(obj->pool, POOL); - - height = obj->objnode_tree_height; - if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height]) - goto out; - if (height == 0 && obj->objnode_tree_root) { - slot = &obj->objnode_tree_root; - goto out; - } - shift = (height-1) * OBJNODE_TREE_MAP_SHIFT; - slot = &obj->objnode_tree_root; - while (height > 0) { - if (*slot == NULL) - goto out; - slot = (struct tmem_objnode **) - ((*slot)->slots + - ((index >> shift) & OBJNODE_TREE_MAP_MASK)); - shift -= OBJNODE_TREE_MAP_SHIFT; - height--; - } -out: - return slot != NULL ? (void **)slot : NULL; -} - -static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) -{ - struct tmem_objnode **slot; - - slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index); - return slot != NULL ? *slot : NULL; -} - -static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index, - void *new_pampd) -{ - struct tmem_objnode **slot; - void *ret = NULL; - - slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index); - if ((slot != NULL) && (*slot != NULL)) { - void *old_pampd = *(void **)slot; - *(void **)slot = new_pampd; - (*tmem_pamops.free)(old_pampd, obj->pool, NULL, 0); - ret = new_pampd; - } - return ret; -} - -static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index, - void *pampd) -{ - int ret = 0; - struct tmem_objnode *objnode = NULL, *newnode, *slot; - unsigned int height, shift; - int offset = 0; - - /* if necessary, extend the tree to be higher */ - if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height]) { - height = obj->objnode_tree_height + 1; - if (index > tmem_objnode_tree_h2max[height]) - while (index > tmem_objnode_tree_h2max[height]) - height++; - if (obj->objnode_tree_root == NULL) { - obj->objnode_tree_height = height; - goto insert; - } - do { - newnode = tmem_objnode_alloc(obj); - if (!newnode) { - ret = -ENOMEM; - goto out; - } - newnode->slots[0] = obj->objnode_tree_root; - newnode->slots_in_use = 1; - obj->objnode_tree_root = newnode; - obj->objnode_tree_height++; - } while (height > obj->objnode_tree_height); - } -insert: - slot = obj->objnode_tree_root; - height = obj->objnode_tree_height; - shift = (height-1) * OBJNODE_TREE_MAP_SHIFT; - while (height > 0) { - if (slot == NULL) { - /* add a child objnode. */ - slot = tmem_objnode_alloc(obj); - if (!slot) { - ret = -ENOMEM; - goto out; - } - if (objnode) { - - objnode->slots[offset] = slot; - objnode->slots_in_use++; - } else - obj->objnode_tree_root = slot; - } - /* go down a level */ - offset = (index >> shift) & OBJNODE_TREE_MAP_MASK; - objnode = slot; - slot = objnode->slots[offset]; - shift -= OBJNODE_TREE_MAP_SHIFT; - height--; - } - BUG_ON(slot != NULL); - if (objnode) { - objnode->slots_in_use++; - objnode->slots[offset] = pampd; - } else - obj->objnode_tree_root = pampd; - obj->pampd_count++; -out: - return ret; -} - -static void *tmem_pampd_delete_from_obj(struct tmem_obj *obj, uint32_t index) -{ - struct tmem_objnode_tree_path path[OBJNODE_TREE_MAX_PATH + 1]; - struct tmem_objnode_tree_path *pathp = path; - struct tmem_objnode *slot = NULL; - unsigned int height, shift; - int offset; - - BUG_ON(obj == NULL); - ASSERT_SENTINEL(obj, OBJ); - BUG_ON(obj->pool == NULL); - ASSERT_SENTINEL(obj->pool, POOL); - height = obj->objnode_tree_height; - if (index > tmem_objnode_tree_h2max[height]) - goto out; - slot = obj->objnode_tree_root; - if (height == 0 && obj->objnode_tree_root) { - obj->objnode_tree_root = NULL; - goto out; - } - shift = (height - 1) * OBJNODE_TREE_MAP_SHIFT; - pathp->objnode = NULL; - do { - if (slot == NULL) - goto out; - pathp++; - offset = (index >> shift) & OBJNODE_TREE_MAP_MASK; - pathp->offset = offset; - pathp->objnode = slot; - slot = slot->slots[offset]; - shift -= OBJNODE_TREE_MAP_SHIFT; - height--; - } while (height > 0); - if (slot == NULL) - goto out; - while (pathp->objnode) { - pathp->objnode->slots[pathp->offset] = NULL; - pathp->objnode->slots_in_use--; - if (pathp->objnode->slots_in_use) { - if (pathp->objnode == obj->objnode_tree_root) { - while (obj->objnode_tree_height > 0 && - obj->objnode_tree_root->slots_in_use == 1 && - obj->objnode_tree_root->slots[0]) { - struct tmem_objnode *to_free = - obj->objnode_tree_root; - - obj->objnode_tree_root = - to_free->slots[0]; - obj->objnode_tree_height--; - to_free->slots[0] = NULL; - to_free->slots_in_use = 0; - tmem_objnode_free(to_free); - } - } - goto out; - } - tmem_objnode_free(pathp->objnode); /* 0 slots used, free it */ - pathp--; - } - obj->objnode_tree_height = 0; - obj->objnode_tree_root = NULL; - -out: - if (slot != NULL) - obj->pampd_count--; - BUG_ON(obj->pampd_count < 0); - return slot; -} - -/* recursively walk the objnode_tree destroying pampds and objnodes */ -static void tmem_objnode_node_destroy(struct tmem_obj *obj, - struct tmem_objnode *objnode, - unsigned int ht) -{ - int i; - - if (ht == 0) - return; - for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++) { - if (objnode->slots[i]) { - if (ht == 1) { - obj->pampd_count--; - (*tmem_pamops.free)(objnode->slots[i], - obj->pool, NULL, 0); - objnode->slots[i] = NULL; - continue; - } - tmem_objnode_node_destroy(obj, objnode->slots[i], ht-1); - tmem_objnode_free(objnode->slots[i]); - objnode->slots[i] = NULL; - } - } -} - -static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj) -{ - if (obj->objnode_tree_root == NULL) - return; - if (obj->objnode_tree_height == 0) { - obj->pampd_count--; - (*tmem_pamops.free)(obj->objnode_tree_root, obj->pool, NULL, 0); - } else { - tmem_objnode_node_destroy(obj, obj->objnode_tree_root, - obj->objnode_tree_height); - tmem_objnode_free(obj->objnode_tree_root); - obj->objnode_tree_height = 0; - } - obj->objnode_tree_root = NULL; - (*tmem_pamops.free_obj)(obj->pool, obj); -} - -/* - * Tmem is operated on by a set of well-defined actions: - * "put", "get", "flush", "flush_object", "new pool" and "destroy pool". - * (The tmem ABI allows for subpages and exchanges but these operations - * are not included in this implementation.) - * - * These "tmem core" operations are implemented in the following functions. - */ - -/* - * "Put" a page, e.g. copy a page from the kernel into newly allocated - * PAM space (if such space is available). Tmem_put is complicated by - * a corner case: What if a page with matching handle already exists in - * tmem? To guarantee coherency, one of two actions is necessary: Either - * the data for the page must be overwritten, or the page must be - * "flushed" so that the data is not accessible to a subsequent "get". - * Since these "duplicate puts" are relatively rare, this implementation - * always flushes for simplicity. - */ -int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, - char *data, size_t size, bool raw, bool ephemeral) -{ - struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL; - void *pampd = NULL, *pampd_del = NULL; - int ret = -ENOMEM; - struct tmem_hashbucket *hb; - - lock_tmem_state(); - if (!tmem_enabled) - goto disabled; - hb = &pool->hashbucket[tmem_oid_hash(oidp)]; - spin_lock(&hb->lock); - obj = objfound = tmem_obj_find(hb, oidp); - if (obj != NULL) { - pampd = tmem_pampd_lookup_in_obj(objfound, index); - if (pampd != NULL) { - /* if found, is a dup put, flush the old one */ - pampd_del = tmem_pampd_delete_from_obj(obj, index); - BUG_ON(pampd_del != pampd); - (*tmem_pamops.free)(pampd, pool, oidp, index); - if (obj->pampd_count == 0) { - objnew = obj; - objfound = NULL; - } - pampd = NULL; - } - } else { - obj = objnew = (*tmem_hostops.obj_alloc)(pool); - if (unlikely(obj == NULL)) { - ret = -ENOMEM; - goto out; - } - tmem_obj_init(obj, hb, pool, oidp); - } - BUG_ON(obj == NULL); - BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound)); - pampd = (*tmem_pamops.create)(data, size, raw, ephemeral, - obj->pool, &obj->oid, index); - if (unlikely(pampd == NULL)) - goto free; - ret = tmem_pampd_add_to_obj(obj, index, pampd); - if (unlikely(ret == -ENOMEM)) - /* may have partially built objnode tree ("stump") */ - goto delete_and_free; - goto out; - -delete_and_free: - (void)tmem_pampd_delete_from_obj(obj, index); -free: - if (pampd) - (*tmem_pamops.free)(pampd, pool, NULL, 0); - if (objnew) { - tmem_obj_free(objnew, hb); - (*tmem_hostops.obj_free)(objnew, pool); - } -out: - spin_unlock(&hb->lock); -disabled: - unlock_tmem_state(); - return ret; -} - -/* - * "Get" a page, e.g. if one can be found, copy the tmem page with the - * matching handle from PAM space to the kernel. By tmem definition, - * when a "get" is successful on an ephemeral page, the page is "flushed", - * and when a "get" is successful on a persistent page, the page is retained - * in tmem. Note that to preserve - * coherency, "get" can never be skipped if tmem contains the data. - * That is, if a get is done with a certain handle and fails, any - * subsequent "get" must also fail (unless of course there is a - * "put" done with the same handle). - - */ -int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, - char *data, size_t *size, bool raw, int get_and_free) -{ - struct tmem_obj *obj; - void *pampd; - bool ephemeral = is_ephemeral(pool); - int ret = -1; - struct tmem_hashbucket *hb; - bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral); - bool lock_held = false; - - lock_tmem_state(); - if (!tmem_enabled) - goto disabled; - hb = &pool->hashbucket[tmem_oid_hash(oidp)]; - spin_lock(&hb->lock); - lock_held = true; - obj = tmem_obj_find(hb, oidp); - if (obj == NULL) - goto out; - if (free) - pampd = tmem_pampd_delete_from_obj(obj, index); - else - pampd = tmem_pampd_lookup_in_obj(obj, index); - if (pampd == NULL) - goto out; - if (free) { - if (obj->pampd_count == 0) { - tmem_obj_free(obj, hb); - (*tmem_hostops.obj_free)(obj, pool); - obj = NULL; - } - } - if (tmem_pamops.is_remote(pampd)) { - lock_held = false; - spin_unlock(&hb->lock); - } - if (free) - ret = (*tmem_pamops.get_data_and_free)( - data, size, raw, pampd, pool, oidp, index); - else - ret = (*tmem_pamops.get_data)( - data, size, raw, pampd, pool, oidp, index); - if (ret < 0) - goto out; - ret = 0; -out: - if (lock_held) - spin_unlock(&hb->lock); -disabled: - unlock_tmem_state(); - return ret; -} - -/* - * If a page in tmem matches the handle, "flush" this page from tmem such - * that any subsequent "get" does not succeed (unless, of course, there - * was another "put" with the same handle). - */ -int tmem_flush_page(struct tmem_pool *pool, - struct tmem_oid *oidp, uint32_t index) -{ - struct tmem_obj *obj; - void *pampd; - int ret = -1; - struct tmem_hashbucket *hb; - - hb = &pool->hashbucket[tmem_oid_hash(oidp)]; - spin_lock(&hb->lock); - obj = tmem_obj_find(hb, oidp); - if (obj == NULL) - goto out; - pampd = tmem_pampd_delete_from_obj(obj, index); - if (pampd == NULL) - goto out; - (*tmem_pamops.free)(pampd, pool, oidp, index); - if (obj->pampd_count == 0) { - tmem_obj_free(obj, hb); - (*tmem_hostops.obj_free)(obj, pool); - } - ret = 0; - -out: - spin_unlock(&hb->lock); - return ret; -} - -/* - * If a page in tmem matches the handle, replace the page so that any - * subsequent "get" gets the new page. Returns 0 if - * there was a page to replace, else returns -1. - */ -int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp, - uint32_t index, void *new_pampd) -{ - struct tmem_obj *obj; - int ret = -1; - struct tmem_hashbucket *hb; - - lock_tmem_state(); - if (!tmem_enabled) - goto disabled; - hb = &pool->hashbucket[tmem_oid_hash(oidp)]; - spin_lock(&hb->lock); - obj = tmem_obj_find(hb, oidp); - if (obj == NULL) - goto out; - new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd); - ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj); -out: - spin_unlock(&hb->lock); -disabled: - unlock_tmem_state(); - return ret; -} - -/* - * "Flush" all pages in tmem matching this oid. - */ -int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp) -{ - struct tmem_obj *obj; - struct tmem_hashbucket *hb; - int ret = -1; - - hb = &pool->hashbucket[tmem_oid_hash(oidp)]; - spin_lock(&hb->lock); - obj = tmem_obj_find(hb, oidp); - if (obj == NULL) - goto out; - tmem_pampd_destroy_all_in_obj(obj); - tmem_obj_free(obj, hb); - (*tmem_hostops.obj_free)(obj, pool); - ret = 0; - -out: - spin_unlock(&hb->lock); - return ret; -} - -/* - * "Flush" all pages (and tmem_objs) from this tmem_pool and disable - * all subsequent access to this tmem_pool. - */ -int tmem_destroy_pool(struct tmem_pool *pool) -{ - int ret = -1; - - if (pool == NULL) - goto out; - tmem_pool_flush(pool, 1); - ret = 0; -out: - return ret; -} - -int tmem_flush_pool(struct tmem_pool *pool) -{ - int ret = -1; - - if (pool == NULL) - goto out; - tmem_pool_flush(pool, 0); - ret = 0; -out: - return ret; -} - -static LIST_HEAD(tmem_global_pool_list); - -/* - * Create a new tmem_pool with the provided flag and return - * a pool id provided by the tmem host implementation. - */ -void tmem_new_pool(struct tmem_pool *pool, uint32_t flags) -{ - int persistent = flags & TMEM_POOL_PERSIST; - int shared = flags & TMEM_POOL_SHARED; - struct tmem_hashbucket *hb = &pool->hashbucket[0]; - int i; - - for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) { - hb->obj_rb_root = RB_ROOT; - spin_lock_init(&hb->lock); - } - INIT_LIST_HEAD(&pool->pool_list); - atomic_set(&pool->obj_count, 0); - SET_SENTINEL(pool, POOL); - list_add_tail(&pool->pool_list, &tmem_global_pool_list); - pool->persistent = persistent; - pool->shared = shared; -} - -/* The following must be called with tmem state locked */ -static void tmem_cleanup(void) -{ - (*tmem_hostops.flush_all_obj)(); -} - -void tmem_enable(void) -{ - pr_info("turning tmem on\n"); - tmem_enabled = true; - - (*tmem_hostops.control)(false); -} - -void tmem_disable(void) -{ - pr_info("turning tmem off\n"); - tmem_enabled = false; - - tmem_cleanup(); - (*tmem_hostops.control)(true); -} diff --git a/drivers/staging/qcache/tmem.h b/drivers/staging/qcache/tmem.h deleted file mode 100644 index 359c2010..00000000 --- a/drivers/staging/qcache/tmem.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * tmem.h - * - * Transcendent memory - * - * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp. - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. - */ - -#ifndef _TMEM_H_ -#define _TMEM_H_ - -#include -#include -#include -#include -#include - -/* - * These are pre-defined by the Xen<->Linux ABI - */ -#define TMEM_PUT_PAGE 4 -#define TMEM_GET_PAGE 5 -#define TMEM_FLUSH_PAGE 6 -#define TMEM_FLUSH_OBJECT 7 -#define TMEM_POOL_PERSIST 1 -#define TMEM_POOL_SHARED 2 -#define TMEM_POOL_PRECOMPRESSED 4 -#define TMEM_POOL_PAGESIZE_SHIFT 4 -#define TMEM_POOL_PAGESIZE_MASK 0xf -#define TMEM_POOL_RESERVED_BITS 0x00ffff00 - -/* - * sentinels have proven very useful for debugging but can be removed - * or disabled before final merge. - */ -#define SENTINELS -#ifdef SENTINELS -#define DECL_SENTINEL uint32_t sentinel; -#define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL) -#define INVERT_SENTINEL(_x, _y) (_x->sentinel = ~_y##_SENTINEL) -#define ASSERT_SENTINEL(_x, _y) WARN_ON(_x->sentinel != _y##_SENTINEL) -#define ASSERT_INVERTED_SENTINEL(_x, _y) WARN_ON(_x->sentinel != ~_y##_SENTINEL) -#else -#define DECL_SENTINEL -#define SET_SENTINEL(_x, _y) do { } while (0) -#define INVERT_SENTINEL(_x, _y) do { } while (0) -#define ASSERT_SENTINEL(_x, _y) do { } while (0) -#define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0) -#endif - -/* - * A pool is the highest-level data structure managed by tmem and - * usually corresponds to a large independent set of pages such as - * a filesystem. Each pool has an id, and certain attributes and counters. - * It also contains a set of hash buckets, each of which contains an rbtree - * of objects and a lock to manage concurrency within the pool. - */ - -#define TMEM_HASH_BUCKET_BITS 8 -#define TMEM_HASH_BUCKETS (1<persistent) -#define is_ephemeral(_p) (!(_p->persistent)) - -/* - * An object id ("oid") is large: 192-bits (to ensure, for example, files - * in a modern filesystem can be uniquely identified). - */ - -struct tmem_oid { - uint64_t oid[3]; -}; - -static inline void tmem_oid_set_invalid(struct tmem_oid *oidp) -{ - oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL; -} - -static inline bool tmem_oid_valid(struct tmem_oid *oidp) -{ - return oidp->oid[0] != -1UL || oidp->oid[1] != -1UL || - oidp->oid[2] != -1UL; -} - -static inline int tmem_oid_compare(struct tmem_oid *left, - struct tmem_oid *right) -{ - int ret; - - if (left->oid[2] == right->oid[2]) { - if (left->oid[1] == right->oid[1]) { - if (left->oid[0] == right->oid[0]) - ret = 0; - else if (left->oid[0] < right->oid[0]) - ret = -1; - else - return 1; - } else if (left->oid[1] < right->oid[1]) - ret = -1; - else - ret = 1; - } else if (left->oid[2] < right->oid[2]) - ret = -1; - else - ret = 1; - return ret; -} - -static inline unsigned tmem_oid_hash(struct tmem_oid *oidp) -{ - return hash_long(oidp->oid[0] ^ oidp->oid[1] ^ oidp->oid[2], - TMEM_HASH_BUCKET_BITS); -} - -/* - * A tmem_obj contains an identifier (oid), pointers to the parent - * pool and the rb_tree to which it belongs, counters, and an ordered - * set of pampds, structured in a radix-tree-like tree. The intermediate - * nodes of the tree are called tmem_objnodes. - */ - -struct tmem_objnode; - -struct tmem_obj { - struct tmem_oid oid; - struct tmem_pool *pool; - struct rb_node rb_tree_node; - struct tmem_objnode *objnode_tree_root; - unsigned int objnode_tree_height; - unsigned long objnode_count; - long pampd_count; - void *extra; /* for private use by pampd implementation */ - DECL_SENTINEL -}; - -#define OBJNODE_TREE_MAP_SHIFT 6 -#define OBJNODE_TREE_MAP_SIZE (1UL << OBJNODE_TREE_MAP_SHIFT) -#define OBJNODE_TREE_MAP_MASK (OBJNODE_TREE_MAP_SIZE-1) -#define OBJNODE_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) -#define OBJNODE_TREE_MAX_PATH \ - (OBJNODE_TREE_INDEX_BITS/OBJNODE_TREE_MAP_SHIFT + 2) - -struct tmem_objnode { - struct tmem_obj *obj; - DECL_SENTINEL - void *slots[OBJNODE_TREE_MAP_SIZE]; - unsigned int slots_in_use; -}; - -/* pampd abstract datatype methods provided by the PAM implementation */ -struct tmem_pamops { - void *(*create)(char *, size_t, bool, int, - struct tmem_pool *, struct tmem_oid *, uint32_t); - int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *, - struct tmem_oid *, uint32_t); - int (*get_data_and_free)(char *, size_t *, bool, void *, - struct tmem_pool *, struct tmem_oid *, - uint32_t); - void (*free)(void *, struct tmem_pool *, struct tmem_oid *, uint32_t); - void (*free_obj)(struct tmem_pool *, struct tmem_obj *); - bool (*is_remote)(void *); - void (*new_obj)(struct tmem_obj *); - int (*replace_in_obj)(void *, struct tmem_obj *); -}; -extern void tmem_register_pamops(struct tmem_pamops *m); - -/* memory allocation methods provided by the host implementation */ -struct tmem_hostops { - struct tmem_obj *(*obj_alloc)(struct tmem_pool *); - void (*obj_free)(struct tmem_obj *, struct tmem_pool *); - struct tmem_objnode *(*objnode_alloc)(struct tmem_pool *); - void (*objnode_free)(struct tmem_objnode *, struct tmem_pool *); - void (*flush_all_obj)(void); - void (*control)(bool); -}; -extern void tmem_register_hostops(struct tmem_hostops *m); - -/* core tmem accessor functions */ -extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index, - char *, size_t, bool, bool); -extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index, - char *, size_t *, bool, int); -extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index, - void *); -extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *, - uint32_t index); -extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *); -extern int tmem_destroy_pool(struct tmem_pool *); -extern int tmem_flush_pool(struct tmem_pool *); -extern void tmem_new_pool(struct tmem_pool *, uint32_t); - -extern void tmem_enable(void); -extern void tmem_disable(void); -#endif /* _TMEM_H */ diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig index 342676ec..4c9141bd 100644 --- a/drivers/staging/zcache/Kconfig +++ b/drivers/staging/zcache/Kconfig @@ -1,6 +1,7 @@ + config ZCACHE bool "Dynamic compression of swap pages and clean pagecache pages" - depends on (CLEANCACHE) && CRYPTO=y && ZSMALLOC=y + depends on (CLEANCACHE || FRONTSWAP) && CRYPTO=y && ZSMALLOC=y select CRYPTO_LZO default n help diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c index 1ca66ea9..56c8e606 100644 --- a/drivers/staging/zcache/tmem.c +++ b/drivers/staging/zcache/tmem.c @@ -3,7 +3,7 @@ * * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp. * - * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented + * The primary purpose of Transcendent Memory ("tmem") is to map object-oriented * "handles" (triples containing a pool id, and object id, and an index), to * pages in a page-accessible memory (PAM). Tmem references the PAM pages via * an abstract "pampd" (PAM page-descriptor), which can be operated on by a @@ -72,33 +72,49 @@ void tmem_register_pamops(struct tmem_pamops *m) * the hashbucket lock must be held. */ -/* searches for object==oid in pool, returns locked object if found */ -static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb, - struct tmem_oid *oidp) +static struct tmem_obj +*__tmem_obj_find(struct tmem_hashbucket*hb, struct tmem_oid *oidp, + struct rb_node **parent, struct rb_node ***link) { - struct rb_node *rbnode; - struct tmem_obj *obj; - - rbnode = hb->obj_rb_root.rb_node; - while (rbnode) { - BUG_ON(RB_EMPTY_NODE(rbnode)); - obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node); + struct rb_node *_parent = NULL, **rbnode; + struct tmem_obj *obj = NULL; + + rbnode = &hb->obj_rb_root.rb_node; + while (*rbnode) { + BUG_ON(RB_EMPTY_NODE(*rbnode)); + _parent = *rbnode; + obj = rb_entry(*rbnode, struct tmem_obj, + rb_tree_node); switch (tmem_oid_compare(oidp, &obj->oid)) { case 0: /* equal */ goto out; case -1: - rbnode = rbnode->rb_left; + rbnode = &(*rbnode)->rb_left; break; case 1: - rbnode = rbnode->rb_right; + rbnode = &(*rbnode)->rb_right; break; } } + + if (parent) + *parent = _parent; + if (link) + *link = rbnode; + obj = NULL; out: return obj; } + +/* searches for object==oid in pool, returns locked object if found */ +static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb, + struct tmem_oid *oidp) +{ + return __tmem_obj_find(hb, oidp, NULL, NULL); +} + static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *); /* free an object that has no more pampds in it */ @@ -131,8 +147,7 @@ static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb, struct tmem_oid *oidp) { struct rb_root *root = &hb->obj_rb_root; - struct rb_node **new = &(root->rb_node), *parent = NULL; - struct tmem_obj *this; + struct rb_node **new = NULL, *parent = NULL; BUG_ON(pool == NULL); atomic_inc(&pool->obj_count); @@ -144,22 +159,10 @@ static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb, obj->pampd_count = 0; (*tmem_pamops.new_obj)(obj); SET_SENTINEL(obj, OBJ); - while (*new) { - BUG_ON(RB_EMPTY_NODE(*new)); - this = rb_entry(*new, struct tmem_obj, rb_tree_node); - parent = *new; - switch (tmem_oid_compare(oidp, &this->oid)) { - case 0: - BUG(); /* already present; should never happen! */ - break; - case -1: - new = &(*new)->rb_left; - break; - case 1: - new = &(*new)->rb_right; - break; - } - } + + if (__tmem_obj_find(hb, oidp, &parent, &new)) + BUG(); + rb_link_node(&obj->rb_tree_node, parent, new); rb_insert_color(&obj->rb_tree_node, root); } diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index bb927535..f81a1041 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -31,13 +31,11 @@ #include #include #include +#include #include "tmem.h" -#include "../zsmalloc/zsmalloc.h" +#include -#if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP)) -#error "zcache is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP" -#endif #ifdef CONFIG_CLEANCACHE #include #endif @@ -53,15 +51,13 @@ (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC) #endif -#define MAX_POOLS_PER_CLIENT 16 - #define MAX_CLIENTS 16 #define LOCAL_CLIENT ((uint16_t)-1) MODULE_LICENSE("GPL"); struct zcache_client { - struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT]; + struct idr tmem_pools; struct zs_pool *zspool; bool allocated; atomic_t refcount; @@ -78,6 +74,17 @@ static inline uint16_t get_client_id_from_client(struct zcache_client *cli) return cli - &zcache_clients[0]; } +static struct zcache_client *get_zcache_client(uint16_t cli_id) +{ + if (cli_id == LOCAL_CLIENT) + return &zcache_host; + + if ((unsigned int)cli_id < MAX_CLIENTS) + return &zcache_clients[cli_id]; + + return NULL; +} + static inline bool is_local_client(struct zcache_client *cli) { return cli == &zcache_host; @@ -98,7 +105,7 @@ static inline int zcache_comp_op(enum comp_op op, u8 *dst, unsigned int *dlen) { struct crypto_comp *tfm; - int ret = 0; + int ret; BUG_ON(!zcache_comp_pcpu_tfms); tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, get_cpu()); @@ -110,6 +117,8 @@ static inline int zcache_comp_op(enum comp_op op, case ZCACHE_COMPOP_DECOMPRESS: ret = crypto_comp_decompress(tfm, src, slen, dst, dlen); break; + default: + ret = -EINVAL; } put_cpu(); return ret; @@ -602,16 +611,14 @@ static void zbud_evict_pages(int nr) return; } -static void zbud_init(void) +static void __init zbud_init(void) { int i; INIT_LIST_HEAD(&zbud_buddied_list); - zcache_zbud_buddied_count = 0; - for (i = 0; i < NCHUNKS; i++) { + + for (i = 0; i < NCHUNKS; i++) INIT_LIST_HEAD(&zbud_unbuddied[i].list); - zbud_unbuddied[i].count = 0; - } } #ifdef CONFIG_SYSFS @@ -693,71 +700,71 @@ static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5; static atomic_t zv_curr_dist_counts[NCHUNKS]; static atomic_t zv_cumul_dist_counts[NCHUNKS]; -static struct zv_hdr *zv_create(struct zs_pool *pool, uint32_t pool_id, +static unsigned long zv_create(struct zs_pool *pool, uint32_t pool_id, struct tmem_oid *oid, uint32_t index, void *cdata, unsigned clen) { struct zv_hdr *zv; u32 size = clen + sizeof(struct zv_hdr); int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT; - void *handle = NULL; + unsigned long handle = 0; BUG_ON(!irqs_disabled()); BUG_ON(chunks >= NCHUNKS); - handle = (void *)zs_malloc(pool, size); + handle = zs_malloc(pool, size); if (!handle) goto out; atomic_inc(&zv_curr_dist_counts[chunks]); atomic_inc(&zv_cumul_dist_counts[chunks]); - zv = zs_map_object(pool, (unsigned long)handle, ZS_MM_RW); + zv = zs_map_object(pool, handle, ZS_MM_WO); zv->index = index; zv->oid = *oid; zv->pool_id = pool_id; zv->size = clen; SET_SENTINEL(zv, ZVH); memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen); - zs_unmap_object(pool, (unsigned long)handle); + zs_unmap_object(pool, handle); out: return handle; } -static void zv_free(struct zs_pool *pool, void *handle) +static void zv_free(struct zs_pool *pool, unsigned long handle) { unsigned long flags; struct zv_hdr *zv; uint16_t size; int chunks; - zv = zs_map_object(pool, (unsigned long)handle, ZS_MM_RW); + zv = zs_map_object(pool, handle, ZS_MM_RW); ASSERT_SENTINEL(zv, ZVH); size = zv->size + sizeof(struct zv_hdr); INVERT_SENTINEL(zv, ZVH); - zs_unmap_object(pool, (unsigned long)handle); + zs_unmap_object(pool, handle); chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT; BUG_ON(chunks >= NCHUNKS); atomic_dec(&zv_curr_dist_counts[chunks]); local_irq_save(flags); - zs_free(pool, (unsigned long)handle); + zs_free(pool, handle); local_irq_restore(flags); } -static void zv_decompress(struct page *page, void *handle) +static void zv_decompress(struct page *page, unsigned long handle) { unsigned int clen = PAGE_SIZE; char *to_va; int ret; struct zv_hdr *zv; - zv = zs_map_object(zcache_host.zspool, (unsigned long)handle, ZS_MM_RW); + zv = zs_map_object(zcache_host.zspool, handle, ZS_MM_RO); BUG_ON(zv->size == 0); ASSERT_SENTINEL(zv, ZVH); to_va = kmap_atomic(page); ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, (char *)zv + sizeof(*zv), zv->size, to_va, &clen); kunmap_atomic(to_va); - zs_unmap_object(zcache_host.zspool, (unsigned long)handle); + zs_unmap_object(zcache_host.zspool, handle); BUG_ON(ret); BUG_ON(clen != PAGE_SIZE); } @@ -939,21 +946,14 @@ static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid) struct tmem_pool *pool = NULL; struct zcache_client *cli = NULL; - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else { - if (cli_id >= MAX_CLIENTS) - goto out; - cli = &zcache_clients[cli_id]; - if (cli == NULL) - goto out; - atomic_inc(&cli->refcount); - } - if (poolid < MAX_POOLS_PER_CLIENT) { - pool = cli->tmem_pools[poolid]; - if (pool != NULL) - atomic_inc(&pool->refcount); - } + cli = get_zcache_client(cli_id); + if (!cli) + goto out; + + atomic_inc(&cli->refcount); + pool = idr_find(&cli->tmem_pools, poolid); + if (pool != NULL) + atomic_inc(&pool->refcount); out: return pool; } @@ -971,22 +971,21 @@ static void zcache_put_pool(struct tmem_pool *pool) int zcache_new_client(uint16_t cli_id) { - struct zcache_client *cli = NULL; + struct zcache_client *cli; int ret = -1; - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; + cli = get_zcache_client(cli_id); + if (cli == NULL) goto out; if (cli->allocated) goto out; cli->allocated = 1; #ifdef CONFIG_FRONTSWAP - cli->zspool = zs_create_pool("zcache", ZCACHE_GFP_MASK); + cli->zspool = zs_create_pool(ZCACHE_GFP_MASK); if (cli->zspool == NULL) goto out; + idr_init(&cli->tmem_pools); #endif ret = 0; out: @@ -1035,45 +1034,38 @@ static int zcache_do_preload(struct tmem_pool *pool) goto out; if (unlikely(zcache_obj_cache == NULL)) goto out; - preempt_disable(); + + /* IRQ has already been disabled. */ kp = &__get_cpu_var(zcache_preloads); while (kp->nr < ARRAY_SIZE(kp->objnodes)) { - preempt_enable_no_resched(); objnode = kmem_cache_alloc(zcache_objnode_cache, ZCACHE_GFP_MASK); if (unlikely(objnode == NULL)) { zcache_failed_alloc++; goto out; } - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - if (kp->nr < ARRAY_SIZE(kp->objnodes)) - kp->objnodes[kp->nr++] = objnode; - else - kmem_cache_free(zcache_objnode_cache, objnode); + + kp->objnodes[kp->nr++] = objnode; } - preempt_enable_no_resched(); - obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK); - if (unlikely(obj == NULL)) { - zcache_failed_alloc++; - goto out; + + if (!kp->obj) { + obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK); + if (unlikely(obj == NULL)) { + zcache_failed_alloc++; + goto out; + } + kp->obj = obj; } - page = (void *)__get_free_page(ZCACHE_GFP_MASK); - if (unlikely(page == NULL)) { - zcache_failed_get_free_pages++; - kmem_cache_free(zcache_obj_cache, obj); - goto out; + + if (!kp->page) { + page = (void *)__get_free_page(ZCACHE_GFP_MASK); + if (unlikely(page == NULL)) { + zcache_failed_get_free_pages++; + goto out; + } + kp->page = page; } - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - if (kp->obj == NULL) - kp->obj = obj; - else - kmem_cache_free(zcache_obj_cache, obj); - if (kp->page == NULL) - kp->page = page; - else - free_page((unsigned long)page); + ret = 0; out: return ret; @@ -1247,7 +1239,7 @@ static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw, int ret = 0; BUG_ON(is_ephemeral(pool)); - zv_decompress((struct page *)(data), pampd); + zv_decompress((struct page *)(data), (unsigned long)pampd); return ret; } @@ -1281,7 +1273,7 @@ static void zcache_pampd_free(void *pampd, struct tmem_pool *pool, atomic_dec(&zcache_curr_eph_pampd_count); BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0); } else { - zv_free(cli->zspool, pampd); + zv_free(cli->zspool, (unsigned long)pampd); atomic_dec(&zcache_curr_pers_pampd_count); BUG_ON(atomic_read(&zcache_curr_pers_pampd_count) < 0); } @@ -1582,15 +1574,14 @@ static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp, else zcache_failed_pers_puts++; } - zcache_put_pool(pool); - preempt_enable_no_resched(); } else { zcache_put_to_flush++; if (atomic_read(&pool->obj_count) > 0) /* the put fails whether the flush succeeds or not */ (void)tmem_flush_page(pool, oidp, index); - zcache_put_pool(pool); } + + zcache_put_pool(pool); out: return ret; } @@ -1660,22 +1651,21 @@ static int zcache_flush_object(int cli_id, int pool_id, static int zcache_destroy_pool(int cli_id, int pool_id) { struct tmem_pool *pool = NULL; - struct zcache_client *cli = NULL; + struct zcache_client *cli; int ret = -1; if (pool_id < 0) goto out; - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; + + cli = get_zcache_client(cli_id); if (cli == NULL) goto out; + atomic_inc(&cli->refcount); - pool = cli->tmem_pools[pool_id]; + pool = idr_find(&cli->tmem_pools, pool_id); if (pool == NULL) goto out; - cli->tmem_pools[pool_id] = NULL; + idr_remove(&cli->tmem_pools, pool_id); /* wait for pool activity on other cpus to quiesce */ while (atomic_read(&pool->refcount) != 0) ; @@ -1695,13 +1685,12 @@ static int zcache_new_pool(uint16_t cli_id, uint32_t flags) int poolid = -1; struct tmem_pool *pool; struct zcache_client *cli = NULL; + int r; - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; + cli = get_zcache_client(cli_id); if (cli == NULL) goto out; + atomic_inc(&cli->refcount); pool = kmalloc(sizeof(struct tmem_pool), GFP_ATOMIC); if (pool == NULL) { @@ -1709,20 +1698,25 @@ static int zcache_new_pool(uint16_t cli_id, uint32_t flags) goto out; } - for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++) - if (cli->tmem_pools[poolid] == NULL) - break; - if (poolid >= MAX_POOLS_PER_CLIENT) { - pr_info("zcache: pool creation failed: max exceeded\n"); + do { + r = idr_pre_get(&cli->tmem_pools, GFP_ATOMIC); + if (r != 1) { + kfree(pool); + pr_info("zcache: pool creation failed: out of memory\n"); + goto out; + } + r = idr_get_new(&cli->tmem_pools, pool, &poolid); + } while (r == -EAGAIN); + if (r) { + pr_info("zcache: pool creation failed: error %d\n", r); kfree(pool); - poolid = -1; goto out; } + atomic_set(&pool->refcount, 0); pool->client = cli; pool->pool_id = poolid; tmem_new_pool(pool, flags); - cli->tmem_pools[poolid] = pool; pr_info("zcache: created %s tmem pool, id=%d, client=%d\n", flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral", poolid, cli_id); @@ -1817,9 +1811,9 @@ static struct cleancache_ops zcache_cleancache_ops = { .init_fs = zcache_cleancache_init_fs }; -struct cleancache_ops *zcache_cleancache_register_ops(void) +struct cleancache_ops zcache_cleancache_register_ops(void) { - struct cleancache_ops *old_ops = + struct cleancache_ops old_ops = cleancache_register_ops(&zcache_cleancache_ops); return old_ops; @@ -1834,7 +1828,7 @@ static int zcache_frontswap_poolid = -1; * Swizzling increases objects per swaptype, increasing tmem concurrency * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from - * frontswap_get_page(), but has side-effects. Hence using 8. + * frontswap_load(), but has side-effects. Hence using 8. */ #define SWIZ_BITS 8 #define SWIZ_MASK ((1 << SWIZ_BITS) - 1) @@ -1848,7 +1842,7 @@ static inline struct tmem_oid oswiz(unsigned type, u32 ind) return oid; } -static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, +static int zcache_frontswap_store(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -1869,7 +1863,7 @@ static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, /* returns 0 if the page was successfully gotten from frontswap, -1 if * was not present (should never happen!) */ -static int zcache_frontswap_get_page(unsigned type, pgoff_t offset, +static int zcache_frontswap_load(unsigned type, pgoff_t offset, struct page *page) { u64 ind64 = (u64)offset; @@ -1918,8 +1912,8 @@ static void zcache_frontswap_init(unsigned ignored) } static struct frontswap_ops zcache_frontswap_ops = { - .put_page = zcache_frontswap_put_page, - .get_page = zcache_frontswap_get_page, + .store = zcache_frontswap_store, + .load = zcache_frontswap_load, .invalidate_page = zcache_frontswap_flush_page, .invalidate_area = zcache_frontswap_flush_area, .init = zcache_frontswap_init @@ -1940,7 +1934,7 @@ struct frontswap_ops zcache_frontswap_register_ops(void) * NOTHING HAPPENS! */ -static int zcache_enabled; +static int zcache_enabled = 1; static int __init enable_zcache(char *s) { @@ -1980,7 +1974,7 @@ static int __init enable_zcache_compressor(char *s) __setup("zcache=", enable_zcache_compressor); -static int zcache_comp_init(void) +static int __init zcache_comp_init(void) { int ret = 0; @@ -2020,7 +2014,7 @@ static int __init zcache_init(void) goto out; } #endif /* CONFIG_SYSFS */ -#if defined(CONFIG_CLEANCACHE) || defined(CONFIG_FRONTSWAP) + if (zcache_enabled) { unsigned int cpu; @@ -2051,17 +2045,17 @@ static int __init zcache_init(void) pr_err("zcache: can't create client\n"); goto out; } -#endif + #ifdef CONFIG_CLEANCACHE if (zcache_enabled && use_cleancache) { - struct cleancache_ops *old_ops; + struct cleancache_ops old_ops; zbud_init(); register_shrinker(&zcache_shrinker); old_ops = zcache_cleancache_register_ops(); pr_info("zcache: cleancache enabled using kernel " "transcendent memory and compression buddies\n"); - if (old_ops != NULL) + if (old_ops.init_fs != NULL) pr_warning("zcache: cleancache_ops overridden"); } #endif diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile deleted file mode 100644 index cb0f9ced..00000000 --- a/drivers/staging/zram/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -zram-y := zram_drv.o - -obj-$(CONFIG_ZRAM) += zram.o diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt deleted file mode 100644 index 765d790a..00000000 --- a/drivers/staging/zram/zram.txt +++ /dev/null @@ -1,77 +0,0 @@ -zram: Compressed RAM based block devices ----------------------------------------- - -Project home: http://compcache.googlecode.com/ - -* Introduction - -The zram module creates RAM based block devices named /dev/zram -( = 0, 1, ...). Pages written to these disks are compressed and stored -in memory itself. These disks allow very fast I/O and compression provides -good amounts of memory savings. Some of the usecases include /tmp storage, -use as swap disks, various caches under /var and maybe many more :) - -Statistics for individual zram devices are exported through sysfs nodes at -/sys/block/zram/ - -* Usage - -Following shows a typical sequence of steps for using zram. - -1) Load Module: - modprobe zram num_devices=4 - This creates 4 devices: /dev/zram{0,1,2,3} - (num_devices parameter is optional. Default: 1) - -2) 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: - # Initialize /dev/zram0 with 50MB disksize - echo $((50*1024*1024)) > /sys/block/zram0/disksize - - # Using mem suffixes - echo 256K > /sys/block/zram0/disksize - echo 512M > /sys/block/zram0/disksize - echo 1G > /sys/block/zram0/disksize - -3) Activate: - mkswap /dev/zram0 - swapon /dev/zram0 - - mkfs.ext4 /dev/zram1 - mount /dev/zram1 /tmp - -4) Stats: - Per-device statistics are exported as various nodes under - /sys/block/zram/ - disksize - num_reads - num_writes - invalid_io - notify_free - discard - zero_pages - orig_data_size - compr_data_size - mem_used_total - -5) Deactivate: - swapoff /dev/zram0 - umount /dev/zram1 - -6) Reset: - Write any positive value to 'reset' sysfs node - echo 1 > /sys/block/zram0/reset - echo 1 > /sys/block/zram1/reset - - This frees all the memory allocated for the given device and - resets the disksize to zero. You must set the disksize again - before reusing the device. - -Please report any problems at: - - Mailing list: linux-mm-cc at laptop dot org - - Issue tracker: http://code.google.com/p/compcache/issues/list - -Nitin Gupta -ngupta@vflare.org diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig deleted file mode 100644 index 08adf5dc..00000000 --- a/drivers/staging/zsmalloc/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config ZSMALLOC - tristate "Memory allocator for compressed pages" - depends on MMU - default n - help - zsmalloc is a slab-based memory allocator designed to store - compressed RAM pages. zsmalloc uses virtual memory mapping - in order to reduce fragmentation. However, this results in a - non-standard allocator interface where a handle, not a pointer, is - returned by an alloc(). This handle must be mapped in order to - access the allocated space. - -config PGTABLE_MAPPING - bool "Use page table mapping to access object in zsmalloc" - depends on ZSMALLOC - help - By default, zsmalloc uses a copy-based object mapping method to - access allocations that span two pages. However, if a particular - architecture (ex, ARM) performs VM mapping faster than copying, - then you should select this. This causes zsmalloc to use page table - mapping rather than copying for object mapping. - - You can check speed with zsmalloc benchmark[1]. - [1] https://github.com/spartacus06/zsmalloc diff --git a/drivers/staging/zsmalloc/Makefile b/drivers/staging/zsmalloc/Makefile deleted file mode 100644 index b134848a..00000000 --- a/drivers/staging/zsmalloc/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -zsmalloc-y := zsmalloc-main.o - -obj-$(CONFIG_ZSMALLOC) += zsmalloc.o diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 92c5eafd..b83cded5 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -2445,19 +2445,19 @@ static int msm_hs_runtime_idle(struct device *dev) static int msm_hs_runtime_resume(struct device *dev) { - struct platform_device *pdev = container_of(dev, struct +/* struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - msm_hs_request_clock_on(&msm_uport->uport); + msm_hs_request_clock_on(&msm_uport->uport);*/ return 0; } static int msm_hs_runtime_suspend(struct device *dev) { - struct platform_device *pdev = container_of(dev, struct +/* struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - msm_hs_request_clock_off(&msm_uport->uport); + msm_hs_request_clock_off(&msm_uport->uport);*/ return 0; } diff --git a/drivers/video/msm.zip b/drivers/video/msm.zip new file mode 100644 index 0000000000000000000000000000000000000000..68bb391837d4de6320589201903016881d3bbbad GIT binary patch literal 3844017 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 z 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�h*+^g`RIYQKN$l-|ip}fOL%pgQ!DRxdsHu7=H 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 z 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

Bc-`^ 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

e4W`fUrfRQb7zXrRD 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ⅅc@V6ec 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�k~E$MWyusJ{921oY_*F)oNWJ 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�-PqPAgd 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ⅇ~q~z0I;4FAZr--tLhu{&z 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

    DCQ$+0xV&S$Q0- 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π_7^2q5hdIF^eo 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%0AMm>
    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�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℘5eu`wt36XKQ%3B`G
    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�IhlOv_QQ6+^O|Fi
    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

    fR| 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

    m5?P_uq!fI%@MH*N^XVYY5o_;FbkP8|8cGJhm*K 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�-+^g$ZwhC49kpMxc2n`{ln+_hSnj!^u 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

    *mpe#m-Utt$XMyg30Y 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
    lNDbS{B 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 w7*^QIS4Mz*$9~XX9 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

    (9lDt=#1=r@uL5 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%0AMOI6n~3DTT2&ILzCm%cCPluj-Rmt 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 z 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𝔑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�@ zGIMhk$g9YcTVDkz1|)kD%77ii(I{H3ua68C{qe3K`H{F4#|B9}2}(t_W92Q5pipG_FvQ3pYI~DG&DUb|GZaVVY=> z6^uGqb1ed5VVRfpJJglULY(S8mGMP)K!&&ndEmqi%PEz4uo0s~ElaxF46m}(d zNK-z<>$#R6%G}T@9=>Tr`tQOGb8X5h?QM!QiJtXWYlZX0e#Ws-;E%Pd`U!RRfeZK( zO-v6i*3t~TQIngSEHVMOMyt#f`xz&4fH!HPlNYd%a^TI{@hGulvDyb*tBDRYneD0r zu9G;8oz4Q@qWP{N?8d1Y@KzZ*hrh0arNHJM!g;JL7I>R1RUf+~26#L273)GaGXTB= z)e|d0ddU@z2y?L$-U9i^&Q8ilc652r``hKp-CYJcCC|(iuZz7`jwCTV6sSLVHysW6;`PpE)i{{ z(5M)qik=%_&0)YQi3M!63anP;^v0g2LJpG$vlZ+pMXph^qQxQpgHB)_)-9q@*3|+> z$b1LbSc=>%aVc}_z)=#Hu@fVJEkLodXZh9ORs2@gN)f=LTztPx;T5z|DNtgU>W9w7Fy{dfTv9Wq8 z-+Zuqg?S43dx7NpZ5WT>g_b{TY;PX8Up-gC{b6GZ{9ro5m#;Km!N5z@Xz|QqW3f@- z>*SjDB^w*#0k6XQAiO>{_GJuswRMVZ!;qzMmvnb7Um0zHx15VGfZX}}zJzSPh3e=3 z^=zpa!dE*%`vvLdk2^rG#FmKxZDfO97Zheb!9a%^K;jr;?i!Al;p}=|~LLSzg zw#;TINl)i<*FuFDCAd0QRY5FpzF^GXZ7m+Y%>ez*T0UlFfu56-I@ZUaJ#s}1H&IWqcB5fR=I$<&+E7S* zN15k)ZZJZFj37Nv)d{S0@@mkPZLp)prsIxLKVC>oh8TmwLB zK(A=iFkcjL4?F*cp}VK(&HZI^%c&N{g8b(CBGB822CBur73heyXCStF zj#?QkSNuhZXtSa)%}IA9Zr0SEwu#>QUJKBvp**}XoUg)`uQ>85MCEJ1V)l$YOYNE8 ztrWY7tX-XAPl9TFF9V9QR*S9iplF!ji}dH!^W-+48+)F-a2%D%sa2wBOER9OOqXD` zD#^6Axd{{PM`U0?nhB7QI?7eOxM^b?|#J1Xw}_{nx-}lS>`y2xP)u zHJ}exomHat%5Y$a>gTAlaTFRVLmljd4h)kR#ugL-O^GhHD+uV6=w?IHf#DLp?15aM zOQMhcC|%+dfr%0)$YC-b zJ`Tl&KicC@WE=*=LAC5Mjp8xt7-dT}L?G|G`;@XPv@e>3@9D9qY?&sWi|~?h1Mn&> zK@~p83jnXyLK}n+9&7}zkju*w_l(8;O4&;7xmsQpRyz)%*J}&w#cDIY61Yk(O{cMn z9N=nA^sqT>S~2h^+T&GXJ!y0RZ`8hS;xBJw!zdBFR#Qh1f3C4Bs=@2DFBEyR{c|Mv z4lQVeytyWqg737}qc*nE3BF5XJbaCfEvLfVr_HaC-y8jkvcF%0>&5p*dtBfLv}0oN zVsqmusq8`RZR=kB=@@gL*P4ia~AE0|L4HGdUtcG+$&Iu}_vG%gs3P@ZsT){OGDmC#98p??a zs6a~2pT|(Fchsd6%a%j2J{m=_zR0Io{6()s7i3-WKS77{rJtzedHxz;>8EnFiM4VX z@G~qy#Mr9o1fEu{SBfGpjYNQ2`jt9s7}8!#1LA8H(*ULQY#a*wMjbq=);*^TXug%2 z1k(ID1DfyDG!14{gEZGss&i7K^ElzqD4NjNpb>>s;e63WUnvLLWWVyUb(uh26F2%) zb~X=aXt_0n4W6ULK)bXSM5ArJhb9}%?iHi0Py>c(gR9~lkziBX=asACL@KgV^Sk6K z_q!Z$xOP~RJI${Lz%I#8sGi?Az!4g+v@M<%qMjXNXx0%b)yGvMC|4#`aa=XM0xGvu z#d6hyH5r)5uj2*1LlHyP??~m<^YA23tE=G zumV&e2NHEkOa?UKlHLvH>&N06ewbASO-usUG(zK#aMBI8gwJtqI=d?^)!r$Wn}E}U zVXY$g$K;2fAyGxhoLU()98+g?Whk*Z6EjR@*st#8LD+x>g&*LgMtbU}V|Z!jq96sJ^E zi2wxzWtxYJK>5aIu|aq!7F6KpRA4@x1}YR(Von_kDwP|Aa1_-!?nEcJ!t30hj3rN5 z#v`?Im%c3X{4PBx>(_PGEJ6jK$F%3lS zyDc6xQ?72zC+whZ5O?2AWuP8Eh}<{M0L{K~xNzSI9W+O-Yjy|kPPc!c6x6}DH>)Bypy}Xx(l7yhk z@W=Uf3Hm|VYw)LRuGg*8Wxkp@C>Aq1e+jqjZ#y$ZF8_!Iy_p~v+CMI!`lQL17XMfb zdOM1jz%82Oh+K|}COIm|Cz|A#pOarS$#KynsiH~Vb;{=A>xK7{xXl1>pp&A33aCj= zRq%ik)M@fyb%A)EyJy#D+hz(Iz7B^X@dj}&yqM&~K2}YSAP8c+W8Az5q=7LUi^ajmLnU&b9=lUPz*5cHz)8AZd=`MHNIkZOu3vCV&qI^cp29;- ztOJ~7X}BK`37i=rXQ&~$$XIShfby&xN=OzcKWLVip>pa#1^eX;m0klX>gQoDbGH*z zEXa**0#FIegS^-n0F?^zVbcIqCdiM25>UCIRP&YuP=%mOUtf2RGNf|rY@z^OT1D6p z<`?(ltK1-YqFI7%5>WMan{_{qp-R3EbW}~DSFe3Dr}rsUQx!w*A+%sJs+#s43th_9tDLthOu6<**|x-GRz&MN}GSd)G^F+ z5vBMmnzAOMfI?>FK#aV(nJ=d(tZ@t!?n6}6c}LmkL^eB8jaNMJFRG!$(pPrz^v*-zF=OLLFSM4JtxN z%pZ|et)o|gxU&OdFr0^Io3kK?AT6p{TR8)N&2wo`4VftWN1Y2))h)YRn5(wtF^cq3 z8Pv5qWTYrJsLt9iyuuHvM>KJpiw6xal60gN)F6+5#rD?jk=7@AVPUn+rw5BL@_R)X zC5s^JwMcvTEVp({{U|F*`}dNJwUQ)CyEho> ziPqLta1-bfd7ej+rmvw$5fxC+=#cmNsk6G3+L^sFl6RoC^e7_5aBq}x@iuaH^-yY# z!wnD{$=_L17Y!)2t-DG4NF%i4PLsHfN;##Tk`;`D*iFR}FaH01l-v*W;cFl)T36H- zl((Qb6R0?a)|ZQ06i|`XCUv=>V#@_@)`5CZ2l37DYYD(vWY)h5OPP}37c{+<4kohb zYktkz4WH!!z9>-_|5w6G5*_U3eBd7>hOuSoz&}cKF*O;uSE8FuDFp7<#J;hYU0Mq~ zs97grt#;r$T9J*=@1`$5f{$qBnz(b7MG*zly|fwlUgn-Ix2 zf00sOA{+_mSL#b|Z52KagXQ`%l$u*k`Yer4A(SZ4hbjc>D?ebI_?rp! zBSgs*9~Gv)83FRUojZ}z83F4B!y{L;$#1BKGjW1XLS?$keKm0I$^OX+cg@=?5Hii1(f6dQXeQVc*3y-MfZ+yRF0ND7!lkQV|@t* z3i(=oK;m@Q!{P{Y21RsJMCWxf;(!knjsSUPM49GnMLIn$S-lpJc%VhW)jpzc*Y1fUY-H!+rTLmZ(xEJ%I}@=wHc`2dW)qc zA2cB5r2>3y23jn>HY>pbV-E5Phm}yeps*+(u2dLjEX-6iucJK7@VRf;4(?GwGTZHDeX3&!$p3U8U&~}*O*}Renda75EpRtbuJ#G0W zj>4W%RNDhv&jW}t*#%Fk(uaF zt&!Fp@q80eQ-^G5=q8wh9$>yKRK>hMf8uP#~ z(14(B^VK5I65*ve=4h(lQbB!YGFiF0oLgCn*%6C~Gi^_hFU*aZ2>OlHD}PSKd{XvG zUvIC{_S;*Eg{Mmyf}WPAewgGz&xrel3t#4fp7pzgZy(ME?HcP8FJIzKbDY6m^GiyH}`G<2L|r^{cUl3#U3{t?znjNsj>Z=8I=AozEK?M|s593% z;Pdj$jg=wneigh&6=w_^LKHhaWCX@Z<2CrsG6b_+@L$v=WSee>!TZ$IW?_447VxhU zb=H{-+^@bZrU;hm1HJ;3uR*MiCrd}v$H>x?fZ(HpmTt8Hj}2NHXaOEqHw#OO-+|g@ z1{>OklysCEfp!fA;z`Gc0)uc4AkS!BK!+x78Ez$VHrj8g7VObhOr$rzvJo0JxKv$b z0HY=9c&!8Im8Kl*fd*iVCf5_}?gC((COWvA?XCnSXp2m-6;e7Hn52cYiZj|k9xzp! zYG5mpfY}n8*=uRQ9GSM2-E0Tu$37)LwPT|>UqU~pE zXl(Ef4UI2ZzEQuWOR{{U{_cMgb|&yu6n7kdyKmpi%ds!VBqSk^iy z=D$mz7oQKC`Og18Gygf??#%3L&vtxLSBKfPf_X>%Tgl)l%%^m9xZRD+Z|L%HJDX4I z>TtX1c#Pm3_htn%@3^lCZpRmN@o-!_{!~|o+09_SsLR9bZ2lVg$ztXOgSFCeck z0N(`W-CDsNnR!9^VkI*#DDO#c$IG1J$HCy4U|wLZ3}WU5<__AJ4Km{DhF)IDcIJMy!7-)09nKfoB#qXVZ04ohV@@zO zaO~uz+`sn&chCxIdGYeW063QUq=qgJj??VL%ZyxbJPhZ>%O8ut9ksXDtHsNhJwf0E z4ZgItOz-hv7f3rVxAf{*+Rn=*y*}*R&dZQq`)lCkV=t%l+Td^JrAx2yDtL8bFO9s! zCDKZS7a4UH8)GT%B;G}M4ssvZ&wN1>qsYP(R5Guq7T1CU+Qat}U(}-M)zP|C?X7LR z!g@Fi@-!}lJ-Uc30;ltD)m~j(>I3e~d>s8O4V{|oQXM1tiIwLoj9Wk|1m;qAPf z(km+wUWIlclh>P+<089|;U%WV!>d>uBaOPpDL#z?_tfmcAgUVN3x&jk!FxV%Z!K}B zwcErCF2QU$Z`IsJmDGpz4`S=*FmNfDPoq6r3@!unc9QvIWx19u<2&LM$t3Tq?QfBc zqaEYG6~{%)xbH%Y9DIw6u4DPKjZ>$Gu&~Q$6N30kCyu59gt1)AEe77rHdl$M8t@)Ys2a!D0he(?HKMEo@LtAxVU_}ybJ#}l zOE++(5j;U{7W-o;aE;-Y*n}F6fnG4xUWk?hXQ;f)GOz6QEQCk*SvOOScN|Y@wX8M+uL?ms2Bb12`&@e?Y)f{^V6U_baYXu@x3%FS z@6RYt<73JB2Z~enFqFX6$$cvWqa?1*Z#X>sKN@fb-)A%cL_L-02E%IBpL^ONc6Ken z&+zHs%?2I0EuN-Y--0zJrTbJL;8sR#x+dJl7$N550Jk&7i6P;@9gKdl$N=tS%n+?6 za2I2aI8qDT%~&knYyj>tK9^W7`V9s?#L{Zv7UUfto5Z7&&W)Jxxm+yASM^wjvaF~1qPe4EDQ)0_`%-X97)!wuLYhI9eG!x$!d zg#zETkFl@I1-@rkw~;^jfbSz(!Z>B=IYys2kp}$8SSHc0?7YC33N!yiW-{I-NG4A(eXhWFMz$Uk4^@NTIa6ylN!^jDU3sgnLy#MgR%yHa`%gr?%T*+5-r_#ll#Lm>0U$bkYMTFM(&S# zO7|l&=Ayyy=@}t?eo4}%Z0SBh?t69V{v+J(%eZ{SxkK3`Khj&u$Se6!igf=SZe6Zo z`)Gc`yAnTvalMkTPR$G7{y*@fPM1cIJw+SR9hAav8mL9;00M!+)Y5Y*zcFbV*`PF@ ztA_Pa(DKqQrq&^Ov~+F0h^{jv9}0Ya6sUmDkHWFJpu+DZx#f{&LyC%YHS^j+R9qn` z4DZT9vu7>u2Ri5k_1d~vO~GZ>fGXADL_Qb`szTBrKdr>ulxi;RaD_53?+fauGMQyQ zmk#Q`g!j7*ZUhZjE-4>tKA`HeJoWiaEoh+iLhLM(4cZg0CPG&xg9ckK#A>}jHR{o- z#+(xlsy(QNUKBs5ZnaEd0&U%xEGwUCX&Qby>g!*+v6WWt+h#lJk6H_C&9i4Q$=6S3 zv@lVDHQ&%|Q6~&po!??7UWPi{w4Q`!^OaV=xPN;7flVoA9;=65L4oSKk0nFqxf_P@SoiJ z!bF_|s5`qaQeDK+0qA6m7PU!0x044;k(>eya;hBr#NP)3Jvj4>&@X)1z)+{kbE=p# z6d3O0wbzb=7pkY9$135S;5@JKlyD~?Hr*SlPyQ4R?8I0iCQ(Kc8LPxRvOUSkwIOad zfPUu~?nqyE0VX?_=&I*TChJn1wcJ%UgaFf=s;$fw3(1U3wr;){8U^g)w7QBIMP_9= z?U!FaqPVl2J)C^I8R!r0?)=nx&ET>JoCD_D%_$CWF7pwsvUL*8p+;~|=<|Hh-gs~?FwYmIR)KrtbUmIga^-+aoD=U+^F?9< zrPs&#Wj4RUnT9`h5J6ilW@O+c9((E}@8)Ud^4H8A|=F6$;ZFATWK#Ygvxm7&1Zt|IO}XL|$J zFq*kL8^CQY zv~}5Src?sATOU5s#7+U;;X14HlbMzZet^F#vO*K%De~Q}gcbaxc4uesgD5Y41E(_; z$wRJprto{^W2q4Kx+0zYD-{yd-0a+(qeexBq1)G5~V1^>$BkC6J9TFrJr_+ytdoKI&T z*bV$C>u++Qr+hKPdXz~+2MMKS6-q9My5djr+iIRKVwR;gl+@&cL%AGDxlGkML!&ckb;AX+$k}ww!_~X48=S*}Xu$DJ$M-CU zd7voAI=X`y7L0iL?kRS*W$&$=pgj{dkz(3QUo>efKM1#Z8vc!a)$cVZ15~k@H*@`1 z395W+lxrw6~kOLBmJm#;Ft0fFRj zdMFwc+s1e8=VCx{xov#cPC*Fx3DQk!eJ$1Yp3(T>PF%>Q2Cwnco!IB3_O9{cotV}i z_?{Lp)R_BaG4L#-U-SzFzR#E;UdyGn&)?w4!C6dnH#%ZruQ@2RI`sPyi>yNXrysP~ zDzwuDpe1cwXwGQR-5~X@cpGYA=ExrNZb2m9;Wlt&UYZoq%_}Hhk!F751r^jw(#>y5 zL4_(3!|WOkDzcIrmIW%d>L{rPsHdVhGpZicOOfAvcOa;@q73spC#b~QgY!ZSsLw<` zndx!@s7z6bIUoQkSGJU!?+H*}MHQwq15}|jtIX>|L6w{M_IN`zs7g`2`3X@!MI+7h zUZDOH`H}TtBxrz&v)S}goYke0CY$j@1NW*|kFk4XFlu4s+Wl03gDLCltXlYM7-+p! zEK!|7_i-&a^p`pSH&C&AXCblrk(-)tMGSu)4Db7`D(Eo;wAm{3`^dyCXV0cW4JkM){(|B># zFBbTL>AcCMO7u?$s+B;PBA#pjW@!BMA`CY$lY3yRsOt~xqFFc31A79y+9%gc83fGI z2J&;}F0!hd)-ac!Gxd#)@OZYFw70t8d~OXiy+O2Zdc?`IP%~d8V}3heuBw#o{XoA{ zMdqsY;TQulZMHyyW22QKALr!Opli#MXynbBHtjfu&mU zJZ0w&H?T|_1SC6i8-eAl945Mv*?nz0-%kKm*mgEhbyRYu;>0&0!2a4~8I=#Vkx5AB zYO~3v5K7NBxpW?7WIV3;Z{KvFJ>XgoAO9t^)r=7}S_CRugi|WDT6bCLz*u0NHiX;2 zcR9czcCojT!SyT+6TfHx4%OxWDLW%$fDMe%A}SL&Oxp>h>}*N`HZuCe2c^K_+Dj7s z;t?p#YPs3-ci8W`roCrL@X)>&e1z8BrNAf zhFf(0=p9_LgX2%~L#6VT9L2pe6>=ou9W!lY$Gn8b&+9?+hI`N|04|SuotxcCd1qY1yl;FgGiKhmlYjq zghOpsq5*f&bx@(T$#?}RK$ABlqqTFQd}vpz9n~``6&4{3n;)7IBQ@9Bn(r!2PMK?_ zO)5QaE1^bN6o2QH#;GRa^Hs6Vfa2ZjB^C)R- z%csul)F#9Ic`5Z|=NnVt{#hE_{hWbC(Dt6fFjO)s44{rPA7%1!=6HD?0N^Q48#&8_1UAaq7+4OeEv4q*v$yQ{6OSEKX4G zywSaOl^PYs)dHuvAD3u|adE)u?vp^d>8Bhx!+l<2m{<`HoauJ1R-?kEY~aoAB#F`D zlN8`=ca_9A?3n|$xtk^WM1Cc3j(dSbzxaI#@D}$DiK)V<0p99cafFLGa$ST9Zv1uk}b)~fZSWq#licb>$N^xY?vZ*T#X z_{#wdDS;X{RiB`G4b-|-#o|;ivaim4X@x5BLk{2&chpK%;Ei>39zCU>L65>ZSxk9D_6EXTHX z;5hesiB)2c3wXWzn8a!vFA5y*K9a9W`~YQeg8Ph=){9wG(-S#tqqu>>-r#nwQY(1D zmB40qH;GN+$wc5Jcdf+nVplkDvU`@qX4>t9$_RcKb>uHkr4BL2p!s;wm8`!7ZdE<+ zIt077$*7~)Dn%+OH~C-FQS%c@B@ap6bhVYz*APhQ_;ZrEcJ^SVbm~< zf?8Dphk~eK8vY1X0mEW}3yio#RZPdSf!J`yE1NT8fD0Mx#ra&|V&ma^RY9at%y%2s ziM5ZrfcG$t7pZ-L%Z$gRauK5}+9-AKT=jKI_K!#t`6 z_d6d`@3P4+*ar?cRX(Bxyv6C%1ZUJJ{!AuKS*cMxWo0B_w2?On27N#)-hn1#Em_rxDrT&)o4=#I5RO8@8w$41BXIiYJd{)9?Ie6>+Xl|>`li|pI(Qd>TohKt@W>w{3g+F4fyNje zaTabBDDu1vM4wjbCe=uk7ZzA4+obv#`MJIOiBb)$GGLmFIwvBq+$e)ykLmKnXJf%K zxbO18y}~#OckYDAv#~T}dbAqgW6xW9UbAtlwRXf;U1at~aqvh`#~;QjmyZHPTOaEp7qlzPPIuE4GCd7Q0njlga0H9*SN z882`mVB zu(JXl1}@1b>ZC_9+_>i@?-=s#Bh*6<+-};UR1F7j0{4$fMMn;#xYxo@te_w4fZKYi zey;?W%4mqiWPKW=NBosAodWXw){)s5J;zahsC4gr8cY7T!a9F8k)I3r3F0z8 zwvZxu;BJT?Z9w+OgW&uq617svc?D=BDQ%BeUxKogifpCCYn9?wT1rhTuX>(wXq+aL z`mD6W#J>E)s3SpX6aVYHOraqg{;0Y&8V3pJN`elX;)z_94H& zwME~PD0c?SA-Z6Ta8t&i@QWs!hAryJBFfS=W!VuTrG)!5E&&#m*`hWQ!NHNRe6%fJ z50@>ne_L*cuPWSQw!9{SmF#M;quXppcZQRbS+^r`u7a;NnPZ}$90@-}e_(6k&d*lj zFjr{?ud-6AwKW?w{&|BuPs+(>7R%eWQEnB(q!KL#u7wMAa?N7vTq&n^^7yK2M4RmN zPjXN@y9cC*cJ!RTR`jYJ%DMVKt$Th3d5D$-nVp#Z;2*r&3R|`MDr3LYu9%f(D>ZW@ zwx*O1vgHd_Un81oi*~dZ+26vs+m^q0P5Mgype?`fAM87?lzwe11+QVHe>d{;)l>=z ztUx~DYph^}Ypf7(k!XAyU6XBvCQ|5ZFY*FOo*z!v3R`OhN5kVuw2zyYRS~UgtcLh> zJ58<(XsWwGTj_OH;@V{SAv?K?EVm2u?KPA|&sxsnRju;RcCc=?94;PNaUrE@IUIY} zk}7EoB!v*w2zsui$j5VFJ5NKTGQm6++4EkLZP6MQk?%qo&+c|HZ?yHEZRh)l?fb@B zE1z)5g?{`=-d7|C&lhbq$2txiniJ1uM*D+oc>>9Cv0Fqk+}`_XiFQon3Ap749mhl= zp#4eKF@mR7%}xcNXhj}Op@3o(h2gvqPzP&gvfc+23sMI!XrMTLYXFCQfZ}<=8B;cn zF&!`LR+|!YGayRf7o*Ks3dY~iZiKDwbyhb1#M!)hD(?5|s8oMqnO!@V)>&gwU_E@- zFK3b6>`2LgNPhykZBkF7mn-3PEgCS}K==FR@5asa3x^ZjV)ah+_nICqC zT4LFHRd64503|6hOpyfgEAp6SIw)CDm?;K=QV_E&xLf;z0)r$)nhS$Lsrevz0!$+) z4WvH9L@$YY#s>NBqtE`pkg=XI{9LiM02Hi9H?MbsLKGQh@*q&CBDcd!Z?Z;=3!Xrc z9Kw9UxX^lzgXo z|M1IAD$p=wjtmv8e*+))q<35UXl{L5x{qRWG1N+a)mv^FP24 z?Wn|j@l_%)O#47$u^3tfG&$xHaZ?=7%UCXgUBGb0DmcKvNT{a~-MjWnOyuIuw_y$H1xZ@E^nc z*um@5HB`5HHoU%byBE8G8P<#4;#41Crgn58p$E@pz%INXTqTZF0K4*GnbmmW17q9jC!G(AoonP&8k$!LO>CL=hFnut%L^~vTC-&m@1NY%q zlJ{tG0qy!qyuZ$SaX+KlsM4$rgmhc6(His6X}H*_5+HgB9wFMLYrWswWQ9OilD_us z@Lyzzq-(vs@Cc#CWyg^QH}8M5m9g91uIwUPKFyXFDbWa9w5VN#vuxj8?0fa?{W2+U z037{~^1af;Gqwya@5R#;*yz(pbq)41MbD?Df`z(u0NEp%PInXd516`92K7<__hboCA$ z3?83*9v)@~dUd!!ZT^C24q8n8gjt@g5K+IIz(<48>rJ3G`FqZv-JO8{)<-=cyG2nL z#$V7pHEcv+`~}VD0oQCR1l^%1&RkUkx-)Jokq@6{2QBC$$&XL7gBDJdlxnW(1zNmR zQij=+V!3;tq%8BRM9@+-mgbmK!a&Pjk+OVqc?f8^vZdHOB|xh#Nm+@xp*Ls^kFw@- zS)jGy+lZ<#IR?5mPQ@vUUZj{u5A||7g`hF8md{%PH7Ux#vGbs@in7dw zq&W^Ys2!C1x}vqz{eBZAaLYi5UOTXZ&k-E}di{5j409y~d-FXIWqE@S^cF~F`T0(u zcfSLXDO*T(R?6&2XF7QxlrG5T6Zqq8#2ngtb>}E8A04Gr_aRlI^)>LikACE2WiHQK zU!z}|3c6suzb4NU`B;(PtSbS1;*U@z@K+P`Cq?Dv@4A6LRn&w50rVN~jZ04mfIjE* zFzAEL5BGz|7uK64=Fwo_MTL7bbDsxz2~`g~shL%^z%Q-u7Mn5Uz^@dZ(oA0;;Mddn zT@jq>3;c`l6P~8uJu3AO4Mi*q$8Oxu?jUcJpj~FC;8rF19sAnd`=cFnb?&5hv$m5n zW*dJhJ8`FV;+1Mv*%k*WF12`pqjPK*?4{8riX-roqv^zGo_VGZTuzMPd1tx4Jh8)A zK6U?hU7#4NcD|o;ns3$t^t!~0PICdFe?~ds*G~G- z7iEFI_mteA-jIEHr~M=ZS14Ve2CM0p2v=_vs@%AtllKAsl-3Q2U1b#`>o*REs5vMP zqNFz>9dxBglQOzOA*pb%Jlga-+$Ba#a?hpkzsCqWDTEi8aE2o&l;=6|x-2M6k;hzE z4Ki2h)+{H|;8~tsaMAhJJQpBwGr9J{1x?qRFf@YlXr6NP1~2k#;qMzSi$_itLokn_EctvQ$E@VZ)aoQ!Yp z|Iu0|wSN0wQl$YxDt!K5qJhF|wneVp?PG!HYg^=Jkv-)R3J?7xYJNy|?ruwK^ls~i z<(YU~4Bbj9hftjp-ByM$Ig{)#OLkv1ne1ryfStaZu836iz#VY#K>kw#+S-_;3%mJ) zWMlls9zI~%1xikkWZ-89l+s(0$8=?a0@s05Tl*ZrgApq?I7Gn{9Xy%+6-1c&VsG25 zkUdt2-t9$pu;e{f-mbegXkSWuGseKlC2~P8%z(2-_JtFe3uuX@uL|cIErr{mm^3zx zx|)uwmNW-fJ?VTLbv1o@3Uqtl0UhsPjDHy|l@$-7Bz&3hu4?1ExTQ6qeu@n9a4x97 zB9A$8AZUQ1FmrHcP_?z6{}M$$P*Jq`c?ZxSMRDd#7ih2|pV>bdRHMl6n}xxwrB+d@ z!`p)2+MJg9@5nGC3W`H5!wyiC4VGauDBr`_FlA;V8>Y-0&W0&7ud@t$-2ob58TMic zXryJ>GKyss8)hEO1C43g!(SdTKw}kUn7t^LaV?Uv9NyC~)YCG-{}7B0$%1I2Wpr8& z=mw>T>58HN>ZxUN(_V*qF~6lHlLxzJ>p`uGG_!F4Xo@1;yqBV!s>o^X3j*D!$S_aG zfu<>PnG^bhrYmxr-;r#Fq99X`2i>H|V}20^nyDz*JVj-Dv!W2w>FQMfs|C+Jp15$5SGpt*`7eYf1;Xt_;6lvz&MyM5wb zRY7|w*nB06GdokTI~2v6UkwG_si>p*r2$%?D8U>_rrf2-XD0OnEmYLW^t(Ze6eXIE z7lIZmN-_uLf$mo1H-A$Nx<^s6xt3C2swlC}5t70o|)8)m-QSEmxFg9xes_ zOi{X7o&s8-sI&Q3ie;tMkk*-?Rf@9A#YAhAW{%kq4O*ut*O45o4x6C1lXw{o&S=@N z5bmU=aO&=_#X^c>cw?z0Zg~^}^YI=CzqJ)kYG8w@e739D3{1qL6MowAK=7kb%*udh zm(^r%i2&_ZWcVh|oat!UWA(F#gCTp+>Synefe%^zY>*H1u+`79vp{>Te%7Xe9YUua5&g#sh%)>rSA3iZaYMOF)k+$}-Q_f}T*6WA;k|J*g<)?3fOEN>Q=7 zfinBFq7w7%O3;2q<*ND*D5^4lNmYDMQMH*uDLjM02UO#mhVva-4m~36Y&36*h3s&J zl+8Db%RtZiAL1ipUvL7SLwx|xX^zeb!{`X-mgCP+`4-c-^6N*rA~GvLzj+e^+R1F* zF$j3#qQr}u`HmlWGUPG!=CSXl8IG2hFYP4y7BqRXqvaKaf78r6X_WZA!hdMy9v|>k zg?H)Zmj%Gr{4%B`y4gn3Q-6}uWx6>&0{A*s_<$>P{9eHzd++%*yU>vdC|o3kS$nSh zD!nVceR8Q6uMZ`#PP5W0B|NTK>6KB~uYgEtdo4VMA|;i|Y5XtM z;Wd?0f{?Vw=~ha^irPN4K|3bG?8cz6$Zl!b`h0UbW@2O4qz@tTjk4(h}rO}XR zy&p$Phzmjre2){Dods;ATZcxBnZ2eoGv&At^V(>#kK(BV_Woxq@J4y0`owHk zlbE%53XXnoe2)EF|pMd)+WCOb3*b$}LzM8r5f1W6DK!Xs`> zor1pIN&%bnng}V%!p~BikM%z745AE3QUJXV^iB{!@q6g^ z?KlvzHaSaUWJJ3#PR)oajF&Ju536RER1$9bIx%kg;#h;I5dYF43e@xp4QHl{Zk(-zsZH8d)FcZw9g+7H4V8j-eygix~=f2GDd zuySgn(%8nq(eL|d8!HiXm!?q=5=LriUJ>f_CU_&YC@lhQPVeAwdV7WT4jm{kFs3>} zLrWpYZ!J5KEf-WgmWo@`1_}+1pk&8D(LEGRE*zR93QmU)2FMt#a~Nrax+I4QEi{yZ zlb>nY$rYnGyh3w&uSmlwD*TMZI68+>&`5G%F;Hr`pyeVh!Ev}$9MM3}6^ywe4GlFz z!$QfkLxD6URya607n*5oJG|~nlYN?AUjq7S$ zWkeQ&dafkbO*pK)WmDj53$43=C)u2XlCmSowN(Kl@-b$ zwY_rph6>qA3SD+4bvJ!!Q$^2M3~VRu`JW=%s3Pj+x+-Mvb|I0Ol6x0v4lD^mu@9UY zIVn`>a`@{ZYbu~qb|uKaSi5qTTZ$ms?h0a{Vju>JiHQ3i2=2J=y9n*vnVx&wJKO7? zx$pZ#(Lm6^K+wQIFf}sr2MC55C>R(B8X5|QCZ1DOAB+uiXn5OfvmWr48G-HFI+)G-*3I_Am2GUw7qpAbn~O2t=HS2ErozA1)i!M2oXugw z**_1J371v8tCwuv`?C%B@qN9kOZ>ZqtotLg5Zmv~LhJh<>nvz^+bpym@U@wO?Ke7@ z&3D$#_WPBEY|2lyi_KSyNxtFWzgy^Y{QE*J!RD*kLi!&2ATRn?^yrJ0)#;@^^LN`= z_fKXUwm<9jg=i@md40ut>{X}8jBIX_%V*i#roC+L)Lu6CYA>5dw3p2j+RNqz?Pc?_ z_Ohw8m(5Ol*$mptX4GCbuWK)xx3rhdyV}d%jOmBWm9P{n?`%t4BE@)NPF45uDxvD)?PO6YA>7jw3p52 z+RKI;BVeEWWWBc!WWZBsZ0FCf?^3Q4w`{*u8?pI8XJzvvFBddlBET>rp8IAPk+jd^ z{cov}PWcW0dBIcg2i=^cO7RdB#*tq%F$b z)ootJvcoy__kNkK%gp7{U{?fq_c1fFUrmgkG zHfUErjUknIRnW&Xt}4BihuAfJxnE{q_bs!glYi~u=PC^PVMu)$a_*DPP>g*W%d4Bd zv$f=Kg5&L-V=?O0$s*cS+pgyxwqvnr!qqo4;Sidum$hNsYke2&8EorlUS1BZUY5hu z7I|+U`gUl-82e5??-!%+D%mpnv_CP0$?l}hn1WrGX|_~oYMZ0qyc){UciFacoa?;4 zWn22AGX;CH?W?H?Ly-zw>#I{c_@>x|#@3XIG7LRV-`;sN^l4l_Y*w&q_D@Ag)7#NC z)5cfx`-T*IzwD)Lr`d?M@?DDEezwA))q}B@VVXlMgB*l*#(r7NzKPi`2b)dD&wc)6 zu@BR*x@Bvx+T!ZA7=W>@p|dtq7eld$O&pK^I7m4y1JJzYxb2EYrn2j+v0rrqcEqmk z<%8X|^~B09Lc+Yh?5A#=H=aXDoY;V6V=3f*O63|aE0pZg3PB?f=V9!kl$rn7TeHko z@b)I!p~e1>UYkL-ZLZ{J>}1f?ya!I@H};_tceW>rac3(os(5tua^iIiFtr_N+@@j- z9!G0;PfYz-*mNg0&E6l)uPt$4dezn0rkf$1;DSaW>y@^l?Gw-GjD;oTdBc^yxC-E4&wIAoctdFy1YMd2d(G{eDK_KP zv11L2It>rA4tmN>*FAjg!`Hi0Pe0|%htAxdmL59of@`k-YiE7h1+{iw_eW=b=(O{% zx#6NK>&MRi?A2Fa-Q#a;AHLzr8y?qU0wLP zQrk$(?uTHvR`JExQ&+mm?~1&0HAik^Sv27IqI9X8JngK{cOjF|lmI6^MK zwpbN75yUivuHvZdPn7-O{H&L@vAXdFKe|2bwzxW0m3fS5<7$R+KSVo5J(f@pV{&kD zJPZi`p@`B>g+dF z}<7jSZ2eYYtU*UC{3hs8WavLYtwM~aKXm+Cp+w@Y5fM6*}FrXTY15TT%=m7`eIjp{bQz=rUg9ZnI3oVga_V{7mEl?eI;t*z1@4=PPn-cww{-k3od-@lfaOeL>O&~sGRHe##-cx zx{jsj1xMIps0J`llG@45D4AkK0DJKcI}HGbpfJ|*#;e#G7G2`))rssD1nPEp6h?+s zfUSE72dWfDY+Uc1vaZ|0>?wI!%%Ny74Sw?D;(*-$l!MtOZ|RSzKRLUHXmB~$SNlyl zHe6O3H?*v}5yiqj5uRNLfC?zGjz`nrY8=B1gR(7-QqGRsVIQ=ztn>ztt}er;yebKo zS}e=W9H$QDb6<}$o#wD@X|@eEUlr+C?Kj8dDub}eMdEPu8UPZp!;H(rpf)MDhzkgO z3X23p>D9ydKg0XSp7zhY_{4orYY;M5R)ea^4b^QqJ4$iD3|RtREQM}eH?>}Zi27W1 zo3uw11G}_9ETT>d0myB5()U01?4|cydeb$xUUSo;#nijWrI;6pZFyvM5g`CpG0YQs zU4TC*q>fs1cZ3d#1xz%IJ4=JSWnHdoTG^Kp(w^px=>$Q0n0*~VK20u79Z%XDH*AV> zkDYRLYOi4o1Qex7r5Z*oLdNTQOzGyZKMim=0-!sT`6S3P(k6JtA(WzanEA^DjCnRy ztkm4_ZV*QN5lw?D{k&Z{5u%LNKYMnON@}kT!q!8 z<5lF>;H|g|N6-N5^`qEQ#%eMEGGqNfZ#V(#lpT37$^=+K|61snwJ578X4GotTKTx$ zU=tbxOa~o}j9(I~D7GYuW_JSSq@LUr-4>oDBcco>dnzVpSy7fa4!o<}8|7r3l9^_U zBcPh(>%0UNO2d@l#TrmYX!B!X4U=<~1y@tBZR=Q7@M|I@l^*;g6G+M+YxTf@6YOMC zI|FkmL-tW!kJ#$C;EH_Wm$>}s#OdpHbOr|1TdqJHRlf=4uJp3B4+=O{YtI(pIl%2sX5M!+NyAO{l2h}EEHNDSe$ z6Hm~{kTGU7rQXI)gitIREWeJSsWh~Dx+CPnbJ_28V;I79WyYCSX0=Q4qDby^vNL{K{&@c+B z#LRP%1@|OQN=_u{Gzp&%?@WiPRaA)~QKSeFZJ9!6$@F}tC;IFyf70p%c(%3oTXN30 z!E!10H*0oEETc6&Ua@JJvt-|Xq9BAVN;%x8?t9YT_3Sf`+acqG_nKrH>8m$T=o^m< zt?5oD^0y;3xr~KX&ck&r0HkP{3xm$0X$Vg)R1V%UMC>Hg;QqYD%HY9fQb!6@#S^;< zxh9KNe~Ov5VJ%XvkSzzGPj1Cr`~hzP4V<7s-NqItsNHN6x2Ob`fK%fRZ&9<(x@V0q zRgg^9leFhFicF++Q!k}Qp3kV6JgX`iR8AJD%M1)Fxk~JX{L)t+om-mJpa*76V4E)dLGa8c!FK{{0fsz6 z9I8=fT_^>6DYjc0B}~FK!E0Lt9WCq(-Qk3-t~M3gFZ4CEo7xAFi2IU)gT!&dsdXj}fGtG}{?>Q58mo z&m9?I>MWtCDMiFib+Bg}Y%L`AF^z=F34vo z+vE!;t{Vv)<$N}bEaF=WfE4FT^-r`(5Qq>7mX>pA_QhC`^&`qI6)>!=OJ*KFbwE}% zmk;c;%U&Z9)5;P>E^M6nAAAu%|CU&fL0p|sC$wm&S?xOEVI$Oeq6kwRZR;*Ox@(A#5(q_g!SQXs<1*|W1ePMms_GwcwIz4Yf);gJWQyYCN1NjnSB11~=9v9bH_d&WQZ?4!%=8^(&p2k{T|i-SUTB&DUOBWWTHk_ z@?JK^CxpD#7?=g|6ZbJ?Lc)J+}o|(i40+bst(C|w(AqOe<)S9Yyb-oE~3LLAQDg^~H zI-Ipd@@77iwFYEP)coa(e9clgicp%Pt|#W0O1P9*vOw4e2E=lkLgk-S=sYDofOq&&MbOojv7Wp7Op6I+hc!XrVBq3_G^SMZp?2;mA|-rt#xWj zSb7ORT)&mKD;+3N`>(&4z&wCV!UKr3?W%rIrZQ6!mg)iAl4{&nk=AvEsRleLQfxc` zWTA9?iVHQx4$U-28LJLgUJ8^VRQr?ULivWr>+dBv`0t!G*sp$g*i(>sf@CgV&kNv} zU-5FeU_G>$jt&awCGXltHA7uF6PqRrN_MaIXDd4 z-^sYP9mk0%=uct+@s41Dl~_RBB%Z8HY$vTajyLVh%>F%9bt>JR*#|_F$vSrTxzwqu z&d|reo?>7px58G)a*-Cq{}AlI#-#nGOi07X>xe(-%3vr}&+)1G!KwQ_nS1TLN}?QHvBP9L#cQ9KDX*~1cFkW#NYE{uGmW(R) z`nglt@<{RHhrj+X3KJqDRG!aF^5ksFE}}&#rz2tE6nz9^v&;KH8>l+#Xb{2W;XYn` z!%w%|cBKZoy^)7sJtL|TklVGdmK zIPxJxYNFv8<$0=OH)E;XQ}B?yBISVKDga8bSg_(SBaWJm(8a1eDwm^hS~fJj>Pkx4 zw$>@n*lyTA)CJ81V8pnl71fN1-xn^GY`=oPMw{aWv0=>n(d?=+8!&M?ALbJWADsw}KvJxhzSJq@q;^2-T-t(&N;mdO`- z_>3Hvw(7;?O)^&%l)rxeUyn&3idlESI!I2qZjXi`Fhr543RbU8gGp9AJgcr^Y|7=* z?;eZ=_5E)GMH$?ro`$=EL3=q$J)o-0WNTzSi7(Z+(ohh{lq&k01UCl?g%YhDA!4Mo`I23nh0Q~5oYrU3GU!}~FTaK;>Sn<=ZL zVLLi<^Lcx#qq}>W-7_(!xWJ4?24(PcZQf3EExwbpo7hgIzV8`36JO)Ohm@?nAA{YC zxH1wexPprkM**V;Ll4yEu@h5X{kp#VroQ}E2!?tda>Yzjm-;d z#;pd8uxj=ne)phJ1mV!lcQZ1r@oI}?%7*y*AUlkdZwITz4AxjGBI^Om;$C~0)_Bmg zGr8$h%e)1lXndZ|!#y{0+hBy=hTnm|m{Eb42kd6{B}w zFGVD3Ftgl*UgT^4G#--3*2{+0(e zJ~;&%F0mU#z!6pph_5$0KqTFrPuB8LP~U>w?l`qfUY&TY5B8P=JEih)IrMinTKvPP z27a}9KwtTkmR37Fe$HCiLNthZMdu$i3o@(jz)+u|nxd&vRnG9Xh{%{rd za#tE+k|7<&dH1=3~V;GHUZ;QjUO+Pb{2#TFor_NH*qX>LXF%H zhLWk`(JE3(fr`1GDF31dt!OYDIjE)SN5_%3v<7rC&GnF`qpCc zE)cGm58bx8UmH2LE-Vc5crGK!oiVPPt6|#$js+bA^9D4KuMvi=TV*jb7M_64XrrLR z+mcX6mG<}|VkE1{1sZB5tf<1MS$QREo&G^<>Ik*|0xYiAW@m#5EC@YEf7o3KP38b| zZaPG)-buQ_54YXb!oK(b13ZyoC@3DU)m5~Zs_3j;ij=ey_xu^UKZOcGA`7ftwZw+b zOM z!`o{y8&E>%6imMnqyokqGP$x6n~l6j630vajrb1MS5&>6y;KoSz`kn z>{$y^Oz-bd92hWak=%E>64j77Be90dJT8Qw>gn*W_0D$TV)!-FDkaG-IzG`5;bEiv zaUK|RM6L=6Qd5m+pse@znWiDDM`4mZpA{@F=K{bt{8A6-M9*V{z3EaeKx?RpQc^>? z&VDj&T!h`aMJPYZ+W0~OgKJUn?Ml5vL;h`%^|--0$Dra);|rCNadCm~EZ5d^N1i&K zTg_g~8HSULP`7EMmN4m2GXLVHmCWH)8<)m;a9z(PMid;1evS96=#A&)I;xZcM#OD+ zm`cU6ZKZ#zmSD;Gc2LRMM%7odXk+cUU_Y{q3vYQO1#LTe{uQ5ZG88-03jahHg_ znTsOPKq>8>WA2(7rg^dUm=LHid}5(C}p zZ*!WJEiQCo+l_%Kf{ynRZ0EJD;%=E6%MAJ9RRf9p!50n;USd42xUtd$Vjc-FsALc8 zScZGd_Ib0IpK`bp6jz}qyIRx+lX~(zdID>1I=Lx@<#^|4*NtnJ_9rzv&%5(!Pa}z= z(!xh~!p=UC25ZzUUl5&6d`Q4H19F`klBWcE0H#Z|Pxbc3aB5a}MJuvdEN%P`Z~25S zly!ORIUKu7z%XqU4|nLhEF*eao`RUpBOjNuhlU5`VFgyD&T_47W<89*s2W)(Zo5t!%VQIu4nw<)or$>eg8EEGHLSg4% zWT65#cuUoSf$s-#9 z=?b(xc$&Q@6g}O?+pOX<#Z`;`X*-qL?#V7)-mbkd*N0gk3ZpWmby~jvQ9*^ZY(WLYv&_v#mYlioayc8#E=lf*=FzZCrWQa z)&^bdBM7P?_8%ILHv*JD>e6soxt1nL_L{QsJcFyB0TII}0#a=;?QD1if+;7Us_)($ z)|O_udFs7OkaKqjPDTh@`R99*t(cF_w+Xj1&NDaJ(9zQ2Hlm`kTJxU55D5j*_s#*2#-|v%Zx|AcE3UKXsVE|h=5`+28 z(xj(8eO!)1H8Iz4v$2_#}TkFm$Q&WIr*f9 z<_%STixOZ(J^K8!o5)0KI474$xuc4Rg_&uaFQ+yi`6(xuL|sP!uwO9xo@P}c@ebOo zM~mEZ7E@0)b5qX7ZkN-z)MJRZV0chC-3 z-cA7*{jt??TPJIdAXTV87vyoUFj!KmO-_@t#cc z!_1e!gAD7d$lV8S@Mk^~4ZLHjvP}9kq`-hT{Q9c4q3>V$ z+A`%y>ba=qI;DFkmH(v)&()7Hd|RjMkL5&S%ZehT0usMx6hBWGC;v(awJ}_t1NEl( z{TUkuwp^e7@ss~yr7iI7`~dz}NGZxGxENciij5jAo$Xw;SIs^0@AY)TMLT#S59Rn_ zk-3i%*TnKqL#ixt9@DevR3fEuvmN_W8_j-4K#YU@^5fk z{4UR#n7?&_fx???voB_njs{Gf2g&w@u_7+6<^uLz$i01T^ zexG%)vIpmu)if?*^9&_YPZ;LNi+jzRqQvTnV8fXwJE_J6N-$oG`)1#sy&Dq4BUyH~ zw#6(pH&1fWcQ|M;nI~R+a7(Ku@w6j}2&af!bG=TyIh>gV8$ZoE-64UuUM@s5I!CkG z!fE_k_y@ata9hcw*$ze!EBAqN`yuY>CL33g^X6KxAs5Qu^BT{;AI&R5fr4s|6-Lhg z(DW*n^4?yXNM`y_T7kRZx5252db0etchb4?%wNH$Uk<-(8gY7l^Bfb`o&Uy2u5k#* z5hqrjA9|RuQ0&h6)_y%Yb?~q#>45&!;9S}Ja3)gRaHrvJ1(ET!6MSfRM;ShdI(oU- zS4~kfJM=fgol1{G=#ViX1$izf<}77JOm#hK+$CNfJ0#7$g?#o5iE&sw%kIr*S6V8E zcazs1U%i4b#Lx?jt3N4;?JOh>Scc!BR0}0X|Gejv#PGk5D+=-AAU>GTH zcR$Mw5^ZUpEkHyAM@1?O=>tcD^CGUD(}*$~-?9!=-nD=IgrPxC8pQY8%Bkw|w>6#Yv%BZ@3NvW=yzWO-7~O*M^__ z_`d*R3!X6;U2hu$8%s(#%6FHKZ?XQJ<-PZ<^BkjkPa*KUE#a_Ch?(4Z*7)Gi9e2Gq zfu>7$ILS_jY4khu(Zt-H$Nm0dL06+^CW*UU>es1n;&hUbp&^qOS9KW^sBz3!*ePLb z_N4;EjwpV*Hb(byVK9@~-Y^uAgw-><^n8ffb-0tLdO06RT=Ko9@K7PKL9Gq{^EPjl z940;E{*gx7uR8nh&eApw#ljX+aFYIi8^dzL3>h>&R;~eed7%9Gr-5QB4rQO1T0V+r z`2$OG`NqUBIAymvF!SD=UuO-WSPixFn_ZNu&1OM@jkALgT?JnB@l6F6Dtxalmw$_6 z=(E-$zUG>X%ccB@@lpUn^1Vyn=;tmPG*=&fLYtwU z=NArglDb0U8P~4c9|6GQ_J zor_fi@7!`gjfiN9GtOr__R(LzUaHqXx*k-=2ahkM5jV4uwO2kqT+-tm)T75=@O)C{ z#$yM@8W`sZQxBWXJWHlW-XOA$-W~)n2)qw!tw70#`zAN$oDaPBXm9*^8#WxTbNYP! zk&1>lMw3+c@~_3k2<0!#T?~Q$~7SK1l!FV-k8ia90!SXC1i5ffO9<$gNamj4Ry zNyu9dG;~FM=>|TtDk@xy;6|}Vo{41zL>D#-R%aDX1eC~+Yx;>}Vaa>iY6vVSn~WBJ z!hd!>mELy#wTBSAb>~EX=FIe|ql%G1Am`eSHXqEiHYaD0q@)`?Vn;@R!6unqQTv1h@qY^4YkqSSp*odp;Mti}im7cSE!pvKizf5+zgmUDM!}Vyz%cz$yx< zk^4Jm&#*w;Jio98kbo`e9WJ_pdOaTh*%34+#C_4s4V5BZb03ohf?8z zm%c`qjXA-J4f)6<>(RKMl60GH19)z_&2pkuhgy)jly>m?1r3e&@daA3tMu|b@W-{h zyLrPuANxq_lWpqbH*;uyz249KgCljG1E`ljlP~a8Y!OZ?w7U9d38v7JQGs$!JRyM# z;o(x*BkBz#eoi*}D)7J#j|<@C>2o@slL{igD!zU{uKNez89uI8MHcucd{x$scZarC z47cpDsV_ftZX@KK`r9_x+D>Yu-C2!Qd$$na)lIIXu_tZz`(`4f(<|K40ojUcemh!5 zf4<`o0YjdXGQ6S}GeajdX2;=wxdaY>l5$oxd{60`mIU%r#^QmJ)7BT@7k1&atJf#n z!wb|fVrx%OyDB-VQzqY7H~pQ>FM1nwA~%F2x1)hbB{x}}K7#$DTE)W^Z;Kgw7yU%& z`Vz-pi=V~U`LYG#SwWn&GP0bpdnz-JY>V#gp?P=nSw+TMZINGhGZ2|_BYE#~`AHwD zfIMpbl+v!Z#bdE^32lcJcQy~{#y8As-SldD`&O3UEHJflezP17kKQBM(A`^@CGnLoVG6k=9z{a4H!r848vVVm?= zI5)q*rV zlo#;WbsJUq9(@in&kd~Vxh}zRz@TbLa1#sU-m&@c(qw91vnTNTb)(Mh{jczo8)ecv z%tem&yJ}{Ms zhQ0rIKxyO6VO5;G?FMxEOEO$mjA1S)zWSYLIL{cphNU8n!TO6Fyg`G64;LuJ!CE)r3ORd|l>4@)Usc zOTi7>ukY`t#1Hn(lu+UFr%s_70GX~?i$5_53Cxv$t0qQ)nFXYmpG-$TaE{f5=#fOq zA1dKsu8I_)WgQ%rhchHi7m;AheGN!N0Uf9)?#earvrJnAnU1KDKecmj4z^3)2MA74 z2W&oqBd=n3h|JjI-?fPc$Vi*vKL)8rtHn6RoJ2tgT8IG&ex|M6_c7l(5=f!^Cnke^ z+M#(Q4IPvmb?+#kUdP9Eqk1X-TA2tahV(dTYh>j; zx6DBXJc%WfOIlE-#+)zRN@3BGuz9;v-9|>buP)$wLt7#TjL!Q?;(3D8-~*41cDj|2 zu&vUqrFi%D9Xw8~UR8^8Y_=mjZsi-*a*o_RN*R=?YYIn_$H-2Wxt5)xj##3BN6GCi z0LZrFPN4-|KfN8N(2r~3i>ja;;L9BnX^ryt4RaUE<-uyecB~bXsHLIV^W;7hJ_qyJ zj*|N!*4TECV^jC>j=i#S6?+M-)!}6PAp!aHPW#)?a?O{3SO3pspWL! zPddvS@{HfZ=HAsk-_srfH<^)G7%W=TuetNGxZ!31akjuL@aSQ(jOoBhB+mX{>el|Z z`{waGL{ngo>cdBP>edCoR%!`)foVESv65{f8Y0k^SlN~&0iy!hEW)diu^PxzmgDBc z3TmJxK@&W_sYzEKuAr)>!_ig!hfc$fVwpu^Q8BI26!#bj4Lz{i@f=@{9KNiIfLvf} z>{?sK)&+h76a{FE@5dKYC+WzSGJV4^^eT#hSc(pV$&It@-vp|}hSUT2gGtx_u!&c+Y6uk!Q$~r!yIzpO#2FhvhJ-;3lrNQLK^E8Kk zu1GzJE8uOrJ3<6dvS3$m>X5!`R0E!iuD`E(CbVb)EagqZgKBpTwZI7Opu8{pHhN+p zUF*Qt7K`ya0s%?mZTV}h8K_ucy0*y8=1S5d7P&p(woJ#?aDSi7q;J&%SapJPqKQQ? zK_1S1U`I%rL4kLj)T29D!9I3ZpGa%m0p|G9a+rx&IFElFU3Y;I%Jx^IK+1J#H zr>w+45F$J%%YcY_mr_G%^SC=-I`TytxFP14 z5HRi30e|(L?tkxNT=IcuN2qE*+-b@pAX%U-*4162`;bSHr}xG>@D{ABxht_gX7b7n zSzt66g<38B$)#p9fCqO+RC-viHJj!VJ>U9#_FpLH=&J)u`0)7i=V`f#n;lZDk3f9C zwT&rvb53D)q)le^36=sW0d53KZX9<|*1d6ut@=0P{|j<n?nEZ34s|Z3xnBG??qD z<}#VQZYzQ?$!h;Scdjs|In(~717fwHsN4sJ=U|Kc-8PYm?kncaFXK#+r{}4)K3JewR()+Nwg3>}o*HY?s=c6VVse0dk zy|)HNxaY`*XAqnKWt-Zi?;4zhf0L;-c0TjQ1)9L8Qe~?ydz@(^`c=TXp zaT6!?Al?F(!M_h@b$10JkpRSAG4Ewzh6_fS+D8lOtMN&0qbO%-c)c5)Q7!uG05Fs* zs7K2uwk)&d$79~Bg_@RARZgcOUa8KFTkpaoXtE%yEXj+y#==(@KqYKRZ{&tg19o~f z#JTO}(3p{~h1BM#f7XzaSdu_%V&%QG%s~r03aXLX-Vwdj@b=_2`alt16}bLG>U)@7 z{r`D(9hc329SuU7vPPOurw}Oz?Q@5T10vSi3jRZtIjR}2Pjxv-N;J4gG^?R4Yzyjr z*t+3+W%wWRTrSwVr_b=>!O^($Q=zgo{U=`h1_E` zh|G0a(dpU-ZVuj_j`mXav*iwZ>o>POU{hSUYz~{MgI{N4dwxjwO7h-e>6T23;EmHB zbg|SuvCx>-?3~t^h@LWJtWouHqPb7%f)$xE{t&W|dL8u){Cq2aWzy6_k1UL)ZIC|ND z;&-jitTo@g4dEg5pjKz*ok*fH(f zK&w{Ae{#j$43NRyOUdoUyC?5HaJM}xlpgq?ZcZ$`z0r}-nK@OLJ4W15T=YOQ4i#=b zM2O$F?&`5Io=#{jP$FMadG7nBZvI8slEcf^EPk7D>hM$bp62U9Vj-uZK2olh0=I|# zl#`>mlT60_lk1bAlD)Ym*E0327t~&dWSTnxT~l}WY~2Su6PpV@f-&`!j`gS# zm$JBfDALn|#{FFD{WQMOV6PNhALL4?iPfPGvxbgio0JMw7om=FM{M*>Whd zShf}rH^ZH(<&sv5SMQe}c1#13tIcarjthNtq1NEadqnR`1T9`~yeE^6__XC%k+jedwg5I;^S58o#UBdfjuQuD6kIq`0|H!O)L6BQ9RD|xNe=;D z(FK%hapwW;(@b0i-?GPCDK74wsauNRZokpozcQW>xu^ENaC{!PM-SBE>`AT~@asr1 zS&rxzOKNBhb8JiV_suNJtVy^sk>uAAX+Nb6oGC`VW=;?!K}Sx!qINJj5~{ zx`9VN`lh-gUndA$CSE3?>PLTBPOJf9-Mt2UigN1FPgQ;2oklfJ`*(6j42=7l*2g*} zCv+x6l*MhOOeOTCC;oMWj#BmziFP+wUoORQ1klk^Xn~S92v5H0BD!YQS@+ zx39lBmOr0MY~8F_t_y?k;(?__i2kQPt|X za|FWeDJSZ3hfs|N@mf>R?O+4=7l0NXZR0{7)bqx=$KX)6ZR4$-Jw@dUR)G0aCTN;eqxGCM3r0 zF=_z+hr{mQ6zseXdEK7N;~NW2aL}s7cirZ4n($u^e-cejfgxqMOUYO^&#WeJ4nB0G zoUO#j-4m5bA9j(IQPM!30mz$^kION~l;gg}y(jseG(U2xc)zs#NcKS=h#18u7u=9kb!59-IX)CslM@q8(-431{QQ6c9|Qs-UXElIEZ?O?J!XG!5nqbmVT{X0^N;>1t^^1h9d$L z!Mj8OP9-JO{+EVog(T`k9tH9et_-I3JgUK_&m%IKV1*|k&M69mm==Mk*RaSS7S+(2 z>FQ3}4aPXkuiTt+)X#6q9197Eo%Wz^nACBpHJ-mO?CKfQp2oX$A9p2ev53BFf9;Tf zJP&1w;=iGTm-9_O=Cq#lsho>{D!4YdR38a&F8KjLJVXgF) ze%;lrN%xxW9Pa+^deG43t%6Wa8he-z)EbHnyA%0XtMj=8*KzM_|@k>~x-3SuDc!`KGPK%0wi-3UO z40Pss{hB%3yV-NQP8d46amo>$XRU0gTk?&%%txEQ?WNC@$480rA<{m4>pJL1@{j$* zAc$4Cor0U2B&ubVE#ZIll#bQ_ zng!BWjOmIMFB^|PKYa0wd{$WVVs)^6(WKjqQZT0vyXR(&M)FtlQk6l7w%})Z_3YIJt;De<0pXk8d#zIsQ2Pai^#FZsq-o z&a#FhqjO(UW0gk0L>&9PDaG3B!9wJFQYj{@1xu$WEPIz1r)^tTRz+t^W2-T%?I$)X zXYm_8mrKk0&EPtbOxrd-+l9#Uh^N3VZiaWU(7Mk^XHEGo`Y!U_=~w(30EUZW^Ha47 zipD}2aoe`}TThk@$Ac-yaVEKHmY>9sqqz4J$;T;eZPkFD6U|0~XZ@%^Se@WOKk4~| z%@&Nsl_^|3StHCKYbK8Tg<)Tt z2vKL0K*GOL3_cZT;FgfYi0iUvz)wilhj^0MJVf|1ehYFF#kLGucI-CIJ<<(}1mBz& z=zTYy_wJsZW$y0}drpXAjQ3vV)6>m%F4IOcLt#=nXP_pQ!-nRb{B@eInk|(4#k^e| z!7fBTL+_R9M-|Kx1l`^~tV$`kqD~I>H1gb00D;cEuUgl0zUiLxWgUEfIZiKD=l&iD z{B@Z+dsMUroC7~84@-v!?Amrwdz8*$QhS?zyj=CJU8lV06^}xCY3Fp}IsHR@YA>6g z>lKq>%`{A1<>N?O=64x(7s|KuyYFtg9PqIr1f$zk=Cm*w`+Eu8C0!gOqB>)Rb`n%e zZB0SFe?>@oMM!v?6i$;GMk&a=KyX31(B^Uy$|F!Uu#B)MvA8@}>rL)FU6lX9L?Mvn zA8|R?JcssH^aI!Y-Oqg4&ROGwPM4}n7p~AUv9nZ~tV_l@Rs5Hw;EajU_?QV-5!F?l z&Ch8GkH31h#!Dp~+UIufiIECsMK@>Lo-rlpW&K8j8Op87$=y^pRY!b}5ZaNvko}Kq z$IF)i!l-bR?Zr!>TeO2pCtDNeVQsZ?;(4t{Po+QnfkoxpFKqjTUyUeh9a`9a-=6)R z=t|>TyA#vB{2U8Vz6kenG5T3E*Sylw+_X}p8+CemrH#&hWVJ9-u=miUX(w|Qed6s) z@VAOD@=#TY53~8VUVz!la=H3YoTK*nn%QKy}nUoQ+hs2fdM z;ql{p4&?LT7ryzt@}eFVK=oJKn&B*>hc&}_rSEPmKaG`wg()!Hw4xq_v_bU$ARonR z&6^#z$~WFig}r^2z}jkgV|?4y0@gnpw)+|yXFYOng9~60_`O~zAeWt^Iz5)$sBE7>_q!S&VG+*`3o@TDJ@w}nw<#!=`yOZT-=`BKI>x8T(y`1exgwXowhV7 zO44ul3KH$<=5~`Su|xJ6_c4V>=R78?xo~J`!g#n(0ha0`F|ZHDh21AooKtXhLW4(H zEx)F8?LvxC@*`3f*u>DK{W3s>##Y_`5~)-7Y~H7e{o-rq-}sUt&W_PW3_pOO4szyz8e<7G_voMt|MW_;% zgF;E8_Z~aw*hB&HPm)$3R@m$6>mStXu~|+ff#ttWwz9G0&a8zq%`q`8Q!fp z6e3>;ZtZ{(h1gH^ZuK4Bq3Wvg&S16gAB{* zNa;yfE$QRW@R`09%m}@!7_Y5;N(vb~tC7VH#NW^x5aqu|@#*`r!p;-$92@qkHTVHM z%^j?i@fRj=Rv;593Ytx1NR$o7wkH66lsNjCGuJ8mfwJNU&266ah$4V^@R-Pq^Q?1J zr`Bw)tCe6!aK=m^4>uqbedy6rDCKwddiF4Nu6L+@MnFaM)t+W=&V>$ILQ}>qJ-6V! z0r|Q}I_@Ur>9I-1PiOK6+o!JF!!U(>gFsK)GgBG8u^vDVOU2UOi3`Cv3RqXf5q>AW zx+x1IF3~y!WYTzBXNVH{8z)!zP?7ap>pYv3{NVC2#(8(Nd(sc7VxW5}@{G4N)t7U} z2_%$Z8_+`RMxdGd*T}f{BatJ{Pk%s;Q|H!Pt1<2oT*MBSL!wjy-Lu-^1L~ox39UMK zd+^0XrNlaE#wRJBZ#TcmeR(i)=k>}5W1n&vyQTp=L0#kzpW5EXriDHe>{P0}W5F^o z0N}LVdQC78ddJs&bg@cZfGjc6^k)g9v}0QYMWW9XlbKWTXQeb1XWf0(-K3gxY(_W{J*}tERnk$lx^Y8+C&Lp z{bv%c4&Y9V+W*lS8bFUr{e7Dt{fuQ|@}qKdkZyOv^wcD*K54p))`*>PjTFaPjLEv7 zjBb36-n7^sdnMw0fv7wBsf>g2YGFnN;hrh#XJjTLVnLbKG;Jc6Gcq| zCD!0!QMRZA!JTmzc>H{Gh=Y4FkWw@dzmESxJM?Pid1z`2p$l8+Uy*B%y<>< z7gF%UG(HFg4wLJG8rw+4Nn)sn?BA?j2!kIr@Z-e@1c+rfSEv!%T!Zl&G25l{ z$TLPD>jCv?uj*Axm=d>pFX@?;v)eX^QpHMrF_1cNd*+VDhj&@WN`IQu)iE(+6`9hC zr6yeM15cltVXv#21J)za(k?M#m%fh(byqy%vPGJ z=gX=18(_T>9&l8N^<@Vv3-_-$RE+ERJ)12Q2y!e6?4t0LjsGA=v463I3!^)8bk?_C z>c>`@mzld48~@$+Qn?Z>Vw+BhEQULVaSK-MDj?wbg#q~KjP27mBeDbR;UX5bCmc87 z_F&}biRq&0xr;E^mZvei8h%5r!c6FfeP1I>llwxx9VuMcYZ?j1cZCc+Aq>uGKOhwO z*ryi!pqPZi&_trz(CC4Xenr(TBNcSu8-?Cq1-49TQl7~x&Rgo0oSJf4q zTCch?8Hy#XCW8eproU){*v{QQCS_{$XEZIP!hqRY*ByH&^fyH7&a`psZOwcfZOu%n;VOuZN@DcVtQUT54dS{llh?sJ^c6_6|`X*MJ*=M!b$=8!~J|}a$exq zMRH$+0xDjE(W<1!r+Nry2(v1~@^E^1m2CZ>>Y+C$#=lNJLdq|`JDu+BSZZBUDu$prS^sS=;p!KSvuu?@ zqYYqne_u z#RGOXAZ8r}=98m+a~lRJjU{)rYE)9!WWX`RV7B`cobf#xV=z|yx)UQ1@<|8c%rfmS6XAGah9Mu%7%|HZ9AbVxks>qwtsj zP2xb2_ggrDYcvNA1|!)Ax5@Q-ZcqN%-M{(iz+|Cra+hzB?Q7ilFA}Q*c8^k0x(aW8AY0mN?V}+7nvQ zzdxIPNt8(>i&0juzspw};ZF%Q9xLA#$*lmRk1CZs>9WoSF>Or+YHT{q!@3keFW5tK zJvk3tMiJCvNi0RrqxnOB@Hc**&ID_T%2e4rJERocf&Xl^YYjer4IFQpLQdeEI_hYp zvAGh4xiVT4W-&d9rh35m_CDwAi;}Iq)QI8*ZR8d(Y*}FITu>rU*J1Q7J#d%_4P;zq zL=)6~85xIdNl$~8P~qLEFDuyKm#^m#8(oT#j<3jBzkA9^9^RLxCh~I-)!VDM=Fd$} z-PM3E`vqkn(`Q=Vo00L4g(H)axVdz0-+MaIj9Yq2P|ibZWgO4WKF9SIu=QS}V|KEk zwH1W>N%r06uO%DoNSo{aR4px*|3TV0zG1H`-tWunS74-RwO6gxMR9K?{a32J`P@o; z3$Uw(wBhRV98Y&@C8)2p1J_D?OgffI9K*(cY31*sEW9fgE}n>VMhw&Qjo? z5pf{Sj0pKZiYov5gQ?n`l3I&I9Z~$PX=G{XK49VUQry|cjLyT|XmX`9nuOSiGdqg{!LD-njc%h6Unr4lS- z1rRyV`0}VFu)F1IYcXm|_3XJ*u-(w|QQT7`UR6vFDQ;i_)=d6$xbuPZ1bgufaYO$#_G#lI>Y`BU9y0dHlguo{=SPhOogw zt+7UT92%RF5hJ`Jvb=Q^pZ?ajH;0!^jUj-F2cA=S!@1NAK?#s>Bhs6q9s%Xh^_K0! zR{`NpOnJgbM0{%1t|`oX{~$leP633jF*d7MEHH_@W%Oesip<;>91MXr?!4zbwAvo@ zW(LvNxn-{Xg6GzCv=-luHV!K0&DspUd>t+fBYH2-&tBHfLYH!}RN&@s-#y7(`OW%& z2>2_X9)$cprljf@Ir9!HYTg#fVc*Z`1OE z<;oYn!?VlK35eL*W`$vZ3o+^?3LtMJh7_ti6KvC@ZmhQj(sOz{^3pr|esplHh}@27 zR3e)#TR})=60nUs#gnCaR4kooNjxrG-uTSwK&$ViPS-y?rukSsMGXz;voB^std_xW ze{GoJUl!x_G6|xqg)nu9cKVI!KEa8UUyUv_uBA}vOaC7wL=Y+<(=yMcGQoVBFJ_AJ z`Va8iAz%gR#qc}K;INyCz;wYCF@SXFUtt^M6RnZQ=$P*d)<5@C2@6Wt?nrX?t|7&} z)pkS3)0ctllPI5W*ZtHRY!rjI9on9sBw!#>VRFI~I=dMAuhLkLj?Y0C)k}k*mSqyF z(|=w)Dm_&6W$ZKc4B84YBRe!{q+U8B6c6|iq4geD{K|TZ1@j{68-(yFQov}?)jd?Ko@9rm z;Q>9^9^SunNq7k^lvcb~QL}p%P($I~XStD%d$L}2OvKr-21%32$0lXk=m6K~OytyZWu5Z`F2<@=WaLd0wb<{fZcL5PMZ1Si|D*e?YXDkOXuB$%(A~8?Z(_^ zY4*DMf1k%vUviRt`LFg;UF{ zGSjpxmehQS%g(m13Gr18b6*P&77W69ESLMH67EEI2O8s7(8S;fMMTV2WIw zRz0Tgw$x|z2YG+rFV9`YOH1_O@l{GmzPQV-K`&Cv>_ffrqk{71JV9YJc7dz|urbn$ z0_MQPvvx-+qqb8y|LJ|yf5Wlcid@PQFqfYEY>O`>lg|E#YE~!x;EL>Yf&@BY*`ft z(rpMlB6?@}L3lfz>p^>bc;c4l&$q5s)J`v(wV>|`_q>dOt$q9bg7Yfiuv)0=qX%jL zY!bmN{ywKGSE47~C56jV%e|2624smPCGp2XZLIaVnG&@-^2Vo@%ii8W#y_6QJYmml zbuU<|2z^;#>}L2j*VxF&u^Eh{_TsaIHvD)40>la~*Nr1cXu7|2^8G;-zTQL>08xG_ z$X75ds^w`Cx2NfTd}Q(JtT4uX+FN{8jGrwOKslkxL$6NtO6vN>XPQ5b>%JKvG={~w z_!EoKbatF0_NCg|UGB28ZKM&exQQb~s?e8aWV|HW zS-wKn6KU`Zbt)jl(T)=eRW>70mN;(9VX=W#sqy8xLIGWt4<~OFLrp=FM{z^+lOc?; zjm_EbMcG)8Hq+%fQyGyg%z&)hI77G^9?#}*EfrVMw`OE6Du+#BhrULJYsvCJK;;rC zrh>Y-bBG%)i4$}PF9ww`q&I+b`zpuKF-mRnx4X^L2%^GXNLWjMOAkd}MkG2OUS`$l zh5r+kbj`HutV_ZG;ikE0ChxIAUz9#05$3>yH~ZTgFL^lPm@7{9JuZldDxT+>`cO_N zG+T}HXm}8vunu+8ZM#<1TIOd>T96YfnO09|lq_TH>CqdP@C2`HWwUWfS6Y&*A;KeBltzST{8tdNs6{@kh)-fUyGFwYpKQC z|Jaim&nv=w#S4jrz3o+QomTz4@&WZBfaWqB*`3`?@%wozRv_t~zn^occXuFeCSO~N zHH(?OGBEN!C0{T(o~)eJ*03gsetsszedSkaRi$22%~+^I+1cDjv%nswa-HePo9rQ3 z-8BNp#iwB+0vBj9Ocq4@3F%L9OSe^u+B=#IdyP0nDv_d*ql-bX#)o}6bBV;#Yqoi` zJ0-px!9VV9jOSSC6+_}|41ybak$IHSlXji)3ztW$6-J6a6u@*(9w9E+(_u|4N|RnlxpRx_y0km--a zvn)BkVwktWIF{^{N4Ahbt<1Vo>I*@n7XDW*r=ZA+pZ|GP$?`1z-M#$dnioD7Qv=)O zUirqhj%sz3rREJ*TVX6`vK3bBzfphRlkDscoQ0H=%CdP3X##?x%~8Ut!@%Zuzw4CI zak9nOTOrxEF02oG-&CeC^aUESAL0;*2$=Ob+yCBEX!B%9hXtwl7c+eHAR}p(XEfc# zdbCO^+>+qI$3p+GOgw@0a6xtQeyDG^J{bzC*okRs+^Z~NBy+*|`hd(NEr>ZxnzF^` zVYT*>z$_O&YNlF%B8KZ*ts1-Mb(4ASVgofB-+b;ku0bd`Uu&#Zm6$z0ua1)JtaB_1 z^)XuVXz973UOxt|Z+=ZyI^xPW?o@Vd+}!+9z&x8Tc(mdQ!7Ra&Bu0;_u-h{)UQsSm zu2`qf%4eKA;6F>UMT+_SmzTv>%b$Dcdj7{ewP%a2 z1pF{N^AqxnWC7?Wo0+yzW_$VPjB1*YI#xmw?WeUGa&Ocwe9n4(87(jVr4*yMMb=fS zS^_C?X3BQg0|vG_CSOWU;`>T1aIEc9n5PvWPxBb1qh**p|ey156{ zr0S$&O8CcLL{Elcsdpd_ke+@j2;PDUT4VTvejzTcb>-=nukhTBKn_a06P1>DlHIiA zn9@wcM0L^I%77E3%K9op6#XK^GeLOAaz;CIy;3&28_6I9<97Z`5DL7BS$et{RFEZd z+%o!rw=f7<#8vVuLiJNkF5rfNdkS23b2Q*-%+IW&AdF{OLbJlRJm+iTRVtf2zJDaH za-z%_VbJY{#$Gs)TM;^Rx603m5LB~ohU}e^zh58%Jz##8(rIUK3iWkp`8$!b%Eb@e zQh8RpAk={4$84Y7%d5j#M=9=&`4Tg3*6ns#l)EqsSk&RzqjO>lpHpZKv#<4Xt`mfy zj_Pn!=Ah1~?!f^NV3#H};5|Ip2(FPO=}THv%R~}2Oqirx?lVNhK!p8hnY3G9XLDdR z?&TycDeTfWMXXr&dY}WDDb~HjhS*B&RV@5-?1sJ5An3E&jsEf;)_rzpv>}4_Rz<5} zUCDAK)jxc-KST4_LgU%Ladm*442?6!3KNRIU9*?`MnSxV`b_vhg$f%4M9C|Gpp%&vl=4nj-HWw zB|l;@J8}a~{TG7UMiFh7=^eD^>gIGfNf$y!#qvA_B?j9McInK&^DqqkfKa0CWg*!P zQ03NjchbNKYd)V!B#Qa56jNECwbo-qclwa9s8C8|G#u;^`5)6yCF^^M16V$@-d@_| zGS%(kTDcZh-Ih(->)}(BX+rqWk2GZ5iqF0YX54h8xU>q+19!qPtp)XfU~1uv zfl#lA=E}Hvp(i7mOo@nKa+TuL#gx7f^h*40 zW@w?!Ku{Vg)O<=)5@FYgd#XuJGK{p+Df}q>jRXgq>r@x7@Sf@5NL1-DE$3J)>d%EAO=_V)ng&|yPWJ9f0 zG{d3Q6PZoFl8zhvCuf#UdYo$6DfFI_6!7_j@#I&YY*c7kf`!+w^h?~Q0_G`={dA#q z8`%A4$~X7twsx(!G&ox&RXHCFPi~Q(_~d6jT(VN+-@zr2lE-6I3QGc3HUGJL8~_0B zsMe^n<)u6!HX0Px>2nM6NARxfkMFipPyBpIh#zi7yFPTw?uR$KBRcyw)ch^cHBY+` zE=IB?eoGPefL0l6)xNtJ84{OFj@gODRbJ$PjhUZasx9l6?faQP2$neaIRkxM+3Q~- z)B7owm~An=I`-36!8iLP%D~n7U`ZsgTqXaISrkwAXpjvYEv zJOIQvqLDp#G9oz=9~c-^ID=#(0a>Rm-}W4+!(J_^QueY-2L%@alBfPzCE4!2WS)ym`MfhGTJ0=r&oYa5Q z%G!qkSLpM1A>3ol=;%<~JL!j&6a3D~>YJ1#-ek?}o(8-#H&;_fTJtws8S4PGyR@)N zV^hhZDv1|stY)4GpQN!dgsUZ9qOoJrfor4(&eT{LSzIgeQY|yGFK}J5$qTg1PsoZr zBsGFl#|J=7mDF%f?K~G$y`=IuRXPRKbV=oMYQkQi8YPuO6q^zTwU6#r`50&!IPXy0 z`|1T2J_Z`QY&7!sllW?lEwKVO>xPSufyVAE18$M{W{qV~6K&Gx-5RS*1#Xx4UX87s z4jh#FD>b&P4mc|FAJ^E>1Az~fc$LOZC<0FCPw_E+RbzEd;7*ypNn;KR@O+88bXHC6 zFVLHE_z38%it-og?+xQ4ptB|i@Zl1lsk4n0z>D4&Ms>( z;bl7ecst-DCB9l`i|T=omiT&|y;NwzH|y-XU4V~~{_fV<6&WVHTxWYKz{lz@Y205r zdp`^KIEh#4tlkcMy#5CF$J08i+aLHOS$?(7;?qs|Rp_?^pQ2B!;d4M|YZ>sV`i?{S zoYh%#HSp>B8eU(Qjg?aVnG!Fyu}CBE+4@}JPaAuGN8qLUUc#R?<|g|tlo5W3jjeW@ z@G=`4*#Ufs{=M*zjXgm9y-E+cxqoaKt#QSDjs9gL@4k)wOyPB%{u9Ud+SpI~0N0x>Po^rHZ~&{_zvm5jW(7(0{Bk7!@}1H8@r|!c)6a-+uLMgn@fQ2(l=NMZ?>^8 z4gcNxD4ySCX9s$L@6n4nUTkNF8^HJJ^%m|Wv(~YG+HRz90439KUI2iyXi|=|PUy z*x8}^z`y979QWASF;3uLr9VHivjeh$f76fP`Rna$LnZJQy?7GgFVNo!z)stVO}&`L z!)+7Od!wDTP&lUB&Jq5%GkXv?Q|52Bv+o*!vuu|Oe>>Re(|~hq*KmB2gUuWYoNGHf zi~G~T9`*v~$@0q`8L^g5Jc4YOa=gO9qO^b)+MW{e*jMx$_LX@_B|pX z1A3+dX0M)zB12D9T{_k^md2hV^)u0lw2T^|?)=dLgsR2v>oPA;jzA9Q0U1e@>U<{* zlq>c(9>wxoEugUg)eK{4)t@2F$(aeNhA74L?r3VUib6T}^} zCOy?}vL@Y?v<4{6WDQW#8ldz(Yd)dOtQ6Fk_r`%xVWVAd%%o-tZ>LuFoeFA)-u>;I z{egA_;;o$51XKjXTe-XzXsqAOTTv{dY&ZZsjdpRabPSD_dDt6NUj_CenG1w1_^eL> zT)4swtuOGR*^sr{HJDk$gW-shwYw%-9gcrPRI;iz$#zyD6tk+W7SWsfNkBDnJ2<=( zPwlM9^*oOaZzEK@KS$Zlb7w-cPSld;tl1rCk7k}{IPWh5n(~rHsL)w60%)p0rOvc{ zfu;#m=`2kJ+Eeto$~oHywAUTH^{I+0e>%LFUG{=U##Z*YEpm9~j{z#j^a5gvW%fA0 z@zhlw(w}$c+YU2%qE0L7lOqV$v*Hp!RTV+qfKvm6RZcd4 zkA8SI#9>@qUkh>k-Z0X(Grq`L`GR6OOGnlOI0SKsrMW0~-*d=0ZybP0xF1CBoU9#y z_7^4;DtxiLs<#fjs8y>9@>^Db8oofu^+SN7e7k)PU<4G=z&K36!rX^HrUv|ND6&#C zfGjIwtsr+T?Mj^aImr4@ypCWV?h5pgK$`QACZKf!IYcGvQHTac*tIJF>;j{>EZ8R3 z=6)UnH9Xo9RdT=hSaxX4o+$YBec}bkS>6Hk4b*_fC^n*x71e-OM(#?pICs-^po|aj zr5F#R8r7IF90iP*>B*psYD2_$a(7o>fdbn&2?eLBnIcfxajk&UB*bqZnlW3tthx2- zjTumWa6jZWKo-h##*?pA;p|k_ng!^SxgNHr5U@?=<}pVu;GydMJl9|}^>RB^G4~4C z+T8)?tHN8AjK(+jSal^=p2)l{fG4Y~Gvr49MbbW7JzbF-{Z~}rbAaVWzpxf~DQc4& z{T%Am`6>cIY~&Y@2EGW5OFS+Ne6fo07aRAsV&F?vxDj}>#)jtsUyiQGjX6#3+-1OW zW4K|yv55tZMnZ<4 zL;IbqGl8qB%H#OE_q~UYq7aCnbH7ADVQHEF(@hbF-U3Z3|mD9PJz)obSjicA%*VL=R~NE@j)EbU+)59XXzF% zdcY6rt5kcrMQ|DEL%-mX?d2A8>cD&SD`fcHZegtiKc;Vx{3o|4DhK~r=NAvRm`nA4 zmU*9BoSOwc#C*Ul9<+g<c#F8w|K`5eu2ZEb_;tI z_%He&)Qg83bv}m>3GbpA9MOGx5XvPmGSHvlR#pDK1Gt2eU@IDpu7r=L&|I-jA5Ae{ zYeSH$^)ikTlMY<3PX^?wwUZ=7sIsb`~ z>y3?cdN`5TsCLav1Qh+({zO1AoQTEQ?896X=S-z&Co?g#I^T2gj$%nJAtgBYrE)me z>m_jek)YbsUn?i=ti17&mr@D_rk;4-tyzq!T2M6Fla>8@53S1A;u%Qm3nUaWDX1Gx zZ{{w@qx`~=Sk{lyuD-Sv?!p@&c3y$qK~6%@m`LPtsvS)h62}_a>IQ|H3+t;9ps?|g zL_siBg51gi=Q92_9~7=a3d1r8eL@wllN~oEGwh7!bowbo< zd2LOLLUb4M8N49aH0O>6b;3jD`dJ;QOA);aP#VtP)u4+E?yaQAl+fTl6@cnAU#Dla zho18wO~mUpsppJFl0HbB^#0$JwCw6=L??@6(sJ(Ia*vtxJGIBO#kLczo~3h3)*xXc*MhE8e!|$=2Ks}!H~l3Dbd~apF`kVFtxa0RvcMaK}8be*e1M$-bqxlVH8t54$CfoFfIM4y*=P<$+f(}mLH<-d?(4Q3<#>QCC zvyaJ;PK%yA7I^3=F#Z+qeo_(+0UALWmvTRL$sMS}MoA9Qp2L&=1-^s_q(@^A z)?s@Me-bYZk{#|bxLpWH-Y4*MK2Z(l&?py*W6;VvG@4H^@Y(~4vFdy(FaoUQcwp$IU9E&uwWERbwV?EQbnA{{jlZ? zZN8H#^|1r`n16;Fdh8fbOAn9UKvHolnow5ic?+oRyLeS8BLLK{NEnCHL7kCaA`i5> z5-I$JbcqM6_N#b2&S-ed*YQ9e^0W*733N)dFZE3;1#vHETy9A{VZG-XwQ@fULrUrg z)^p1U9pbM6z>lr>U9I-Lm)8S7v#O<4h}Ib38LN3@vBwVlyH!oi>EgLI;90AhIeg;o zFyNQg6FOmzm@x);&N^RWzBn}p_z&x`^@Js&Egkrk73NQ1hbRdG{?nQ-3)v^u#RI>w z+SDFZ6I1-a-&&RR>{dKRE6Za4~Q4hL>CB#Wfj|K{KN(||CWbA{I&=zr=D1Q&Tdi9i0TE8Y&Lle)fbSojB2 z!tt1zhed>$XRb7S%2Mv8@nal9!YTKd`-G7rLEBVwJB;{9(7o-kYLyrn4Z81KB2fu) zp_HAAvuMZMO@q&fn1KL2w+0@6_?JNzX9E5PrCfd`Wwd)5JXYNzGvW#FcTa*yMR$8at4~UDa5toofeHO(_rD$N zupue7sO;C5pq79%s1?ep#ZL8P=XBsY3HkXwnlD^KeMl_F{0mAjKj zXH=I@bI2w+o)U<~mp7KQiDsPhU5Hbz$QIkXyvLF@=~|^CRnN()oI$~h7p{8-Cb0;;jJ(dUEe=~549s`M&yg|l6&BcD3uoNmO;@VwQLWX zi^68aMGaxaXT+O|U)Xl3CBu6aEB^Dj@JoobDaBvc21+y!^LMp^1|tbBEDD5YGT1+D z2sx=3&UkWWhRu;V;dCR@&6{WB3kuKBxJZwnjYXDwIR(51Eu0krr!rh!3&&dgV+&Ve zah99}AX4LMo9S0*aYkWI^ZAB+29cboe93B}LZd8dwfKg1r>YI?9|GZ*qIM1`u|0hj zU+PNfm2Mfj7ZYKJ=KFxc8dqot_|c+aDRAPLR1^g0aQB%p*R^V4p4I^By8Es*}e?BL1gJyhO z1pJzhthLyMDEYUqO3%%j@#Z9We#a;Jnh`$@_-}=GXvT)Y!1F5Mdo<(0vA`cy!rL|R zEosD|Des-&RItCM{C8_&r4Jmy7N0+9;y+Ws2J>D`JU0gH)P9!X_i5svvEUFb#72BT z6E7u$g{D^HLz+k%365YsqKS32;3!V-s3wYr4d7QaQCtj;Wj>|}F=zn4rHM-@e=qa9 zny^kAz#nMhmJ#5=8hRr56HV;#frqgFcbYio1*bBf*TjZy@Gy*AY+0lYyMx4FQ%8n=`#9&H%Fn|0yr0_SOGG}&0XnASXi@6bg=D7XN6 zlFg-y2dKV9npg66UF76|OF8^bUEE#(9?$yRt&8wL@C38HbdeMfp3J;g7kiq(6`EJ- zW1lYisD3r|_07m-%*Ol^eZBgoGH&obLf7xz>Bnpj`2=;BE`cs}!6 zy67$iw`s~E^#RhS_Uh1LZL&Rd@q-iGrHz*9pC*eP4dTT7v2w64L2q;p#tIeVOaC~P zchJ5J-a%ut1r&E%-gQhVXC?CJj zgEwNUQ|XD(jVB7gVUfqcumd+`f$$2@N-01$`;pi;%v_~ru@^}v%D|liBn@!Kr(qJY z`Ci-vxA)^h3!dHS^y;|NEngk4HxSZyoQAA%IceZsb8-#t0lf#}b?P93_z#zbKT1yc zz$q8utR^^zC)2n!&SQZYo?<34d>E5y?*n6}Wus?m4B1g^vTdAcaDP!G-BD@eOLa|* zR=)XCk}jWA5$Bc!I7iHDge115xz949agUv?X45f$jc6)Mqh$_3gR-65;5IIxh}ps4 zrKw`=$OE}R{0ayPQRIM04s{gS0?g6ezlj$9n`jXn&Dd!HdDzNteAWPpROF&Yr}B)2 z(2*T89QrpXlk8YC;YpF8xGrAbmo#5u$&Od#X9Q7fb$k>whl4IpK8;?s%%En&QK zh;&4bih_64p(2RoJMyqoGG0(*PBz8sRq>)V0Af&rJqt4UMrLI11(!;8eFA7{9Uml3 zDFH200tRYSiKH7lW`Ua2 z=GkY&)q|RqUygBq5oo@me8W}7X{XLn*@+2-L2&K$XUvBv2o^ zDyR<~n{=6Q9P7sQsaNat+AH3mSLF5j*+t3>@IoH&8a;10p-t@W0RB-|FM=-7+XTE; zXPcm~g#kC{7nD&@yfhiOQCB7Li4V(xoAeta)QkQHF5vaLQhdGWE&<-a*d!KF;2ZTd zR}r@2Fba4R`*z@#3vjdESwq+@lGA}VbE*2o`Fh|j$X9Kr#3#+*EvTN_K+!ywN%w9e z&s>B^>MQaKe$&OY0Q&n^k{rhT4A5CVYPLkWB0rDup`TR@f%wapv*2td=RdmA=$ghl z>|o#0B8O>oiY*S)08Z0XWQ%CA0@JnOQA(44s0U`SuR{pRC`-FPN9H8rhXF@u2PC>g z`(R*>#@2W7k0@X+qeo0=0p>Brh&K)3NJg&+4guyfCb|3CTP=|V+H*Oojs7qLzN0iX zy3<8xC$NywC!!Yui!|o?-V>HZOz)BHW2`t5OuNuWR3OJGTT_$!k z1Irm#ij|?j$&9PSi8^2fP;H3Ch;ncxn48e)0#9LHuZc_#cq;P-OQ<#y1cid>OF1exj9ZKW;5!OYKckBbWjeY2+d9OD-rH1gVBG4Nk zwYZjp-druoVbsq99aj`&>@5X-uoI-#`BO;D{~A0J9tonaQUW#lfJYp!LTQ3fS~Zg8 zI%bd;Z;Q@Q3{pXQq)WDe*i(QYAv}&OVzCbxsv(>l`%i}h!?bFTnpP5K(DE6XtSzRf zgQ+VIg_}J2X!=S3ABzr=O2ItAW=PQgK2Rcx5P<0e5}J!l@k2TEEDPl`u6NC3hguRp zA0br>5kf>#=HmsvjvPecoO^LFY0GbO<@ta)1&vDs3v zb_G`=>A^E39&iG^14iCdxE3%053(jd`7CS}c zMM-VsN$2ld;ViP|!TE+ioa0H~sg3x&p|EltNiWZXbjE&i+NjL)92BjNa&M(#sRO}% zBe{RaSe$b(c&{k*U8Lf~Q}V;j8%;0hpb=)9SctMs6=%&Mw_}reU#B53daLqVhj>BQ-FVEbcwTbfUhtLv9uKU zhOUlMJmRNt;JdoH)W@^|KhZnXS-YD~go97&mAYEn={Pm`l&;QG)3L?^KjWl)7+DS! z-ASc!6~+9R&pV-_SaTlG(EmKb1mLjJRij+p5JERvEJXXN> zFp3LVsYVe|k$JK7%5czV1fwM6;c)SoJC)9iFav%i&q==+iytjI1U!Mt8oXgLH1ImA z5mY?>Cy3^F}CrGu31)rpbh8SD6E z6zgED|96q*4G~blEFo{_3=duuDbtKxq-9G;)XE|D z2BcE2SxqO-7Uw#==$DV{exZQy;;r=!8txiyJDSzIjDNNwCa< z7V|ww+(H2@HQ%LDD?!WDyyU|z6wq>Y3nd3@XeQEo8~+07fx@DEcv4}UGm^2sjk|&J zFh2Dn+Kqw5s$lmAfNnA;3Qsd=bC%9aO+Dyl=ugg-qf$V(m{l0p0ooE#tg7&1Ht1I6 zmx6an&{hzS$&*xsB{<{ydfem4S9P&*d(AF(Z7=AFP5cV_QZeXBkj!TAAkaP}C9`Sl z2JPn)S>yaj(9@=Fw1uE&l-_)XBNlW(QI2tu{0=J0H@>98{#m72Vr-rQIut7_QjWs5 z(j`j`zHo;?>PMx|fP;rx%w6rsu`JL@S2;E$#a~lwUSjc@qx$V+P=cw`!^NOPbMj4d zg9am#)M-OAC~0dkzr^{`wG<-rd~GM(^e+xf1tR~%bIEdQ*;7oCTs)nP3FwjIOHUND zL1O$^IQcrxAqsH7flfMMRPt!PVl<&}hlP)%=66{p6oJ&7)3($yq4;LD4SerF$k8Bm zFU+5eT@zhZl*mjMK6wu{SIDHZsMXX?gBNa8_L3XZYXHp9VM#I zB!q(+pO+M4%pD18dQXzqsEGkJe<>-+SY8ZTfC|a}R7cdIRN*sTa)Ubg1Ru8-KnqoU zON=`*Ks_jev_=#W_4erMgk-lrXwex>*(Ne9pg!eSZ6wVEEk-MVYK>|SXvsISEcJ$! z>bI0l1;#y9pk<0$jibS!6-rAT#`)2pm5Ta|)Ev<2i!zm!IDEuJbH02p>B6|p4zDN7 zUU{CX@Fe%jSbUaP{?sMeO4Adk!Ru)@6k?JGJ)_nO7jEo<4*t!hbi1P-^z1KAHLiXL z0Ubt?vgX4m-g9wQuDK2LJV@5{!8Fic(0a1273H9#)>2v5*h>~$%3ppWQoVH=Z`8r> zl{?k9IAqsAKVj4IQ>av+d>q6BUg%{sy~u%ZZ;5HWevgBZ^d=* z4ug+rXLD5AD=4ei8F43j9`FtAD>X%k)HdLoKz`3#kxeO`)Gk3v>O;p47M}gE8_2IxlI-4nR>m2CN)si7BVOiK$uhfIx z`h*FHyRaI*;r&}xiwzjTXv2Fe(8EbN#8UylNS*f+qM#8Nt*Z_$#EX<~9Bvr1v8WK3 zpdZUu#-cYS0+TqYGBGC{IE=AeT;2;znye_)`mZ51&#vp1+BVp z=SWBjSrP|{nA-r!XfA5KxL5@&)yoT&!SH&j*I50h0zSHYJPkZf-{n#E7Dy`J_#@eY=jvmM3j!d}cmr`}cfiK52WVbO0aK)km%!U_NR4^9*n&^D$k0^tzDw zEnR)|YVy0f`slR>uMvC_x6RGWCvo2P0eo5))2##e3tfHW+RJ=SS0A~W{IxC)1PXdEkvYo4ah{6s5mO53b;EFKUN_Z_|%Q@V6H` z!@+lQ`yRE4L_7E{Fn=U{*=+FL%*SjZw;FseOyBC;3yUAkFEc0n`nv=duzk4IHp!+@ z7ZLQ;+$6ikTYQn@0Qza_wxZ2VU!hGJq#3i+7=1qsz7DPQ4#FTe-6xskuibXHnha>q zIw^pY5@J~f(9o0(-Xm6|0-f4t+X;)r{^>v$`<93|hXX^{+}kRql>x)FC+|`g++PX@ z;3_eje1+D0H(PL@9|d-6Uv6g$?#pf9a1BF5Su~AYa0K&F4MQI6VT<1@8YXdYq{b@L zgd-jtrS09S4*SE;QsJVt3GmmnL3F+!{vx1XTIvUYG&)GN0B&t_7TkMwa6UHxRPG zgSFrd#OE|OT`8NCq&@NvgdJmUn)2UQ*QZzmYqC8W{Qgm)GL?cZllSmW|g(zR^l7(7l6?zD`K9Y>N(|EQ&e&UaL4o@kcZ7vx=*_!DE;YSjEIf zaETUpKk*@}sHgl(wRyMjC*02$fXA}ZjtmmMF7P-of70FS2A3f{{-pZ{YP9jDZF`V7 zo(-mJ8vIFjXCinaMj?OF{h}3I&ipez;VuPFV!p>AI%k3>gZY!_WpUsNF5edpae>NL z$@!ndC(9$jQ+NaPwL=`p16OgUS>rE40>RbV+WUw%`(w{VGnF6N9{el%zt%`RrFMiQ zN}wP5@CJXcHv&XGEr$Qrc~2@3D_T6kSZ8F2f;l=8>QnG1WP$GMC2bS{Yf%uK&*l(lupyY7$mNefhk+) ze?TG3k}QzXNDF3+byBjcKQvqdT zh>i!|#pn@V_WcD+JO%-c8L3i0CzL?iPWjUhZ$E2j|;d5$cw)<2>b~1 zdfdFTfFA|(@$A_q@MB;;jvdwsejLoluWM_-d%=9%nv(#20?ga@?f~$U%=>VhI|lp| znD_5-ao~N-N0EL$ct7(o?6p41A%#xn2zf{-wXU!is=L8B0XPJm6o^ z+X&0mFZsNN67u!G1EavN+jdCaj+cTd;5V6f;<}vddx;1}qjVd@3E$?@TjO!t*lBdz z*G6XtTn~#_p9*}BJFr6x(tz(X28r=Wz!O|cm-wm-_<_ybMve*reuQKRJ*uRiFvf_& zMBpjgREb_y&eM!ZDCWb}C?*0?G0P!MXpN=!;@N(80mOq;t~q|@=6CA?;9S4$GPX^$ z*8=PP%u-M30yZ!PSrP|D$y6z!h;|4Q&(D*BM<7U?SS8)h!0kr|0LS5AOJ&6C@=n_+ zNc{Vv5Z2kOKE$JV-^EJzw{YW2sj>8g@qs6)=$c=@#|*5YXLc^)%xRQyhStDc+Xgq} z5LJf5iOf4xX_=Sn{kC2lX3?!$1$7t)7mlLOAd?QN*E;Q2Py)jM1&Mc217?hb~PHwcoK6_1^r$le>Dcm<*&w!%3@HS zQ<9(jkg;N9r6fmeJ5l~DNkQ^HRz<;l{&exVaL_2*I%QzH#t9myK1qs!F&9*ZtU+FR zjmM-Ulxsu!n9d}l;>rR{} zrD&!OBm$-+L1angM5?=4A9<@XcI9rfr0Gn z5C=nmL5xA7x(H}6y2OEEpp#LET@!%8j2^Ms59nfy5%)v`Lm0i{XTng%B++RFhB2lH zPbN?>rVD!{(9P%*eLcW%#vHM{0~o=WFJ?yoJ&Z--R0}YYu|zB!Vd)qEk4z7*wy+ z5rDMs?z2>1rhn6_bRQoHzg2pBtkQjT74Ua@hNg7zLM(8#ez;lb;8Yp#3cfFxgLmVl zmg+V7%6YOZ((F;aRv+4=?0q-30Iz2AUz50mGFq>z9@ZhguL1s1@0_i6FQp@a*XsXn z<=5i>j0In>Uu@;q;$!XL8+4m#uCg_Qx9HY3HcyQV0B=QRY@QmM4Zd9uZsRx5_a}qz z)sq_d4fHVacKy3HHb-^&fgjM%Yswtu#*A0JL;uRWeD!uFym!%cMz&6Qzz-rjeqrsQ z;_ucAX7CH@Qc~l?`afFu^3?5>;5~Zme06zBM9cvHNyh*HzeSg+Xqc!GVK(H;aA!=N zPh;(6O^2SmD_Sgg=2X%&wAw|}(9?KYEgAX*3iXMWNug%Vp-_u06zZEv6zbzVnyk7p zePLHz7YyI3e`=(8X_&71n(avzF@6N_8;$2EQJ4$-Rx>B5u(KJIXw?NRrk-wCP~e|5 zOal}*T&o5Cto2)jZQ)yJ;9g`&97*1ahvYwaEso(bm%o z4AT3rIp&QA8#=#wYhsI>ZeU>NYm3)MfrDY4=Y6j`9PDD=tA#I428Sp!xHXox!r|Lm zXx338Ek=q~Orn{GMbT399*uLsq9`evG7BO%iz21y%PyLQSmcqSJ!Lc#u_!`{ULlc( zMd4EP;dGjjSmc(X)S)yhu}F|e^rq6xr0cW!66A_DaE$&z9q-~dQueWIMLhzOq757e z=3V`P2yndKZ!%m$1@RKI$&j?2!2A|WjHK;EFn=GkD*-$hhX8D?OU?i%=|5W7I(KX| zc!>VbdbY-83;_?-zpv--g}TDPDZ17`jKS=jh|S9SX=&6Q#DavLSsEq%aD?vAW7Ko zp#?Wb&T-P_T$QWeGJ|icJX?*_YW&B*&v*@UT}?pTJob7IN4`bV1Bs2>QGw|}llDn3 ze24=IUL?te58FYZcS&*>_uE14S3#t(>w-a%-%4^BdBvcZ*!@JpIGF*8A1BFUJUt&Y zxK&b&v33q9S&`Rxu>zF3R#K9&HU^ZgD8(2v6O?t2q;%u6T9EGZ>t8ZSR0ceK9jZ?Zcau`VNMG zI(TOji=9n%*T`n2y^XYzb(c%ZkHuD@w^q7~P+w?`RRP7YDh7UC)!RtVbchq4=_EaW zpi!NKRP=`$Yg$N6f23`0Rr9%2^(WeXp!#NbGvYYsWKjY?LJQnb7k<-FKUK{i&`>`w z0;$MvH=3`3Lz{Rl4I~%5GVsS)i+8R3>UW?|Zm#3zSGICD^DZhSo9jd`{NC?QRk{4^ z1)a#?jrP&GRG(4&1{5_8^l_*xfly6ylDDI(Nlqz>QBCrxY7(z%lGCb5l2ns?c7&Tt z?iW6fm1(BS2KquZkdK<=Y>xEEL7hUI%<7^~aCQ09ajn_(8s6_ki#5$A&GanB)1PLD zL^L{0BV(Isl1Y>9sc!%pC-eqB2Z5K>!jXsj-^rFm0RWwZ&|F>wggtQz%P5b$m7 zM2pmz+V8x>8-ACYD)g?VY9#2ZWGcxVJe;p!IXzN)0@_r~Q~Tl7(R?Q~7W9!KuaS}q z`q;jJs06Q%pp)iTtVqxUf&VMAmV@WhGnE7`B#{^~SJp3czS)8;IBL{mGMut+&OLKtL+E?*} zF0nuZPSey!&_Z<81E;fEJxZ;$tkxKjGZ{Ej`&Ob?{GkCji?y62WCxqAsUDUhWDlFu z|9TTA=Og?igWB2`R{hI>9=G1IxThJ z*uFuVDltf9a+9_UsBZT|dr&p${p}XBkCF>sR-K-Q00G)R$P*8eESK$h5}Na>Ke3%Mnb(a1mK*ZBP$sm_1eFpz$#!KywZ{kt|ENHa2!F%KkArnxLFs03x**RJNd>Lifw49{~v7@!fs z9crF?aV98Rk$|xQl!N3!9+($Exr$<7dI04q^1=!P8mTDBxO@R9Ur|bIUu&CXMuD;d zr5ia8_>EF_2A^S}{0jLJB!)Ps2t%A#bvLDO$PeQ_2tm|seD?yjul?SVun}o_YJ>Dr z$b_6p4E<}ivpy66bm|w{)ciBF5+(dv)5D%$z{=8vxhSCFb+>uzjE?#B@GxG&t8Dli z@s&DQwi@j{Ku`7z!qZmcp=@9jQUrcsHJ%;;jD1VuIjiyhWS}=`9wADFn_lqor}8Hv zBsJpS;KsoYiKVS(H%&46_F6QQTx0b6yV_+DJHAI#uwMoJ+5K7{guDtX;#MaV!rs3fJbJd{1IE)0k|0ZFcjfAdZ2)&~yzV}YLGeiM?@9Tt@&qo0!*HeJzLJCmf zj{x2^^T;^4YZw_Pk02#K@2*^o4~qE5@f7huG(|k^pzNGu=_i_VGjD~5LEkgyX2B_k zz%q=1T%UP^aCrp$hF@?gO|2>cjZhS%K4m3iAkXepLFaxH!X|#q(?y3jg$DiLi#3dAX zyZ-!AwWKvB0q=h8dn zF-Zk|a6P-Ov^zRGq2Yhzozqev(tgGj78#?W?&p+nJ7yI##^~HL}~%hYwhBJ zbZ|5+^F zvQh4AHMo=uhF|gi`6|8^Rzb~GZUri%{JAV}1(=QUmE*vb)+tst$}gaT*O>=2~59z5J?bNY_HW?M$WH-S-`u@ z{|A&N{<#o*w>`|tmr(}Afw$RJLvPT;p-S+5_NzAW<&^3c@cqyi8{wnv;0NqCE#%({ zxSOiE(>~Gs5y^wK;N1w%Lu=~{@E+#f$Zs6@5iZYOP3$B^JZ9$~X4k~ubnxQ{&m(3` zD0nZ2$0gI7#)F@0&|G|ZT62QmvY*jp{x_I{3jQJc@9p5v?2iWX57kE{gTLVLx7z7P zBKyqOh>tKp0;yXCk_%p^@h6d9OfoZb|~Nnv(b? z8J#qEq~D9kyxsO7q=|x#sfK8uz)k-GKUbN&yo{db@N|9|2j`qYG~vYd^e(f^aUh_a z>u3iv#~@j{d`eQa| z+|uRzW$=XYvLPs%GY*Q*uXnvqNj!nMygp@@`q70^VE!O8E7Eo&id1=j#=RbkGp~)W&G;1tqJO5W%Xw7O4cv z#|?NuwI~XnC?lSfTl_K1gtmDB2jKR;Ccn1LXs0)|r8B7p3ELZ?!qj)PX_sJGaMOx^ zTr-V7Gi!kFYF6H4eL5NVp2nAQL`VaT$^Q~|Ch#>KdmO*#+?$hit{Wx<2{#cW1PMV9 zL_};s5PJwoBq3L9iG2y7q^PB+qL$L4tEIH{`dV9Cd-c8cwN-7k)#~eO)q7p3*S_C> zX3ijQ^Z7XWf9L<7ea@UYb7tlmYE=$*HwJ!asMl0Jt}pP4AxAagyhl6WM+&|Cox#A5 z6~^+%(|}*7Urb4GxYxBnY2_~3h%~XCc$dswY}adkGf<^nuenV@ODa{pt{VedDv3MX zs|-A($F_cN7LD`qR2thRPN-;n4N8(^uv7VDry_N>*Dk+7%I~J5G(~`>4 zQ$gJ%rLnFQN}9AxXGIiy_dRL^KaOHgmz2eZ<$!uf8qR7`jxwabv8-MxsHY6Gfc2p; zd-W4k$c7O0{#Y)MaJcj9qZY=lbI(Qr9-^c?Y}dlb2+(@FSmG!t8&oYg%(uq@H&U^? z|BQOf8oTKjg>Wtu&X3wv(7ZNivt8&Nl0aLe&c$9F1=@;eMd5mK(#*ffW>+n~YZ zMj6FUbtg0hMyrJg0lc6gu#rL!pW_3@C=BPL7_hP0GUMeX!+}lI*28qZt3Ocg&p=Xm zVlXh)P%l{gRexZdx&w>3rvtD6jX-k0nPHFb-MxX$^?^yB#{lDv;p$cRObW1t@!TBs zDr^pE2Zxtull4_6#G^Z4>5hYIYVPR{b5SYND5+<5%~6Z4CV|d^OqHfspzQl;7lygmo?wxkq?`{!76KDi&9qNKb} znYrwqCzH~70_a1#SKLd*{}Gk1zUx0$<4@T?e4-}bWdCp#B)2lx0)1*H^W7xSXLd3l z?+p4}9R}ctsziU~$sJ)(0ys~GZlvC9^`jR!%ILmO_Ji-W0_GU%(;Pq70yr8T?Jt0o zomzVv(#veFX>_9ipQEUq#v}D*fWJ_oxS%5RIxK@01_0FF)u?coN8~0Nr^#<+7K~dP zA3-L+uTa|BD0K1P^MOeU1NcWxfNd3qaA$8|JL7wS9-c4&*j^#$IsU+8h2iRnLSBQ> z9QD8eiBKvs493kYhBT0)X5ekqo10=RoR4&V9g5I8tI!<$LS0}NWBq)Y&Yd-YU5zJ! zl+OMJFjX0c@S9=4ZaSUcjR&UbbS}sMc2}7S=O5<+GmH}=s0gHul7x8fPd23~h~m>p z-aMZ&@(Ql_ug67b54b)9m#7eY#*fX#ce4e^&TEw5e#Q#Ol${oohW^IW0$n__DR6); z_SKa4ETs+M-$erl8gC2q@X6zVgA{VUvkh>taR(?innVG!6-MxnN`OO*$c3`^*wzd< z)aWcQMpXn7r86rpdZ>o9E2F2Y8wvedtv`3a9!PqO18_Z{t$w=SiaN*OpQPzVVfvmn zt+UWJg+!{lv*~IAq(NtG@X$ReYP689y>Sg3NR8?o8u-oJ)y5le5nBLr*XR*R=1AaL z)wR0#oebbQg|U28Jn&(C_}pzLa6Q5y^zrZr;0EI_0%wT@D!ChtFM;%mBMrn!QJ`@$Ar{JQFVJbR3Zh*Ob z5yEa30CkqR4>E{mVG@n*MB*<{BS0t?NTgf@mxN&^;|X9dRcherX6 z%^w8D^B0=|Cz=f^y%JT$_%93R|aoh#J62R)W9)UZVh5YV`$*^GBnBQ>+q!9{yH$;8bgw zK+X@C!0FaA0>iPZ8CYhW7Z|~JHUySi*9Cg{`60j=mjA=Dhq%xWIMZq>FqTgb0nSp! z@%&0WaJH2xv-q~DlmyZGZ8q?suY;aD{2AfTf2c`_j(R+fpu13D)(y-Txk6u zFrDuy1Xfse*UO>!&|$zuRtJHZ{HG+~Vk=u<7BBAsthA;G%;wD_fJ>|`0*9mEgHXPK zk5P&DK)DsiWm>2{xfCa^pCv06t5uo;`&&a+%Mw5701mL`2n^sX2$*GU7Z}20D9VA> zDS;mTMi<~9g`Cf(%nY`!2@K~&fxv7lc#SM^9t9j?H5cgR+Xn)NDvZH7w7_9jhQL_< zQVDRlHBMkWU)d8l!kQ;A0c)p#Bb7FZ$J7OmvUUng=4<)`bF5bcreOOzaI|$rU@DeQ z1IJi*1g7&5dB9w&`C3`xyajNq^+b{^@$HnOaaK2>&ElJifO*PqHow&xm~WK`?Qnjz z5wO78ATWntEdY+U4htO12aW|6T9*YD(5c4D=zw$7QPjJg=!PhF(dPr+-$N}CvaFsq zZGkggYEdp9lMS4uFoXwF-e$W_RLKhHnF5@H{cviNCKc0MSBBaISQH1Gr?g%^u{m(Q z>(>sl0tV#*7vLu)Wd#IMW)`~8)r(>ZOaxZA^3;de(q_O#3bXhss(?yYjg_(>zH$SX zy6i)fPj&)6pl~c-9tvFU3KPZ!Jf$D7%HZ8aRL8kqH|`bZ4vJ^5gQlFF_FmewuE1B(7t5L`7zBJxVE`{r1fBq@xu+!HNrfK1s1NXz zQ+<-4Ui^J0Ra%=DYtjss?8WN^LB1?|@kX(fvXQP^wDa(Fw8DV69M^41RSzE&qg}xd z%2bW+0373r6zIaUlN7;dJ>mj?_l$m@x zP=1^Wyuft~NLf8N4me(EL-@5kV4*?}uQL`{fATdGZ1qtWZCIk{5KtVL!Y;!7)%E19)74LK@gdIVQ`^h2+isAZo^y z=jj1idJ65kLLC|#mn+Ojl@t=UO0-G&7MQ;#&FJt2SHo04Dg`%RaJ)0u%i|*`PM1#R1#+2MY|5&y^&9Uz|G2pf9j3f>oQ+ zCIQ>|_fs=cn@WJm{*&D@{fhVK6X7V|o){XN^^9z%Di-Z_N>9)KPTg z*>R6p^qr3vhQnl&bzr^B)^l}$kE$oMi@(?axWziXUS{hF4{)pXIZ(WY^anm>-4f{G zA145}DZiXQIUcy(LK(<6=Oo|`g%P|?0dS`!-^snaaU$?>D@tf%c+mjhE`_mt>lol} ztCzrdUO*u~VHFEZ;D4zHd{Tv+#Q*6A?zJifCi6wfz(w1I<+qh&d$Qnnz+0iKpk&i_B1Qo6I5y zA1=|a)DjL=kTK>Z=lSH^tgdig580wo#(oIun2xBI&|p1r(bjFMt$~#KMwb1CeXJEQ zMxl!j3jsD(7{CW50h_?1J=Zn69KGj88clS!LRM1}YOc2Xl1`BDeqw*of|GiKa1kO1 zG9(9#hSX~gNcTMOu3kmvX#I72?P_plJz+FT8*SG{Evg$;Xroh*^!to@UqPH?^n_0L zH5HOdyaPxbq0m#Rf7g0Qr1D#X0$(JTb$>0)=mQSMTFMNb^m|O`8atW{rPn_en5b3b zAYpz=>7mNhs(IQMo@kac=HOr|w zro-B@$WV_r=(h+xxm>pOx{c~q@dsf<-!5-MLY-9mHhfj+shxzatEO_S)89WKkyoAF z`a(qukos0vwbQ;zApQGi+JSHlGM3#NnVtlgs{KBrf>lON^KPBI7J3m^+#}^Xva0^`joc%0g}!g?zRZoymUoef?hU6ygzD7RT;39 zqd{#%ZwZ7qcJGyM8*M-@2J!NqUuE=7wRyk68+o1JAavACZBlP&V&Jd<#aexd? z%0{qL1b$k1)_HnShx@rw={c~AT6IgQ$n~!x96Tm<$iHj5sC!&PAxqa3NHU+0NR@^^ z(N>r|8bg~EE6-@Qb?@$J=&$vaqz@~;+agM}YM1m{ZK|tk1Eut+(&-%U6W%C{Pe^rV zrBdmtB%@{MW|&o>4XKiQ|h6 zbVZg)wBo8~Ov7#p{d#o;E^V za!}E?J@5=rz2Pw6S!3}datL@K3V2SRRv4WDJZ~f$^4-ou5;8`yMqNRBc&XrB<5K`1 zG8l$`fh?0SdjRk~7SYzF};VgS4YQ;0Fq`!>0Irj)KcZsK5e;^(YDuKGknc zN`|fEV9B92J0(Zi%xMl5o;_ldIT|?>?)trGbL8&qPz|532F?Ii}va4$bcgMTVQqqy-!iVM2A|l83YQHWU`Frpdd*uwz(T9 zSd!&%(*c*B;=nGO5lEY8^jg8WDv+LaKp~P$cBnmw!At}a*$3p7I=90jq5o!Gj_yeT z80Ag4)pRQYrTN+kw>Lc|13g&)x^qa73)^l$|2!)w06%vF`t1urA#7L*==VEKkVLabj z4;Wx96qtZXM_`b#U0@P_s|PT|ctv0`e!=(R z@Tp^f;YMSjE#?P`fc1G-L(byQax@laeA1b$ z!MNQ2;Oz;As8l=&UYO9tKy}Lri3v^bIqwx1YoGVZkMsk^8O@du24FG(*i5ZRNaw$0 z0-GBx>@(gv0^=2C@@L3z3l(w}@0$f|sW6+b3In!MI6RDgn0P{h!Wkm8}-h8f4xMr_`zw-!>G3I~fmcSBq)~ zrh`+A^@4X`S$IuwXXA!iR4cyVPUwzfZPj}9Lut^b8}=ew>T0*zPhQ+Ks@SO#pxOop zeEO>H{PJVA58O(^RlkE>5T8R=33ud>ocS(Nvm@2 z32=aRT_|0vy;F`C`Xa#g|EOQOjgojo>mZRc>WSWab>Q#W2Kv=c_`6Zv`6F`14P!ee z%UFKU0X5bt{jn1I;O(|PRqG*<>IIRK=GtJKHh@H`Tf!hy8!XlakVw^L6I~~5rz_lX zMJ93G0hd7PUEO7U!4ngY!GR4zZA@${S06&P0}r39l4)P;fQs(B67`EAv_BA3Mx#9Y zSGr5eq0?tymCTS7g8mmYS9Tj7^uM5as>5YD(V+Q~!r8-a(1IU#$j9+X2WVlvokU*7 zfwzi@1jVxL13^ox1jVzrdVrS6zBGXq1%j6E6S^d3Q78|}v?Q}HEYRw+ zLYKmNwgjzJy)4_)6}0Xfp-ab%ENFx5MS9_PC_#_N{AH@Q7^GUaN)(rJMe6lEfeXg2 z`UU4#ZPfLCBis<$$P1O)@Oh6>wMN`yr`^b_{=3mcVMH$bq*1k*n$ zwmq)4ob^uIrp&ia0(Dmnj2&nMN=NyL1{O8})WdFIX{qaaySK!+g6mkRd=#FW%~INya7wd(=<5ew>)J)Ic`8mWHGljXGljY4YG z&oF>;B*o%%7SL!(@$6W0&={maF5z8*CuMl=3*{6+hlWtSwPv@BV9qem+j~HAyD;e8 zmqC=}9igDVND5(X$ACV3N05h|%K?2PboxsN9Y`FEi}=WaKkof7y3+e9#T7{>?Dzf@ z)d&x=ntFeBSw<^!`MEmLiM1XIx@M1%#WCYwNb<5hL| zbO@los>PW#&v-yzt7Ee1_uW5Bhr{3O-B)aCQ{XoecN=U81^g|lUTmRaPYwazuz%*9 zjcfz_PU0nlz3%|toTv6vVcR zndRbP?%QQA;wF(0)nDtWi(UK^aO4bCJJ8$PK8A z9J&WSsh5PglhDQH*NxYW(j#DslYdPqIBp3T@0qCTp0EhcDo-(_AKmKzMysgQG z>L=SEZEvSDLBA+(Y+4}bmZT6?I}LPOl81d~f_}Bja}S02PrE!DI6%Lt@(i0c z9<|~ykPD!ff1eDcp)j5wtp_v}Ci73-K&QfV9@zuvXH=?@WZN-7e}&onuY`dLhx0Ck zK|nR^rielmj^&&C18XQO;0csBkHTU;asV(?p^v|t4y>tg3O_jlSW96U|27ZE70%*8 zt$|?*=kap|z}i5y3G&cDa2>GP8TNA;I2^2YhQ*Vg@zW+bsC7g+TcM-# zMH=Jxs*l*d1}ZW~80`)AHB{)5W$lF}VSp^_D1{-itfLirWLY;-NOK6(*rM|ND7F#C zTW}65nC0+|RH1`rJA9+;xMXqXC=8I5F{xiq9N<)ioEIkorx~5pcifA4!0GBuD1!ey5?E&7z5{w4Q3jfd%U5aKq$D9l zON?BVqSW(3)iW{%*xRY5i}1vEx^UU)2hjsW2gI#<*z?Uq2^$D>3O+I00Gi??mq{_XJM$!Fqsm{xj+aX*M+h zXE_(tRlm>sRS9^YbLR8J?>qU9c<>;_OI)&a2Rl)^;QcNhkOj`h;tRFM?>zY*;tUq{ zmt1^Y9JtV#_JaID6z-<16*<{35x)G56JN37D=xk!7WxUuEAdqqKU@l)~TScOt*1bQ}Je{JyT+@bCSB zZzv4s`+5Q2R2bois)dLDO5a(d`E#@epVD~FKuZy+2r34iH&Dc)bI+iVE*PN#WB6;0 zfftP^fw6phD)23Z?RcM7z)K3#d4qPqw{_?KsXy>fx^th|6ZmJ{xo33(zN0($VoKG! zx^o}Y8Tc37x%cP*d{1}odwT%i*PZ)ICh!B@x%1Y*%SNv1+<$ZeKU6q}KVBDjMd3WY zr!Vj$g$sBPCGumS>iVP8!JjBzY_u#YD|Gm-N^_%z{Dm57lbIY0t*y|$Oq;^g&z69tWe1119OqWaQVPotS~}8Fe?>$}Gz%Q_C=aD}lb9(q#?GKhom z^iUrQanZ9R2~b6G+Pmf}Gv7R*R*?E;nDz?N8EL?o<`t;Kud`7MvlIsKbv=ReP2-?? zqJ#h!noR_Hc&bG;ZT1w%`Ro*`OLH`ka^@Wge9&A8q@1-11wLdxE6~edB;&Q_X&~k7 zPZ_}VDyUe#WgPGk^J{_eJl_xas2Ordwvy*!fLqL#0+aYP2XLD?KwvWewFz*iStu}t zpBV$(tx}cBTSox*m=7FMYj#HgpH|q5_jLlFH+Krmz$50n0<-xI ziuYv|@^C)7Kk%r+9D5PO0a-Qrr3rPQW-w5wr20?GP(IT}O|(&q>PG$t_0k72>ZUA7 zg=a9X@!DYYJ-U9{6*WWcH^L*}?>6&}U7uG0pmNe4k29D+lT@rlj?Br(&2 zKYG@A>1xa`o21$S*qfjYz zO$^cg9+0YPlRrMK->LL^Y0XLz;vcoMkh;m-p<}{zkFY>X(S>maa#YfIh`zZ_e?0a1 zg*wzhJO6Ip)5pwLi1EOWoQ99Hoo!yQ$7yq%_Ohx!=K&W$C2g$_5qKKF{>D3SKV2yn zcTg7$zbAz~4_VAVPO7aQ5Mt&3q&jSv2m{B0K^Jb%MphW0y7pwz$`nxjvm!PRTVR1A zByoEs6eyT3`rG;obfs7mT%|c59LCtDW(^0fuhB{}?-CB*-m7W!Rd^;+17lG#-YMvw>w2f6OR48|hhe(G z+k#j6(Isq4XPin~Xy8y=j9{kKVC(*^2h&VRYWed&-}FZn%pF&BeO} zaue@73`v@LJ0YhP6)x|~2yan^iwfc)#}R}v*PjaF*HS8oFQcg-yqV%eb7Tw^zlHK$ z>M{Gkmfyn6T4|{HsA?pBfk2$SEzreBMFMLn^yBk70J%cT5#_d!!_o-zc^y)u4(at^ zU;{g(u>1r^X+smyi#Lhvw7_<9 zYyYzBgNkt3=HM3p>iL?7a%_Vtot2iJ9<04wk5xP=;5_!-FJ*CVFXg@}07B`L>)EhifC~~aLE1S zdwr;Ez)JfV@RDBZq%DzaZ7Dr!^KxNM&KI;fikb?^wnPrK`EHSh@1>~@ue#Nrbs8dH zwk`K<6h&Rl@|Fm%`~R_O^fFl$D68tR!l1V>So&Xrp}Bvk)cW`PLV;?9R{cS#^eU+* z;ouGrL8Beo&^oGq{A8%N$x(GATnZ?vvmh7d?m^L`1qI+7Xi%eBf#bB(8Qq z?EF57`^Q7{n3)+sWtln2gOSlUmCnB$*C# zdNMHb7%;(A){_4LjsCe7)bua+rly~tL{0xUA2ogRdJovP`Ci(#OC{S+Ym=?JCE5P1 zHrY;$61J%Zu*)2hXRl;O4vsJ=mGKZ*y$z%?-6E>wjXqcU_v`(PmcEV2hfkvo= zv80ZmQB_CfoOg!+&}d1qtYb20%u|Bm9qya7Qm1U(2}<-6#Zcwhi4Lv>%9n;%bMhS; zLsD7cZ?D4edPS$DBo{kB0OXV8$1YQv zCrPr{71EVT@@LnHCQAxn(HWpAk^b10}x5@T1g zK;@F$%<>1#kW_=!Oa#r8 zP_V6S;b$wgFKSeO9u3+iLqO|`LM?w)wsZS2_5Gvl@w?wYK)WQlBJ-w9ag^=0@2zL4 z3ZAgCMI<{RL@RBItmm6t<{6=%A!jS>=Z$rL!s*=mkl= zSo4XXBj|8InUTJHbj&aI73s`o^BO_-(ltTz*gs-HFXJv3>t5K>j=-a+58ze9(Xpgz6Di z2bV2Q-@F7{M1&?oVdi=|EiPLlWz zmL~TBPVUu7&gZkuy?|3?L_7T0&&`0-UGFUEi^o}3f zR~I-#`dx0ZfOz0c>35~YjK09x`(%zRwyqs;?#i=-doA{SO(6D25k6z#EeE)ur_k=V z*q{3WD`c9FS&;>k#yQFtuM^r+7W3vpTe&`0WZz%D_AHVasFTHrN{wdKGS*93lLv5&%mD}NXGjl~9efvdX8^A0U`wIT2!i9aCC z9f7N5yuVoNuau)TEjEezwb_3PPe8W}%-c%%IB zZ1!p+;C^-E__MXGfCp4lLA)N|!7PEx1K6Muz(W%E2Cx%>z!%iHlL4$o5xVlEfW>EMW-n<^C^-kOSG|F2JMm1kGcC?4=^$AA-*j zUI}Cin*d*t-=?kxve})0f0TGFkTp*Qz8WfwzY1hOgaBWY_)Q=?PRTf?zFP&dW0dCO z5`PF}PqqM_koZd=d#fGrq{KUctTR>jsg5RLMG)K40QkB(7Bz_7p<;hiwT&QV`2kN$ zzbk`SjX>ZTwVX4EebW?pR%+J=vH9fpTpf|fO+oC}6yW&|5`)<{5x@)5@77>;n^JXA z{akr4b9Df|B`f7rFgw{Acu9tQEtq{f82GllyT8J?uMqer^;s^MwI2xlv#k9)!L-)? zxZVkZ8zh)CaD5nZ^b&{$Hhn;L55(>0nK9%xWOf$AmKj5zhe%Hb*JRKz_341!?g$z# zDFCamKqKr=5biyw8SjkQGf&f7!33!0RH;{|md!zPp%8&Q6atzD5`lCX1DY=_Ls;Wd z&;m&wwkrd)P!ea~w+2;63TI0uf)*iXYGIdfzt#qhizyrK(J7Rg_l+~+Ao>{}sI)}R zcFedeWtWWmLrDSbuS8eul$22BK3bqsGL`6KNt}I|3HroN$x~UNt00jQvyc+~>2hSx zy%3G0c*f_)&!`_fm~jmvr9zC}W_)3%!6o!+3ICAnA?dHF?B09z9Wx~0ChW4#yX_Nr_- zLcG=-^edV;D2uHne|IEJLHsmx=spsK7Fpho9#nFu&|XC<#{$Wc)Pu8w9qE)%P)CrO zg{YKU_0HHg0iHi<(tD4b@7{D)&;M%`GD@mLTJ5)sjNkvmCTWl7~H>30e!1lck%`QUYggEIN+}R;NSt2-=En&oehkGFVkV=pL11 zvYS0YnN5dA#11Jg#d-9@~__qoeIb zjGr1iak&G6WFZ~cB{L<;0c31nmBvIwZpXW)8TNrkOE0V_^u@~9qULrVcJwU zJOpm{bbHeMJP6|0U=nK>5Knf5xU_`KBDB4ugDHu^=dZ;7hy~9vD#5V^IH((Vt_ZCQ@ywCn zc}5lV3&Fjn2X?BL&mnIzgQS*Pr zZXw%^&7^$*ZnsPbbN|KGnZQL=?Q#5`I}5`icfc7y7&+sPLV^kkiim6E1}dVN`)+QC zsJNRe8ZNn_QCV7P?uI=zQ*+NHSJV`@GM6&5SFd<&@BRMgoJ+i=Pjl!0{cmTv=bn4+ zG6kt_M|JNt@bRH|yG! zs;DY`+pKh$Y;Y004&Za4Jjn@_B#x3C_`gYlnMwj5v;G>)Vfe6%EZu|e7<~LLsro~y z>QAz${}<&gkAu{PA}_J@G<;_gt4Ju#NRkl=u$qxQL8B=0GE2|K_bhy7s7NTyNRmY) zN2EMt*Ml}uV6JY@BW4h*{2X$r&Gq^7cA`eX9`5W2or2%8{Gqp-p7 z_(2W~Jy!%zLU8N;2r?dM+V6-GLr!bGOie$PFRMPRLtQ8y>NJ37j8J!BaiRh+l&KV* zFRK)=TKqHyyVbG1bxo~xO(rvrmZ3r`GWQjkla+a{S>O^eO{OvAd;t3_CJWdl3(zNM zsswTl(45b#S}PjL10Nu&ObM->y3BgR%z8o;=7D+?>`!G~^a;=vD%Zd(LPz6B#rz;* zj=??;G1Xx=Tm3t9Z$g(Kb*zEb%41P=NHc|OCA6Mvk=}!pH@f*QR3Ab$u{=TRCs3V& zYVj3w^fD^miv9OB)SHC5tHsaB#QuZHWtBBQWJbh`2oKag4>j#F)TV0&bP>>fC$s2| zM`Xc6{nkY)iM2!}86lEvggO}kVNjc{Wj5)WSn}UJwMN9m*fH=C)3Zbt@>)mP#}uCj z`zY9RVIKv%s#t2FohqwXzB_Y>wnq-omTn>26B*6OYTX&A`7VXr?Q1Nq*=U@d)R`$6 zAIy~OzB)O50BZXgp)I*%; z2b1gXz@Fk%H$$%aZBu8D4%fxm!=U-A4RR00XX#Z<>m}x|;d1&)qv?w* z<1D&9n7BPek$83eUPmHZMpOiLLr1F5L&N?V1I-YGMEG+!D{-M^r*x&>oRjb z4$R#&Fy{h$i51s}bAUK3dki0#jT1GceUCzi4>j?;$W(5%`4E;{>jPgrTwPN*gK$M{ z6VDK)^fmDt!pG%U*#SJ?2)KtZ8Q25sHiZMoibcG_T*6%r;75eZ32VifxRdZ4b?V=! zqaHZafp_7qIPg5Q@|cB<^@ceZ_sPMSM}yJhTVXJI{^y{Bk9p9MXCZ)n+~9^f=xk7> z*7U7-5>|)QRw$3*!%EUm;p;j+!*7^}Rf#&RNEGi9z$(K^Aw8q8tLZKjv5!2Av8ck-~PUFzFYE5Bo7a9$#trOjTjfsW1}7g0VcT zBmDYP*w5*M@ih&f-6{+^6-FY3eOn$j3x0(ZR+e6buVQ>2t1#$P7>N|-^fSZu!tX4F z{hEFOU(fLImdY^bR2YdAmQWt{6Z`@Kp#N986JIs)>7l})Q(+`hSbINnNf-scWD3(* zdMds<;`3Umxg^xgC83Zha%_2I20RB-BxC8r@jVNlGv$%2LL?KBE6XE~!Sgyr2C?)~ zd_Tg+cFT+mG9yVAk(e*GqDj0>a7G#22~TpDvK8V4vN83vGHi8QDRa8ZFeU|Bh?F3ww_Fq~e@ z78QYtsYTUT`d)k=#^;sWDhNu|B9i6HW&Y)R4W3shvN~&pNV%lEZYEF9q}ONgd3@Wv zFdC*VjF!%gYm zbA9Fcv*}-|jWh{D)$NYD)^Mpjn_zfKr^-{lswqF2!Yn@}>@|hoO(EW234=|c$P_M^ zf-^t~sirX86iQ9OYW828DfE;A8Uf*-s2IB|SBI~4w4-j7)JjAPR4Wk&gvyW6e7Knx z0bZqRX6g_S16^(EuRI9RFurtG_5DdEuA`JXr=lAB73#Fdus;iwOYGN8yT@E&|0*0E z*snt#Q$YqfLP#^zA|%tOxCp_y(EM{ozK0~Ec^rn*i@&f(Oi(UqH+3npg7Ndj3}IEqo_gm4O#OR_tb?UR$r=W{iF(xW*a)` zq76>jhQTffY&xXr@H7`yVNfoou84EW%xhKV23lq+1-uU(Sf8kxit4DQIyGNvke%)x zUoe$ETHhw9_@sAkLgRZFn_iWgAx&Mn#cs2V(h)$bFZQJh;99Rv0pJEd+#`oa3=uz2 zL_>4}6!%F{7zRb7_%BIu9SYniUjy|9>eK}3m!U!NO$R8Nd_B~>MU%0hJ{04bbh*o* zsn!CTwYuGE`V0xio|-KFL0ZO!+`_>yrLqJ&g}sYHhiXHvCgN=Bw+;Y3b;Bn@KP&|` zo3@yp5eDDg_!@Gh3sOh@YL)pqqrZn5OhCblfME)b*29v{4@D4+kH$K?vxH%Hx&sRJ zU!B7ADeeMBdX!(w0f3C8uS98^JE@m$Gr^)Wy<&@%cSbe%-O&e1$CR(2+HFPF-j*kB zk!aN@-0KUzUq!&u<~YH1T`HVIDdCV`aqqm^cd9-~gRw$?)6p$SI7j07X-b4Lz3qW1 z$D$~*Lq%HT3-b5*ElJQmdfEFr^9G6}$FYvHEIgJ;U_XbQ6m-A*_f123VTUBFX3!vR z6UWeYFxNB@SJDy_dQ`6g0?Kf+WVYFZ0qE$)wVql8q+lJN?b-e}0h2=jy{@`Nx^8iB z3&B5jDoh(toAGO&$_&+m0Vn#d7C_H|C&tL!!%x=4SHH?=xVlX_d|+?LwJFfl&?{f8 zP6f@7kK5rmSfFb3UJ790Lnfemd%()6X9QfruFtFbuRwwkEE0bDb|wm@`_}$%41@SG zb9F^XHOAOT_MR8R*ll49N4Kcb&14on0RpIcMhy9_)%J9zQ zff+>_(U|a1)c7uAINvB;HrtYp1Fr{TW7yA~VcpBvJZV*>qE5w)(81|UCVkUPs*Plg z8p6;GJ&$uWyfvY`YlAWq%2TAACaZNQo*siTieq0tP^~tNWz}GOOQ!dEsM4E%7gJPx zNjG@B!&roA)y6R%1a~=vl1U9w1=VJvB40qBGzb;xLgwiuqAllZLD@;QC6^3u?Kd}* zPKoMtOh94lrAL7(ko5aU(@i6(->CFdx#8GBb3KghB^@?2M9u_~jSK+wcT8A|{bmr)=RYMaV$R-SXq?&+Sr@TmzEOM0&hu9wCf(m6dp+mGQ zqfs&ib@gm!3@3P1{~R_UTk90V*gjQpity=%h%O>yp%r2Wh+ml*{got|_!zQp>LCgW z4})hj5p<*_#QG3vUE@Ee1e-)A+RzS`+^=ODqG2?5kJTUTT`Toz(5rv)R0c)8fCYpa zVna-$*(-W~L>5WobY-M&e=7@hXo5N{Cnc68r0g{k%0wvNFISFd8~P%{8#04TE!W_F zC|=iE*>Pa8;7KqVcu~ZCTCRJx;t69?0LI$l4-rr~4*nKqZ(jmUtzu|gt%SyLa}hL; zi=YX~B#mwxbrzbeJ6&jzbyP>%=37RT-&{(au5o2;SeaJ`9gfAi=t51_$_!Q+q zQ?-aR4%AEA1bt%0sQ0g zgqFkxi-fjuyyoAiNN7on-!3Zr={s6T%$gg4x>pbB6E>1;^FYWloGP*fR8;`trW2Ies;%;tX$n&LcYI63OGcR`F_ zL}Gps!~`M!>nOzMg?REZ#5Cc%mK=JGW)SY7t4N%56k_8~N!&;wE!LCx$rljYY$4IL z9b)IRByOG$aeNc1%I}vTP7rkso&oVyjU1YfgIFNM-IU>tZ^&WAE{Mg#_YW#~j}Y6> zhIm@^<<ht3 zJ&3#>AAtG+MDj9jUNTAkA*`n4o`b@yfsf~sdlvQTH`{~*Os~wMOy7Z3rl-neY(Gl$ zVR!8s|P*kX2|r zrlzuHr|yX{nIY~2ouU(=3TAQ?wXwpJIe&Q-k3S6GZ6G854QvAIGFh3RQjj6ZYFwQU za!PU--7bQHBn7xa-US6ynbzPy`te@I6ewy4g~JYo=9~ddfYa~qRLlDy6%=K+!?nv=WT_iqm##A|g6id|M&us{ zMN4uZDJaHYb~ciNo|EL%Lg)o_=CD%AP;Zbc8Q)>&w!@_=^>tY00f@D`+aM0ggIND> z5H)8#%o9;T!F}QF9y&$~s+=q9Q6<ID7pl=G1sv{4C1c1m*3@Fhv*ct=w%ZMQ^zReI`UigHC|D9|57= z%&7VvFw0{l+{t7$j+oUj#8zpqn_7$5>YDR1MsQ7^@IelE_FoQbM6N>?62A=Okz_S` z5mlAsFsgk7icGP}LBh^}xFn~MITz%Wf>JqH(oW|%G z2@ZEo6U|anLV!CbQM1&N;B@CCX_nd&T<-CsG)o-`VQxIGu|!GmxW@zPO7Oa~2Wggi z5^5T+ZAHbRQ5jH_W+!zUfZ78QqjBt(>6V6#vC0)whozA@FIBz-iZ_qQdnZ8&1*)@$ zehO+_7%V$`7B#-fMnO(7iY_mFjC$x#TYI8cB)Eyn1%5L)>&!c#V*9#yVQ zvanvTX_4D7A>`rj99gOM{BgFXxyr05S)$GS!A;;lt$tQQD|cN3{%Vc25IQ*ZkLx$< zBDtgZoVmc?6*~EQr-A>nX0{@9@vkocHCvu+IZrqY)D?PoRteCm(97qptbjH737s5F2_#v9h$JQ&8DAAjftGOJumfgi`*E;{`P5AoRUdSR| zX5l?^z~MI35xmmEOE!QxQWFXc%y|E zECtuHHMJ0Lvha0xz)`mDS#oFaY1GbG+varQy%wG}AKXy+U$^kZ3&HU=zZS%IE#A?i zHCGdxeq&DtiRMd;6aMFT6t9}VwmdlomL(@6+B$=UMu%G1RkOM4_o=j zkHFc=e$2`v&Vt7&K5OOQ7lCtaFJ;MJ2=SWJz!Q|c%*y+Y15Z>u%f?@z^7CvDB8l^D zd^Oo8+j0aK*!a>(;391b+7Vwz|I7uyYC9B4{K&>1>;f;b zWs7{X?0nfA@G`}7?c6vDUT*tS_NSf46oFUT?o=f%u=6|f!E4nBFS7GfGb-?UJ3o5| zTx44)`^U~ZQhPVpG?)CTm3QcP&GoMB6;WKVozEN(^ZT~Ng7+f*aqwo_6H)vDJ3qM) zyv4Rc*bm$J2gF-#YXu*(^U^oL+ifRBai{FO-JuG6!Ojbhfp;jrZs+swf_K^mHnC`t4<9lUeA@QC$amO>U!wY*wVjj0$A{P53x1;N zf7XZdSHR!fz7X~cK71F|_ea~;g0J}SHI(lc+Yf@T`|yt^f&XdyLvX1NZ?yvao6Wa} z=uaO$VjB1l)t~o$cv?RAPn#j^k9>I1X7ImkpSC1^;=`YNA6&^E(L?bG+8>5p9^TJ< zxaBA~*j`82%Y1l;o8S;-|J{dAIRXx~Hxl-_4!(LnINY8jIN!mGXM-c`wLPLg9lY=& z*rVc$9p0Ql6L1Q$?-P8$!5`8D9%X+?#2<6;m#IFD>~eUYa`3O-1IH^q>)_j|{}b%$ zaCGobHh^0wzT)6L&x2DHUw81mpMzW32Z{1Z9lXO@aHg`~#VUaMH%sw-2S0ZJ+}Hj{ zo^l;n5z=BRgcd~%f3Y63s-12E><>0qzqmqoJ1zo^dc{~H`jROAF~vpVqW=JNe()x@ zz_M~T!*tV+90WS=0c)JvhLErY%=!Cj>U0+kGNbKA6z{$&-HlE;pwLBX8JBYr6fVhO zoS*v_1sHGN14YQSj}!MK_5i&B$QbGhX*mPmVcH3(T9Ha~9$Zc(rmg@~dAYKx+LbwQ z=t#bSu2BE)%-Vzol$F;86!=$dKtUC2LuA$l6kJ}LW%GccZz5yOGiNoFS>3tw1l^sA zYU@HNbN4}2&s@4r{tOfi5~Yke28scRQkw1o)i0|oO40O@xSJBbm{xesak)4LM@$+? z`MyGN5qYvM_&l8qoSXrRa~fvn3{Ogu8#`gdn6a9tg(gcCf9lec>Z{9gdScP$Y3b5s zYZ`0^wNgt(@ei(gTKCcAvVIs*o8f}Oj1ec`*;Z!p7$5BbwHq(UYs9_-dOqJq6lGLe z0!otz}9+x4N8&EZ-+pcYtDg#uHhq zY;PcXsmib7+f}7plsVIQeQLDEdetE8$hW=)WK0g~3{B6*u;TL0 z&HD2Ys|c}Z55$D8P)YkaY*1VCa!r4h3sYn25a;ihwqv~A>x9zH8v4yu7DUlG&DMc> z$SOo>Vj^u4s&ZI0=a_5__CXm?x$`vdU+oc6DGHp>*w$vmnAxR4D7ii?15#h3>rl92+S}gO8TP+i)R(*geuJSK!M|I%wE+AUnxYo%8B@UP!D`W-Iv>1& zy&SFpJY?Q75_{@MmDPYWzGG{5cyF zL44NE-?;?70J~a6dX|7o6<@LQz(VjXuv%4i+5-NP)fHT7mlGQHggN{iRvL@;KXGUc zHno1xlAE1QF;h%!1hh1DMow8vqs#lgPL<+iuc3fV`qKzGFjg<2_UnHFvFdd5Yx&?0 z^gOx0-28)L>JNR1n|PC(k30?DuDd+MTiyJZ1K{1dSMW~Q_kj=U>Y~KWqpAIe6z_HO zKRyE=R(!zC19HJfRC$Np+_eULR7b_Bf8D(KZSXN&Ui95{^O^I&$CdwmH=lGEd_oTi zBYxyYn`fZ|>NLUW(&5e4*He>mWMDi)mQ7B&3CuwX^L8&CU3F?7qPb$eeu*Ng(GlGk&U-=* zhwNOv2jy3b8|hJVRken(>S04dKB$pA{H(_C{h)X`#fM?_0a7=(yqfbW9l6!3ykjP* z9-ha{B%p|X`&F%mEjV=IJTAO`~nSmR(=0A#G3V+Lm#$h z9=am-9~xztcolN9T2MP*#OffvR={N{qv;LI|3R_=8gBH1g3S}_js>8~UsNRuz|#?s zTi!Qy8auCmLZqk5Xg?7Yrfz*1JW{Wg5_cD;9sj!)3iuxYyh^Eupvz_zMO|HU{gE&1<0ro+%wv`C^NMS)J3+- zipNZ#uHVa+;D$4>P3_(}6vjS+sSmP=uz$P->YFAUohSv3kTXYqWckQ+PF{%0)ERt; z!h3#!AwSey^VHe_8UceS^`ECfFH3SD8Rc+xKZYSvXUts+rbKnJr31BTyiQvT2W%HpCqS=Ao6C4YIcJ+|(!ozE^iPwKMq=z)=J(WK5`zk zy0f56H(ew~t=VTG>M6%gw72}piMSYSX0i`_a7|p-U)*_)nE)~1B@(-m)*!93!2)dR z?)!xL^|^eg_jmEieY)l-=wl=k`}Ft{&;e<47>jO!K53<{V18W%Iw+}<(P}a1P&?rn zsOh_Q0}uBG)?V>941szP4O^PO=m_=D6qh|9k4p|a%}GB+4v0>?S?-u* zIv!XEYI>}?to)sKLCL2<^5GjL_y<)=Yz|geuOy)S->Cc{Xiv?UWawqunC3{U4s=k8 zd7wwV18VUP)eElGpwvCJ>HpF+XRK7 zR~I4!U5ix0Ms@A%n%I;vY{u)@pbV-{f7t8LgXz7`UAB;mcWA!}+H*H8Cky16yEbkL zJy&X}oJWXzAd`W2ETb0 z@qf(*erx$fCyeKx?EpTpj2D>5ubu^dXTd{zU@HH-2>8^JokcjDH<=3j-qKH0GMf)v z3jD#M$u%nDYpCEKE%MG(6CfPYq8#Q3}g;9o8B&eM9vq zPcxY}p5(LyvNQQ29S)Pffo$wSi=(GlYsp>Q;R0xCT|ri3 z$6?U4bU_Za&5npX6J91;9N1I=-@N%o`A#X7>JZA`66gcLqS&K`D385YFaSf-UQ0-DQp4gBha`p zAbD>77>Psfe<~&{7qkHkIb~yE_130sBDTICiZ1H}kv^tFH!?l+lGq%g?5;5t9Qs0z zXo>kg-w~7h3BYJZ^S}g%awRwmG*LZ=Vs82~Ix&;Z)h3+Fj8SjHng=UkkY=ad2ctSe z$urh%a6RIG`Do70*=Rz{R5v=#=z0{v)9Q&nR1@Cx_JXX&2g^V+CJ1t8Vz1TT0*_Js?kuecp^2dkZmXlC0w2ZjF6`%Px}bY%kjxU|cJJX9v_w4S65veYZ!6 z^)HF9Qm1|JI*#DDr46Ale#KpbxMk%>aM%sFHmLFvOkxe(AYA66)iNkTk`>1%J@RW1 zxxKFH_y*kUc=~gU4ZNYMF;>*(a`PB%wY}+LAkO@8w%+*zuUJS9E;FdjY1*H8&@1c6@1hku8;$7 ziAew|d0Zu!wq}~M=pFP(e67h)iHRz{ww$Q2Q^pR~;_GPjJpVi6tA&i=caI`GF>Y?$@d(JEZa7Ko1iHr5RI>gB~pw zIrEIzk3o-RW2YJI7JI&8xtt9byUdnQ?qJ@cS%*1NywVQB=QZwmMe6>&4ey1IM!> z!TCD>_Iw2{(D}PF!3j+5DVD)dE zoXm>l{?hsRjo_Bbf0NFee*kW)`g5z!jVa)E=Kj+8(qV?-IBJD;E8+SLbc0 zeO;CPfX*At1$SfnMR|vHJ~juO#ZCx5rt>+|z&*_U1v|B`zv{2EI(JV14^(_b=g)S5 zhcJ0Zs#NElcY=qr6f5yvo!_1gewkeo`R~&mJ35F%j_#K4|KUJ##^D~ECq8C;eYJv) ze@?BSvDgCDUt6EZfyEXm?x3Imqx0vWh9!cWhW#9<(YJzJIAMX}{}5!ZpcjKGiOmXZ z%!ODmWSmIq(H0d@z6UG#{@0@HEhqw538^(@BlR)J@+|eOGLiPCaQ>r$<_CP$wqO#m z#-FT?KJkBhtA=e!5nVba%@dc7dDGw-e~k`VV+r-Zb#rn(a0m1SNS&v;z{U5tn3j8! z2n$4U68_;L#Dv<*D9IPgF`Gu2NpjXHGVk}rQqVRlZRyH6>e~ATWj1;zP^UfOZ({$iCrhJ*HCyslfZ;HRO>2+ zY7-+rPFBnNKFA4Dmw=!kNe<1~6c^>LCN8iFbN@$J$bW=|sxV{USWuYx2I`&jpei7B zW}`Yd1E6#?@f@ebR7jJmX5xMeL6Jkv7ykxK(wcBdcHF^CwEqG>H}20QI?NS89xjOz zea)MSCl`SHr7cX;2hIluP&uL2$b@QmfEKm}mtT>M{Takx=0R*C?f?c_Bm4A$*=7A4 zy1taa>U1K%>+e&c=qD5gBgLU}Q1llHhEhc8_7f@fE1O_>iB=FXC<;j(k!hn^1U)c}9+fjei+s5$RSvmDt*11HA&f4OBd3ZEIk^<#yaA0M zez*qWd@4b64#4b}Ys(M1GAJ$9^Sd$G1Cz#~?Fw%(Gw?$IO0Xtq9*Y8szVaebfYL{Yc^ z1ND9XT{ z^JhDOuPN-$-`odWu5X!7I2aG3fGd=BINpE(uGIg?A{@oX7XeqPT4nRn&w;B^u3S#> zeV4&&&^)<-qIs+ly$B!q@HMDJe?>l0SGt%MK#%>@g7?B3pl{TpW-Zhi`CunP!h%;p z{cT?oo09n5pRpQ^U#wuSu*iCho?`P@ij8J6SmQ^im>70EQugFap97y$RtKL=&ao^h zNtDFnT zaA(B@jIW>`Nmsm#@lU878H!gjzKiy17sZ8)58ejuspIq!nIDPGU`mgS1o(sd{wbp8b25d&Q!dUc?af()h~fiq+D1T8?71H10Z0 zv055`v<%#X^-fYtXpZo_ioS3M; zE&N$2cr;TN3Kkx{3Ooj^-U|L|19+_BjTRh_;BjVuSh!;scs$FKZ(LeO?gPzPT3e;>f4eb}5Luhqk`UUIhH@RqWK@r)-2nAiG+cB_Qj&Qa67=62 z)QAECFny3F@h^3YB-&mNQO~$WnQ7~2A*(isu7!$LcvMmPH$0m9ke~C!DXbfs4cQ2z zQC5JV@pzDdNZ!=t!=765sCeBZg_ou3#oz^o_XAN_Ow0hypxNZXT3Hmh_Jx z20s$zT_W4->!EP9u|mvv1ESm7lx$C7bN-#)_)VUc4vmqs6zQhlk`*wvjMsJJWXe`9+s}Pgd(C)aL2eB>n zcXU7e^dY4q^+MQB??KzW6N#NCKGjRQ3@yI^1eXb9RM-zB_4WeugYb?P3bn;FM-dUnZ!Z_yjTx_P+o zIt@Ij&??`rKBdsX?H>U@Qy9S49t56I=;XK00?#UR@n3cUFX{48N*F&gA9!6iPxT$H z0q^Q_g|pX7PlR3f^geQN$(tXC^-EnoPmRGj7WlPF6^A3M2<>oEZJaGUi<_&JP>ZVO zO6cT5P^3J199r#odTx+v-wj9q)FKVrf>U%Q>Rtc`f5&$5r2Nk%$d=mhA)MS}amtB-Ej8i0=4whts?^4^)(%WPg<=Y!py#sDgqYN%b}8yTjMQeTQ;k%jWb?(+wE3VE zxKRr6a5%NaKG|o6HVwAaEMfC#b~@<*%n4MqV5rHc?pJ6=Kx*5iP>J<%>hrQ@nwu(< zng)YK4|NkA8EcJ0`hCF z9xOX6??T45l@7oWi({Aq<${*3?mz|%>ZC}8#s(sn6?0Z8z~3TXry5C5oHgeXTn(hP z8}(wUDzV+a`8w~os*Ws6-(6EdqpK0U3;%->u$0ev)OD+-`|-z_lEe{&;G$>zH?^g&YUUt&bc%5h9H7W z$bTGYsJdeiR-u4~4U1Q5+&Kf3_Ag1{u*`yn^EybZLIGv)TnejDKqJ(+6pd9Vppj}7 zN(`Q%r*W@Tq~cE(WET0ul``Wg4=ZJC^F?$IxYj*O?;#{0(e=6i5o)x?_b zHJezEry!WRR6}361GFC`Z!=^R=pd4kw<+@&bcnym8jA}-hfUpNJ_H@{)0A!=%mp1) z6k{xV1UjZD)|gJ2J+9J>H|`$?o%~1^qy;kjBA!+aKnnLp__`?fr{LhO7XF{RbOO1b zhn8~8jTDudn2T6K&0c+SDJaa;>Ea!r${@AaVk)Q#B7xjk;tUFp0?A37iT(a1&l) z)bh;@JcbSHH_+BHPLWRl9gyF$(IU1D_-7*ITZ)44s<9I3weoyMiL}7nrPZtE6EgN9 zsO&n8AAXM3NqSTCJz5CUI$3^_8j&%`*1A7lHj$YFsQv8LU3w=VolQjug1*f!xeq|y zOtZ!Eo1pHd+2Z^rP> z3+g*jQn=B52WS8aB->LXq7DpiD(+Mo|H1!XlYUrp=R&f#yZ)y`&4{#}N?iGh5~2N1*-ODg&@(vGoDJ zSf%Mpry)AbhC&STpd;#e;lYYM(6N32O1E<^gHEW)a*Po(33Lic%93Xf2c1T~WXX4D zfX;wqS-)8cI)~bmWgT+}RGimLmNj7Xa9isOEko3-)A;fNWS<;T`*g^zfp)^C<<^Mc zFE1T%fe5XPh8Nip>Nhj3*F!iM`S!v;w>GhaPewDkQXK^LIw(8R9Qb%&<1G zLvLi6XkBPNRmL3!Z2_q@4o5)S5KJm=$P>_Zr4G08CaLPfOl6~>SB2I)&6QTdUI>FS4d;}(&6-;)J8Su8I<>wHTfEU5qKIRLWjsN0G{Eg z>D1Dq@@jCAhFX)qkYsbwBxAan_}jLKh^@3V;xF12N}C>s-YeRK1}g1YbgQe34pHU` z@S4VFGl*fgf!BdN&wIUqQhKWS;ipE_Cdg0Cl++%`&#aWf@`0agJ5)-xh{fYE`gxst zbBg-iI0#)jG9;rurm&@SHdA8NInYN}j|{IZWC2pn)V%@vy;g|(?I}nDtyk4)8NhOk z4$NDDL7bG2IFtn}uk-ta@V^SIsH+C<6>;l#xUF`=p0RNV>+V)IL*(Ga)SQBU$q zq1w>d2@2;geR4zRd-{oT{N*n90l15qye^hr19#Um`Ab{qh!I&fZ%=)O+9a*3y8l2& zWy>#ZsC;Jr()RZo%>1RT`R)>2tg8*MDPaE6Hsd@vmHCRUHpC8MzM;zvu@>La)rQz1 zyq5fdjt#NQ{3R~sZVCQe7rWC-@H1U)fE~*GwJtZnTKrrW+sBmPf9vAVffD=z`JD+K z24-{AkCT|$9Mx!737%>fi?@{EnRc=EAUKVAu3hZgP=XiQ)egtu`l-ge3H}$-SC+oR z+yuY)4tT0QuN|AWMqL5V)7jjGetZZ#U*FJ<_g-Aj2d~fv1@qpEVbj5@xqgdb&=~<< z1Lh6X^DlzeGGB3sBd5UYVft2kFKjLvU;f_8+V&G75OkTNjYFd*BGPGqb!z;IFD8u! zx-_*~(Gg0!(At#J#`aKswBZy;eY7vu5V}KYJxLp1?XC4{Fv!b-v@|E>6`!sK`fJJt zA0$RB2fm`s+DsTHmYfB8SQ;-{tOu51b8oWvdM~i7);(WYaQAF4f#bx#N$S;{>)C?) z?ly3MwqP?`a4X#b2Wsdd%Az@cBe)!Mv4$=W4q}VnCmIHEaCwbYsEKRy!4ji!$|46T^uGn@OLbkmtdn%%5Xi83wM5N+y1$iMQ8*t7!EX$bO`S z(vq?^;aZoC>WMDe-i5p>E1^IaPsV|(@w2K>7xRvQBfvaP9J~mQ)LsqYemvn4xH?t@ zaKHR83;Y_G`(@+X;MZZY=YF|wIXH&%n{5xvCwV@q4K!;oX#Ekm zAuDMv9quwnhId2i%Cm@3o6`ivJdvPq3)>82mQ#QM;&k6&$ba zlKs98&z5}bM3e4N3Uz-nZ&G~!gBeqih+VK6q z_7U$Eg5TvApyxiK-ezz+ZZuPUMd>l%_FDB##7lhf&P5}Yi);_8+gZCc0x?F?8zFf` zjHA74-tYDA0OC4541du1olrb40KU-qO-96D0{+bC5w*_(e_;%=MbObFeY`0SoPDAU z?cP+lRZ0Vw00%j8B|5~lEZ|^9AK};w9OBq4(Ji*D0}geZm*^2ucY$df*eiNY0H!-0 zN(>So9t37M{w*`82XZ!$sar@y~aCFga_$sTPt!1Ao3>|1r#7mBb32OZNRB33}S(qZGUk4XEg7=1*~eZbX> z9`OaGw1zQAtbGDp%NQ!Yrm9-U7%4h_3|!9`Eov?XZeWZRwGROc9LfY4FUFn+ZenQ* zvG6f)Gh=&kb_=kOv8xEq0B&LIBWB(OZevUl^KyaP8Pmkl6TlA{Glgd&a0ied{@;xO z?*#Mb+RekjAA$Mv?73^;-C+J4n{gk!2h5*edliBAG8by1#Uk)N=3Q9%mj&Jr=Fh1< zyTAv){QiD@9{3=bUoOrTf)6oY!TXj2dW+V)#~iiZLv_vE1MzW3c1Ip(sH`WjdrMW< zhFids4&F1b&Ure;he8F5;03@lW_77~Tai^=HI@R;TGe%o^m5LsuJhZ0#fPQG4z4p7V!51bdw~c>y|f;@BYJP5S>tWTEr8ff z6?})wVG}Es1MhMJ_7O2@zDj!xh_E4f=1M z1NL;8xh{GD?8WG|1%}L)sZv6f$+!@B?~3$j+8ORcC#Aa`+%Eb6FbEE|R942Z3iSOK zKE4ituz$ZM!;YnRTjojkjLsAU6L4H%eBeQ9Cw$HQm}_MS`eG7T^Qw$SK?k0<++unszUK9tP+^y0lpbOm9RdK_}o%E4( zN5SoChfB*Y*7PE9=|(9dufSTnrTaa&t5u+lY44WKhTAXmm<`w2R93(D(?}_L?=#pz z;pq#h=OCJSO53`}yW-jZ5Ti_6It-TggMsStelQ$^0je(~x#Skbwr}*3YHcp3T0I%m zMoo#@7-#c9@1BtH`d}FrsO>0uhrXz;Ii%vt*-&vi@6TQ7EaB6n;sGZ~#eYNQbiW_y zv;x28^!eHE0h)l*Z`xSYpUqQY9Gybosnd-=0kkjk$5$rMtL7(wl*6F1)_!C!)Dhg_ z)qF&gOBy?r_2+L{{f8#oI(R|6ZXL3K>Y8~7DJYOT5flt6ha_ah)EdhqZ#QBs6Q3wb z`SaMwK-Mwh5#97AUb{L*n#S&S8KCOs$ElwdfL>G6So+03RJNm2ogXP$5k}xn{M8kI zQ7eHllwd?xG?Sj4e6&HB?us8K!{1k{(@TvFtu_HmYY7q^BCr_f$5J2hWj4^w=oXF- zf&PphF@Fc}6-KYvbpU8E28l-_fgZ+Sv3m}%3}dMHjPO;)a8aBNEDPjiZ)<>FAn$&g z1q@(}7L}d=0~uq)`Fp@}jIrX)8NeXMII-;}usmbDIJW{=fiXcmzYeU(*h1WU01Req zBkmjoR$^=~CQkx}FeZw+6M=%UE01MlQt+n>YIYL-h5Qwx&mApsv`*pVFrS#IBLHbX zG|iScM(>@fbYE*0WaIRo!<6n%p9GHAt7}RJW99)T=(PqY9W31k%;uGVF_`sc*b=Ae zU-pxEfk6Y(X?kw5vgGx+37o-(y*^?U-Dsw+T3Cwsq6j!!zb(s=CJt`~&e8j)@`QK! z9`HhaP%2M&BkzG1={D04_2e2jPamGjhNtRT;N`d(8=k)10A8t&PvyDgr$@l+^_;#u zxBQs6K<_t@4NZGTf;Z{Dx-v9{V#G__tpD9yR+Y3C;w@OH$abgHnc%Is9Zy9cQ1-X$ zo4fJU^EXoChkB0`UKVxq7-3X0yAR?ve>UrjGk7`-G5B{sQ>?h6#r>IFL_Ay5sNc;~*ag^)s8UeC+U1 znbe?swwv7p+PPf?i+$sP4qdIu3Ku8l0G)b=zJv*3FZKXkoLVXBZ6}V>V57IFqRQrCHC@?ml(X9MkYP27cX!8_%=9LZv~d`=MK7kCD=#V z7+7@#IE1+v_VyWIpb?51o$dD};0QelEO!E3ASFiX!z9CSxp24ys8$R9BH!pKC|W&b6OE{gpxTY3tgBHl6;wx2AEW*%P+dhSMyYF{ z7!@zg*!D4~o}v-PGfK0*qD;KP*5pq0bVqkyhtljcQtRydA?cy~D6Fd~J+~i=?xFVLy7&_^lAf1K89l?C?Ewy3Y#$jRDQlBk5O?4DEOcxuQ7BD zNIa4hWaQldRry^~urc8iP&JTL^xdPN>Y+!}8{*)(pc;xIjRwV_T5n3KVH`gPita2a z+9yeT93e;gFOE_ixMYBTW{h+6C z-?(%G^nRmcrM}nFK)uI+NPXp3f%>NQSL)lk5Y%rfh}4%tB}n488{^nYP%=oWul6`l z{{#@JFR&Q&!P@>xeP3pSQuxg#AZ>^(ap1=ON_(C{hz9SM6dQn7g`uaVI}YWA)>su# z46CB#zNrUEbX@`Oh*}Rw&kr;zlaPvjsIjJn)bt}wPgUc&RP_@r0;qNa>xkp|d@UvL zBecL3_0yj!>gQtvN>tP@4?!w&(`0jkmz&JbQh&IlwTsd{huKza;w|WttLwJ8e^$QD z+(Dsab>%;W?4FIcrF~Cozpp~NjdPc%Jgs>Kw2vzGakk8XS5?VVejQa+@~NU=RVAM# zaCONl`CL^=xT=yb>Tq?*_k}O#$TVxn3VNn0D4MF|@9U)?hK_!+iiouWI!EC#1HnX{;{wN^@OP zd2|TbFmGtcg{;)OV}UodmMMg8^}ch9U-&(tRG>SWDv_7AX(18cVxVUgrjtco??aoa zdb&QW$VaM-nFo3VlFHk%5%f4?AW=M~kD#aK{#4rkP6;-|1#@qC%_EP3FtT4a_k z?7~_O7qWqM(^LzK6tabNx288+b_09jum$yMzw;!pmo{1^6(eh?H`h=s%^3P><~R^B zgFbR6&Z7cx-=6>HzP&)pgUIUJi?pK>-RdTbwNHU+-9EGjRg>PErkHJ%To8G6y4D1^ zwH_qIMVgsqeYOLrgCIt8MDqP0#jLqJGloBMY1Qm_OMbM3{H5w$Z6$r%3IrF49^#)b z@(kx`D=9tI%z2{{jp&&rk0>F3=~h0e5dX3q&cs@JH-LCX9VG_uWNfTn39P4^#_GU- z?U#)gL1|4;U%J{fx<IghcO(4VZuBVtRzQltXLh6G24JNo z62G<^pB@2*=JX?cPSd|PAn~RA2O=a@V%#9AR?59Dt0EnEyHms?3|=R1H*7HRo1(4d*?w#_!ibRe8ooOKIhO&*AD>e-mozQD!iH7*d{@ z(&JUWnKS|RC_8~ohpTcxUPV4IbAbXBxv}&X6lfX?$L4{`DGI{L3ZNi1z~c=ZR9=}D zB5}Hgtw)9YBg$I$0VP?H*BD`$B8ZQvOSE|&BA(Y-^8|8f&=y-~EjVS}jX>o&qs>Ka zU1mU5dwzh*rR^h79Yt=nyOOL}JSv>?QTUAbMl$Mq<&Jl>pl46Pqk?B zJqzE6>9BVdM6J{J4n@1Jh}Z6@d{`}1yFNYzxL)T*ASPc1Zr~lEKB5x^F3|rzN{z*_ zOMn~Mmg5ok)&e*2tU5-#wF$VHtu=8XKL=RI7%wVP;4Rh?u_xDoTQSL2_N+=2csnQ6 zMkH(n?m&i>0c*)g;7%Ulx{BI`z+L*$>B?yIE8TZDOZ$la%Yb|MM#&;zIdHFDECZ(q z*G=F){f5NB;_@8ee!g#-$jApC)6I>GDf56QIjM1C?jhi5S$v*i^?UMxpcav1n7M);v2i7-#|J~GyH}OQkQte<0`>~$ zp*>)5|Dm>CRY7dmg{&Ha@s5Re;PPz(VL6{(!v_I^4y;3nbShlX{qt~U9I`{~`4R1H zVXv+!X}H1Rboh5S?fVNxfO-t_svA_91?q{M$>x85C8!r7$!?jj9Q1zaVZ1+@Qt7Q) zO{md#Ca7;YN#Vwk-Js;zyco9LdQgAUrv5plGT>x}nhJX^fId)-E!o&T43xsVfQ_RQ zL8+=S4K~J31`Xm`GtTCM1}n-mJZC{eK%1WQ9tWm?h}ts1Ao!gI%Zw`tq}MtcG~c^=xxB?bUuAiG@S+fom-z<9JvbA?Z;=R zE^_(|(9Y-;?@a-^?EL9Nl%57GWmhE*79(c@eQ+X~dNuoe4bac7${a4TvVex2cR-ZC zH(kAx1#gFUMZ4+fp>?d{AbJ{NjR_3$Y(!}(Iz^ZoDRx(A0iNNZdyK%yG4)~hg>?&f}E^rOIwa0dN zHn^sJs(BdO#>?PZ_J*d3%ySINY;Ys{ z2X)z+ly(~2m@}4bFJEN_uT*M8)z!j2(OjuCejT_qn61fw-2-l8Pqni(IhQit(LBzM zp6_(Dw~P97Lv@e(6Ny-$F7&Y2Qx zh?84^%bd$4MvFdqz~y|S7;$MOa0O$m_(wi)rBjW4apEwQXq9siFP&U46S&%0O=2H$ z|6|}9^CycmG4>I7t+SS$*GC+k2hPVYg79|sC&$1WoLd+1dWrHk!5g73wjPfe0p8?1 zJe0SuSJ?$FbS9bS8ZJ5q-j49xwfdb0?_l1JuCoWc6Zzro>G`CH-A+C$Tod8x;5{7v z2GW}Z-pk=1VEx5@@P6msq1JJI97|8|IM!^YYp0cXPqdIQ%jv z{p4|mX=QPuXZcgJ@+TKWexu3Ua96(0KObcVt4+b=C5|rdsIYI~pD&(fa5f<)#tS%0 zOOJA+&A5|F#x3cB!gyvmNu@V~5>e4RS<%;XB=XI{Kex7*^DNCC(&wU8iZU6}`>>2o z8vM!2=F26nfVC5I%5#Ny4qcx$FYL7uad&e(<+qj5#^xlolH=ZW0Wu&Zz`h7?O^XC*PSQs-M|8!#$iqqEz?M&smudm9r&DgvJ4Q`w6O`XW~ntcT{4J7sB`41Xg zT5_G=#?me+SSyn2R^>zvr-Nb?X~w*ppn5$d>BgcwQ2mKq9qEffZ^FN2yX>T38>iJGf;eT-XAK<}tDlZ~>J zW{Z}R1{fhkEq_v5_iUb#^t-*uIrYXtfp2^S(PFa}8qWnSG1cOvtmJYn*z~Q}flEp4 zo<69@_Q}isN-6kGg73hqq}oipG(j8+MA5Paj4iu<6}jP8`xk1vc@l`{GX=mJP8zRYgWMMWN?@)6J{ zih_)5`$3l!g&G>&=dz+mW6U1VUlc_fjn9LwEa9!GnU_IV6~)20xeS9((%r8pEBREI zd-W!&tW3WTx^Iq(1*HCmO26FeAMyLA8Xq3B;Y*DVPeAIF@yVd4W;Q!-1bu2|bHonN zXS_e%7Lj`ts!8gmQ3k}$Ldd#X`+xqq5ZFT-I9ZK@DeHheHU6d~-dO|eMG^Va6%{9B z>H?a~Ch1xVCD@E^ZP#88RSAAVN^w9WGiGz;VliYUfVWdd>_LABPO7baLvejiBXAwf zkW}7V zy%-=9EUG{vbY}TV19yZQJuWmUPTK?!k&}>GBTmgGKA#1AOFP2(Ts{H#wswj0IW`R# zkHCBe$24GLE1ym70Gn9(9D4xRlnWIk3aN8kx6Z|#VCn5KpB2l+dWAY$4z-?t6h`m5KZ%d?JTu# z%LcY*sassh0d~+{Nc4zC*MS{@ym+?&*h#B0SrsQ|5ipT4SfoAzzNaNf3>Dw30Cv`r zC5CfFP^PTH@`Yd3karGr?d3pHe$bNt>(6o^$uq~$^^O&)(&RsdqQTK0eiZ1K4EmcD z^ernWTqKGgN7w2A6(HFPFuO#KT1}>F8m_+72O_f2z@H~A(C939xhpMcq4h?R_z7?k z53LUI164{6W27ir1zc>Mhc+<-xCH4av*Pb_fVtYQ5;Nt>iln8Q{}eSvvbm@|Kxn<| z(Etgl#nk;PS&S@K0r=A9>^hF9W_l}7T{5pnHP`9AI)=VdP z;M-JJc6Hh+4NPEkgyLXq7%23}DTF@Q&J1Zw-8_US@>D*!6>dcuqvRq!#6v3~s-3=b zD$*W38shf)m8mN2m~Frg`d1PiV()5TqVAfe(w=q_*hLSP=oW$Zf!*}R5r<8l^TO z=oQ&i_R|XBK)sp7Xt9S%oTd+y7$d$s4ov4v#)^BpfEoI1DUB1~Jp_)_H%g4>MpiV{ z{M9_TWCzE;z<;U*Hc%4>gI4$eFNCFFw=5B9$R7qjD}`?@5i(*$a8EORp){Em$4atu z3rC>JR-lo84wRv*Kzu3N92ffFK{jJ6&X)fZhYQIo-^a>0`*f7w$~}lgJFVnUBOL2% zCAt6)xAtv`LVYpK{M?BOl3kQfF+j`b4DeBAKUm44?)Z)nQ5-Ice{uyGGHkjTa-a&y zx8qt;^On|DAk;34R!#Zic4?M;W64BhN0?66k8t%}j~Iau)Uy8l)8S4SA>F6Ry);j{ zFT;%lbsSt(Y20GR2@564`cREg{Uq}if})oU@>;s?PWqu z>>VgX;SB27_8wi}ey5mvwVli}F-^#n(agRZVw>kzwCA|~Zh$%)y}v)7jgECHpjY^8 zba^O!f8)YzUi6a=nMb|;)R12<`k@;o(H1zu^_|3EF@6DXr0bQXYJ|u=4;Lam@7`+iV*)>*TdlA1MIK`DGF;Toa7dX{*T4Gly zzBcshTSOXv1^bm!qT0AneQFI!)VnTKu{Loj57^cq0LX*?+tnCPklB#nEhw%&7f1d_&^odI@c49C%^ zz%H&KK+<@^BVbq8Odx6e$U$H?*9M8vSo8zz&e9kWGYiH17!9ClO# zd%5gOl*V7%3w+;I1xOmNLzUOt)e%StJ9sszs6!>s1oB(zT40vrZ*x@z{Jb4F#=(;fQFI^C4pjyGJqI|^fuUZiX+l0Q+mXQ^Vo$69PGW2?c2fmR zanxU+6mexdaGJwB$9E#-YC2;dQIHLs>4=kolf~%cz*&xWB&LW^Y1((Jn@>2HK6xU) z5y6<2MMixjf8|Hj;BNar)HiebseD+b?W!DJ5i^<$)Ao6dqz*zyl60S)f4@wGK!1#+ zgV}`p`B#dya14qge1p0Lv#9?uY=i<)Em(j@qdQD~tYG zQe?e?U$W%-eE8yGi4cqoBnaT?v>lfLzRl+IZ*mMM4f{Pmyg+`fWhNYWT!GvT&C>-B zs(o=3&9e?Q;~3x>47Z9@CVf7iWBRMwC`h7u?x=aPO{&Mpd~3@j-8E_fc0sD7>v*DO zJ1!$!%-35WnB#bb+=Cv&J=f6z?z(*kWZ+AdBNJ{+@iFtL5!K&G9Y-9=AU!(G9TVwN zkN6)eTu9BR4|(em|F-?~=0> zwSzBl3682+s>(uM&JI3T`S)O7(0oE^-$`+}Q*8*cp*~_Z@C!Ym2u<-k1z=jrf9s`WC(7qJd$U^TP z;9Dl5Y#mXyi2AUBBu3@A=sTZykG{PvbKS{P#acK6xSXHR4l#Z{aHZ>;JXNe+6M?H- zrMXydo&>ITg-Y~@Zu!799M>y;ybWCIQaT6{)iwgxF$Rk#H-Y&sN4Bb#6%=>9tA&(? zi+@qd8yF+S>?^ww{m4v{bxSe4O7{8Rv}MiJT8wGOQ{(m{{$rmng=E8l*LRZ5)sh#WN#N;&1ank9#eL^bd)u%B9wTn26=gM>R;!4S!s z$HXc*+(TGy{eE3nOEeQM*r!+yQHCYjV8y}{O*RcnRLmk)V@X|Zu>#>ejWxic%a+K# zMEPY-N1qi|V)I8Mos%d9&+_#@*QKi(iet>p00a#?P*QL9yaDg)8C%dlKoCog>)E|p7i zYA12IFNq>@t?!>4)hcciDWU~P=`V|VS+R0*|JP^QO!&IB9VKsO83C4Aaj*Y5vtIp= zZ0)rIeaDGdA*KATC4XhxXr`OHFxOmRt9i@)%2=@vu7u+(gb@g+iXWta=Y!}82PeK-);Cd-?{m$&}1+*0O%JSt*do-E=^t#XnT?WiS} zE}O;|1j2}q>uMR4Lfpw?>nnVVW#Zp(WUEY%taR}_W)a)KzPCi7EFxbI+;|Db)l9kC zGBaF@627sPZ_+ZeoN$pS75@UqPL+daTPxTCGqQhr2u{7T%zy_~K{R4sv@1_vLcD`%9R+)r@%z;y-w#w|=^J}AvI zC7fUk^5X|K){leSihPXihd}-pb@OpO2hnRM4IV_wz6E!!4BD5RGDWL_DW>1mJ+v_3 z0j|1V=WDdrc+xD0{bKjh!3Y_+y8I^KTFP%0u0DQCaP{?Di)(3oJb?lEV9HHx8d4Gw zXEDCtf?K^*I8Fg?Yq=7=qVGi@_6wi$NQGeGT6dHgZDX}QrIFt+7 zSw)fffg#X2WKk_dA@3CcStuX15M?Wvm7-^jMC($vhjn-0bjlVmKNC(DIb9U^z8T?F zo2N1Te)7Odbex~j_8NkPoLs5e)3gg90a6Q^r+`8g`53L1fWj2Hjq(>kmA6Xr81BcQ zDit8LB9?K$@N8#K)=nBH+hxQMNp&~jR=;XlRV%ij-OS9*zDa@4d zz*3Ag#Ln43AFYbSXjuG!rM0FKW5kO6K)2RMVyq~W5A^4hkoK{}6ybXhSV8-{#KB?{m8hcTx1KOf{J07jtksY>LS#|ORWxNn z&$LyLXFk#yo&LD|`Kk96JR+7t)q96j(@@>Y8ZacH#QC4VNb~$p@#}G5bq$twpbuu^ zz}I*=K!OM%>Fd0Qum$G$z#5Eg#CIf(;*{HqtEYf9852dwG+-^puA%fpwL_vAd*Toe zNNa0}ycGOVHn0w3KM^w@Sogn#oq1eUMHI*1eedzuo0o}cYM08?%*x7K+Dk1>EYlWD z+uX8Tcmg6jD5helxi6RkqPU-jgstaiExG@>CO zKpXMT;5ReO7^xW?YW)Ff0jknmIw{d zO7MymdY6RO{X^%QX~+Sc{#AZYCYkt#C4-NGah>3H1IY8AC|HILHsVeHXYd#!c)1na zmUEeFCA7D$6>vzNXUS_VIea9-5CFHrQt-+$705@AkcPr#OQE@?(3};H%qREeEOHSJ z7lnk|86m#ZySm430*`obAOaK}y)ohuUit^o=z|!H!@^S+LqzvoSOoHrzo2;OaMgX&K?zI^RZ0RVao%DcjxUFSlC}`hi48HJ zF=q^Frt&6%Qhc&`IPS6o^x=I5wN~>BK@+$yZKDQ6gC_PcWNnonr80?a>7X8n0!6f}!_k*+wG5HyF&7b1TlV71jMQC$+cMMCAlk{%qb z^G_|MGj){sh7hHl5b<@TvRX=Y8}Zky1i0_Nm2S#5XGnU8Qr&5ihqH~lo@H!B-T$_| z4TVXfAc+&wosvavB*5)WQ_^Acx596{C=E-87xl!42!t(=z0{#j?alqrAxyc3JoD@l z`Q9t!S@M#4w^N`_(!kW%8KBNof7HPG90zrQVX{{m=s6G{Gmr~5vVIuLww%~ zdZFtQb9!`Fww(3#`V#Yr-aVL3fes1XKo)6*(C<^vJnW?a^oE@7i1S@QePOL^%Ma?u z)DnAofZk+ktpXQ--hvIhezu0*HiYbNw3Hr=rb1NFHit79vlsMPcY~bR$N+TsO%N4% zZ!+j}rU2Ed5_CKoM5g2&0DZwS^ECr)P#Z`NiunM3+%ut66LO033Zfm?Lr&9WG!K&x z`7)8SAdgR>k#mb`RS7yG6#5(F&fEtcWi1c26NA1a|NX; z04sBmw9U?5uyb4(O#N$&+NON}#vkD|#8BuVASDFrlAdKfP!fFhKAf-BAKm zf&=xgR5mwIc6cM{&4R=9RLZxWphrJd2E0WuQa@D%tS=a?r)2?y1mpEes`>^%`2w-e z4)CpD`7CStr{IQQ`7A4cJGhZ>nx-2q;5Kc3IzQCfT1;C+ht)OJd{@dFWY6uAnJt(; z%=PGkPOj@dnD!7M~gsk@W5!B=M7066l3%B z6>@TQ_Y?Hti}9vlKyUI$U~Gzf9@I6ER%H;%}_B(inYQu6Rmtl2s8D2M+5p{D3vvMg-0D1)7di?{yk!CLX zSDCoUIX1C1x>~2NzrDKNw8>~)>kZw`3vyD%FP~3 zEqW$szmi_Wph%l%qN%C3UW7DLOPxnPU%|=;`M@re;=k(1TPp`-ygd&**m16q56IBJ znnCTy5!cs9pU=GT3=ytz>WOn9e;;KfKIPO$o(2zh@CSOePJRC@@Cb(-Sb`4*NggI& z(q44pO+Gl>als}Z^xd8Xju82e&R`E!&nU2b(AT&E@+8N_LjIu7*5c_gxcr{28r6`V zMq^Kj*@SiX7T`9k4L7B_+-|kuLsNk}tTsH2;_kHC@U0Ygm(_+xmH>APHq zY%Siw;GgE%r&X+h6}4nznU=nqt>}LYSguhOQ|JEaR^WbZoq^5tXoMgWfs#_FZ1z#74Ly=W8g3&BL)i;O%0 zl&*hs0r;fwSgp-_k%MiXQ>?BjV>I}h+T>|b8L#ON6obFi+MA<8dJg!EaH^)iumoHy zJP9Y75T6zP2&2WBz0~W)I&n#O@r5VOX)eB)P9=|bUXV6pJP9NK zf9!d|egLWHm#Ff(8-8B91q?A$(v63)9#%@vO$EMarle1#gkKVL>z}Lu_7tqo*}e?q zy1Y6A*bB&Y`8#26!C-xQCh&FpcllhG-%S9963UsMTcH=A5eH)Q;8!o~$Sg?}L@nqv z>UTVm_Mru`eA5$UHaIKi&1lP%oKfs^cQfK;+4lYvw0FB8%U7^FPSJ`6}D+rJ(-6G_RE`a{4u z_9^SQm28g$&ag$m@QU4tv5;o z=Ga>maz8Y2KX9dBS3NTvm}l=|V2ED11DJ1ruTahqs{t0;V}R6YHKu%vB;`2OuA>vHVk`f%&ga~6W+)7IUHd(Uo ztx#MUYA65Uh`RSWQ@uN>!?8pdis81i6o!!u9!ueM1O#X)90d-16inTRZ^TOSh8r47 zEDiEe(MUrX8Z!-zQcI(hHTILnQA4B9GT@S>MLvq0OK!E11lmL0D{xsrCj}-5mVCf>whWA26x+OdL>&*>#h7-ZKhYU1=Ys(&pjt2Mugjb7P|UD^n(#M z+gHd(MXjQN_3Vq}yKQ|k@D@QY{q_~W`hqTO@D2kTMqqQ`4Q5JBt(4Zq0&h1{3LenL z7NOf)JNW^6z=O7kV4;BE0T0d~|JQOYJjBNR+b*wb# z9;bjP+`u(?E*W$$lN&809lk&~R9P?=E+y!`WeS{*TQ9->LwaHm7= zu12-)8P#xLk!-a;su8@%SLOyIi)46y(B@9{;QB^2omwP?iMoAw5UVzSC=;U5-USf( zzxBBdZhjgykMZHuJc>)vJY+FabrJ7XD1D%T7s+>m3sGh#7umu^a&*IQ{96nu2DGdg z7mCaRcN9%2wPS6JK*0+lw&*cdl2jmSZi!wKk+m}C83edh9Gt#- zX0e<3u(jHx)QWMfj>wF5!ZIFN)s6Z)S+W9mTy*=BHh4=t@IHQlycuEeK2b$pM>V`p zZY6KeJa|K3H%`YGg9aRPTl6NLkc?^k0DR_NmN8A3aPCQi<-n#rfqu@I`?K-u-)f-^ z?w1>l-SC%CdtZ5y+Pi&sA#@*3Vcm9>q`P)J>6R`e-Qw}2n>fwTjhGJI$MT@#PQ{~g z%a~4)=u_2O5eV*VPW%0k0P4czRLk=~&oTL^;(eg!nF7=+$3R_~+-m7;P&aehFN){| zbK37@3aGm|joNQ6D1<3EC>#SzOb@1JHg_|OI&ETl-m?XU4X%RX%cfz^Yy|Z(4GUZZ z>Me$`nXiapZ04(C7@PT;Y1r70K(CvIIdegwreSxC0`(EY)TI@mzRfoA{O91bZ*?)Kwaxw9NHmR@cYBf1S1G&xrqM&kf(Edn6UW#b#;cE*!Ba|Xd~i+7du=sV z{Ao342$QDf?*_fkWLGIiKp!wURDL;VD3eq5-3A)Q1{%wByV_1wox-H6#A48gOu;IQDsVj09V&4LXaduns^vV; zM5en`_HIxrQ!_PS3uqG4-KyVa&__(om2WjDjj4s&eE>AsY)HSCfu=IGR=ub?r?F-m zHJO^~45kNd&Fi6>u<|npZO6Y;fer4_NMq*z{R!0i(kmfQ?xl#cfZ7)|s{Iw9g`9#D ziZJASOy&dIWv)La>#wTUY54EHUq`Wu>5{=Dl?#0+jRDyA#kd z^WHi(1+?6}wlZ2bUtVmQ)|_c(p=5dMm;hQWW6m} zI}2pJEpcUm)-pY=oXbG@Oi%MA|CFh-`i-nEVCt%}YCwhPa6lnJ!v>&ZUVnTOpOVmH z24ox1OM>Fnxw)Vs+~s`yxxNy(F{gw#A;UQH7%Dc992(^C(|ANKysp@8z4oBTA37+; z7Asw%&3J;2?QZsFIUj;T%o;yf3F=|i_^$Dwm!daujZZoT>RDOBH9jj6)C(g7O$%y4 zgZsa4i|zeuE@84=r5}a#)oy$Sh+W;c7Wi5hLwS!~9UTXJy_tdKb~R%!FqEa0cI8|Q z?88`PS3ULv-(ak^t8?MNx1;v)`OT_#9Pk~M?sTZ5iNJTeHs#4$6`2L>U(4r*I#j|W z;6PSh;8cflfP+|?f!9;3fkRkY;#4zYf$t~DMrmr>I^YM4dr)mNfI}I}oho!Wa2R8y zQ(Za<9L`vU&4i1AVKq+?RwJn*;7HCW!%IDy4h-iB=4`K^h(W_`u@N^y2@AZ`ZYtm? zE>V@2I*eU6n(Hu9;rF=I5WBBlo443k!0>(X7M!3wSw6Q?c0b#BSPyE2d zpZ5{2ajDz30+ZS15?9c`;qTgF$3A1k-RV+4Qo~5G4>XGJQj_z6|Bk;p3 z>j-OH>MRv-LO&z!DVJKk4VXIGz*?7@l>+=|hJoi@>e57D+G+zYy3{=%11I<7{pMV1 z)l}dV#vfg(d;H|!|0)E2M3~#k_ z5^y17wzn!c4P3;y%v*IS2WBwldaH^w;Nl@3!ZqG1kfb>;Y#=P~R&j;ERTtzyUDbz_ z^J?btdAe%q4B#5MalF-?8NjvDRJ_&oBw#)_?}QfQ6GhXvmU2}jt7=QIuKd%7p>~1Ga_EYap0q&A*Dg9LWQQ&TA8-D7gS-?_W zmXPMBE|&xMO55;LgCc?ZIOUmss%PeoDO{kzKuGyK$*Rlo!1 z8U0mB8nA-nX8WrMvbnN3Un75&za01(U$Sz4)ps%QAg6rMUme;7JjD0@WqlMtUSRL3XY3ujw_>nI}TB7Gx=vRF&z{~0!kz<4iwMiqaLmVC9r0I zI(-V1$mCWT>p@9O^;OnlP%=|Pb)yC}Mpmq#Oh$N8HUh^|G2BnAB5SJG>@_w7k2@;1 z1jX3mj;uT?)9v?C zjl#Skac4aHWYhP!TJn+=^l%e**0durA5qSkcJ!x`eP!CQ@DS)clRGFp?0s9@1u7KT z(U&y8X>Cwj^;QDtQX_e27)bOjQ>Y3h`i@iSr+N`xW_kzzyg)xN4WvafcIt| z8?}b4r;4L^zcP7{Kh37O_f3Nn+l~e-eq?AbnesD12PPRnJDQoMC4(MiqK2Nt%Qg3z zf21)E$^2(`o^E}<%oL5bL?|eU`dgyOB!WYs>Fdc&uw<*PXe)TiVIBe+ET3rHTLonl zG7!ztRRizmWirF0+ZuH87#bAR;OUPI|CjLlIpaGz&`tQ~rP$zhm}@*+Uk%3uL;UP1 z5U5r#Jbn(Yk=2gk=Q3%katmbhnCwa~0?lV~sFp5!F|+2ttD+*6d@k3%uas4<%%`pI0Fda?raGn144%EezbKN5L& zz))NKH8Z!nc0=(xh}Wea0sUg;b}b!rgDj!k>^Dk*zXxK}Z1Lntw7+8B|o7AV8*y_6!JnNJZ{e8DMe9qknm zjXOaKCu2yVIExgzC6hw?T6(Q;x8`^dS{+6V8V#WBojM*ri16lymnP_(Ey!zYzhM{r zuW61~D_930I;Pk5Xe=fP63_5D^B77t8c6h5xGnK4JkXhqY<-*Y!l#*r4v@(9_~1YJ zx*G7T#xQ)|?|hq$rLoldk;TkpD54)LizF&8DZ`OjjDQsN143;6aYcTvWv9v4HG_f?5sPnvhYdDNCsm`&-FMMY>4R8a z1MylcEX3t3MrY@mxJbs~nu1}9ht8h3+1(#uoL5$}OHg;}3jV;`gQ7OZb(`Q|U$eSc;SzAYVmPK#-cD>F2x+wAZ7wd5?36)65?$n>ANV8 z;#yi?`T}Cs4IWajnhrTz*_lEOMN{v3pZ2vb-vr^K2tFan(Iox)@$b!dP>i-`3K0w> z>XVz90}&lVT>XoP>!PUG?@JsEl90Z&n(uHiG=i2_4A32MxxQYD;?xPTrOpXXoe)i(vtNdJ;_>Pn zG;<5w@k-fU*GrAibdB?;)58f!T|?cvC~JJbcX1)#9BcY~1sM8XyqpHJrW?LsKcxrr zg&!8fU%!}ME_mTjcljxk|0>;^ap(PC3fsY*2~90ND7 zGr2Gr5f28Gj=obAA#Kj&|3g75HPUqbJ}Unebdj_d_rVD%YmCGfEL-$DC_;~ z+5!1iK$zaaQ0wmq3cOC)PjBFc5AoNo2)VMM0Ooi*Ovn8E9;Ohk?AH;~w|yQJJ)a>f zaiO1-j*EFVDmnQQWq-wp+qO{AXXZN9W*KU{S*h*xM9rgO?iA-^W)Jo@cN_0_NIq#y zHVo9Q>xa)o;8!X>)Uu{yoEZXj2!d|d{2d+4-XFI3Y&4^ani@HDOuFAv)r`6|M0ao! z?&vqZuo})N8%;7)6&RlTEcF=ThUMkb$6n?DlAupOv^^4`Pm*Fdr$fLJ0hI!jxCus; zV2w~|4?vix=!`$jvOZ;zZ+(v_qb}nG^M)yI48UapFc_tw=WgSYG z0K=<5fYyUo0I4kNVc4wT5U+(^^yGPYK(P;7SW_FQAJyt!(7|2|ZR7M}DtmE<(~C8= zx)(#8UStEG%OW1>RC{DEieX)XF|O9>#S^9%E7%Kqq!(n9UaXZ~Am->^5D==sQal%g zX-xEJ8wgA`7sBXu|7%4WENn%2ZA&Xy)r+w4uS#$>?q32AMg!2Ayd_|HUa>9N*lH@+ znvZ|bt)YXhsd0L-7IySvEPKH%ZwEk4tm1_}@FWgwIZsJ6m$NpO!6|X?vydQ~Q+hEI z@oC90?c+>BVOO8EiuT38!gAjJ!Rh5IrkAzsSB0N({zvY=N!P$ zpDCO{E%+k9w_u|)gQaE$jqC=u`vyeBDLN)2X6&*mWAec?_2l$i95TL!O^xQ1K_ycj zfoWmlOd}KDB@-vLvw9dmo#da?Y;>1(JJjP9YYyQU(|O2wWgV-&KlY4D_sghu>LP)w3> z3{c2IT-~RTzfd&gV$3CO7D7`qps|3_G%Kk<^{}i=Rm!#cgQBAlgPY+hKt>lZ()*pX z=W+Cj(O1ubb+cmRbct?c^t20jI5C847}*M4I4V_+|X4*)+98xSR&NU z#F@MjbiR3sQz0XQpQ&a`gf~9%T&PY&C&(%>u`Le?I_D`XA?{U--6A<_B`55yaxRq! z)g(D*9i6jMA|xjwj+1i{#lIC}Biosrz8_6a*iFt+b7~A*J#+rk75>E6TjpwIt%7n$ z7}Vj!DpLnPDO#`uVR&y(yAJA7oYu4f5H>-;f8$mC>s$j$5t=0h)FHv`D1Z)A!5yrC zA<@iml6pl-a3*GDvxGR|P(iA74TE5cZ>iy+Q$xqLx`yGKY7DGU(t9=|U^gGR5RiC) zM8mBKDk>jBJ3jT8&|(Q6fbd}%x%Ba-Jqn=Panq(=UB%Q?8MzXjIdC`J`k$&Sb||{ z5Vn7%1o&9OH{eX*=LvPbE@2N#$Wd#42KsUZlR;*mfvYkUwzWTLIGu#|gl!_8@u)L) zSg350n-GUh@=4h4;3H!*PY6gjP zpIUQaoyB5PuHAx`-wRWqJ(mkFy@VU~Lofu`OJPW2*eIPk5hd%r*4*EESVG2#Qj(=U z>yiOWvL#26l^&bS_E%fNrkR$KEp1y1Tb*XBK8kJW@z@&4cIOU-mg6+v(!iCHZif-r z%LcFkzA7}gnaZzV0`1EGYz_kXnN)twCykUX!t_{zl*(ldV_(-V5qFUAW57DlWb}98{bI! z$Dg)U{LX%pvKl?%rE?)XV7E`Uyn0rT<5pQGzSj0qh5hO4H6WX$%)T&dt9)>pWIk!7 zPoT)RkOQ({El^QkLe#s#-5Qa{>u4cRiacD%RAnJ|u!2b#SMe(RLnXywNdbeTfM`;T zg>@J<1Id@{0jS9OR8? zCSe>`p88T!ye}zWkQ5Z%y4SYUz0R%sE4OZuLHb-V$o31Vw_Zs1JERody8mibcXLbK zL@Dsdhl;qSBIsv$4CM_%34>5lbSXP{Kxt?gsfaZX;Bg60LcdgKo)#JygodI^b6E?` ze9{ohE>e{)o@ND;B<{BN;D1VJe-m05gqEU9`%DY%0n!pnTB<@DZUvJhuI6n%_6qGK zzXS1@w~1A|~Fx|m^t*)xs%vS7Xz z3=D#y=wi|YbK|@GEG!t$uY#HAU?{qnI|UQ{Fk*`YbGcw(5DY~Z^Ps`xsB*qCSWl4I zNi2M;v7EP-sk`O2xn2|e6bcn2P)XABbmxQr1`na}VR9D*jCavUepKb%sY?fJ0T^nN z=e+HBDoBTIau@_3gxL`Cod|ypEboUwxEsQkVZ1d!2(agaKbwyjv51N%SCLBV4!tf+ z9y1yt+{NdMIC%Sb^z%j90qAx+c~E*60{^>X(N>c!Hk{Aeo{w15=ditT2853xtbmZ7 z0FFuDK=aq(kIgXow?o)VVK0Qv?WH7ARj{NHrlf)Gr6khmN1if?IDSdo16j@vmbA@t z>kb5T-iCgXD-^;M2>DKgKMIy*?IHApun9s&|7~p3N91BnS%@ki*J71GF4lFxsjFiL zX;pSOB9Gsy)U``d`S@)hS&S&#}gTPK^?AJZ3c9vENqRPqjuc;|HTx!YgDCN8b!E^=@ zt52|!X2UNl>9u;3F{3lW_j!8!j>t;bz9Q*|5O%XJC&FI^O9+*Xx~@}{w8#r*J5tOs zEjp`{)O2YlsVNBFEhlWz;d+x~E_wEQ%2-NgY|ewp6$;@N2k~ z?irFB@sc|W-cb8Qxp{+P-Wu{Wd!icRYrL*LxwVwHhoBS6;Mt))> ze=P*x3G?%&N#+>lKkSL#g@6xWyP8~O5JoY-6X9P4%XrDJaiPSGHTerAKQNNt3vccT z^YaEwW*>Q!UCR8w!&XeLEf5wkzZ2pA6PEWSzsAK9mv8caDfxks{5{~Ee!~2`nUlGc zJYIX?Zc@PZBe~i^Xk>mT!rvVhyNg_pv}O@E&C{JY*3cfhxd}QoB*Rj2{2G!L!au+~ z{HtE_5eX^FV6MTKtX~SAWSh5wK?;a!nBDi9kxE|gEi#{0OpNo~SfGZ!1NddO;*-Se zZg@+{g6sF;Q+MZkw1@KbU7)KEw632Mq2FCG3wm#xKQY=*{f$>#z5SWc%WI(b(R%Ee z^1QKgpZQ7v9QVA=`z{(SHx_RUJRq#sUjOXK&Clzw;T^)e>Ylq!6-gkTeRCvPNdO$XSp|iOjTpWjHRucw3M(3X(FAkX>XAq#Z=&*uDlF4`KW+ zNE!u6StDn<$mFxI&@t3Qw$G2_G>mf_1qq`dDQo0H7g>SGbwoa4`>JuQ!$=h*je?}C zksrFqEr@I)ve@=D<7h=#)(e89QIM2@M0`tc5gCJ_oCOje?}CkvF->azs`VxzN6I z2^RT%f}%lClr^f5sC$WO0HWH4qty0!vF<}LJ`g00f~2gG6_U?HcEM1KZC?bAF&KLV zNuwYsYvdXi*$a{JM80AB5^zk$xL}_kVH6}~b4FZb8X|Lve9KPdb+VkV(y{D~Q052? zBBTTX$(#87`{e5HtK{nc%;rrVYtSI79RVvuSR+IzaD);^Smy|6m=PizAwh(31+0=1 z{|6SISmt$Df$CHW^EusY#ZyRc)uLQ9b7z+@Z zkeWJ)uAK<&k5KI_!+60s^IALe#Yx8)I%bH24W`ZpCqPH@sj~ofrov1_`d$gG7DIh( z`|70hAO8>#j08;vA!QQU`F-YDsdd7EdGGlMzE5mL;H5e{L&IC?gWPCnxo4GfrmAJbHAtZz7y~#FzSH26cnp z?|bNLwB8wd;S+B`U#m~r4!bb(YiR4VRy080FF?xsMLg2_<|11oM#Fv(&3OTiD*cQ( ztQ%i8+Ncu_t`R!OF@X*XlYP%P@>)C6!@aULV4NXFc8EGV^cZw@kGial)zSVwiUjb6}goB0C!TQ>s4M#B?=NU&{Ye#yi6i(v|F|u&#Ec`;~ES$O&Ug#E{C4~)VDhz<#zk%Q32?#@5b!aq2qhm_dis3EkX!q)zHmCzG}88mpmg z!BD^1zIq%RF~XV!1fyJxlr>=%2o16ck={r+cG{^xnoBQ)21+SiAaPqy1{vRD`_1Ma z?`-Zrb8}DWAyE$=C+aYxk_JiCae2%O-~x3&f4jNMR=m;^&c*LXxf6^zC|fr?oX%@7 zPS#g@qio%H9(1+!@apRsFka6Yd{w^!GtWEVoS=Q?9GnA3En8w7d95Akjk17foFPW` z5xO}s(Ai_^a$<@i*+ixb3c%y$0q24FuskqFz?HNjvgKQGKO3SeG(G9!m7XwCeh%Q= z9004sP?p!X1;+-Ag9oGp809o;ndM;#3$hWBUbIpvuP+G4P>fy&9i(!Rl!<)OMYcm^ zG?5-}Dsq}l8Wd)w^r8onoV)wfx)m^Zy^80p1mjJv%C3Kdy|w~UpqH2P*D&6}Z~F@n zF^v?bc&iQ`{ll4FHh+*ocgvUl?)PXJFi(Ja8(?BgAsc^7)NE{aTx_J3@;Ho#QDDg5 zCNL<@8aDA?h1Rm}{{LXJpOBeB5C1A8t_zt*n4ZUl)bCvm zy`Aph4Uw|yh60FHSIA`$9RRk!on_G8YnDMDxTf&e6ctDq7oa_#|1CeKpe-#x|D2*I z;E117)WRd5v`8;Y<}z6_niafkZ6i+rdC&Boe@K3ZGYRz_(cGXYX)eJu@oOpA24R#O za%%1-H77VVN5H)#Kzr^vBsJ4kYie#jvSyGSqvmU+X3dH=g$H7-{o|xOS5jsT&Yh+QRoRHOsDCP`$d6)ik%(Xtco@F0n zu`h`-byfo>#-z$9E_S&!Sx9uh+VL9TcX(BSW$FouwyZB$Q{lhZJIiadm%HQkNN4wF z)OoPq?e&G?7=dxaVc8a7lx=~s-WI~pFoTRlWFI2$@%mzM9D?zXAZZjNWsU6TBI6O6 zL1dv<>)DVCsZa6xig0`!qe_@)6eh}==@yr%7?Gt!-fx)7A+MlbkJScB2=Utxk# zm?&$e9G9sUkqtyX;7vsz%qAD>2w9F$!qA(eS8COwf(n1~~Z-TiN zzdUeVzUVcYnuou0X=)k@BUqS(0`;bQB4KkZsD(VCPSqqJQDa1Tj8qjy^~YUW^{ZW4 zH4lPQ+EM{YkKw>0XZ}L{j-3CQ5y~2XIfhGo;uMX;zs0zI@Cc5r1kKp8%(1;3CT~W+3Lu=*NXC9(qA|)3Zd76Lf6tvwpj|!u@~q$Jb|8s33LoD(dIl5f$?sV z?UAcQh;5F!ci!cZ<1qu$7{;g^cs#VZPb~O<@*c%Bq9x97A}}7yK|SW(SU_F15y8# zq@}9;;%gDo3v#wAN6ht+KQdLVieG@Q{X;lufKrS0hO1pjwNlI;{kXvt)|Q)tzN zlKm)f_izG@are*wQb4W0h({f0CpQn%6z1?84LX|$nDx5rypDD9%{!NYq-0$YF|b&=-V)L%g7PoG~+n!5eb^IE~Tt(Qr@C{*{om&?`t z7;qO&dnrg4f-b=Mf>ly?Ho3jt@)&w$s>xSZ$b5BIs$OEyCN43z3*KR2H1GBay>nh8 zKU4W(Di|BUSf?13He>qMNVRh&Sg%3G25H8|cc2+Jr1j4E?!)X`nk}Gq;u1Ibikk3m z3$D+6D%c2`U}KpEodIU&vk#KZk$i6FOLm0X`6Phr3NPQl;LgXpaGR;L7U*hR;(lMz z8vMH+*J+Nbl%T1UWmYL@x}TASy-g)MRTzffIVO zW7-9iODqc*-}A@%%`##*L&4#uAQ>Eum5!m& zG}Jf?1y1Awzw7MM?Pf|pA;SpnQLWyH0$V+w;${;?cRZ1%fgO;ShijLJ!mD|{$|pGU z6VvdXK`!agk3X<p<5EEG`BRMHOv`p6jDbxJUXK)z3h#A}Y$`xk522ZN~JZ zC>8Dm>ov$gA1s8`~&W{ZvyS9xq)cO1wbwx{XjY36Xk ze>v%4%ik;jX8EhxCiEiK1%61vC9Zc$p?aX(aj@;%aid;T3w%8<=&4({yBu{3R}1!( zwHeku;AV3__J+A1qYT=>c}^pn*oOO@XW0CYfE}AoE=QT1Msgo?TFCt!SP{7;1?g%T z`T?+MR%snTE|et==_(!%3WS!&HNdz$W)fp_Ho%Tyu1!}fh z!ja_q>y6Ri4!))ZI3DfSn*7N0%j&f(W8y9@G~Ao0cu38L%hQ1!*-5Q$HJiWktoy;ZZ>u6BRVl!ZsZ4G{@?w$jmZPLC#)s zM>s#m>Zlk+ZpmEq=rzoP4jn@?t_Bz#@;~dUtV4TsDiP@1t zW@DzB)blKbCT*=2n4Z+{X}hZ}u~u#O-i~&pkkh7(K4VGm1I9>sBV^Q*rHp<7$izbu zFh+{EQ+TALW~q)Rbh09aqsvH1CukyNf0ip!%1#TVQYcm zY1h^$*8{d0+151rpxr}3S~bsGX&0C1;~&{sN5R7ID4>9ef@(R9R{+_H>%m})Q*?_P zO^a^;yCq6;F6}H^OpLCREl!GdwRo$$#o>ru{%*Pve@_X@dwGT%0{01VE8y{K;b=4kW0bA;~PJ}wJ4Yg)R;v~-{AIL&fC z9m?|y*4&1x6Nh))K|=3T@?`Cq9CyJ*dz9ZVe+00fKLU^+nGmDpG%eYYqhe_&bXgBY z_{16TGOq=((t7T%#`^^;%o~J_5-Sz)s#0=T>AY-n8ofZ)P{7l|C;RgqHS1+G%ltl}Bu0ZD8*l?gDG6X8+PY^UY*aiKighnD=KMk|5o>uP ze!5?M0-l7BDlJA~bSD&AO<}h#lw^)+8Cy9ul-{ete`q*^@~iz`>1w-3R@ zI^-&HnaI|Nd+TSFh@@%=y56~b1H3v!8Tk|fT^jpR!^nW2%unv zmW*UGC6dgPpv*E6vBbAtoGs#()z;S5bk9x<7K4SX^i<*L7C*jk(%%tlr`9j&AG97$ z_xbO1C7k9^dHx@&e`8m|Y5wLPaXtgr&B4&TLx*M_LlZ1JG{dtwW%vn%T(!JyIz(r* z-B^fdnQP4p7C5B_U`)JOnannz*A+a}<`-OacH?@T3(vdVvGBAmlN>$?`W|5ZS(O!r zjvEv_{w8TLsUiyr=j!ezV>~RALMFs23czSkj7pm^eHIwZ6a?!v$V@?+nPL=ZW(v|K zQw+AB^lk;!giAc?FKX7!--Vi}M9>_0W0?khRSgk1^9E6K<}GeBm{0fxHOq%!NMw#l z#Bj*tUr(vdO_Yl&U@oddxTv;4-Us=HLj@LO+2g0tG0IBbeq2j6uQJ4|GCbnbh}TP; zy(Yy*)~H^SHoZnoRWfQk^H7>8%~~SP-k17%L&gN}_YsSdi9Z(QJHB;R)a^RuALV zG5Xv=IlY>AczdsoH(t%xUZp54uGSVy8%?1N1x6r0*g-$%zQCi2enB5^!PPSt^kY5E zEPctIrGV+z*_@@hkR5|72blKA%Vw66mxn7=^D0BUD#g>D0dCDwQuNG`+B2lJXHb(h zON&93(+#isD-z(TS*V8!1k6~nOk)#a495#0wXvu1=T1FKSJ0mu4&cw(?Pe)Od0_Z( z_bmPCQYbh11wA)zD9%*Vd;5AB@4abz4=}yAl-}D4`6l)PnD$v+@bBgw=~>)6lFU+Lyh-%pIRd(Hbc3^FX*}Va5d9=Lz0d6KDNCFnBH4M?-f9H z2CjRPg5LYYc#phdTfe&;1oE;FnL5 zl=lc&uiB-t*unJP+5iv78}GGh?`@{{wjIEGYub5_qWt!dZih*(_gx3&-F`vOl?_8A zGFw&mHs1T%_8wq*?;d)u1@e1w?M@DQug!R`g*dK{HLo(ntI|BFTHy!?-4NGW0}Uzl-_HG)a>5IdwaF_cG7#}hPC(JJ>lM? zDBF=R%y{p^9`a~iJtNgG=()wX8tA=ed-GroD6WvDb5Xdk2MXmV{MrkJY7|DmH8ZIp zp6V$NIGuYN%HBv(Tc|AEJscOUZR;oG#)e#WZU?~p^6E;`?BE{I1!q-(b|N`e9f#=r z)dWR>SDGBHT3B3->&8C8H(!w)kmMnn*?{Xx#jLcMRffrJ5E=EFK_8Q56LLY*|D^SR zp)za0*04kDY*b{$z5sS`sEG;$%z&{>VH>z&b>#0c+)^vjv92#_I_) zUNg;jQ4)9S{36y~$nR(6T_aC~#j>M;RSbb4f*ai@1m}zgGX}2jf=eVsE~Y{;u$5FG zxZP4PH6#L0r9#ihyG#wYP=Vk^>rK3}e+!HjnK317i$xL&~#3)4I$$7uZ&RBH}F~$?k zY47)f^@RZ=aTtf6`(3veNc7wIGkL;lzD4GDvDHbH$@iWEV4woF5SYCZK$-&HBQXAT zhWlkZ2<#`2eFuG|fCMjq(sckbuZ$;9PKlM50mxE7E+wWt1t3R#XzUXLuU-pakOFGG zRN;Oox4*2mm_TzmlhSZ6fd(4=ayfUV3Rq2GTs44sUrHNw5!xf4_1B$8Bph`=-^Tjh z1mt+P@y21)5+LLFSz}ryvZWSCzLt58NKfv73$#qR@$``?+OE%YPWpq8DD!2cP^XbP z4?GNHn%0>}q~U5HTeRIeFRYMRr>#(8$1X@b>8l3BcPL}DwvuoYdvBD zdP|cvsk*mGs?TWOj4L4cVZ_Bs^7K@;xl1)9ioLbnm8~iG#a8`6H9ZwI?Or?}p74m2 z?@gl+z&&igJ*Hg|Z({AaDeChhlzcDDqoWTs%oPn_R(cKDe~XJ;UIQ`^dHIow6xf(I zG~-*P%F@?}jFVU9OqTASHV9@1=~&ehp~s9JY9?tP=ghzpcz*#r2%duroM zMSXS+ZrXxgU4T#+){pBpsR(Rj7bcE4m2$YQ!s`>b{h`i$yPfaxPn1apdZJ zvG{5+h`e-&X=sHIIk)nQ`9fMe2@7JZ{4;>BT!kk}-X+xwG3R{zRA8VG^T_lx=@0W# zKfei_BtcRvH(aWW+y<9_EX4H$InxR5UkbQFxCbV>39;Q)Kk*5GDMGwsgWXm^ z{X-$X394TrMB_Si`xGIBGY}}c4;dliRsbCV6y>K^p*#|0wD*dg7~J=T93&im(jOPz z9ie)Yg27%sQF-H3aJ3^?_fqtyN4^jX37?B`l)PAy@RK)QHc%jXBc=**9Z(QcT3Ap)iyx|ah7Nf8#S%@-%M$&vqx{hG` zuQXF8_!Z|3e<9Gm3?H%`}5UeEwaCfgWBVT8Z*-0!2?*1aGbp zcuKFm=@~7GF9vpp5Q_GQIMJ_Te8AiB(2kS*abf~q3t@n|dAuEm2Sxnk1p={wm;hDdrK$tip=uW`<0!*jK}Lnh zZiZ`HIC!vZUqZY`x543;V64V=kF|VrXsk!sN>uX15d^F!)SsTo(qu26t6NE_&`6BM zV5shzHut8bk?3F_JqQk!`yT94?niejm-pw<>J-&)!%mgMfR+!4wMOZ%SlNz&kc|qN zN{jcHcBlJXEy{0M&BSG%!lx#l>> zlP%HX+qdRw)tWJs52=sMby+)sq_K7)iLvpyF>Lm@4w@6kpX;y>6T~FH>BD$djN8J1 zU}Z!KEW=PgxrZmzYusT6piHq-+BLL;cH2bN>8nP?(DEc}Xx$w;)r_#}K_UAWB8w~% z&6u3)5}sm_;GSl6OOA4}87l)!wYq^pFA3^{SE?FJu`-I$kP@4w+=4g48RDoI(+}4q zneMonJ;Ule*)u~G9Tme^IU^Y{dZzKQL1)=w?9o|Pg>c+RS=a0g4?yj8s?C9v1yE*g z0*_7FxY3?(n^e#OKH?~cRSU;0t`ekXt`@A6P?W7(72ZO327#0Qsr+HDHUYDA#+a-U z>rjfB!^#`(tkT(?RpL}uIml#{couZV2+t~A-RpTbvqB$i=Y<42FC1d>Lif-@eW-hl zPCVE}_HZxoJ>7|{mphRqxf5CPff8A7mB{+oiL9@krTVF~)Zd+!Qry`n)lNbKm}(9) zxn-c8Thdf+Nq6U#j8JaLbmx|=1Lc-%lUs7^bTY_JC%JYy8EmJMA>Ayo!^1PcP&-`= zv(wD*_GxHDt|dGYd}%ktKf*Cpxf2G`g}ub&(Xw0fXgh_CvX}4C?m$K62v2{?$q#=zffhkqELpL>`oq2LTUUoD~%V2=ai|gyjEhT_R>(w zFEg2ZnmaL^Zkt2eKpthf$km;lNee;aXV_hLdFM>WH43xr-r8Bi3DcYHxb`x0!uK+B zZJ=EOu}s-{r2Up@fqRcrPG=;dVHIZEP-(_05jmjBq}S?P?X-pV{sae`iQ^HGdrMMd zHNZV(7r8e@=eqYU=Yh10FAfPOf?Q%-b#?0e@J-VNZV$McP%GTK#tVhnaH;@YD(wB( zGGS(%mrr!UHwzbuWcjoxe7kV52;VQP5C_^YtP~0I?yr63zeKd(Iy8vz{l%psd~a}> zt!L`N^7{vS*8$r+5rv()q-F0R1Ol@CFJd+)vX-g|HO-rc!1WeOyOfdBvN+`W7E?%iAW?#_RTrVj0fE<97;%r&Q$ z!XJR~ld1&npdEz9pj)whqaM~Zw^8<572ELKMr&9zYJS}|hU~zN{Lru(mB4o^e83JG zw#OU(fNS9y)X~t+Z&0s?S@r%%iyTgs!9+Fs)JisJceMQqKb-# zi`{XkN%A|G62JinpF4((m0W*SD8Vt2@j8L!uqw42q) zDtUIM*Ruz0FEhm(@OJeZw(0|U4#(_;c3l?B%~stC2UNwcH$6LY{f4X$ObLNXfnviC z26k!LE!7f~qQF+=au7?(_8djSFYRoXBi>NVhV9S^lTB($lfb}s6vKX{<=IUuuoSO5 zx9UyqStZ+3JOx(SZu&3t&;1xQ9IU)>vNh-EajF` zvDYf`$|PS?q9duqDpSzVtu`!=`o-l8dMYafz->4_RpM4PvRhFFI{;l?_FLo)ilkj8 z%_s!V4I?FaJM>#YIjNz9UTQ%?XAyMFF*&O&D7y`1?%otN3(b&*5|issLKTHrNVpFT z?5GtqrfiwV%0mp`K~zFz79kR=S@Q#1DRye8rjnJ41PaE7tO2{#oYthHT(>eH)g-QC z<*Fzm3}3|yr5-pBcib3SZMwc>hlb}RPm!m<5|3;}H6>81;tpq~48U<|3W{tka2p7j ziUYSASdq=aiNf8b*5hC#l>+{QaH?8y1G}uEha%?0ev_K4H!X0KgvhcSHkDX4V(==mR2zc3%4wq; zB3&c4CMYIS5iB|1x?T5!wvcCX@z7%@lS1FwbsTqcY3NnL5i0_x9&w95E!tb)GORa~ zRz~Eo8SkK{zV9rloZe>o>`uYl6bVKu6}NoVndiQ`o)cRs7U+BSKt)nxQ&ZlR(`fQ_}o%;KGjH2=I4o8#;@wkpr-FL<^X2w*w zJL_|f?kqcwrf)jAr(meE**S}T@g8gfz3%H^6R2IZ2OC4}{tkAsx$l^nk(f?;oIc0s zVHc`1Rrh_z1knk4WC}#=NJ;D+N$dzo?A;DFhT7q>_8!`@`(o11@8O_&R!6=#)2$Y& zo2_COO>MU8Vny5Xydmgn5bY>Qx(cc|$iuw^?=!-o%Hcl-tum0&C zjIAuC*4dHPAJRx^m+qNI$9pv<%hlTE#Z?N`s$yzvY}L-RepHHt^wCH@2MKN}1ej&D zoI=AMt$SuIS|Vl~g~9*XUVNs1U4qi%*Fcg2XStdz@2IJ%kHO$)l~=nG3! z`K)GZSqysEo`VY&ml(&U*fprVCYz5-33Gf^){alHr)tF!eRj4| zZlxSC{-|s?Pog~{Yv-p}aiw0=ACM$3l&$y6){9ciJ=vWgrfwDO5MT#cB7K50QN3k^ zRe^ggCI~eZU{STCwrj4xo>s6s?T#$LZSK-dvw2=TdA1M8208STIXa? zZw}S|%?mvp-H0mmD|kBaKTrOR8wXzV!-#ed)3g7m7T8vWBbQQPInFJTx!UxMcKW8` z=c$EGtD#j=O}1yX|MF(z*S8qcXVH<|b2v>}X$6!2r47jc8xF$ze~aO&8kXrP67Cd)F`E2Bh=%ul*p<_uBOUi0{@e^ z`~9MNF}fo`G^$hC^&P3J(Qw^Jo{}y>;8sasrs(nAh=cNZBC&o^jB>I-dTN9v2&KDs zW1E;6WLKt{9XF}P*hGz?i%Ys?%oi{l2Q(Yu0v)Sh|b;C3xv&Gi@sTmPyfukX7D6Q2j|!EASD z=t5uHxu&Xri`h)lIRQI@s%aL+O>-QCAZr`IfXM~B*14k60aedyr*{`27 zlHlm06mevlJL_{h*Xa9?I8#lBb;zb#6>Zh3{`MXT4ld|mXn`WG6@ z%DsiO+)YM>iLS}?<-50CXhpWkGb~XVM?1S`xx!5?*#%On!F(&`j`myWk(vR9z zY}g{HZuyMvqbr!El~DKvweHAhDo3=Bxt`h zJK0;&!`5__!T{g^KiL*Lv9r=_CTfpKq;u2ErOi4Z4@k&` zXwR)gevsJ$Xir2*h70k~%tRzSZShY9ya^rJHSd3l_$t`%6fqJ_%r=jB>Y_i`ZphS2;;>3r3s zHA@WiJVr+4lwI?*fXzY-PKbtM(s?>zff(K$5+XXHTWIc`A$b(hEzIIA*>-d{BUQXH z#H!S_TL|-Y*>-F~?Kny0)gdWp^ef^&*PO)k`B=4DG&8*`b$08A42kuyo1uL0 zQ2v^yI+mJW{|2#Vyo2fAPJZU;=#WOA^=ddytp>V#x5Sv=&n8CMt0hMHVK%|f50Plw zYj(lU_mSXd@7V?Bcagvxot*^m?w}CBtj>g40|ze*GW~P}(`Qpme*lAD)Is&U7{)O& zS^c;@y3f~VPw6d22chG_`|pwyyu6zTehvi*tI`83@c>*VG;wd58ZQ;)2h(DWHYu*b zx|D_L!=ozo&}Yw+>t8C#-XqAqB*>o9#bSe;5Tss9JNo&1er!~$I4yL<$FTT7Xm(aH z5W4okS!B*wF=uqns!v2jy44msw>3orw1{hw@}M z-Et;SB)N#-=M_;txjVlf&7@ic=x_mgA0}YBh0V;>^x^!|(b`UQX;3ygZb8e4!1=*>8;;I`x9dP?`O_ z462{CNVeBap1k(z=p;&qfJSBZv$FK<%LUfmXrVIuSsA|l^@1zq#&Djz zlCd#PcIj_6mSp>JEPK}?ldV+;*ecacPr(AR53$l&`-uu z?ri$0kqAm;4o+c}9Fj(}U~GbvssDOVLnhg8VhuHVaN?QGWU@VmnN1y#QhSSJuCQD9oe#pkuk>VqBup4qGlZl@KAQ{*kEIy={J}^$t9{rPDucoE*92vJC z?-K5Nwv75ucQM%O%00QU!it+G^MWyYX7tfnuFg$RC^%Y<@zyVo0Y(Vv0EzV3FC#r8 zk-iTE(%y6a8WK(EV~KR|FC*QMh3K-Gm2)(c=YmO*oH{3?&jLMq=n<>+v_cNe`$uH^ zUm-4_a)GEkK6@VJQBfY9!!e-=rJ>Ri_ zM(3;auI3N;lfqXT%r(cH+5+0tpLOuF!Cc+r9fzcT0$)bL#|XYm0=7UG!Iv4Ib!PWI zUHhi@n`Qsb1M~xdRhVmyITYR+!0E*2BC5U?>X)Xd-#p`;GxdFvG(YU7uebeGn(M?g zE}a|yJ5>8Ajp_3u+$ZrvTfem=?pWuzK2zYTw*Ao7gU`5rDeA=QVyb>6>PL#ci|m!& zdzN^t$@ap$zuo>K+7Fs)AEoh=?cRL&&*#6;e*x9L@%)gnl6?}sLjs(dXC-oZY3nb}Js~?8Sl8O3-s4tSJ--$ZuI@Zm*sPC23O;R?v z9e7j9W-L8E%goMw^nKAT`>Nl)e17_u`-GD(aQD3)S6XPv8-aWHxpY*=7 z?AN(J=9A!wzLdI0$s!3~tml{E8&88Tqu>#Mk$^8hHrvlVTU$P!5AYTcJZJZsWAE8V ze+&0phOvGdSIJ3!b?cYpuRoKa{MyPBgwE#Kt8;HXF(3Kmg{!FfB>Q{__-4OixAYBq z-Kl9losj#+AXt!gv{(1uU84!zC>rvM(zg8#+kY4B;|ZHc_N6baxslp_#rCtSBPRWd zJza~o!+xc$u*R>qJ&U&SU$JZYl7q!mtV;IT9q{Zl+bwRe8K1GydfW0f@JDm1yzF~^ zpwV5E>uWeYZsYvdvo%}-+S-82J==+>GN5g=S^uVd{S7zbW?$cCeKY9hCx|$m@zaG* z5QZF(NUP8RJP&;*^4z)`X)`t}@)>=b^ZpGAeRPt}BMrx|yoPH*4Aa6PWNtOB5vT+A z5dDdyq>jU29@w63g$lq+!GPcuXl}z#3{wd#x534kB=y2!YUl@4lBbzAopl0fkc$Ih zTvp+5x#Cxe=Xw*@K#ekY>_!=L4(*7y#EC2S!B78;&G|O#ntgoBjc4?&yMabmR=jCd zD!2jAtnw}`H?Vnyj@jvGSCOZA(tVPc-^#sOB{_`A-khmqZk zFW`8&W(6E4{jt*46-wh<_Ct~lJ0h*{MkuZ^t#U-C*ml6fnhTBLq`!;_L|Pq;%JXb- zm8gX-G+wde>%|6@2c58vTNy%ba+*ZN0y`jyLwhj3O9+uyhUwAPARX}KdZea`#{EG$ zLT+fAZrwMduej7Y>~fFQ9-*&C=^ z!{WMxCV^oam<@Mn2HXo;n&Y*?nvhvY)8|dERn^+Q(^A%DPb z$m=_K(jIDdV~|S=+@QEF-*CpJMZQ7b*8S`EC2ljwxay>xa>E@gheJ@Z<5|^Ectc5Z z0^8mdoC)S7n_8^`szIv^7bvwHGGq_B2{5EqA;o~}dZWU{MUv)*O3-18xNl;_&~w2f z#Go!^`B30SwwzW&>T;LR#i)@sC`{UJ2vU`1J=EyRDbzf$t~DXD7LN2G>!~|%%}I!W zBM5jJG|NfgQ@+2+rhK!l3I)xv)TpgGkFNnkb+ySuT(KxeXaqFD$hABgbdWIYUS4X# z_HmJFb8!bTh}Owl{bsEVC_Gvy)~&$2abH*knX0V}vlaR3&PO?Xt3h{}c4bMBqe~be z$%;#_HUwG~cyKadE6{0!7_|n)-6Rc0*KxuefM7Ks2H&squ-!J}=+S&NhfCIAinv9Rx~K`wh6DDH*5^4Z_wtP`&k+L!wj-p) zL)<%tH6ev^6nI()9o6BgiW-Ns9INF?hp&OCUxhZLbd_b%bw8LYm$`_-5US(ao}66G zhJOxP@BmVE3pUu+TppGre-7ywy`XL|>tH7S5JZhZn)3FF%NVHcqJbGex{x<$IAm0G zbtdGjtYsMOn&{LD)twh_DgF?xC`v==4PkNcE0D$=pG~m~PB!gA8!lvFglL%C5W3YQ zBhrMjBYQaFq*%JRcQGVy00MvFC9)N{$~YDYKXzgW8C@U_wPvXp&&5Tn#<}8Enp&i7 zyhZ=|eB-V9L^$s+ZnWig2z-V9V*i#JaX46qXNOX-4L`C&L$Ar!P18UEQ&8s5=8GpZL~U) z>Zf0i)7-Y$l5em@Ki_1lA_N%H(%Gul+tLPHUj`?2l|LDHXtrPg34lf-n~GK&^l!25 zdXNqfdx;sPI2C)!jW|q-w?MdDX)05p2y2H%`499Gz*b}4w%BTm&H6UkU}~5(itEyC zDCAoYDUop_2*LAc9WU8ZaD#3TwJc9K9L0W4L8HRKxE7Tui13K!yBew3<)tcAB+@US zP8pI=s?-aKl8bj{G-+SL6A(9qH?#y|JP);AiKq(lz|fF=Ra;F-N*lt|5pcU3KG)&o5D0*wG5NMFxSatS-y-RUd!Qu??)8IAkE2zT`mZ&5CHVn z)&_7h&&6vUk`Xm6%KQRNrKUlf-nu{p^RSF5n zPYSUF+rxI5W3?tzkgu`HA-N-_>v5+QwE`Q4UKeXJoUV+hRd=gOCM2(-AC;jy*m!VlI9|j8ZB4o;qL!`V(r7EeR4Ij!Sz@3n| zKbYe~CE-g>2;b1;n_i(N({|)AB`5^KM(hw<3bg|KG|*1HPZV2YHSpm?VXYNa{GkS@ zNwY^Hhmk3Vq<{=ChDKIekxFdJ@LR_u5L@Gv2@zK0Qa{N;DK7CQ%mrcT=Zi)!;)7p~ zhBcvS_=XQULRV_}cSDu`RbVJ2smQgVXv!yPX@EQ%W%(8ddJp+xXXV6c6Blxo5kiJE zwUSJw=`HzE2rV4Q@8b1bgo>JY4vFWmc(z4`Lbf6;Q@yuE(MqK3hzFz~>|o-TaOz=| zi&qAJB5ocpXlkj#6CzJ!v5+9vGWa2vIlo$&9mpN3@`qqE(qI4^&SkUl=8CVn+Nw}7 zJb9QH(sprV1|T#+8Ldxic&Wlkw<6gKLlO9-RGM{?D-YmU zh}CLL=6WG-!8S#z8TjpZOG$AuL5G0IcpA{Xbi4?4kJDCAC3l!sU_<*#NOmM&uEL8^ z32%v`RS3#Z{$O1M1H_np_=G5{tWJeX?t~=LWZ(WxHljo~gvHCivHq6Z z_HTeWkRU_3tBW9LG9_42s|f-&M^fcFZB1=irC~S}$0<`+R*7I;ZnnvHo0#!1#X*R$ z3?+%|MQ-0IV#P-UAs(1@4GyQ-<(e;|OikFij6F@R_9_&uWwr>1C&|I~l|CtEX#r?? zS_Pg;3Ge`y^o6I!9vj#Q_O^QGj}`|^MHr#l;8!?h!oIK!DMV>T=m=!Fp_dta;MXmU z!iQR_6I-@;QI-mg)gKSd8-Y|z2>-{HrJ~leSnm*^+BrAHc2<5gl%2xRcJ@o<$kT{K zf=?1IL>IO>E$6g`l>}c+qUTcVm&n_1x=A13xPPOKi+#m-FCgB@)x_xsj5+2M(N9W+ zVnBa1%lvpVFy@_9fCc8CxtBe5TnE6mgnH>$*fGZ+XD}<9*;+E zb=Q%Vm8Jde$cilvy;t4dr`X+B6*DYvgfs&27gN|q{w9sA-KDIXwYsP?84Y$iE<>{R z)TS^{1f!nugLWBCN{0-L8c=#yTS`jXAQ8ZKurd04tNb!NbV=_%@h{Dsov>W89GL<0 zIcSI8-TwaT>tCw24s2NwU{RmzW6GvLimINp4MlX&kr3XDp`muD&4r><0gF81;ZJYh z+}x^|-E_RnL|0#H`EIkq$!{GsUi|z;p-~6iSX4R$h}%448D%ZcELAga)oU5EiINg; zj*IM$i=%JH8u}ENjpPaOPmX(c+=g9xxsv+R&AX59m7;0O;6Q5GAuOV{?Q{Zc*oaMS z%_dp6`4P9x>_i9a$Nh(>zQ`yjBlLuk@Nha>1gO(JTnz&fUiOMPOeSGFKmKx40}Xw+ zseia-#4`+fOgNcGCV=D2bk2Nq2N~(HtGUXMnr4ZAQIjeT>;gD052!RE8&YLlsd!WV zz;#=aBm?7%&}<@9o?7Q@-97`Sk)J=M@an4^&qLY@(;pJ>07yo~`3TObipnRKq%@S^ z&B$IvZX^ps{)LO!N05{eo{w5Y&)_-lio%gh>o@pA)O^2@R(zFTeW~ymLk@@!=`aQt zHZ?fTB5~SSYUs3I=U_Z*12AchIC(m*I`jTzX{GR*PFPU^C#C zIf3{5TcUC7hf26U2flu?gJu3Nyd@b*&l8r@V~Ihj17vmc$T}bECZ0@Jigzq?F8HiV za<2}XYZ{6#QQe!JRrY3`9ucwHMLr&vPG=(nSFrg0+xmOP)(@&t$%_F=ZX(wUN#1;_ zzx*5~huSB$S@v$G!yKDyMuGq_N>xvafHl_EDaZAUgMCc^!R_K#{7JORibUIN*FKK9 zrXV9Tss3Zl-gnn$+wS(nIct77%`ho(i#i;+1Hb7til2gH5*kmZc7+|iZijWhnVCbr z44p1;pH8_w;eR5SNFI(rzK{I`x8;iMfy5(2gr$mEL}dr)usV)rGn}`w?^E-5p?m|Z zpU0^6H(QvW%6p!D#War^V&AmSLNj^RAY77-fgmuqJVs$VvLvLdQAZK6tzfEX2$?vD zIFXuEM=?r+?0QyM9lJXB3@{PyHW81p@284Ix6;|rOpJ>a4jmspMJO_KFj$mjian{? z{R9M|)tqxH!GyxWcbWc@x(IBg6>DrWzI+*1|7N@nVZKM3@J4S$RnO!iEE~s`Z7aZvjoBN7)O^PTu<0AKcq_zkU2r z(F7Q@7*^9^LYX0JEy;KXaTpuVa+lOjvZD~MIY7``qDP6I0y?a3IB&RI$_!d_WV;M~ z=HZFv}2**x@ui?^TfqJ)Q?-l%B7-jISpQd*$M8Ra5WR0swq~QAyolw)PGH;_IX9{ z128iLAHJhZ);_m`U&2E~#N=td1k++0syUtd;6-{?J=-V#-P|ch8p8>Tk_h5)70Fh4 z0y|)eZ&&9KN)7~PkYW9Kg30n4fz*R-iTg6_O8Y)j@MPd$!9I~ZTt9TS3huLj5;ksS z7%{6T762!5=n-suF#KGV1a!G4fqwQRzYpwc^>bHEK~Qa&gK?>PQGDg`+71J>EAe=P z(_<|v&Q8dpwx7Uos8Q=r^>HqB?!n0%G;vqP;wrki2nH~!=KS<4#Ot#FP_*Yc zBDSH*CRH5m$$&A!gJNNLo99W;P;t(bTy7^7UZFnP5;gR(e?magm-P$(!;hM0G#YsQ zXZ_ocf4#54bpCMjfh`SIf9?*+GjN|;kx?2OiS|<`0>L=k;4wmpN;Ut^ZNYf2;L@kd z>tW4kFIp|4Fqphun6Hc|eK_nd`%(hdJp|TeIASy+)5x60u4*vFuFib0X7Sud%nkkO zf(%e*>n$R5Z%=Ghwa~hGJ3QpeZK#nF-K9f1KH{9`@v@ML+eBB)g=Dna5Ntni_Rb(~ zN|W3D4VzF{tb%>+E5u>&^H7PXVoRz^l#yVTjF#*>epdFI-GqHj5<3ms?U7ZOkcSwt zd97-yq3v3K{13na67yo@0ZX`TT!qT|g7J&y5F^KNQIp4sj_>R6SVAGw(8&_HUmh>- zD)^|Z&=AbNPGI&kIKL^S%>Yw=(m&7DlLaXrcHoQq;2#0Wvk%Y?(|H=S|Joua%@ zvtcCoh=I$_#)$0}jym1b5qSqV%u7Q@r8GQ+3krPJx2ln76e=yT z49LzFY8V>xNROey;7+~$_T%^ePsO@{HUe@HYz4R06fR29Jw%aAfk=4X@ijX7n zrV(I7=IJt!;!fy70zGC~PH9oT1>R=Yr$%KvVjrV}Q1LE#=>fFM_O9A<^;D-()JDdq z9O@_msIFA-E__#)kh`C61h?eCPw!_xpsrZ zO*4?cGWnv!NJx&vt4v@J?Or6fQgu z+aG=>L-_jrU+=ziIH!b9r1%y=_^SU)V%j*@fqZU91YyJ+LDsM)aVBt==}fBZ2_+~Q z5;bG#vVN#Z(+=TES0PWP+e^WKZ3vulz^A6!%-Sg!;jijn-~M^?`{%{$FXC38l$vtQ z^y&-9EB5?Ff8=3AfAH?ao0zujT<*5D7P-rZ-htk{5F+(bCQfq5@O80P?I1oG-@G4b z_Z!$o*8t;+fF7UKo^~d1GnO3e69C|La8hC@#I30rraTk9u|y-FE4g{O!F6XnpMT^OyLS=t9Hdtg@&1$;c_+3c(nTA!qQfu)L?O5rQC!*DwD;T1bGIu{ z;Rzt4-#Iez`tuP$R#X7uTBfjn`R+{>{o}GrbHB3=CP_f7FOvtSy$Mrg!jrJ1)=DrU zd(7AWLM|$1XrpSV>N7`xi{@IpxD8iDC=*5ZKla^n5Jh=S9A>DVDig~Yw^+k<&Aa`4 z`|VHlyZ3dN?Yo-~@N6c|{c?yve&|ijwFefFovCG6YgF1oH*LeB35cbabZ407yK@j) zZ0OQKqiIt~FN#F6D!jh?<>&hL`|s(|_5=lOah4VWfd}t<+?v~=?!Ogfqc8$`dIs(+g*GzS%4!AQi}#t>f!spUW>nID7MFAtBCI>!g|5oB#qdqS@D$WwqymO z8&82Ug}8IU4l6}~U@oYf4;tOMtcH!pTIGL5>cx>dT>=)HAz>dDgb<$3Bds5Qi@S9O z;NJ8T`nfBh_G7TvPxo50uQrE`cph9*OJ6aaf+3NG@oU(4y^sa+_fz<3=YK*hBD#uG z->`rn#ItZz+5fuqr`o?7kpR$^9C(*ZbNv$aQ_6xKs?w}gibvSh8^pd57axv?#)Yv} zZ7l-)DJ6sa&;-{LvATNUSPDM;Y9 zsL<%46!ZiuRViXLsg$ z0GNO1_xw`P6abPIqPT*_jxyPaDcE&59dc+=|8oBp)-Y#J+Y}K=4waM2hfgs@G|kv5 zDY@ieRzlUaAAg54HonclhBF5B$KQyq1caXA|Ih!Sv4okd+31z!?gIPP;A^ouZMgt$ zK#{*7S?DJ$W@w8hMk(MhSEHetr4Lq7`YIl9>ndJKng8L`tRy8PE#2_l8W8KHl+{Z3 zKxtrqQE)Jw5vjlvOZ@vaBJWjg1sD@W?!aX+rUllZGgt?=EkO0F$_3tH3M*g?aoXPY zFNd96RByWtg8~z+?GPUp%E~NZ-v|=&QbfM@Bst8*WL%RwVnnp8jfuIw2vewusG;i+Z2>5gay{z`gTvG$IeY84#QMkM7_f7#ViB=iVl=kPXf zNu}8e#oe_dfHFY*Yo=0l`gm2qLHb%oNyG-RyQ1WyfD7UMvTa#^>z=LrA$XvCriZ7u zh_L$lg7ud6uTLWMJr{Ps3034rqd;=^tScMTMt@nHrY~c|iVkBUe!mr*vYMdI+yvQD z<_?xR>LO?ZGQFdarI!{1)^5PGmXBeBo3`4M{67Jk%1pu3D>7%8l`$uPt8C)K6uM}UZq@ZAgH;nN+Nu6_+2;m`9# zp@daD9;R-YCWeCmgE*{ zDNE_2NBrc`kHXtz1QMYa%7Gg69%}NetEw%my5=K8{Ss_=`CYutKoRZOX;3A{SNHc? zHp}mW>mrD!GC%}o{5|nt_~R>*{acQ)w5i6$s)>rKxW0<{l_aQ^VI+qeKq5KYXQ{;` z&?$p^7#o@d+Y^XTNEe92(bRw5BE8cWxK}XiOWbDICgta>7}Vo@67zXA`-nyn4NDHK zAx+4N1bF+-a%jO_dJwIQdh`7WmLtc=@t`cZDHH#6bJ6I>VTqO3cNrtX$jU*0hcPId zEyPtX5zcwaz@vIw@4mQgN-0_j@xRtt+fSLMEz3|0kiII{SF z2FC9>E^7Cgo{rb)C zH}7theZ?EG7}Fes0G#I-s3s0VU3gTpgyiN+W#<>4UtWGu@@uU0lB0r(7IS6sWvHcy z%*7|d*?nX|96f?`l(Kq7pA^MqjPF&PBWE@gfUCRtx)+ z=t&)lRoP1$qp*s%hp434gHF%8=qE-gqQ9(07u#u4PrX5(K=JyiRMv=PxCly4$1xAT zGPF5-<%*??nwF$)o;HJpEY0P?>o53uXdtUGgwy0jK|k1EZr@fOd#+ucC?hDSg_Vdo zxgJERmgA>p$Qo^Ob$`dyE7btUgAf6<04u+#=XKXs7Kmyi+v65TKWANEcRx?KqDg=U z7IEBl^a}r;aa)bkVSWyO@Ai%gGO_xJRb+%4vt!YWZ|hlwkL8Me-c1pW%4>30Mu3P5 zvKp*k#zyGGMVKl!)txbMPhC(rl+>)q0HOIX`<(TN5iXl^XNuJy8`l@=`AevzuW)qM z8o39C*m>xwpC-=;;_}v|9(S-o7`b-L$6G2@y~&NH+>$gFMqLcU*(4s^T~|(Z_LwJ0 z6raUNaGoL{0Q3j$lVn=$p`i~+i>kpcf3QeK{n%q*YrRT3g zg_@Nvr;wx1JB3`IH9|IHcXNs!f^>UL#yQ?+(c?szCi5S%G?inbqQlT+vA3sjxmKSu z^qGi3*g!6jKKTXzTLtLs8{#oYGWWmvo(FhnB&+6Ke1U5^1K|lk1Q6J8! zI$h^4?f5#Fm*Y1I{X#Z3G(j&(>BVJQ5=4M7VmQ{(UaTRqF3@vs8^B2OkbP9CE(Mxl z-9U3%p7;vds+OQ6S4ldTdij49;@aID!71;WmaSZ}Uj}6Pacf*(5qcDYUqW+{!^B#e zw?ggnFMHRu-LN31FIpMafCJGnt!xQ5WR^jqbGUZy42NdhEhZvZA2t!amO&## z)zqv8aJ|L1gA?O&@lA{s+g$`NEok{l?D2b+EJ7+~w?5R6h5v6=q46RFcYpf#6SDhu ztj_puY&(42j3~6P6^vs?v}b{Mo}=wJ{Qczc> zY(BcRj$u>h@0g=8QnSI`VJuNL)a4cL+x&V`%Uo@Qfr7Im61B#|)Gv_OHvMiaJE{=@ zCm;C1o+)TV-)SrA#%^u$Mk)AGndM~OBDK@jJ92jwHkP4#?sSGpjw3)Yf$PR_3j97? z>C=UISYacqf9A|?wSv>*L((}3%+>Pxt&A9KW=!!*0Ico6YRRAu99dTjzQKW-iXN)< z17;VV1h*u#=@Nk2bmx9TGu8tf_ia7afQKzt8qPfOoM{iy6wTC8%zuD~Ey%-mhZVwn zu!pIFri@sINp~&KeMA@b9JT4kgSfku?P>%!^i#(b z)q>TZd~hGl{rm9~?iNHPwnb5@I8BZvzi znLrb&u2}j>u^cbdJDvKln!d9X_G00rWLlBMm5|h%W!ap9i#jAO-2j0F$Gd*3e!zJt-A0yysGxejvcQaotVik3lf#b}4nJNz+!0Bg)=kYo zTq;103rDPDWIqnHB!;6PLZNbs`4w_TW+0#HX*UTlNj6eARFcUPUCU4odLv~~m#r-G zsDC%+J1p!mibbu7_U&o?{D*pW?l@ z3(=Ug;N`PS#R45`r_0b}WXkMq7IDEkN; zuAbM1T9i-Ln)b?IwF!Vx5C)VPXlKLJmI1EZVYrmCl`Y3qq%&C6i#*>zmIOI^sV#Wa zwVMUFb-69GA6xmoN|6=b<~QS^Y9lLt#> zUs(}JtPNWy&a~=Q{WNZDFv?8WF)zcL=N)&iCW?c=&7-{+CGlYt&pBpol!D7~8KWrb z3)!d=$)isH59S$+4nWGlX@#0KHN_I-EyG)p!yvS+r;Q&>sli?6q? z8gvgC)GTM{m?_9J23;Cb1*nT52hYYT?-N#2n98iB`6_xIq~A;9zk1H=;BmTcF~U0v zlg|5DP#e$T=)7or`XtIE=rxGlNd?oQ?BtTmOtNW0C(J+YHi4iyb#(2dDw-a;HNrpP z2J2yZ*SR~`@qj1IER-_#J- z1y5nyRcZuk@Bo&jP%$cy_5h5XUmD~F@C$H`#1pfd%mr(Z#wkVQf*mif$lvYCbOV}f zv&#pN4dx5dt7Wq6B=i6dKN$5zxH0V?G)Vi>9T*^pVbK&32njL>V&R;FLJQZfP+>rl zJ(w;Bn5(Qr)KWC{dP zEgeZKa~Y<+z16dlbmO7E2_Dn*TUQ;z`j$aMz~1zgEUFH1a|f&#U19YsS{&wtof*I| z=~Xy-ITgYc5Lo`qvCr5_NQpgeaSgsnTZTX(RbPORA4HJvg*57_bjqT=lyU z+Rjfk5>zcAtCXG1xf&%j_DQVE>KDvHFW#0NJN~`Y*s>!qp{AR+JaHY z3u=+EPE7ivWbI(FqUbWV<@BeUzIxNrB@%($ys%-a>QFvFvTR)2Sy&j|>EBPNNO?Z- zCX@_dQ_jPZL_$N_$~YUoV);At2IY>k;z?pX>E5OLmu_PVxm>0sT4su$dy-V$s*=6l z>B!LEoX!;3Ja+?2O%%T2p}?a^H)`4$$vuKA0;!JP%om(CXV>RP*(N?QQbna#4s_=t z3sZGsf?T9qS#|W`lq`$a)D(to3I4l}mhwZ~GgIS7>q}@{C+-*p;pBtkG5KOhO1VhU zS>X}Yw>g!j5p_)2Bo{^(t5EmAf((UPQnjzU4C+@5vb8Szw5Iw7^1&j0%&AB4#)rua z5g|OYmeuDd^*{xdi{z4kV{GZzMoS-&+aiA8jyvIXr$pIn&WnIkW@5Q8h}FtQPzu%9 zp4cn2k69uVZv^kJ=FZ((sKN75MPgSJM3g0$9uX$PeX~iT?G}u*emVmMZ}+kT2TD*G z-?Y!`sklXR8rnM1r0hd>qplmlc=NS;hxwhsd1T&*JDbt0zK_F`yw z+ETA#M3_Y<8(Od^$pmd`LYD{je*T@`oV@d!3x0PY;uL)|`F507AET+kAsUV)p8#$) zQ}|ruEqbX)2}k_ze}aIAzwPFI(B*RJwnNEv@@qQc;F1LbKUnZmMS-%&WlfSw^vShB zLRt;pU^t)9o;f|pCs>{;q<#UI;=3cr&wdsLTyB_tz?~TrmAx|MQsprW$+G2y8{f@= z@&phYo>$f(=V4(dG%E9JpMv8 z#}q`87)|2i;nw;%Bj|Bi)utR}CxEz?o!lYyv>X%x43!E`CFeN0gvFW(F7fQpOK7H% z>2E&Q`L!E&Ohun?5HktkFpYxsxZ77Qo@I-RGJxTAhf;(L3{tF>is@b^~Uh|myFkoGY4zDTRX1% z!l`@9o>$J#^zB3VzWdC*ubi+K6ZMSr=N0>B#_Ro`r1#a6^r*P>6nSeqe9>4v76)iS z1GPRHwYP(zIQj6zy)T=u_cMp-9S_f&PR!#CTh-Es{G9Q5nwj^xgYq;NZ;mYMnU2zD z56LU%;(d?VcZjXO`vAPebgH!FpFacdmrT6dFMBG#dJDc{0v;N_SrNK+|Nhr zfx&nG%DlT}4|nxdWAFabVRv6R-VV_?HsyQIx%{pKW)X$s<;Dfbs{-y-R7Ck+<1}lgR|U zFP(Td^*+ucG6QMz`;EfmSw+F*_3>1^_m0C0Pm?jWpEMh<1XjObP+sf-1z`rR==mQ$ zJx@s>&ip?xQIC82w3hC||M_}9dA{BU=jX-2L*EGfRSs*)A$lJq2wGm^%>0|i>}{VR z+Hea+4BdOrc)cW%ZyVegw&%{CFP*xV(s&+A@DNtxhYaM4&#>}ciziy1ewRUgnO!w3 ze#N-H_)_Y+&qtRs&p%>}-?G;M`OfqFpy*mc!hiULznyf*S(a!&d)^-oXw!Y;*uU>M z?oVmgNsRqd*^|b^hsLsp9~}K>sy7AQBZ&MZ^8hEsJTi1%l~V!nFEp!6HGbxhz_;w( z$&#Be5C-5^%JvYMOHR3SVaTLva8WLtIB%c+)pA=BLI@;b7;_$v*joGYm1F@&3_wYW z=km8k0!~AK*4I>b{A-C0xUvZNe9YfM(=Xld+d0}NU7+{VC)Cr(rw-+}Ozo4DdBanz z;wMAfDE|X;pIgYHRVSR^x$V0LOMX`0618oj?N<)-3mAT8%ZTm>S50I6xP`7!NL_6j zBS9|v=j);CLNzb^hXAs+u)6l2q>eX%YGHr@qGoIA4V!>7JwJU&E=IV9s{l1GLRpBgMz4x z=%*P!$^*y(NQ#>PQLrCYBIw#q#a21#uMFS!M*Zd-hM&3kRWlSk)fIC6^x-Wkfs4v& z`KdpY54twm9Q%h_ZHfK&A+$eUcA)ZcdGn91{#pqByEGIcGxfh=XS2U969JKitRr5= z1EOY{WdzF2TO({7W4QrAxfU;4N&p3m5rPxEUrAZeF9+gIQCLxfO%Or4%YT?x*$pN* zTs|!^HX9m5i{;P;r?o-kiu&Ag(Gq13ngh2i4@_f(!@{q-;Kgydgv>-gM*LFRtHOoS z^H5!C$_zXj{y2>=#19%9hUQCzt!iv-4J5P-!tGmw9I!G2F-i|6po4TnXVvpriyurz z2ldbi|0Pi%;iWIv0UniYH{{RhY!6?B{2i#hAq1uxk z5)6x(g?2%p2}ApB_g6$Ub#=Y~=UKxy9CVKPYh-s1iy?=(M8gQekmWZYWSFKBibI$K z9+VHNzAxrG#3JPBMS7)EDB*H*(Aeg37=#%NLgQHK+#aE>D^-OqD52jUbi_dku@lYN zBEm8lgc!Jb?Vp??bSE=in$W*W`ZP-{JZQp?NE2G~;l@07d9(24$IDM@H_^ec-*E!V z8^tw^5AT>V#9K5nAsR*x;tf$)pcyUBp>KCz7X0v!?1>mKh`H%Qc?8svRGH~=I3I~9 z7Z@%wJh((JmxwZ-%7As4#F;SS&K$&hIsBK;E=-gW?E@O-LWwz5#0@!!CrVXiku8ac zn4X?84<$O(rqrR1x7MlcN@~h^0pAWvziN-d#o6DW?xl&krqHtsv}aGw8*V;-Xv^ zPw|cS+Mz&-qZr55vDNh~gi)d+jbp64`%t9djEBOwTw#>2tHuUYoAEQ609~}t*mR^{ zBq)v3EF;?acqf^BMrXT!)9`-(3cuj6jUXH)3Wu1Zaim3p>sYDBP6*AkEO z9%Ed`igOje_x^e!OHkACF3c z$E2qke054*!u_S}kNgV5A+tOlFtMYaC~z*q3S11RvxtOmfGU z-#9*LGdv=YeeC{=DIfn&=v0Po!>#r52S`ebN?n?VJg!)gmht6l2oV!xK48o~7Xco)pw=UeB@otGN8!uS+mw}{%cOCYNo(s&M zwHFiYETn=VLMx;xC{Kn|imvX@si9E(gz3^~#2(R$#NNxC-fMkJ5}8nIqWT134gway zN@N>#me9rR45<;q56$dNWh#9R%CC(=!+8iEvk;JNA(by6h)bBsD&KG}HIw9cDod%z zc+NGk-`ydxNg@#1o%&=^f>9;RL*N{pkc@D|M_sMqB-cAp9)KV|Vce;Y6KcW|W`vE* zVY9>`c8fVF{1nVmd(_tkH4DiHZw2oJou`7%_kzxlOdWD1xXN@Y3zDXg+>+(~ST;Ap0_y)C(N}DPAO>~7&u$$P-$sl`Mm#?=CE|(T3Pj(@C4>GX^A-(k?=^dhl-6&rYWDX`Al(m}%fm9B#Tx@ue2 zw*U(VMr?uW*8vDBioTk?Z9v)h3>pFptXi>){u5U5l6AXtV# z^(RR<4MH#i0zEjp#P1-W35-wL)>?M8Mj3tq0+p4%f|xU6H=N#aj>7~vqo1EHzE9W9+`1c#oEa}cO>?0}78{oF$y=c#4BSApk z8B%!wBA2Q=z0&}=k~npTR9HwN;7fE#o=87*K$E5<{#Gf7z`XK`loKn)YRPOhiLY77$&A2n{Erz2~ z&FcKG)_zJFC9F#?0l;|sRmdme3jmti0QHyX4r|(ywHF|q4>8;MXh*Rq zRzfWrdmP1bBE{Rva@yQhvgWjQgV>RlZdm)AG(@1;t{hNj5~9+rD3Kg)YgB9Rh9D|o zI~uhQ#UZg0PCzgc!Uw_vSjUc!#h^)ABo-j{*^=cpwG)dmdmZH^2-X5&-I>dQHJ_1N zTY{Q1{$!1ECgW-o+99lM%{h6LB+zVYvs{#?Jwms5icN~WVkHb%s}u*tN;v*!>!_oK z3AEY`EX=r6C!Dg?rTC#(3A5HJmMWwfBfbBokZKKLb`vYiK{)Bej%L~O*1jO|0W@=i zTWei9Pxx9K32RP$oN(3;iCVtd83+t!$0|%wdf+gZwTn{9dEp$^^U_;u|4|-~38R;} z-V!DuUJme7-TEMW`+mT*E?LS0xpqvzz2 z4!{}JLq@HTa|QsXPYu*6Vjxt#f!a`uGXOYUYM{0v2EwX0P%Fy)H-M9-25JwBfl%@W zYBORW%y|Q~x)=bQJvC74%R2*rlcEM{r^G<0dxM>tV|lrR(z&WSklyyWes#B5^bUy& zSB<>KAZ2%UuTZv;Ev=XidP2j+gKZnPG2oW!UAo+<&&eVeA08{!&&tvjp7X2v8J$w< zMc|O?$ADGUYrwkdOTZ1)&jIs!(QgEfsUGhymulih?n>OUbBSA42SfF2;*K0k+Q?&cPw$k>5$3lh^gv;sbahdJJLV=_%RN9Dscwo2!i7nk7V|7%*?LOY z6$wpPg|q~(wPkN>YT3RijPxnK$aYQzX7g9&SlHgjPPv7|Q*K3At!{^Rr?-x%)%O2{ zw+^Y*ZVu^~^jpl)G3>h&EOxg65Ep#%+15KGU%mWYhfuaJvr1jb4qS83^=+{iKqYgcFkC$He$MvBch74n z>)7}kLfM{6>%AH-Z>cD zUlz*t;j~ihL!7fqT26fSNG0Eg__x!Z8i~iSO|e{!#!a}Bv9FXpH4=|uWrJ<_Yr$}wvR8Ibjl{idFqV5vFhkihp{GWoUa?`K zyr}O}iGx?mt+=&+bcKsd_{FIu!ZY$pnXmu>OQ;J=XfHUHz^L|-+{PW&xVoq{Gz}VB z4b)DH0iYr6Hdq9^=G-sOq{21v;X{aZ7%Mo3bULI)his5fr-QT)vyGm$T_I;}VhMst zB$OdH2jyF8srzoiTa4afIiqS%@z#mp){qX<5Hw0y&@jYbgx&`5jeR~Schpi3vhF}J zBr^a(JA?`ZzJy6gbMQJ}l2Ba`OYc>;nwB7V?L}CI zGzV`m9@Q;pd4iBBNIW3tg|vN}HUq({yS$&La~zbA?Vdb={*@sh`#d@CkK@FW`FsFv z4nW}A>&cHnOhe#0l?thS36WQ_AR2B9AQvI>ZuAe<&Mh{+DGK9f>NXe@MKKr@MN#)Z zN{WWM7ez4`6b;3Mx{tV1loXYCXwoJm`ao1PLDVJDh)4y|hl&v+DT+RLC@Pxp`(`iG zHK!GqXncNqueJBuYhTWp)0rA7eTl+bvKT5UVq8KRI5DEqUbTNV!%)ctV=JQB`-u^i z&ZsoQPGsC-m5^aVrZbYjG*e(saJ zSuDj>))f0wk2o*F?x=Nj#`vCSb;ckha4Xw`(gRei|{DVA7YS1xC~zYCGE(7$y#W8obXZY`A5&rhY- z8n~$x=st!p&46U^HiPa^v@pI;FAZNqToUrmApbGqN<{PezIi-%AeL_Bqt+=5bs>tH z&sPVWUdhY6Rj=oGKMetsE30Y~CCa?z?*cZi%+9<%U<0NDkjpSM@2eg-NA()ypB1UT z5KO|W$e%+ElnFZt*{5yn#l`s#M(nE47B&yiGX8?mj`dWe+ciN(RPMAoh7pxt2mypw zkv^u-C8n|h?iQM=ze4j*^WNoWTb1^&e#&j4Pb>0IH_q-@%}{SZEEAC1Z?39Y>n(O|>n}t6vW4CNcYI}^!#Wlk z2yY->V}18=q?ZQqwQ~8u5lAe*Kyt-ClqYQ4pGwzJ;O z|90ptbl@hP3jr--v;3F_MHF6HRQds}dSzL}n4~jXC8Utwsut>}qN*F={TK$3PQgkf zr7#r|hIHM*4!`pk5y=blA$egTSb;kE6<)&BNCdnOhqFq?S;bS*j8DfW^8RpFT2r* zO6@3oY}j6DRlwGdsuy<#%P)w`>%46qk-1>*`nY=|K62XR_bql9`Lj`yMjOgf6@3G|hc=AJP(oWcz4XBC zgLI<}c-lE=hY^Yz#{X@{3z){kbc9z!?h2DfSb_TZs9md5>$JJJoAaP$>r4|ig1^5J zrwh4O8f^?|2gHv+ z9SZDKFg{<7)9${txO9gLMAojwRn^rvz? zBNXKK=eT=y#2nRY(1sEJAqtm~A3PtL3I)Vw3U{N8bn+Vb%R^QAgW;~SA@mL-kJ?&^ z<2#qj&E6mFR9-7#5|JpNWqjR-H6=W(9H4=lwD+F1;yurM$3pVLV%QTwjn^^G*}JdD zzivowc<>(fyu#aqYngp{<)M>EGa;x@LYr~3-D+LsEk2p%LI%P-;)U+c5fv7LUC5FS zL44c=+i7ud=juP+qIIY5L2IfVMc5O$XO~ZBMK^qAQDMCGn_}vP*_B< zlP=RzSW98Ke4K8$b7a}p2D@-SB8ZDiuHmGMlbNcM-ifJD-J>pp3F&x>cV+C{-cO<5 z9OBTQ4i$#YA&&j&P~j!yPx>K@wk{kl;rMWp=D>Wg0v!c^n`yCz?xZW3A%C1gb<~?e zoOz^^F3#*){WRW0y%{mAa4=#F-&-xTcA|PG*^~qKW&>^Kg0&dpmYLtp#&G@=HboIT z5h)5?W`^qKGgq|_DXREfC?~zYfXE!k?R%>_X1&El%gOsELT@0qKLJImKOpybtQJca zP+Z=&0cq4Um3){O8J!%Nk65IE%2Uq7$VJ8_Nw~nRvmN07zq4hq{qKEpaNYTa7P_Fm> zYY@=^ZZ`?>Sk|Z5S zKVthWgqmCl)kLdxC|Fgx5QRUBbj=j3F9Z~sQ+4nHwueHP@s(b$VVSB}Rrf52J_r}^WbpB~n;T9BDf2ENk4OwKdZtvJz4cMMXRSWqshT@+_6@ITo zUTLIA^+=J$X5?=^svly0F}IJ6?EEJp4mQB;o;hO;&U6jjgF`#k6jpayT34G|LYUZz z@4?bnv8wbG3LE2^jbVHr@#ly7k5Vf3cmBfuF}7%*)%K;ouqUytTf^S`7xqc?KAJ{F z6nTE2^BwBsri%Pz$QegYvTd#~*3r|0cZw zHKHbG@7aX-D31!L^48#H%pIjrE%HC7*4kb=TM?DeyebLg{^+z170{5gPf&ghy@RHl zeU!C%4o#p*^k3~Wl#6H%EjxSD2CNrqMeQj3gmNe9LRn{5xd-*4yt5Z5-;D;*sI&J| z9x&SrXdF#Azqd^}`yzY3gqBg{_PL945tY!7&YnrKpQsTvA^)cu8QbetREa}5i*l&j z*=H!vq9Q8!_M6Zi|K9j_wN=@px2zeBh6VxS=5WxvUmTD-M@8I zhteqii*^fYL;kngIW&*zcXh8L)R)jQimgK{V8LRpkU-T$M%KzSTZpc!W$ zq&$S4LBnViJ@-HQmnbizM*H2q^1QG+*DX2(twSxSb@%_z-?0bdp)S;odQdM~%b)uP z_9EpHnnUx>?rq6EId7-|Ri4u*=TQL-{DuAge_(%(^808S%{hDHUaSRbMu#B#sj_vV zE|hov3CgdbN%W4hds_+3$=A5zZ=>9fPDLHg?rnM0hX$R0n)1hJ2F*IVw=JP%RJXT# zPN&?1dQslly=@5j-z!q67S*H5&;H>{+F;)efjxhg_`;3-^(~>Hq;E+2vwD5`yG8at z_N>$P$8hOo-bq_?@YPbQduf~l_dn2A%Y81nr1JgzE^sVdsH)#ePWoRK9#$?{9KO}< zvg>ao%4K{9_Wpb|7vGqVPyhem{ZBmooc+Q#NtJ_Ez69z|PoU4Z~l8&sx1ig=ME%8+w>Yx7Xf)Z#$s~>`1IMV$ZW!w>M?D}QjTQBP2 z@ojJQw{}T%LM&d1SgkM~Z;x2KDgJY`bx`rvbMX$bcs158b5s<4U={zHT1%|m_eTfD z+np22`FpLtK)a-k>GL}?mfte@)mnZVx%{rS*aum=MdA%_;KnuG7Hc=Ev?dB8MV(ms_<2EsFb4?g` zb2siQis#mKf`jq#8sokcKUbfxoP$~y@6A}e`%lETM!eT!@rH<(w0K*&c%Q`L^`Gb} zYGeE`7H^n%3Zi&*F5c&&k9RWbw?@2@joa+n4Xkkvz7w6j?v%C9^RHpdyl;2F8tpct z;Nu-nyY@BOZJdbB_sjL7Mq9rf+imw0wR<{W6TP_W>UKxQ#;yB${ixpNv5On`^jN&MCu{iToYm**(=k?2fp0tndlZgov}@P zA`um!{9|H15xp;-M?Yh#CbX{?xd^(T+6|fgHLJfPvUyA5DYRcN^lvlv8t;bkKL<6R zqIh2-nisQL768^FuS7s}qaAv`e=<-~guQIB{& z`9j5+fHnHNe{ruwG%5Cyzlf&9ZCMAaPm6~pqL0PFL^NaeSz}48O+<6zX58D%z94dQ z`O)f&A}>HoR$msi@f(Hu`o@&8)>tR<2wX2VG6#`EnK6HZu~9si{e?T7#QdT5r3Y%A z`^9ru2eC5|4U1>9j^bnNzqlXyiVf_ecyEI5I)c2xnIO5K%v#9e0wNBGed4CMG4l_{eJ`1%@Me#!R7it~np!R7VYX26jfBnWG zZU$H1idY;{1u5B%&$tJmzgIY!WzOTrxIq8kjRaW1KdoQnoI} zZsV*m+AOfi*lEm*Td`iE#x>3ue}vk%WwDd}*c|c|VQFI{)V}qJx6m}|+|1HCO z4uLye!gT?ae~b7iam3AtBPtG5oGetF0r3geQ`EV&IMWvAV~aCmab_(}(c=85eodT< zt?2g<>kiX*vEESex}f4@q2lDA;&emB>4AzKu=Xn~;aN2jiPPy>*D&43+00 zQ1RD^kFb7F@mrzdw?W14fa>3+e#Ff|#qCuc`>ht|e&e{YXsoZZc^IQ@=>Is^qo{Lc z%t4LY4K;3$)d%J8=6W=~W}FgF<@zzsi-&O?7*pE@rp1eyAJq7*qUL98H=b(jFlOsR zUPC(sj;7(ItgD!3+_dc{RK6wSoN?Z`VEoaz2(`{j)_>XTGdtP!zjNT2ao)K8E+LOR zRDIgGXl%*^_8Etb?;E3C1JlM+jeT$@cq`O(TM#$nI)}P$?-zBQL*+Sc{br2|*6v5^ zSGSwp=ZslnKh!t_Q0)ex`i;wf3;QW*zT$Dbp6nj%X()R;l)c;Rx0-#}>=RZm8IuiR zyn3j0YcjSP+hI))>j0HUCsbZtqONnOdFPA;sJN3*`(G5bFM9+wLydO`RJ?Vf?jNGg z8C2X;p~lHUUAKMW-K@8G3F{;t!+lfnwq$-#=XM5a+>-TMf6vgq70TW&UPc_a6ZQL{ z#_xw3e*kLyL8y2`#%IhwZ1qvAPe6_H4pe?6sQbp8wM*?4=Dp6?Z7dkajPDp1jEmxR zoX1Ax$2_3ctFh6ZKcU855RYd6_qP2KbzY65#@CE<#veuUToR8V{yva(tQWQa;yU&l zYCXC{UGGry%85rXAMrt+55#`%cjCTWf7ZUw+TRK_kAm3C`kVcJYc~d!*T=>MsQE?v zhCEZ^1LOy_&KavWi4Sw0#ErO5iUZ^&>b?XO?*&o&ByPif!Q#$Bw%3^yMI`pG}L&*VxDz? z%5y=~N5)Xs&7!D}=0&|89T3r%^C#-{A1cn6sJukwB`PndygoMntoi56zhM4FsJxfW zpKcC$H$aWE4l3_9sPW#1%De7B+aFQSm{56VL_POI<(-3S-wPG502OD_>{C$pjp(3o z-&h|iP7*3k3Mx)5)OdAfueW;I>d!#Md%^7E7H7izuUVY;q2@Uwa!wYkeROcJCyi&w1Y0=d-?{IvsXu zs1Ae-pLatY^(JhC(0mBnD0IK=cZP*w9}8V)bjUKH^%u5n=zc~A+oQtv4%PFJ6`u~R zzi53@bZ|Wh(ZTg3MhDmPNVMOTDWqh`As~l&o@f(caVtlS~MXVJY zjE{~D#wWxE;}c`OS7W_bW6kr}VB8eu7{Al_y~gJnf5iAa;|q-|7pLEd3&yvK3&tnK z1>-x!1>=+Byf@;4@jc^$`<51Vcxb(ajSAh5uq{LVO89u0p}xoQSMg|^IutfO^xg^^ z{!uSJ1Wk zKzwjLOXGuin#F7u5C2}&KeTSbCWYon*gHe>-S11$5kWnQjqrUctltHz6$^~GCGvlY zg(x02{MUQLW&e-uA8G%wq4gS$ONHu^?N>QYS#fzru_|jt(EhRFL^fvKl9 zK1YV_gTzC{qd1W>IG;3)gJvOJ?$m9-elL^fv< zlbOmiW^gD+aUy4MK9@3^Yq^Cv+|69(@u=%NA^v|pRW_fZ!vDvh-kFaRnZ=y2*BV!W zC5#XM$wqM*mS+X|DDge4#c26haRQsOm3)%815?>kK24m?p&TJUN<5Y`I7fcIcoDO? zN`9?)19P}jez$lp^LSMLg!l&*@}m4DaS^YIbU!2Y6XJ4=;yv-+=|Iekxv!(WCjPx4;7E#L{5>PA)dpf%#zO* zui_SNmCq6HWG;`$=WM-sT#{MeKR#vUn59#eOKz2=ndU|=B+A|DG@4F1sf^^V)MzR= zsU$*bX(ejzq9}JY>6GR=sU(Uks31H|77qap=O`_y|1+&{j74MJZQ_@z3B^% zxgPE~xnQ4mVm$L2VYo(aO-Gpvk>D0`zVo>q)AX$Ist@CN?09`Taz`+~0#1K9HEqO8`#>wy;;Zn5p#cJqI_tvXA7n(99*d>-!Udu!wzRahTkfR{e$)dRK{?VxCBfQs9QKp_u zq&ALUU9zebA8HLv$`yFoa8Jc@Pgn8K7fPXP9}E&((78oCZo@DkAf>;LBt2od|D?ei~s@sF`) zuGB|rC7{#q;oC>iu)>^)2c2a-LU3*i86Pb>Bo(``9p+wl8v;Kp4s{>4SsbX5LoDKL zN+s8@gX}W;GWr%Qb&Fw(F^Tuqh*c`z$>DV{XSZAkYN!$=wub6eBkkxY-BOfe8%kS} z{7?_JxPx7p)NIb3xchvOeaMJzy%cHUBiU*e_s*yBu+I1cH*n@#aA^a|09afgNO43E zvthXrB|{2I%WKx$Kw;=knb+9s9|XkWp}W_<>>_er#hN`Yq;~8(Aq}u zT`bSZWX8UVPqIeWcBK^uR6OvS{nlFmSb%vf!Uh-4yIEhcUw&{waxqH0{V%gPZ6X8* zMLnNXiwlh$4L#c$>AZ$;8k3k|X|^&qwj?;nw_zdJ3-Gkm=Yq@ha1tTO6KF zlzp10G%y;v0cXBf+~1I&c=}{(v|ZH*xpD)Ihl;d=(535rFYr-j<|2*igp)qacg|Bj z#V)HSM%ildj$XLhtTkSI)+M(Fot7^x--Zr^OlH_Ymxi;emKidG(%kkn= zm#T&YN9oEwTf63m>wi6^Q@F+2+`-)0EA_J;fYCD%dl*xO0cnn9-F{x7r##|!>LK^H zp=|RUNawA6-^*bc8ZiU=suQ-=#P9J(0xx1dCV}-kNWsu(yR?^Oy=g{6L-6kXQ-j8k zLHtkd(BQdq-ojc;wnuXMc1r#0)$Wad8_5KwvX)$&QbzZsFbf192^wr zYaFuMy}txQykXQUA~LLFXF{uZw$_&!8|C|9m7aN6yp+Gzuh@Ok2-fl*;AlBKN*lWGEPW!xvL}F=^qbD5?NIVOs!#bG}?Bd z$-uQmJD7Kb6|T#P)RIbe;lf4Nm*f5l6SQ*|QLjC5=qM&D zP=1uk1uKUfZe0UBeoJ7B)duQRFn4l_1qULKa$sR$`}ELj;0sLNHr8A;CXcjY=Oflr z_FZXO_w|c9Y1rb{0m?7~=hVu!Xp8mPV%w7Y2^_Q(AQ%lj#}vmQLDcXq*#W0| zQW5(vwCpJy&;IWV(Ah7OsHo6}#27d3DU@w{3&uyc=WNJ~H3Pc3UJsm#8H{l6o5c_s zR(975|LtNE|4{XPS2waFW~6?R0mOp|IL%SzHBh z#gQH(HX2h{A+x0NES0RimnunD14=6=vNM3ZD7TkN^d)G*vx@E0!yEc^T?{c*4ha?< zuAfcB_JAnN=!yys=FaLwrkd<<4bt9UVzwk~vkr;Syj38I8Tmnrr_U0g>V;Y+0x6~2 z>c<_^gWuKl(J**7mq+0)6%2BfYjPQ<2R-qL*jXFwkSRLf z|F_@OMK+^hYOSHp)d?;Z$So~o0!a*y-qiPeW#0h1XOFp?C$fw}?W;+!=gj(HS#e*2 zNJJnz0~p37AkKr!xZu1vlunXJQ`xO)UGj@9kQSQV13~vT!NfxODSwID((D+d4;t{K z(mhSus1?{~MhY|cK%Od%KhY-MW!wBy%BHE##KWP*p+X~Pq0k8;p4u5wD$&VU9TupErAPb7S+YL z`Nc;Y;ll0?80jUUSBW7=$mta_4eCsuBFEo6u%?cw?-c5zH5b4N)pcIc$3-2&A@(#R z!>J<`u(YI>m0ONk#BbpUvLM}s);ubu)idP$Xhdr3td3E)9yo{5p4K7T&9;A1 z>z;m9pZQL9;#GkemTjOxej-ohA9N2!no$y(hH<0j#+z z^#Z@8P!k`~;cT~1Y_r2M!lelRe5*cOi^@x~ z=0PzBuXX}KnAc)7a0A|7Jk{%izMIpb-Wus&jr^LPVAIl`7c4o6u?)fh4Di35>v zMjn|&FJm*TKb$2Ey{MyCGkMv>;q#aZu-i2~AXGm~d7e$Fc=aXb-@9SNY$6UkgO9i| zxt2kKkxsQQ))yA2#oxx_8cubqK?Z^i-gtb7-0l}{UEz=&E!zU+`YZDF^a%o49m8Y1 z>bX((9%8?9dsRvqgR96#psV(zt}?9q3|p8( zW>FDAC1JarA`xrCbF8RsW(ETi%D`{NIeFI1=3QSx0W>oKSb+U)cI6gj-5y?VhHmE= zz|w9_Jahx!g`%`dB|b}BjUcX$vZH0wEum#wZIiugv#AH_IF5g6iFY|ja8_BHtt4bU z)9?L0k$W#2HYLjxiGH@090>#PTx>ju7048`TnZLOd4qlr((iNV3kQIxPm-O%%+ z2t#aNC~*)CAGitWPM|P;`S8+{kS`C&d^Mi#2Ba33yjq|POwLUr{FbHs|6NE<>qz+# zXMf%nIEzNVw|bG;rKr*Ymont)(iII~40kiiTp%c|>us1Q0g=lX3Wm+14X|uQ1`LN^rW0Yizz0P3ry39Ga`^&5U8Y8}&RVvcJCI z@X#YUEs4-hTIll~ z@-oZyKwA(<(y}Ysq3D{yKp&+$#p_fzgt?13vbT;#t8@RaB(=nl;LL=bxY-oW#B#Gf zH7X_3p6Dyn97DNki;b4;LEjtaH-8SOg>ARbjcnwqi$Et)U%uVM{Ny4KL zr%NJ_ZAd&=yuGm@`|`wlRiVwHqaDmaiuJ&Om|@l;`wfvb0B2W1db26)wl1ksoS++d z)F~to%UG7{2ov_VIh53(3)%AZ_yyA_#2&vdfy3E|_5csShA2qG${}C;O3;4~1pFvm z1}b$ZXo3vYC=O1o7v6*A-Wo4(b1CDJ%c99SZy>B~Q3q~Rjuh0f%oqFZf&^~n27Gkb z?JrLnezsNkO)kFy-bYQogFsh2xR8Q{mF*A6dpVJP7Mzv<1V4k3LJI2_s7qWm!dn-y z-zg$xZT4$#!I}EmU`TfhW#n8qlddQO2jDAR?m&^-RWm^*h^;z#j@VpDkRk#;t6sS1 zGm)bvSF1@dd#XPIfGH5Ae}TgA!1VA6Us}jDB#lRETQq>vi3{8B)RJ@LHD%f^6;vb; zPX>OFXuWOvh8lLsDIAfBJW>;XXe?gyDLP#P!{ohXo>kl>!zy=A?O{ zrmlNEhOr0k!f;OyY%itD?hHkx*p{V{1Bk^FcW#bnpLMBfX~*Z|=k`ojhIf$`(Ba;? z;YUXi(Q7=Q#QP~$;BF$k>K-9RuW2&7;nu9-m~JPdk@r)>`c*tf_o!j{sDT2%J)q>( zMEVEtebW;wl_h^USwD7{Fv4c$cx>oNAG@^YdZ(~aVL*Vn>J;IMWrPyD!T1>y6Yf>_ zu;JjvV4#MW@vj>YEYg-;03XCxw3k{WSF#BL|79yii;b(;f`!;+YR^9`?A!Vu=5}ma zu#o+d9*_^D>(IXWhTBknmC z_q*88T|S~6B>PV&;ZXU1JmBB{Fy>eGA0~l+>XMV)o=f+i$P*v(t#^Xj>(sU!qVny$ zXN+hf08ON|$?vese$H9d;P6}(j|^l633jHME!!B)4rc@MawgJ0jo<4W&&zNjLgTmA zpmg=(HT+kSV&|ML*q0#C1n1YX#RC8U0{n}J(p%%T*PyH*ZpAn%)LVeq zQxdlS-#IU5xTgoqQF0MJa>R|7!M1jD~fx_@5<+%_u0q$K1& z7v9{2e||c=0J@bkM^_Nf2LMT=;Dg+l9=}5`!8mEXbvz@(GjPAgO3qoY>NL`K`*TkV1sYL{=OeIp`bQ z(06sx;ghyf#GKRO=CE^+yYt-T1}`Nl=nb3cZ;mCK3eId=m*(xG51R7OeE)uS+2KDn z^R(uqve2Kuhqhp1k&dHRrq4~CnSxE7h5Q3@4st;O5*`mWpYDG-EPW`=_PNh~*pR(^ zp9H$f^epUxXVLYkVd;|fGLl`K*MD`DwMTfZNKs?oPu~GX-}#QDuQNsZI0sW)rA7zI z*BQ6SV(R<6%UCbDWl-4GWqIYfrqQ&f)2ikE9dea}8VFRgem=mjW4NhD{@%~zfT58` z^rzeXJH}2}JGrnz#ZUQk;e(AB`noZqLNkgUud0c~_ncY-r+0dFgeM6u;s4~S4 zer7gvl85*HakZ#n_*6`{U_L3z^i$@bwlIPZ>bGi-!o?f6F_yVoaeCI2RYz@vIEa^PU~zms;vz> z5zoaZrdVeobWh6TO|?x6@Ej(08&$fL|IcZ4CQV`8f8~#>ZhMV_FYzzsZKHG6zKvIW z;H5CM=e|`k@4?wGAxwaIsKG4!DolqFN)LH#f*p{cR>%Qj96~-lH*53~Q;>YLEj|l_ zmpzibmRY{--;VA6j9hy#N1Qt|H#aAqJ3jY%E_2Rru4?fq=6>>BnTIGsWF$HxLWvHD z1no1*n|Yd5g{i|_fE-UgZqtq(d)HyAHzgE`pU-6|7DT5v^5!x)?0-_e%5L1pX#SD1 zdN}Yp=VF&(3JBl#&Xj)RkC9TZ26IFMgQxVR=c-yiM2DfB{HUzaY2pH^P0 z4&M>w3hWU4dtLviV}HNuDmMJoRcJbV*@$5|&*nOO!j|Uo{FXv~TNgnZKJ1peV)_wY z*eR(oHhJpyO1rcWz?cK?8@kK?a4d+UwJr_@&1=tH|71So!-d;K++EL~dVCG90Qj&Q zL6=qTI+b7l@ytE6OVDAFEy5CcOxgFfJGrBQt{pI-8jxMp9%*_LpzTVOv z(7_kil6~btNNd|;)Z<+}M=UbL`z$hCc0+$qQVUtW#6ZQf+gAfJRwwSie78)qqe?mz z-zo<`!n@DIpKp>ZGDLsc@|%Evjw>VVf+`EC$5r=l_-ya$v$h`oBZfJ;*gI|1pHJ*I zfOm6buFjx`0AVIXS6=k)FvV2B0`QSA>Cf@Xoc_vwxBgJY?9cI?=0oi7yY5g$NhaW% z)D!NE?3#=XS()uS&s*mAIf&Pwt^}gS`UsNN_3+Rz)m_KP2gLv60x*m@O<3u!2C6ux zR8_gE3S{jN;rc%g5c_2uzB7iEl&?S!%OgM^s;yCwGn1L%* z#)*3Tb1xB(d1LaE2!Ez;4EYeU_~S)qT?*e&7`SVnJ98b!3o60H7IJ1s@&n+-an;@PH`aW7z`Ox1}rebhZ`f`#q^~S2hS@uisPun;QkGC znaDp~DmlXL5?7Xvc`8jz?d4ZF_A>Xk_J#>f`)ZqXE1LFqfXemckB0VsW_U3N!mJ05 z*U<%w{eO{M!*cvg)RG{yYSz&`q#(L0MWR-XaKiQ!)G=T0iuAxTdK78CE_qa>n=0%i zTkJ$~;NRk$B~)&Q0BgCx-qF-pumEhnMY#E{#=!1B!|R zN>70Ahs!~w@oq_C7h91Qsb&0S_rp5+=;FX*_`t|i-&0KYFKr{5iZYmdyJyp>iueP1 z09EafX@SnkBZzZ__uh}+DJ@gfFTeX&ZP*v|g)tn6#Pe)uA_r3kxf|CKWN-SvFz3o) zRj7EQUI!Yvr6l}XtH4=NrP-e8iY_XZKeANWdxJEyn-83wC;H;SsW4aR;`v7_3a6MulH~C&(**tOv zM<~7r%ileoo2t)x4)0&ZhZ!}j?D2Jb18r%xvufTl*`(bEE?zJIGWV=m_3anIQIVm3 z5g;x8KAYJcu|jv6#6dM1&Bk{yyA{?$r(zg!E=5q3lUaLOAUThYF4iW@k-4*UX3v=z z8jIL_4?gk|KYI}X#?{H8kVx~<$b>{bg|J-6PA3(w6N(R!ug6&8}GqTm2K%r4mcunw=OD$pPxw zvZJEWYy-8;0_hIiiew)-->q5+j|x9j5`NPO;jhK})_ZOj3s|RFCz^O)11O=qd#-Nq zcFf34DGH$+B*2GvPYv}!*giqpih`>X_l?I(XNkSR z?In|FfG8`y$cZNbOu#rmNR~h)ozAbqgRn!#73DW4NV7!dcKE;v2y<(k!I*xp4RPez zRCi_Fx~*_P4rjUH5ly%XTUhBea6zpBU6VpTr_#V=d@L)Dgk?WAVrdZj_)~-7fN#WA zXa^MS2mENFl7rm!Z$gFC(8)#5Sup#q>QuXd z3Vyuc8o2Cjdu9bWOZ0`SSWjD^e`fYPsq48A!#033SEu^Synw?jm7z0;y6$QtHVjVF zp)flzJts|JDlrJ#;{dQa-gB6GUepp78N@$p?xQDjYH9w8(d-o1=&Fu1LWrDW=l%w1 zFY?q{8o#23oo$Uu!qS_FLy=R1AMnEc?hy|^k7_d64s}D{C-VQ1JIjU-=S=l+DYP1| z4d{Y8mK9b9oJu$NhS>9LYS0bBipC88X7HK8hT*S{-#0d({e1!8&9=FRJ@nbi3B90; z0C)qvOe6p!>~RPdepFt^1neN*n`do{47A~e9i~_h z&BqLW-x>;VhX5|ry&&0UYVWDb-LcTLy#sj=H**G1x0Yrv2l3p@M}C5`e^wCh1?1k+ zAGR?X77>{QIP=z2PX>emEYEKf5UF+FH%^fjYvC>y30s`w0m9NcP6U1%C4~cUW5sHe z_f78Hzp!!e#*}nBwm03n&wCg5YwtM+<-osywb6Q{xgheQU$|K-A`Z)b0Hiqu@Jett zLy^_M-=%N{*{NqYe{nV{SD!T#R?pR{ihK_jsJDh`15~c^%L4&(Iy^=5#nN{E9VQg{ zEiyxAq%9YHPn+P7x4~fk@0I&@X%0C(1F9a0PVIhD$IM*p#u8aa@w`}*@U0}fOI_XC zgv#>(l$c1{bb0ued^dk;B;0F8r+TOX7lpX&7j-r<1e!Z{1)zv*?I-j`Km0d8WYi7l zHXNC{RCFXx@@i{UTvRx6G(>Z4<{R%BNGx|t75AF?iR)B0o=JD8W7y^L;q|lLz-cq? z5yNNJUj3WJm#x!W&$3~8O&YE(e>0QIQ$1%P><+IhQ>Tcka6meE z5!0`=NWc6a;~ptpQfq0lvuZR6Y|+a?0b1F1XHaI1{LV$s08@}#LbFS4Vkf@|K2QJljiORgcvL5~`8xg_f9U%cVpq~Tq? z+v*kYlc zV1z(fI>%dROCZa3mm}F4EiDJ5TMRlH{{?dc^+$BPX3VO8o$ELRa?l3eo^IH5f;#)X zlJR%ie?>;FHHd2OQ8^3iK()- zUU~-%yZeRa02BY4$B3-16|Ms%$Nw^{atm~&523ninZO+Wo3*g}n|KDI&osAVH-;Uq zr5lAF4b@EK{zKXQ5#G-sSE?sxI?M4ly0n-hwy@%y@w8L}mZjoeG;jr-n@4!@coPBz z(tPC2){rEvITt`$i;ddlBiZBY=&EFE|$L^U{`3<&eaGl-N^H! z;Z|!i+W*1rj+M(|`+dr?j>0N0jejBCfQF54mjw3aD;jT4Ixg9}W;Z(+Hmhv_;X6UY zj9fu4>$dQE>!o6{{uNMwZ%i?+K3@Ao8Tvf3+SmJqm|?MYaliGRJyS0LPxC<4H)q|r zHB9#Jbv?^+vl_sw{%5ILpDm04^&YBjMDT@T8F&s1vOT8>GO&Q@{oy5s9TFu7xAa4V zCx)1634Mt4{ZmXgyf6}|p+`rliu)4*_xXSGCNAY~^?SZ7bkOYC>g(ZMVNn8v!Dz&> z4%9au2@Zg8uHprmaQC~1G`G@DV0($ywD0QJKu+l~q7&e>-T1l7L35z$8;H&B!z$r| z_e|_@iOU@-EGXjA@k=i*+xHgz^82aQU#{H!e#q~S#k~a)H3cUQ1@1KuTpJ9UUWA=3 zIkT3kambzxl5P-gEMcP7G39Yol?q*z!s--Gr7WR?Gx8cw88#jT;uMt6hS0K^%5rYn z`D9bm$V=X{7%crJq+i1P{l7NURJ|Q?yX6}^ca7R+_lg#^6v^I(pB7VgG8%UVM_#m?c@|wTMqbia%_5sHov1a{V$2=9& z+Xi$Uxa0;SErA^413K&3pcXf0Y&`(z*R&Wquv#}1nbG77dUE~*CqAg<>t*iKx}nmE zhu0=ZB$1VkAhtT1zg{Ru8=6L(cc+iZ%r}rO^aS&_?Nt*$cCexjP4|g0<+iBZZGd9o z;A_}m7RS43%{U%2IJyXEL*0O`Ju=0H#NAc~;BnkSOjV9dm%{}JMnKdtOummGJbx(# zSiQeT59$J-3hl2-j=8BQejbMo7M=j^F1m>YWWk=3^};PCH-(fxd8zk4p4z|;BV-Po z5Jc|WJ{AvRGv`n**b&S3UgBO>(ij~sEZBWhiGS4Md^`UW=26agd8G?J99+mj0k}#Z zhZv2WR>2+}4ah8pW$l)mcSy{cpg}72W9}2h77;6GfloTe46PM1lcs z#=R<(X2L>DGv};FhU@ywF%>}f21BL>5Obie1tc1j-2!Nz8XSQ-AfgcI%gJ|PDeF~z z>DH_(bpvDLnLt~I85j_H3j*6oh_cy?yJR_Hnx-DmQn~?IWNFJSEs!QaGlo=jvfiqerbhX-?1GB7pb zz!*|JPrTK3S-7!9vw0h%(V;?oqKg4ApU>fgSEpz|J@ihy(wUO+Ea1T_pe;w{uAX3x zKx#Onw0-PTadg|bFl0&S{;uw*zgFTEgl%mK_7123g811o+Ny$JQRZ+k)O)&nGNAIr zcvi4o4v_ol=m+2(r}AL=uK)ltUig=wlaqx`1Kv~?8+F-_C&A>z0RjnX7XtV=Is41U z-My3Dvc*_;8bY=+u*DEMcg&mX3}+aB@hbQ6#KwJAEjATRY8xmQppXPAbs(XFb|W{3 zwp#Zz*Y(~8jxm;*0ZJK2dlfy9PRZs66t7MYja>?Fz}X~px@8~Hl#+(yt6_+2@l~K( zO>5@5xA1U1*V{yRRG`0fEAr!>F8>v@Q&eCV<0E|VCSS^7yBGo2YO!`L4dzn#9KO}oP8W3DZ(syK-p1P z)%yU_$as|-xQqn)vVI>eT;gCw(x$DolJkjSfT((eB}|&40Y#X#PG_D77^`;6f#49$ z#0XPtuWfrlAb{n{lImy%~jtcRNG`h^pZ;+kEda|q(VNuVeVSR|2;(e=~E2!&;d-9?aEar zz9A-ixk+0+{un)BCjw>i_Dl1Srf(OjvOhW*%9*Vp4x{0;6H^REREIZjl~OE~?D31d z=7exvoB29dSgI(uB0uPm8Tty3P}1cA_lqa)-vpwBOMZ6yJz??)Txb!8*zP`(x!CUm z&hl)}u#mYnR0t&m9G6?yqc>5tECR6rJ&%j6idvVm%%-~!TMq$CPh0HmGGe`lFcX-s zyCp+mK$iHTQauD(!TMZEvgOxKDpit%vnS))gWf|AA_B_n#?H`v>~dA0+s=8f8w=0_yxEze)Wv?aEGoOvWvEPydlU@-?YKcZYfD^b8HoQGOiIq zG;^EY#d5N_6l5OvHSN>%;bl>>`pbkO>U@olCj{FXQYU;!qb6PGg4r-r-dpY9zV=b) zV&Ap0YS(jemJe&sSP+N7UfjngISV`xge1Tyo$?!IM>y+M7984KkBf4PJap8qs})YV zBu}(+$6d==cs>ox_H_FV+K3;CeRHbEj22w<_JnsCNPhtbTU4gsM*2lLj)J=GO+Bo9 zpA~@kWnI4-$kT?@z-hLGGHC6&mmMA()YdPIuv=60iZS?C>B!AeKG31yt>}KO=5i%< z7vcqO0Xg;}ZYFe-QSw?Fm<6kVWBMCMVHY|f(Z5oyog?%XR`WL!D53;e4zl+181kv| zvuu*%c8R>JTD86A$E3$Z+U_3N z?VG!4lEengx6lm~+bV7+4f{C62v-BYq5_YGf;RnVNkttW^ZZm{WXVNbn(}qXRKq9Q zC+DRiq!7<&J#4?^)8n!v*k3P9N5UV37)kFV-}B1r5SVao;IBy_>^~uQb?_CI?Ah;D zSH<>GK_71ezVJvB{eVDC=xW-H0NAdT!=RTaH+Gi%NHG8VT)~;Du*dJ~H7BxeK3qZaupFtm-SD7o;ZW$I+wnFoLW8h8%V$=_9nixyMCiDTj4+Ul2HkyROzRKAX<# zd#_@B1it%2>Ivr;akDn7eG12N_oKx753oA~J88;Sl#87qc1u3U)eYEb>fz|;&NI>T zm&SkW^tE$WZp?Rr&*Ao2yzmjpB=7VRI+f;2zEIZNd12Yo#yPhX;3MyQ0#rJh3!EYK zcb?n1T>l?%<*z;)Hd}JuEca-?+dwt0U!N4+TmOMI7ToJN&za0Mo>x!4pn}+P9{n0T zMCoy{rNWal7S2r91eNT6Z&l&%*|{a~&$ck<)#=5!X*)C?$(21@-)eI;_{OyMyes+# z)seS1e-3i+w;PqL++Iybg-*XzI{SU!ppVZB^zAgM__Hmfdb(~wh%MZVtiQBYI##P!q$!DAr8cGC9=NpT|9`)VY+XNG|3fer+4g*S zHgxkdRA$1Ac_T|;UtfzSUFiJQuFCmnx@etydXt{h@DqHuyEKFAPbDZar%o>&m*ztY zJO-cghs3+kk3Yc#qAu=^SOJ@6$_Fp}!ik|03jG~8QDepwkiO9E*WmIzv4)>>m%Cxb z*pI3ciBU;w_Sj>p*y(+n21I%Tc}kWubz}O_X1Jo5YTu_TY&`;6+1n-ZY;Nf&V0r7Ks`Z&R)z6y)#fF!ll-4Z z55f}t9MsoNP)E7EsZ0LG^95A)bmLF4jyQqVIZVT3#5EU+I%N;mUC=KSM-eH+XX5X$ zY}59)3NuJ_&}$L}%N(gitHp)olN2U97z*C&GgOD@W|Ls<0*0f>38OT}U6 zdvZhmOYxQkRWH+ZQ<2uz$nzFv!^?eYp;lv2I;&$zuSvE^B^w8%8c=Ss_nbBNZTlam zDpqkk6B9m6pa3Hw{G94c2^T>MoY#I{>f7)*$iGv>#^%0InRB#gpZ=`p_?R5a6GW^U zh|etG3_G0`vy?vKi*kSP+xl~?RtEbe4}+QwnX1|gq=3__^d}R2qF;ic`lfB6c1!-A zo3ZQ5O{VHAItw|%QWM-`>;Zq&ZXm*E(MMbxaQV+WI=z{Uz@&}NTXLJ}j!9vIvJka< zQ#kIRza00fcms73k+47M$K^YiyB2k%*YsN|6Dr*-*g~%;doXEPBsah}c!F1JfFG4N z)8$V%=VA|0hfL;8VR6YP9pUOfB3>vOX>=(YecyO|3raau-heuv4uB?IV*XL4g%*Dd$oRb@}XCB7~hl96E6 z?$L>QYIaugLn>(Xj&zG4600lVXvtEyk@wb`tR(Dpa;Seb<-KGhEmFVmHjB$T^)y}N zQg(Cdu+3G@u{fc<1p9`aY1W|d zmw{6WpZ{vvN#Q1~JVMt1Cd)k}Wuvz@%-Jk0&s3XIV1@LP?s&ZSao{&Dcl5|0LJb;ntmWA9e^Do8bl3y7fxkaC|HOo&K5*L5 zn|F=S`KK93D4mgzvoYGff1V@pSmN7PMYftvTcjgDRPe)k+LtI!KKy0Z`Dq)|qP!vDP0q6rOjQG9-u;H1;EC86b%U(9OsYZM zk`Fv}_n3J2Y2v}MA@q^iOVDXtGd=LvuEYAIu~+LG0MJd}KlKa}* zxv%-WA7i>(7YBU68MQ#TA}EvR&?CC|hLoj{x?p-(UHlZA%=@X%06#fdcH&)!hb9H*#xd3V)Iy>7_{)Z7Pgz5u%37~*`P4^gCO?b+!XlL#rRL;Z|8lBo`GwRGx7Qz; zjf9F2TmUH8YBbD|(vd-1$c^yx^@qkvgG&MjE61;Ok|5uk7~tuXvS18OlO~KzLozZ% zF2PT!rRoIb4^K$^B6h0o%*`4_6#}SVvF}M=)95cv@N~5C=Gfk!y7eW&LkmiDdJf?>yS?#u#&?C^} z)Lz>BO3P`|3?{TE8|9)o%-LhZOj}M+{k!3)Rv2V77UXa3S5E!*Zx& zMJ)nbQP^?hd-Sr~tc?%gl$Sh`i70 z`Pfd{ryJkkC*Ss;iqjvPUSF=2I>$Xy3dP&d2dI~W!#77pRTHPwKifJi#68$#Zd5>R zB^4Wk)(7xxj~gYA}@kXd&>LZB|WH=o1s8vT37%lMD3%^VOGAv7Kt`HN0I^3+7(@ zDnv};DX1OG2RVE2?6)80rA>8MK2RK({0cS2vs1#!$A;Xg%t~3PU6;El!wg*Y7MvH| zUg1%O8j`vO>EIWpQA4Ret?so(4=r2GLk~HJC9Ed)$P|eu8>~`3YHQGhDRKys$SitW9YF2~U%{jq6K#f_f! z$^@W#NVtl7rgV}dGB(iT>xj<@)#j+G5T-MLfbKmJr4o+@6g(x7er zNt-49G!2n-<&TxM4YXgIrvtb5UO)^LjkBiSyo-ly4_8%(Eb4`7lxWg!9Um@+ozOR> zwqng%Td}U(Q}N$qp-v%?&*T+#9hcmH#g*ul9ZCp;wy1O4qtTuxv8HdRzMVhVEeZR8 zi6VqdvDSf*dh%V|W6lso$_rXVY(8G+y7b*{$*ExHOnn(KqvePocz+JbANBY;##ESU zt%KiKZAUr=a1{QZD{9-cX`Ayg%I@nFr~!V%%@5bCJR>O?wj$Hk13yb8dJC0~OIs!I zDm&ZkrfpW|xYF?ucw4oi0PEQrngzg^q@0cWW=zwk(2J?Dc1vSpf-m?{VW}@oAt^6! zW(%H0t-iMNI5`akFwyDhJvn3Av=8*-KofLKPpm-tYUwL*`QR`-H9^Nz*7HyS-B&| zWYCjWERK>}$R80==MN*aX~e*;%U$QY%m4sSfnQY_$RiVZ-+0eK>Vf7P?v1FyN;~Ie z#L>|xv#vgEm!g01pALP+CV6tSt0|9*$+T_R4@g%YE1E1mD)wO}wPMag9`f5}q@@Kf zTAVyB*9ST%H~^c&b%>qu4w@s?e$yMNnMC1OQG5xtl-5T)0VnT0H z?$5KU_i54x5Dm#M+Zwb;89n2+$Mv#l3+Kq`Q{Tp#w-ve$X7C=1&wwwvTbq`GvT)%n zT|Bsf=wow4uh?pEKi{8s0i{i@0S0|K=vd7Vba0ZlDGrs_VNSD%thMTvPLwnP~9Ao7I_Sj7&pXM&{>o~?~9~CgLHc#kSt3dd4BmI%8*<+ z6>M_E=aB`&lV2>3MN^4~&K^dvX5@w0!_Rmq)FpDslvk{!c0txKa2I(y<~vr2eSSjZ zXBp};xd^DmkB${j4jJ?Ih>xKk6V2lalLqy8ML*DeUjS#49x5%eV!Q_)A4JZcI_r%L zLWDR8=17%UZH>pWoAxn8NWZX4qhUI&A%U$3=Pr7W5$lZ+V~EHC!@IA-=_88#6!asi zXfH4+PbZR(HiRD1<)5|gqsxwv1fV*G-o&FzaxGU$>YCsyU~?3<$3XE=lR(=KA0f#= z+TvqA5~G%6&L9h;0A)*J-Dwu`lcZ41)-eAr#v#Ssw=RX*Wa2{mm){V|TtU@s!IX6W zrmx~6o36W*E)^_CTCQdR%m!=|O*RP**J%|5E)KaX?vjvOEkHS*WC9drs%?Mt?8)vr z=8z#8v^>{oJ%GXxfeo~)^5ei3Vb?}yC@(}y7~w61+wcxx*)OM9osdCIFHu(o;jiJG z))iDzvi1k$Uxj5fG}})$siibpY$SX`M;)$70Q$i9I0M@&QQF!P7aTv%ODH*9Jb~UW zaWKtZNpzE4|QA!AaIsdd$}R`o;tdy2Ayk3(21HUrer#= zm`@J_HGaulAwZl1dp2YGlEw*}K+E43$>@|YeoJZm_A#WHRD94!ybBa{vFskXENeTg z3<&%_E0$j#vOj8ZI0;+^NcwNfXwTsE97umSgrUj2Mc$lUWwJYxZB4m_bv?rIqJ}S1 z231E|TcEb+A=R8E-{gs!>w+u*d0Tn!yzHQ-1nD;iyuxY(Xq6ey=#(E)PjCS+G6HF% zhtwEDsR67Y@DR2R*IMtw$|`Ye6Xu@!?D3_gyPM#&8$jEH7jl!BMj+&%33)>t(8H!} zp1{Duz+ZT@h!b7C7h-57i`_PhJyk~ikBxdR6PX{017!GcF}!b?oY6t%NE`YTIMpvc zWNXVBpJ9VS)K6DfMMW(~_>4l-=r2S!OX0V}3w}kR_{2r>434tZ;EFeVxa8zvA@tVNkB|FRaC_fj98G10ER48{F04G)BCrl>8_y{?08 z!6ofAHKgCLRYmH?A?R=@&*Cg=BMWZ93&RbLoT*>QnzHA;#tm+siIrq2V1ud3N-kG5 zTQ_1FBvrY0SsnNW@yj*c7Ac}3xCv^6M1NaerP2=I@rkPY{S&Ms_`E6$^8`D*`UG2{c%nQA{2hNq^}`ja@X`}34t$>4d*TVe zC{TmgTc2Pf!RK+;ui(yIp?aRaj4L8Op}Ib&LZ6eaeEW`VUh}8(ck|Ak^U`nUrC#&? zR>Yq%`@L_cKD@t9SM|KF%pBgAiTny-ZLlyi?vc~X%xcO@xpueWm37XU--};;I~?G- z8+qcQj(`2vkE1(=%0JERZT4!PRfA;~I9|BhoT=hMZdFNC@ip=fs*NfT;9;pGX{V`8 zOoD}g-DiKm$I{eWZZxcSMOh$jbJ9x^38|qKt{*nh`&!W>CQ8WGNyRt(;v(TO)j2e^ zN{KlbBS|LK`w#`SK|iY=ep-DD@jzcT`C!^O(kE9^3}YmyVJpi#X|-rytNiM4OHrQn ziqJQtqGltxgo?Yk_@`oB)8w9Xy#S)Ws)H*s(2`{mpvnx_g?XT>#nV}gCfyRo7_&pSQ8QAk1N+*>Z-Ka zPV$}Y`myykX>H})PwCoyhgSEafodDZUU?fgyo&`i&@T<^OSU!NRW#VeZciuvxb%j^u#9RFU| znftG|)$jUh{!>_CX&;OWT8VS1>)P5@H%s1`JNDJPymz_lj*uxHY4$J|I=}YQL_<(4 z%Hx{v2QBQ!31c6x)QMNRG4s^4m7`o>BMtY)iUoIjeC2$Vf6pH7NPHZ3Grm{03&LzX;Ah35t~}ryIek)texUR zwZ6QmRWMoL+UHDu{EqQ4gO=xe)0bwVc!%iS`ch^?0an6wryMY*tTukwr$(CZQDM% z$;*3{q>{?6+O_+mduo48^{iQ|R|Nn|O3SUdyRQ05VX?;-$T8D6v|f4Yz(!BngQ5e* zJM}wh*4Z8p9Ub{E7@i}&ju~!+*eo9Pv#WIOF0I{~R&W2E1ann+4n!gD2>Oi&FODq^ z_2qK^h7a5^O5IXoCG)KO5BdxT`Xb9O|2v)f3KPS0_J@r(o|>5cW=|YyL|`yN+gmi?^Bst~BsfB{vBdqCm{<1{ z`J51{$L{+&m=O;QmY_={yP8zje?x?SpUrSKK`k%SHTirFJM z+{3)Q_mJNSYcTiSR`=${?(q<6@4e@nu2oso>lTm z{My6&dz^5@3IQSyoA{i>dp0Q3P)OgzlN2uxV1AXw>qmwv)3E3nR`S;Z-#gPkE_e5S ztblDgc@;0=3*Po%;v5)zwG#Fyl(Rc<7}xIMgbzP2}*aqc-6&w&!}I zXQ%}SUNNE$gQx^v5q3k!=N!t1Lju})Uu)(Watf`z~%Lk{F2EAM>Y9yoRA`bMv}hvS zK?}#OKoF@dhr4Jy1?bw9{mE9ZecoGt-1QLPa77NdB|3Gt)ZKjt3BRC=+Dl~;H_h-f zfqhmVa#Uxz%o=(15?e0`4OXNs=DE1}PI6+_=`1FB2lG+ZkOl*FU(_IJ`Fco8U2;BN zuab-y_#;pKhbG<{z}=8vwB8y%O~Ej-#{Db0+2NA)nowaPYs!UZIjO-oRSk-o^^(&t zsY^VP?JI_uU7FJ@7}N|dsQM`x*c?eVN)Ve6fw3ytLNukdNlq+KR^}v~p16UJ3mja7 z!Plc8)GkqL_T~`ZTEHEg0m^-6AE3($K?7V zIopOsAERtTWLnj6Ji>hoa@4_cWqB27zb`vyfo7~>2{hd?N-vB zC~8^>$7fA$qydS{) zOUZgUKgO5L)WKL>XPpc2*v5uaBt!Q;!a5OTGE_O!?32u5nAGKIN**izo(V$S-OD=>MAX?_b8Zgc zR7_d1^>Ay-9_I59uCg?lRD}w!zS3biUsc;hGRd)H7&Fa)Y2okW6g)q&V9uhL!^QkF znE?_cnvfi>1c^j*f6y6{Cc5lOdaHJtr13o2${Xo~OMn4oWNms6=SXGI5j z{z?3G&30m!=9eRA-wKJrOSW774LlJpbLIgkLpu=L=9T5CYGxlWg z%TJ$9oDA(JPuDSodqjZ#%F^*>DA-`@7f4^78(G+hzbDU z-v_|j(VEW5#n{G>)^HosT<%cxiRm51wpc3Uy9C!hNyw3^^f)_ARw+_pAas$edV?v&zBGg7YN@SF0diwn?0@_Y(8784=d1) zzbPHqq8-9?!ytK`sr^uYOrKpfFr8nq>H4E-k&xwBEI52V2m)LRft%y~v4s=3+SalE zexEhBqZJYfb32xU+krqB&;Y|c5oOLLcd42J^8f_eR=|2AzN-X~Y?5EOQVNdvq_zJw z6e9HO>05u8_(iU@@=TNv_JjLXQy2))U~AxcXJ#jblNj8cwJY~cObHwgNDM0O%>x;& z#JbdOeLN!+61vS(R46Ib;7{8ttU||W;AQ_4pu9?I;CUHedf)LhdWYR6jvRP*=j9E$ z&Fx4lTcQt^-T()J2#|_oCUp1VIt?yH3sOZO9y2E1dd>L|YG^HvgFkSS?A6`N0d?zR z4mhoAgo_}Ovvw20`lO&@i>27`~?qC?5JyD}<*Gr*kZfJ18WAQ#+mjQ*rAhWxAm?>wl=`#+I zpeJqmaITe7xcPniwL{v@s~FG9BKszSNA|joRcT7fe!{eAI?Lp5lq$WPQ!f_3p8QzH z-E^n!xD?{U;CP%2F6rV=T=uTaS{v83Ee?*aGr3N*D7wCKdKj9&-XwjINmqD1awdY& zQ3wwn-<8XQI-stHT(g-ww=M6lo=#3DMJ^@%iQd3lPLreiOvv`_n#gaCHXP|9-l}>H zfBLy7$Ap>9TB73qsO)`>andbicB*w@xW*H4-Ta*+GsTmQXlfu8Vulf(&X$jhx^!Bw ze>r`7ES^>ep3p7MS2=!yP1~a`o!^0-(J5O{Zph%Y*e;lKDAe^E!%{!{ z*q}Nzd@?Bn4X2?Io)-JaadKRRfb29Y(o+5wjxDDQJG`RIhQDRP}9RG3w4&Ny0v z-xm^`2w;s586FEjyE@Tf^}rt)$rU!jR*~$!(5680t#qx>!pNJM_dF21U$KK^KQiDO z=?S4YC`gC*$tBpFty=cpq|(F3Uxy^%ebmaFCgIRkS596=_aQ69^Z^v(%Y9;G09$wZ zMpxiy&9QW&rVW<}EddqI=Qaw_+z~Uw<`*I(_E^@x{65tk72Zdt_NP@OD^aBS{rSJB z1SxoJ!H`z)Vlz1zZlHRa2RqS{0rK9+$_NmdAnI%C}1B9Vmb!|7J%&D?x7+J&N13ayR;A>*yqJ+*@@>uzq&8i7m z&McF}&%(Yl-sGb!4}=7kheBCp%3l#8F>5=!s3U4a*b5@kJbn%ugLcC3`jJNtsXR`- z>{wfnySilQ6(I__;9W8tBVX?S$g;GHA+JE?K-8o^txU{%4IaZfzSAKNanH3ys*~{prvMg0cgIBH%1E zFU|DI)g3>UaOBM*t%cJ2{c~orhF2pfGb=L`9PN>M5`!!XOR?NiB$)coTcNo-y9OI& z?`4a=T~t1`0tzHZe((8u1689j0bSQ(r%2BkSlR7^(~>ZF^W4o^X*XtZC#Q#~l+2o{ zNp;>3ep^8$7G}7uM)9{z+l@F{B6S0Xr77WeVbajZT%ox*<)Ai?yliAU9_Qux7 zCHQGJOB=!WdOi6<`B;5e{qHKl7D3WOM%j%}IT?qrX32vC^-`kjO6&K%U8DKf$_CCK z|HRnrpklL{RVYASGievl7tbFUTUmWK_x_%9zA8XC(N}G4xW!n)eHexZI69V=8V*D* zZBFBCnvi8sUZqbA6Y^OrMTR~<*$77m9FM}gh;T(LP|v-!8gaY%0N`gied4pZ9e>4Q zI(I6I@BkW+;pNEwqnD0PKi4>91%i~WG7`C;F~JD(@f5BwV+PQG+LD81O2^iepg{QV zp-i?(%$)7*=TE%~-faGKi1iQx=+jXJLcHtK&+yb_To4XN{k0lS4@8k5T}<(dkn{G+ zh@>jJde|>?fdU}@IO&I$g`e| zj%Z&Q-BXrPVK;3H=8|FA2dXA-L28iFfZXy*Wu$^j^!$}7;#HZNR&%>-z2~uF%9;R+ zon0R|}vTm=FA(>xvW$)3-43ZEeFfgZ|LgNmQ-WsViF!V~Eft&%ZOI>IwmV-%80 zq^QBE1tq5}CpLv`j>NJbVt|5#gHdt8HV48WC?%qz z35lAclW^}9(sbRmUQH4uvma_#COlO`)|@CdQlX1I^4ZHz@RLRH4&%0wKM&C^i55S- zN_@vW92zl&4fYNj_2zk5&sQIK`@}$#ZB`2~2`~k74ZZ3b{cNraz1r*3h^7TRfy`0r z;|p~0f(wa!(MfI`k`NDM|3_O*a#+m@3II?B_kXt4X344R2^svzA+`Gy9gJ)l(kAlu z5;6&t!pevsz|}~#9q^mtp#4BuL&~_kr5XkOCJ9rDlE1s}vx1e^-%|fv_>``E*Ne;c zSrq;zfYoj)N_B|1iN)`Sj^3JK;|xY;ekizwCgJmA@1lev*rRnjPB8?G3Kr<3%e# zp%gLikdbegpdmT>lQI|8W97ZuJJ6l=A1dgOc zBQvX6RaHU@)z5qB&(er>3XSC_r3dso3T>J=hVHO2JAdO-VD_R7WBEe2>P6luGN~}4 z*zOI$nY&N>%|XXtMeKlC#cuf)+lvQwZhumd-0K~26Fk2rwcdpKOz4JA!{fne*>{>$ zqD^|PZf@UhxdA^Om4;Iy*fjLY$x2AR;w!JDZ(cq*<&EbG(7lZ3SgjuInQZsM`^rrW z#Ymb2;1jsTrz>RL#5I)G-?q1&5lw9cbNoX3!Uv%S^0n=`l+U09!iXi7+dy4!(Rf{t z=$fT{wMyE_lcVwsq#HSWfGEs;O_UH6>J~DTYw=8 zhe}DC%&ZHa5HN`}S2HahGf*+E{Ha<$icdpTE#=to#BG*T^#J1{yK%g1t!)EL#nQ32 zb;~Nu%$+r|7b3w8X8|AF9(cQ2v$*HC^go4`c5>7(=<-aqJ+^{NLVpdZkN(|E&14n7rQAbir!L{uj$%E&Ta{{tS@zAt@T@TZ4Ud z80L@2w>szRW!Y$XOmhnHH|x#svfDpL#pktKo!}=6p`~Pl2cVw}O9M+y+;smyPMZ>G zW+W;!4loqkn=1~l+jM_gW*vSK1mBUav7bi-kWE+yH%v|GRaf#M)4#5^1NDMc$@v5>N@0vk@B%zEDwlVMws7u1uPNlC(gn zm{Qpc=G?2u7JP22$f~sV*|Eugczl6M&TZ8#Q*#f6UYjt|cv_0Lcyh^~Wbr7S183>b zI%9b+ZKu{{v%wfz;YF}yo`7tR@tf8=8B_T~bZme(zKr-F*Smh;SmR34V-ww^mHOUs zvnCIIRhflpM{)i5&*7DQw9A9ZS%1^096jptKGLCzL17e$K*&gEvm<=;*d%3$5|EM$ zlUzuMiZy3Q1iNZ4SP7pIP2rDBJ+uLSgpYd9I59KH9lEudbQk_Z59^8ovOJscI!gG! zi4bUQ{{$NedrsVHxY;Aeh!>RUF zEMs!B)qdOVXnOa^qv~o3J=^08p*~MtUs2M%Rcnzfnf?cl{c>&QE4+EDorx7_(-~IX zno%EU%M|yu{dH^<9JD3W7hUhu>ZJWOhr!sbiF+pfREy6W8@VPGFhlwSFrHdYx+Rti@Hy3SP@)Yqnug*WWNv;zk-jl0I$n?I`xf!nkI9wgu7k+Fx2^>RS2Gk{l zm#(xArEN?c?k;spXnX*sjiKB;m(jGd60YnHSWbVVDVoiFt2eNQrCJ+Ik3$!?($(9G zY*MZzW@{W_+osygZGq0!2F6u?qsezDCsqa^anFj_ccP%#7ZW##PGHXo9-I}7y3loX z0>tQYdcMw`PWCV}q*($OkJA<;Y*i8H9FUiGyp~z+pR!VC%@?9o9$Yu*ru^{r9l45D zhXK?x!oB!Q*|z;MimN_W(ib`}?3cLPsi*W$rqIvJ$90Y-YXOw1oy(Su)Q>$EyTvP3 z!8Z&e-d9s>e?1tzujXpO{cnzQFjj&=d9XNa4s3#r@Uf8*ZOk zzJW_!hCdk)yLzA3HVD0$+Z{T1E|Nu>ktk~HVt`! zqF&!S?g}OyHq$sttB|7>5xZuv!C9pJ;M=ztxo=)nTPevATK11Ub&v13BN&B{x`Tde z&A=n@gez}UbR>Y>x6tkmXoykkBR`jAzIEF2_eD6l(3A$=C0w~t7-C-FVnnn62rcKg z@eu7`OyO2{%$ZZSuc?&)U$6dL4Y7obY{2ywZmgX3CIX{KK`WoY!e-_4Uq=WZl8BlH zz2714Eg*c9$!j+@gk4am_X23w`t_QW<>oCUl@D3w%+ihK`HEJOF}&Z5q_}J&k+H1T zVO7#;aY+U>H6*U*iL}ja=8c3!XGp7FYFjcoG-kAbBzuSS1Og8TBfAyOVAJrgTkE)= zT&_<Li`qRAIN6pv_JyP1^6yy0Aa~m9|1i*Q5!vK%9mamBV*kRq|Kv$ zhllO#`)~Di@n9?mHv!F{3mdNZS5z-kHDGyRqA&s3xrC11ge!SPqyZi#W7ioGb85G8 z43A(adI9?hn^OD&Ie8-p1f>n}tnp(>m>2Ze!i-n`0!O z#jZ4lDOPTL3yFShoihGd`1}$uNGaXF4H9C*oT1)$*m+zzCW6vZn;r$w)3#E;TCHc! zjwJv@Mf*<)Ms{K~4k@lPe$Ka0XMPTCn_59#_29O3SkUC)4&EAT$r|abzgYalQ4hd6 zC@L1CV+^++3Q_$#$2i|$oa2>bC&Y>lNJCFgz{;H;kHv*%0avYNlb$mILx6ZRmqnF1RC_O9({amZ^p!WSz#=4_T1O1vl#f z_;)Zh#6c^ovkFTZb6&&poZ5~6Dk}n1M&Wmc+`BK2RGbA18Ds{~^Amy^cGe3f{*04B zak0uRAPD(kZqSTwj@vUMo+col?T02T8LeuZ45S-z0y;lG#n@W zWWZ)6<2y1UB_L56bnz145|zprYU!G~+EemvFXcauVkAxn7vh`<=lir0;@uy~@gA?3 z&>xIGbRY5^HoICP_sM}I+^ZjuOI&sKQ*Xd3TS*KMt(LW`K3l8PwpzyT*ggKKU#!fZ zS;S_&6momrW!tx7f>HyUGEd^200O z$@%8T2tQ70!UVaZ)}#^7%$WR ztk`N?ntf~n&?qVcWHL%ut$1(3k5lekoO^w>GJHs|Wh`^M$xibiLs_Ok^L3$~lx}wQ z+ADkn0n8BSOgj&hs;svw4`{&DkCumca@u`jceNUISjXKN^eF(M7p|xvk*j8quQKTf zy&2sh0z_6JXvIe|21rq@kG^K>+NkDU2ly?qPteu~g;#r#;E?u4-G{47~{pA~+I z`!p4HI|ByVML}#7efhCuCcn9B`t@+XdE4HHyLzTt!GXQ_V1Wv^Dtw((W5>BX+g9}G zK8;UM!3o^@M@#&ncf^)4*dts9PWd6KdYsCiXLgwA)&$sE#D|OYEYM zMFH@kTt@F3w)Ul8+9en52QL!`E2oSj@>@z2fPJjTJ~n7ifNw4-X|Aw$@xbZc{Sv)p z!L&5+Ob1#X@+j}?0a!x=Nc5aN(|{BGM{{#F=jY726($nj$N%fOw@|uV5=2Ykc7^+i zC;EzbLG-Q_+JM^O_I03~w#B)h+T23;W_)~b6sdF|g;MZ~Sw-|X#!g%XX@LLGi3O%L7KL0#Q9NytYjZ4oM zq;*Dbz7CeE^qhKNq~&04BSdIiYiim)k$8T(zRqUW8}_liD|CC16uq{|u;i`>pKy;tM2ge%K6VHI+~A)#pK9lPUAP+O_H5iP zbGD3b5MJ<(GlGt#n$S6VcP4ACsDlohEo@cE@nzI3e|`lhG0k?OtvpgS)PYM)hwJe` zD7X;7 z5@g2ko|4*3vpDx&!SnL7Nx{`;=`tJgmcp^=_mb8dPREx3aPp*w_Rc=t zp=1bEDQd-ZnLAaeAX@HT!G0!mynn_Ekqjee#D^e>6N$z!RM$nq&US`5W9ctF^bb9~mL5Gh z6Gi5Pf_Z1?XmjN26%;DhRL~0^%wF%dIxTd!!gCpn7(+)jvM zBs{2;8>2jfJS4gxqd2OOaZudbeGx^PP5^i0A4vMalBhAz+te#)hIXKv2-79xux5(l zo3`37yo6SNz*H4j$xOwI_iNE&3`T9xJ9y9tjR`O|kW7_3sWY7njgqJ-Lobqzin>>C zFXu!}5KPijbU0$6(8XlniQxmO9ubYwRrhV&jn(jtVhA>xMo_jQ_F}NbhiyorjwzzB zqM^&KT!hS%ALrG!K`7sIbS%40EK|Q`Wr&t7q2{hp(XhT+;(MJC-!UO^Y)xpyTN{_V zFD^m84QA%5gQ+4rm;s22(;y zOm4F(vb|=>qP#7Qq^HiME*Zj*G``qt==MG7*L>Ue$(4dn=`%esWOL1ze9mT6cj_nT zYq2`ESY5}*Ye$oNQz-|}`EY9-5MgH^*)*}YY~6?2pmjs5NTeDE%HN!SqQjLqZsVdFrh4;g$fN$~1F!?@x?iT$rBu!En-5ET zY&w{O09%uzeJGIeAs!WnEkhx?%0oGYG-FAFgM!L4@%{9R;7^UdmX&;u^6?rOZ?6Tg`KV8Rbg>Nk~ z5K*549@72dAsQz75z&Y2b3`MIOCGMIl5lzQY~d??=rr*wd?Y!3NpIsgtl=}NO&H_Z zTVqqTpouc#Px2Q%VJKYDAt+sWsNoIS=EI*cxRO2GA_G0V;u#O00hZSlF*tcfwsRBr z!q)SBA_rh>#cp2Qtnj~^@5ovqs4f>C60fs!)S$?JWntdp z*Bu&f00ryM)XQkx6S9~$8)kdB5*VLTu4pvasMj*YId^bkU*GNtyq$$NZa(@OZP5VB zXEBea@5k>g-%e!`(V;~@S{mPlJ8nkmr}|v7QRh>n2FAS)7;@cRrz~*dh~D5Z*LXEN zZ>mjeAig+W(TRGv;BI7MvlGBwg-l9-r>QsLxIayh=ncS!oT_TIVym!x6ZnAW>U`meyIHs6Vk1QM;n@sceqd0hpT&Erd1RlWN3D8zGc!h5REY=2e z=_9we?Oe2#?Fdn#o)~L|ByA(tU`^}oR$+eVftNmZzz(dMl6plXDGXS2MG za9LJa5wYI@(S5;$ZZ}(DTkZHyT28^4>(s8E_VgZ~u>!1UT);n+HtPd9Va81UiD`Xg zOlz20ZO0W3L?829PB&0FGW^4{{R&j019xF9DtHvZu9N_*mxs><{uCEjVC81Tzh1*; z&y6>2gMH?PNU!>X&xS1e;Mq8HdUK{}%}wqM8-LU1-|7Q@C^ViH>HHGr8w7s+a7k=? zf5%uF(x$TM(G+o%Ei;yx&__JYyaYtI7qOMhmYHkl6bj_U{!M-N#@o%=xEvI2<3gR@XD%(h?LZouzS62n~+K;Fol+o>~s zYVx@S?^cRsuF6~2YlOLaPQa>BZ=Oe?BpvcWn7Dp=#sPKNJ1{xqGn(McmF0z?fQR6P zF6hcUYLoE#R6ChT77`_vs^v$WH_0y+ruRBhHHvW$)ON}C5Ip=jhf_l{W~R+qU^>;V9Ku;8Kwd^{01q7%D6vKd=*Y9LBJH74p@Y~2-{4F z+q+@7(0<+y~2$lY!X~YMpXEs}nYxMtW5LOyyFKfJw`> z>W|X~?jNv?Iw7u)WP8Z!!<@H)TDGyjgq}imL{q21n4TKG_vQDAj%&n8Gi)CXyS)BDTjGtU;^Y4f9(7xx}!45=)gnoDO5~-@I z7a@&CqPPKqZ9)0@U7n1+w)FRmUK<)U*V6dS+L&O?4eZe?)nbEayhE&xzB|Y*qPf$n zo4_ltps5*EFzq_wX_QMRm-hjRJY{D56Xj)8G}DQie0-Nmw5!opSr#!?Bf)obhPx4x zVY(3t|GE<+{G@G8=f-Vm0iov;99Hu!J7{h@gCUt6>v>#?B&y4I)VB;h6)UD32S&G;h0H)=hD=vY8CCF~gajD`Q|} zj%uwex97b!@Ut@i=+3XvXSi{3eu~~1j?3|-e+sYA%o9_!mK3OOB~}&-f{cZ~2{P7E z_mtL*{WrtMtvzekaR(IeFRTzTTm@l^eEvYbv?({DN!JYjAqUM9OO6#opu@R+Rso?L zqNmk(9bW>F-lEqGH{UwcXS%3?pkX*@&`c?KEQJ@H@zN{Ejk~y(z35^};QF@$$wWC6 zWpUg$0n-F#2Ou7|iAw0C`?0JgR`+WMwOheXGSwVv)JmM!JzHK0wFt422g?fC9ai!< z=$Jhp>LHrram-H-xUmyEQwpRFhVRfK*UM{3#9LqNsTdAYqB7NBtdf|g6QddJ*2A( ze4%FOW}kA#u?HDzpL@AfU5B9w6`YEvQ)CWI5|JG7l85;^3LU?(jS@-kV*M%yhyp{O3LnBqRGe5Juuvz zzjHdMG~Zy(m5rRHy3x|5z>y(k&wr`PWQ&<&oqot^zcO|mIt=34E}m$T0T?3C3nkld zE%;8HQFsqEm|b}y(UYY|<~h54i{4iXwcM(iiLe4E7iomvw!K#M1s18 z@=BDpW>)d}r&jH)@Hu0^n^&wFZJs4*scM3bMY&k_ZrJ#dt|+PsvsBZ^1l{kl3C=_; zoUzHyTn_x)+1$^B@unjD6rDfF28AY}21C-eD9|7@N&^$I*g!?=D)ozaFZ3%l`zNW- z2~m0Wfl1#$lt7UnW!L(w!aj%{uu9u>#zaJKR2rVGE>0ENy}uN3#uS!O%)8rf)EDL^ zRl0Z4UW;S}ix~5A`7u&)6)CZU$Q>nH2-$Xn1W9V)pPs7V1$VslNQS84W&e?RkKqTN zGQ#w5B~o`a)EWZ8;t8w(iVC(?r=KN0o+uOA{lHzjT5=?f+Z{0=2b$$YLRgVpcGESf zWw9Yl`hh`Op0>cFg>I(mU88v`Cr#B=;!5H5CC!{?t`Fr(KAKX|dA86JNs-z^10dvq zN+MOTe^7^1Ap@#z4Mf?7hMv~bzIKIN@p0w}`$5VR)-EcHB$xK+40``mY7-7Is>dkC zc(xTvu*9@?4wPyC_UOo%o;(Y~#Li68(qK&H>6X^Hx-j-Qso1KSgCP^pTs^sAT7lIJ zX=&`Ctwba7c1vY9x%WVdH$}>nbPBD1|01|j&=vO0k405RVh zRtb-M@AhglL5kqU%0}u$TEsXa+B%wn&HkS;D9yw&QO6@i`q+@C}%q%bRH}yszI^za?=C3YmSXS!j2E$p&N`%^~)E6^Wh@uC@ z$L40&HXnO}?}#83@M(DV=Pu0w>QMGJUri8n6bi!2W0n3E#~O?SO|%|bU4e>zXGYw1 z%8(`Ne%a_Hcn(d|5uFA-rQqJEkpaB+DlktEE`A5%wIK7(PM{-{2(LMR+BL2?;<3ax z@!Gu={&Z+u;RV}B1WG=sdTUa{y^JdZLl3%5z}3=2mWv;(BBi@xW ztNFyprOVh&24=|+vZq)y@I5uD)BbxIo|@Ji`DaTduEtc>RDr}vE0dq#HW5rnOuZ=f zm?a5+AZ9yqg2VsPXr$0*W%4J@)+g^*&Rw9t|29VuPk2@kiZFHK@2>y{4oc|whzISg z`RBHx`d`(h9WVL&I@J?)+8C>m8s`t1R^Vx^H7>)^UWZ?Tr`D@|%lm{7Ue06D$7X2s zc`QT8nTJnhO9T)_BLsr_nZ9;#Dz0B!=G~hK>Z~+m%%q-F!)f#yz;QswJ4iA8*aSal zUSc$HVL~?>%eh#D-K^mP5^j{*pI&fpf@NF(*7B^jqZGTZQYy_-FzE|luTE#2nZVwr zG>=>?IA~qWywlfQW9*b8(qCfbdc-AMKLB`lq>uTpB_8sUArqO-A5llQb~>^Up3WLb z#Cc$mQB&)y95TKzJ_6mg-KDJ`|%bLuD&^VCo86Y;UU8@lQ>S zLrb8+?8+b3sO(nszxk&zZ?FcNXnO-Hs=gFLhwv#f5rxdr6OIq z(2qM#eJ|xB`kbo}@sP6cZ5z8yf$zxVKdJGZ#6?R@>*UqN04IuGW6z2wy2r{H$1*L- z5m<(2VY0wCOVAA6eqjH3I#|?aa$n*dH(U+YJ!g^tkB1I^P7B?W+d{b$i*E0-C-gryYp##_{4du!Uu4V-fQshOg->fz!*?2a1 zBHPjGHENQY9ty?B3w6P08;~qQ=vq+$2Xwb)i|oK?O{HwXB-Xd~;Cn2TuPhTg#O0>5 zmD~^mA?sxB(OTsmW_~9B%WOFHa6aK8k0#8Ej^H`_5HXbw2A+E=9i*Eh38il@QXtBY zPT}fj-C>e*tyzsVzeaXDW>3WM+XlGJw(nUdn8$vrK#oeGa;R2I*k&ab&CWcv2qJxv z&LHCxmC(ccuE9U4soB}I@9>ebi1mzFd;JE3C}Lz}XYGF7A+;Y75B|3`nm`=XB0Z6h zPMWJ4UK%Jhj5bgF9f;Vy9#9W4-a!*3g0krT$xm62V+f~(2)s*T;BSr5=>FKLzm`HB>(NY+%#mt$4rPi)qYnCvf6>2Lg^FFc0|`$_An2DSHG&xbr*FV~28G%j#kzbBqIJGGN0D?@;I+RkBY-UCzOXE>h|#MOmpI$MSs5D5g_B zq(eex)K~5SwVG$PE;^{!qlAELlzhn(eFG%QpC=k0^caog6qpKMn4%*k9~EA)5FLc? zru1XQU!5{-vD^LDT5=!kVSxHK6R7K#5u_Uzw1eq}RzWi(-q=TR2e{lFmwMb))u3ivZv9Kg*vkdca2cc4_yGSCwD=ELfnoX? z*zX@&G0Xq|g%!+_RM%}5`H{VCdJdp;HWVcj8X`m-t|Tnu*ZN&FBjQABcnFC8p`}28 z{jH9pIZIMj@TyB2jx#)tHwO|qSpk@~E|9+sGka@X{`YpwUQxayrh8QwQ*KGVq2^g) zJ(>6HoZuu7d3mLAbx9q3czY8hz$Cp+N7f3 zI<;+@J{hP?`p<~UZA@(~0A2rme&Cf0iJfqlAXQvK~Zq!%tW z4h~xiZZDFYt9wUatLU(4!M4VAlJukoV4ZDg6tQ%`s7+uckc$cFU*RU;!DrB>$(Aic z=IN~{{aiR#TV;NhQ^(=Ci730mjui|yd-Q{O&4^^r@nXqd6&kuEb;rzfS(wuLNsJ|B zEDJ%BJ?e=f`O29{NES2^T6vv9TCW=Q+w&ztkjnMQ$av7UvjOV^{869S54ldeNcI%j z8pwm$46tA(O;RhOjhrAU!g-s|0f#@foodQry){U*8=1O?NoLAk-sm8?EPjWFUj|+e zo^A`%%q#_pr!E3N{X@U9?}#+ln2iD?ArZ;%{LkgZQ;=hpZ{F+{i%_Ad>@d&<=Ov`( zhrAoYuGCpL5}q4kR4p{&;-2ebO3sxJte7pjM~vW(=hP{%*)u6GD*cuVCmjOO$5|Ol zoD{Djii!DNRt&JapXCi%9M-C_KCeHh=?fG&HqaPay`t89zftILoI*~(eCpAJezek# zs=?T=M;{QP&F5*Bkpm5dvv+w!AIHg#PEJo3?|OX&+#vR0LDWSy16pq!?36meSe#^! zg{=k2rpF6jKE2EdQWsjCx>#^N-MBCd)Z^VS6ONuD+PiY{48D+d9mf(WoozQIRRB6t zdW}29TbF`ce!k&nxVL^#(@+Rg2RSBtU;-1EdrkN14DQ(T zEV%7}fs2Cjyad3z0_5k+$9zK*`V7M|Et?Q_SdMr~#|K?8y$)If4%=c|xm$dd0~2a^ zFKX+NP^%}B-^3vFnMbZAJQn%5qrz-1UtF&E8a?3z9Psm`z2JVGq3JV zoqdHtpxy0lQr{kdwP35Fd=&=6?ZbMj4om(ls~psFJ`jbt#8QQRRG71O)Dwg9mhYn- zN~mmg_nN!2WRmsLSN@FOhPgm<{iP^B2|%~j?5s@iC_IZ{7p51QW)=_RyvdI+Y4LEs zr>lTZwZ6?a(B0I@eO97sbU^PYZ#bOp_>Gn%WGk@Z<~Re9W6VVM`$fz(pDTEH6C^fzv0_VBrtuS$J7W{DoA=MmW*L>*pm0|_4< ze8@i+Nl+o9V=;{NkA&uQ-{fHvt%MX0aM+;D_v5;@uYHzDaXo@pA@i5|30e$JhS5YW zuJJu>WNhQxkoI!sdIflBQ=x5-nx^+A*X)VdBE&?(ZkP|7}v@ zsmYzUeywy;jS?y@9>#4X#-Xy1%ikVa5o(AmLT|Xop`DJ`$n0}Wq z;^B1AeOhqWq#$nKxbP0p);18g0YJJH*xU|}cYuml2^?$JPnXX(<@J-?Ew4{IqEZW4 ztma2DApIm%$|kqRQ`2KZO>1ZPmj>PUTSCsJwa3|!>z&YfE%dNExys-D1FX#?w_?j^ z_dE(mWl!Y4&(kKd%icZ%G!t6Xw5(eDbF_gPrHdGFK}=5{EY@hd=!yGyx!j-z z`{;-VYPhE#ApSnd0?O`gCP0vmjS^A>7&XWFcGh~0KeP9c!zTc1xo3N2)rWg(;V)w z3GB^&k&WO=0AtB0h)i(O!c)6&$T$;lZIz0KF+vp4%D4d`=ME{eBGwxN@x5i3R)p#y zRVcz@%X=0w(bSlMi$vWuWQHE8-ThPNaFt69DY^)h6Vx-o@apt%rB;Up83iyj_881! zX>s_du*H&K2zHNDRktIV83wUol;Zxfc5 z)Hpmo?{g(Jt6`VkKQ&Uu{P1vEa2qa{&0N5}3)%kRaI(k*wJ&TnC!D7>UFki`ES-I) z($gvv73IdPYv@&8MQ3^mog=gwoo;xC@I9vP<8arMt;hMT`d6^~MVK_4Yw~bZo-IbO z%;qZL*~?l}K2}~9{YChxaBk8Ms0Cew0<`kM)JCZpxD3W~)48C8*5}h8KaJJPfiZ<0 zb4i1DpFNa$8;6$#zMs>%_`jB6U)MWYsX1YW=UBZ&%r;Ww)UDTsz(YZ#LoPx^i!hdp z4aj)@a|tCPo@;^7&~*3GskRsAhVFThZL^i~YR~dEFL@ek-Zukkifk}lYU$S%;B56M z6RA@dT)7-ie@yujzewMM`d`$1v{Z6L+%>7ZCo2GR zom2ooINgjP#^AYNi}a?@@TYPqAZAS`-!wi)-sy9?>zPTSPEsZLOyVrUoF_qRvAyt( zmRc~3^2XdF>;9c9o^w^i3$ilv^BoP%0)C$p#?~EJ+z-UrOM}npdRP^i45B+h2i(9lmwHkb3G~V1 z9rGp6S`$XI9&Gj(dzaC$k0)c2`YxIyF?KDVq(J7*fZE_jm*aa^P*?k8aP#lir)j#9 zzpT5$y7hKQZ27LS)blSFD^`b~PFS&XGr#>G7lgdm z0~0GLFh1%FwkzkeiXDgCOWBu6D=tiq2)j*Ct+YZaH)NrIKJwuZv``+g&fa0l49s9bWU(7*$e(K!gTi$lj5W z@KGE#J0$x+bzghQWcf@_ZpT-Rrv6G5VXnUv52sXD9Z38s*I{v-RF#DnHWOsZMY+no zry(Qwe>AS^kI*zLjocA`qoa#Z^_H0 z50OG=lDzap--A6^^YsF;!9X9I4PBBd%NHRh5UpkYEM&L3tfY3l=-}l1+hVCj=?~Bj zf{<~0E-|s;>Q|)o!$H3H%_oTB#mE_))r%N)aQF4aUe{K=nmoyN;>Q(H?XkvE1ur<9 zcZr=ng%_Q@jqLoXEa5NP-=uQ8gPOe|WNbq9=SsKwwV=3MZQtYHRFuphx4o4;Z1vdW zAf@M%Pf20>K?JW3Z(0$aHKtg1a9-z(2%1#K8@Mr?Dd4xF+zDDQ3h7XyaChmq zQ4nHn-DEF5VYO*W4tKy~FB|TJw)iY&X}AXj`cr*viU;{Ol_+4It#zVz!SZmI2IxK? zAQkT}d)lXlGge%dJ16Zu7Y6u*)=tIyLu2p50d7L42N44I0^?Dn$#NaCb(td5>b#;j)d$n9v3Ne#Il4#U^@Mj1GDfK;}KRCN8 z#~*}}47!w502ZZpSQ@c?hmi^fne1-_qUla}iNwRW|B^}K5mX;ayP|0~bxA(dRftQO zS17K?^qcmc&^nGGO8kCGfmfkSRyX)Nq3e9X^{8)1y9g$tvQ1Z&7@G1{vJ)e>p0e`q zw~LNB%M48BQi;5|=KV96QQWHD#n;WUE{q6NHe_eaGD(Y5JQ??X6UC6$-JH8rXE35X zEH|bTyJ8!nqu`q@!xz|h&RNz{7rcFpp5_~w-lP8A%B-ox-S=2qV19UVCPk$-1o=aK zHY+w-G@TidI;rhRfn#zLq+6s36lntO?!n2J^$pgOa{;eGP6fUdO+@B}Rhk{UWs>W7 zxwLP5^h-z;u@>`LqkbS%ai={!$2}bnhNPhoZlNjPJi4&C9f@<$XNAMQV-OSZ!T2qy z(W=%wu3Yta_H~%uU`go3KM*ooH_x$lkcQv~?Ek%U&jzoWOZ^weOa7M`A^5L`0DVIT zOFD}lHS4%V0hDi=zC*D-fZ9KAvsg)V$vb2a>#5K8rcBLk3=Q<=r4(4dUG7pXH1e#9 zM#;OJXVV?#e^Kz83(`)gDNmtcXYxUJW`|~ZKdQXJet--q77w9e8i`;#&@{d9t2x4u zY6S{~I)?B3fH$AQA%q0!nmUdl=hq~Nf+mT+Go*RKRn-Lgl?y|KEGf-G#SpMOu=vJF zNHi%5Q7_W5Zo-jRIOi#lK{ZwQbYe>#A}OWthKkcihzP;~OQ8%Sl@bKcv3QFTOYW_j zq*h^sX&FK`DwDA>g7r)til&5NS9*mJEGZktor>vou-EcHLz#ssP{c%i%t#<$>~Vjs zc%BEadcxaMue6AN|G^BOiHcNp4z;96JZU5{rX_MOQCV$K^tSA7|4^)kGP``e3Mj(j z_?vj+!Hm*rFf{1wUC4%~LMK&lV|u^%0>CdsB=$GV7c#j=A{3qysi_{pW5sY26%t1T z=)Qhb@8L69AJ$W^whN0U9LnWDSR$Yk4o-mx58#tfdDg=SjXFE}-&gAO_MjL#_&avp zOHWd4tnoS9+AB%vY2?CY<;|vv=g6G_4D`Bru{n#y>LX`MhV{ww&m|Don!!59C=X`;@&&rsbL zeILS|9Vh&`G?(A6M{L=o$tcsI?#8cUb+fR8m#w+(hVX<1iz5xS28{;=84#@Yc~h@R z5-e7sYfGidUe@Pqv(|%q8JKV-z)R)jNmKi;i&du~hfB?LNqainWz@npVl8Ov#i`QD zm-5qJwjTbDfDh+CKNj#gt+<e68}qNStzSnW{bIuRsu_dA88&#sJ^w#t3@_o|$e#+~HmDv?sgfoU6)K{3S^ z1R?PrbfQTA-U%1H(TJfry(dU!V^h{@pgg|6%Z5lb%FxRhu&fbr#4`G&3Dr@lKysdI z|NGXRF_PRnjEG{G%Cmt>#p;y8nkenNdm0%&syi(FO=L&F5kT#SgbmKEH z)g_!!q_lL*h(gS=FepqDtQ+aI=UGnFdTd%DJaFbb?h@3bU!^Y}V5ZfXsYAJfk+x^w zsb)Pqz@&UcO9g#-t+%PRC`{3ob)xwPOf)Su#MSWRs;;m1I~1Lt9c-&r<0k4TkV{GB zXSzdNXQJ~?PvBImRW$zqOnqg3K8C!g1#VVM+pq5`CSwqvZ1aGXC`x6SGO-s@rZJ8S zCCswV3uaSp2igNLkji3>E7as1(IxViHxy=`iWj8|4@MtI$bg_4R+8X8(H{+i8CWp9Tg1V1)(%K=|MP z>Bja>rgRoN8rJqp3@G2*-%!#L<+Q+w&A6gGB7jo zpN)Fu*{;+>YSlH=FO+&*m|ZtCMC8_6G^51-AX?bxDBJmIyw z^v1T{|Gb6UR~>U}yz%PY8abicyBiQJD8Q?-U9EiIt24l2c3pW0_U@E9kzrw+g5k|H zS_*~k5F}J9M_$d?!oWZBYJD>Up7}&g7^2g|S2-sGFl1=?9ExTuxQmstK$K6J-vV^^ z?F!iYpqndA%-m1`nlhMi>)+lQE|%}t3*-TW#?ovZG6U5z(f(~@ASp#hkn+KDkdCv# zLg0t;p*N|6fIPww72Ho=O0C#4{2S%LFR#|+b67Vwn@cJUF_0J`y@L>D2)zTHo*vO; ze#fdgwh~(i&cB&DWkDd8Kv`}ZqkAxahy1>ktWVZjP$*KSc@zN_hB3ndo$x%$f_+B@ z%_IdkT1xp{0CJW(Q%N=<#t0f?Wi~-ZC=IF>s$h@YTJWKk}u z=c1xH{2XEqWxlK@pEUCGkzGyB_;(TR-D}lKc&gWZ9J&yW>-b1~@wR_6AQp$>*~P>$ zTn~~t9}Zc0Y9AQ`m#lzAfNUB|okG`5{MO5qQpY0c7)c79l=XV z)yw1_Xl*r_PAmS$B~u5T2{*sx=b8;eF;j^H6%ZN|ypBu zH7&p3B-S=HuF^YJSXbBp%q>G#iIvET9RPBHq&%7_9UhTp(|AZq%J{TVdTQQ!!~_@` zqHFPnqM5FQ;cr{G#>1HjRr?78{o%g%K}aJ%A>-uk8DP=ugbwY2auy*aMejL$&O{p8 z_4kj0q;?r(#fulG%8ej*70st3mS#4Ro2D=73WmZ)*=C?I{&x3W@=v zDl6Hh=$?TWF8<~cYx<`NY>n995i;5`6pQqD2iVzuoLr|vzEw#=%mN4XeDwIevRz6E zRnBM$MRR#4 zhV}-p7>y1HIs**?)qD^j;(`JL8?$_Rs@x%2IzDOBVS$=_2RBj;`5F_`9K|g|I&@}_ zCP&NEnI4Pcb6J!c6*=Xtm(q0f#zH`Kg->&}FMa%#A02LjQ0@;7)vr<>JQsSCI zEe$_d>#&oQ5t_MN*;i9f1<$$(4$oz)Q9%vUiR!rBVBl zXLA25Gx(DvWYRs0Kl(aFQIDlLyF^{{8#f0t=*v{o7boeHG&UOKE(KmSn17n$jn_@{ zR`i^)I~ws#?RMR*OnB%RattfLerm*tpxR(_9TCSUjX2#Mv93hF0JrTC*wQ5lrxSsf z+0n@d7Nb}EDl(sHsKGQ7FOg-Abu_|eVt<{M!nOJm5S%896hNY}?uH5!)bc=P>r${J zr0)Vk-MpBwix}UL6S5Y^>veF4h0T(eyorYlo}-JHX=>JmAQTZK%psjG#?5FgE{im# zPOj}852Ev@@>;Yul`Q~gEIk|~duVyEj-H7$bHD!|jd5;1&&}bVbs5b9Ep z`MMY5jH+2s`eKH)7XFPHJKAw3|9uKdpIXsP@Xb~&=EsazFQb?D58>B?m1H>@o_KiH zH)+;6vs5yj`U=5#)lj%MQcOHi;mPh|KC$?CuPfEec_TorX4GoV6K?t%Yp2G7+bP6=r$>GD6scAliz?B_{C0 zdDD}Shk)c1FCZ|;TPhvAt$$5cmt>>AiurYMxYJFQKfOv$D%z5qTy*hc;)+gu5sNO~L35qIqPlj=C<&sPQnyY{oH3+M%0jaa1LtJ{<_!>6hn+Y@JgJrL zY1y|>yPH4?V(Q3vJkzK~hge87e;;d%qYo9)koR=X%J-U0N^DXcu-{-gdVG3RE%OY0W29ms@Vavw5irs(H2m2miJ47U@xj?>nr*-{aHr zA|@895XXA{7;8%s{o}R@2-NyaGi7*mmmL#5?(iX=)@s@qMg8u<0ub0w{~iwxN)*o7 zntr2)6>BSrR6=yp=1|sFPU~fvg)$6Pk?$G~jGy@aMV9fk(8oe6Mo%1X2M7!cG{8*K z4kr)aDtPxAyCN1|JpFSzW%-+Ml^}vM76rJAc2TprL76=ypiy{;*p3DrLB$rhKKb7L zJ3g7|9S%hD59c!dAPP)S4PKOq!4^Q)Oq3I zWj6p={QNJf*2ECBSyH5q0)LtjcBD{M1hmyc?1mO6#sabB>SAPt2VMyZYVtOH9u9zgc)~k1%9*g<5#SClsG+v+6!xp}e zwAEaJ9q7Vdh);yJ*>`cG%|@f><~HM3^p7N4RDikecMO_kk#Ef3xw;ewi{{(E6+C-~ zi*+H}4&y5ru~3pwz8q^bHo%Pb;MFB6pRA|hKdv5s$3e4=!t)Lc4Vg!F<@u~tvyJ}* zrB@S`ZNs$ctE-?&^nEJ&oS!Bu>EDJ>DP^G;je_YD?6noatvSh<*Z4#ykG27F2WRk9 z*eR?ioKdxai}OSF$*Q1U6nJKf#kJxP3XF4G=@0Uhn5;Svkc`<%R5$TT`hMHjmbivU z$iu_{X99u)Yu&~7P-zCH4@_`f)v4WwL6Nmgm0p7Uefk~%7*jzQoEUL69E1Dz=puo_ zB5+8?@fNnef8ln3EqaR#ap1VK2MqrL5QxE)aqBH8Ld#Yth60Wv-HPu)JRYF?z+IXQ zj`?wX6pHZ0gbLgyc_R(mLd6JZf*<3dTk3zy{3gDw#|4D^m`_QaEY3dB-IM%gPPD*G zY;;x+p2qo<$o1hu^|I)Q-3Y`eeYwuivJti~d*{JuP>u*)zk3KB6ey&Am<}#7JvZ&hKh&o-U_c?w)YH^aPBa1#M+3*omr4iiQ zW&s6EO@~B9jTGO|TlY@_Ra;?z5bXPO<;S%YB`Z7ilA2{FlMO@>)-hDHg(n^AL}S}g zyfVUj^rBZtfpfDuYS>!SWp(ZRrK-UjGN9DYyVPow&dUuA`r%56>Oc&5n;>9oeh|!& zGO`n;*fOz@B)ZThi!4@{H{w`PS1}39L<58RwjAcmP>u&iVyflv_rMz7y6?it?on<| zanLO(%n;P=+6kb&sO&_V71zQr(aa|uJu+Qe+=oM+N9I;!le_-Zj_67_*0x-1oS;Oo zR`7tLVU2uW6m5dE1}eBO(WAN}5m_G18P5r2FkpLjxEXcyW*YEC(Anc;b`fUNDydjz zWu1ZnAOf$V7jJ+^7%stiQ-!hZ5VD~ov-}j2LbY>6kEfD{{cRscLfBd@B_p6#N&Vpq z@7gJFvoM-J?cX~#Svvt-tB~`Me(WY_`e+4cJ3Tbf+@p&o7Haj!W4JgI3AXSC2`PoZ z;y87P4{iU=zNxk?Q_`{d&8oo~RA+JnXYnD;0ea|@qdJ&CSdG36p^vv9*`j$hu+4+*d-zUpOf zpwEiK&^lL6C`Eb_%H>cQZdbUQ3d(t;VxjT!FNJU@9!tb-Sao8kaz-&o1aovT95G!o zjs(Y31u#^)_FV&_@2?A)RzidvrUNU=69#G*o1|7`>HcWom2o`fr;yxbpGfa#+@TUz zu@QD%t^Nkw*qHI|dEsyA7e2Oa3CLyLuLi{Kq5(awjndXu6|4GiI0z$rS=(D^N)oVg zgl1Eai!Cy&z%s+GGY;+T+nW25>#4g2S&A_2=-*9wT44a~>ecf>ANnN{H{YA@HfUa! zuKX}j;EqD}LHL415JKC6NAATHDP4F(!)qx)52@RLuTOf#@@yQdh4XwdPgm_eO0ll~ZxbyV zli;EJWnL;;q|qQdRh6gC;!3?fLfj6)p$V55o3ahFjsi zm5FO|W2w@xevV|ozM8^C#a6g#*Rc_Kcu3N9ccfxTU=jkl{mQ6le<*Hy*-ezOuWVfn zJ2hK(7ri|P=8b#}ctZ~kM$m%l!l`x1j~6LslDh*BSoD2!@0XBSx2&@K+M3bS#rFAp z3~@LeJpd;ZgiFKbvO4l(7aNAjDOC2;es(0DVAT zz#$2?EE=#5!wo|5T$0TLU*XQST0iajs$}5r5)aOKsisu3xKBuWLLsbUPKN?^uTpuj z4gw&*mSbRViD&D9g<~dLn(QZx7MRDF_W&_e%5{XTx}MuM(c&p*Fmwy9-*DE&avP0) z(LqK6@R3@3)vc?Quw4Tu*kzzD$FiD2e~P*Hy!)7M%qPa=M%eqEcQl2p_=Wwpb2P*x z-5)+CN^&&&Sr19Nn8&MP!0V0_-xPR+=P#E)m-%fREEv>g5@NMBu9qIwoto5m{^G%} zONAN0*>pa>=6iup^SSc^yo(2){UQ`-M&XGy(JHG`$l4BVdAU$QlM1yo8fk7~nq(Q-`JG-cQ*k% zw5F2-&_VHjo^l6f8$qikxhm$N>r4@|8viSslGxDJw>DD;R6@x$5B z!(ozXF|u2DNgQOgLRK#?y%}EWp)D7E+FEh9F;%frJ*8fBC`#GKWe^P>V3bvrV$GFSq7u&wf#zT z4ULicx~J9L(c4sy*Lm~VK)C)vbFWJ4$lOWUAQ{+-OE>4gw^dWIhPCx>iZ0GuimP-( zK^ERm&$3KJ_26SE`wl|{Hn6&tBURmb{ob3}xMo8H5q!&T)2IQFB8o;J7zPG$s0}=x zC5!;xA4i~!n~OHj8KjDw z+){%WO7aenNzOplz!aPb)Fc-U<&Kk7g5H3dxqMM zBkxE3@5AFP_cos&4uJ@1pR&K zpUU1pYW#nz08jF{hw#BmIvcv%wOEMP+P`y0`2736wSMU2bDw8xer43xKNQ_0wLF=8dtk65RCQVPgI+bem)H8LXMhmPC?~p$K$R1C2uN!iB z#%eP7J)GL<_e@R6Pc1oWlk53t*ZHO5jj5hyWE=l(yuO%Bv9IAN2<8LV z*y#>jO4-O8--bW7!Y(=A_|WQ-$9ak?vlIpyv4_0-drK2I~HB;-!M3 zBfqxXFSbCnH`B&?6zovd$9q#FC4su@mZ%fbo<|FxKM32`m$hqtpOW(Ty?6PT>&n zkRl>5K`z54z+8qS6WA7$=oORsY{p5xNx=FXADWb}B2ZmHlA7d$a#_-l7N#OlSW1!R z);!feThXEoVj?^ZF^NcT!*)xe1zE`DX_pH^j|61Z@`gPJCv3lbDEcA7hu9*SM5qBE ze?Vsxiw1!H6%n(96liTq;M4+)w*5mA5dkjLMM>#Sk02@gOG^G1oVep=^Y|F2+8swv zJ_D;Do8uvzNzgiAa;9V&W+dPYO%dE8e)sdqk*oJLx7f z=7lh?D_-eAQ5{|`FU)hczYpWJjJ2&*w%aW$9scWa7dK;&yJXe*=-Ww*W;2z$hlR;QMER zgiUnj{x%iXMG+(_%)fh?zDJur2PgLAK?$bR0@dMB4tCT6&BmA@#6bBoynq2uW&x}4 z1A}l#0Z4HFgg|DA>hN-h2o&i-P;99O#IflKxPHO8*>k}caFkTmPt7w7+e1FcR%vj~ zi}3^cKho-d!r4zey66g60038^|KEXyg{h5$sS};?HTH(n7Tev%2h?zm7m2uAP4SJ( z^)jw#BCf3IMA49C>5PE|QX@yHL`t#G)5pu-Lj;MSaHXy>Vdr(CmwqGnhAs^S{p%#T zdM}urEK!+Dx8QCrD_q?EICWVjT?QtH?`L36=+$215xaf-#MU#!SiFRIQJQY!S;Ls? zA$|e};zp?8ta&Y@Hx77AVnv3y+nV^C_%Q=nn<;Rnv6#d89=);XcE$#uvnT?RseZ?^ zxPI_413t7w43Y@V_Gk%)Gx)P1Oipt?XxccP+JBi7Fi6`|@#yUa1|Yx*>f>-7pgnJy z*dPlDMA~%WT71qfW)ue^P?_pR3qdWr@OD1)1_(76J`F}G-`gOkT1-uGo8FhqaiI8# z&!49q3pUc51Mr7lUc9#OC3x}x9D1ODMs6~Vj;WM0Aaew==C6O%ATc;}UPrUs1eSd_ z@E=R?AS$k_d2rrIket{tl36;fV@rPKY!-17CpJEunNM(#84O`Efr1%}r#iRwZs8-T zSE5b_`pbOIzFXSd(cSm+z`Yt`(trMFW|Ij>Pw6>~C(<5`p++g~?{IGw#2(?&xy=Y- z(F&ZvDP=m`QDcRt`c4U1)#!+n2Oh4u$;2=O}wQ^Cnw-67K0(@XG%3ImL_5{;7IzuhZRDm~C{q!5ez zY=pAvgim+!GDeE0^%w>r;ZsxWwtXr?(TQ^3b`}}Z3uXtNZ&Z0chksj|FW|k;R@d@!2y$ri_U-WGm)_>+w>J#fKXUVn`ACSo zVs*7vmx#?BmXD+9rZeUk@j)n$I4z2_ESLM3K&NsRSax z#kC-BA0JW#FP>N^`0^59QI>n0J=Wh4e}h#>fV&zh1)@b-31`*Y$>x>$Ms?CCVLwP_#E7wf~4sSEKi+AuO@A&}Z3lpc)v| z;70s!%p8tJD*WfutW&mwu*#eOwyPZs<)ZoJ>+{ZB zk?~?68BlIo#tA+$-TYtq#0|O%|K1=QdXD(HHQ69Y48H5i5Sa^~o2_KFwuDAa(&9jb zK*DWs(k`1I1@e40DcNAvo#`QlnyY#MMpGb4bh#QfV;9k3)x~L6MPlNz!OOU?X8uco z&a0O2=B2QumEwe%9}#t4R6t45JE!MTL_ia>wzeC(9-Qa!rCp4KWcr9lZQs|MYnVh9 zJP7llzjRR5%4L|1^FUC<+?O`(vRo<+^chObl#L=3jctf}`qu_U2@&~6YTJv1|Hh0$BOSm*HEUVOYmvDTsQDu?dbnFQZ*kGic@Iv#ndyA z>Imy~tE=xmvS9TnOb5~fehqOX=*~>?l#>UuZ$0uo$s_#62X{?Z-DY*006Y$%K0_k;7qaDI&0;_GEIi zh1y(MjO6BAu7(lQjEJF)X*GaWklG6w7Nn&U*xc44p`k#b4>S7b^iIavG*f=v}k`- zhMyMBpCQ%0tiEjeyn37@rw$`_eWkG;Zv~mZ!FO&$!dTrqH?dVda-_JT-VT@g%HV9i zMeihZSEzTIySxd~&Ap|m_Vht_7u`YJXkM$tz5&GzK9xH6z`B}-!-HaxZ9U%4&sXNG zpFkLB7+*T=^&uKu(KT@<(LiH%NiYr5Oe#}Li}krieu=Asj;bUH46=T!pFqS@ds zo!tu^hgWZ>7?iM+|AaxxwQ?nz+h62&54DXzNFg!B4LnH|#;{Sv?tXd1&QWt|tR9)ik$MF0tU+Ik{NJEy+Y z|8#geV>INgO}Am{GC;4LGVXeBVJx)-7FTeLdvtsL;pI z5>Bu|_QwCgl^BQ&IiFOVK7J&FF&Ukx&}2>6^8;ozLEJNO(kv>KTNLVROnM?hHNV^C znK~b7+fYum_)R`Ih}JIbVFTSV0iGw9w&ZQKb9|&vOTBeqzspch0T8%F4I|`nyOl<; zBdztzPA=bKq?D#T6Q%aX4U>Qf-j^m)Nh63zEqT%bxYPtp^jO5WcrM(#@=&CctCGrI zb&goti~#14GW@qb1$T~U6yj}Y(`YAFs@|D~l2nCtYAHY*ZTx$nC1LTD{OD1^ zUjLG)Rsm+7~)DIK={?)q9+A%i(r2MpGUFJXx z$-Ce-xIO(ltn7nqbXi^#SS~YnCf2AngLelw(JN-i+wgBiD@;K-%yY`ddwGkCe8IN` zyWkTjLRYvD=#*io14itx`xV(%aQA(~#Ku+YmVDCyB$8C#Uy9e)sZ*DgOvczxgE)t? zlmS9|Ktx~^21Z~cDr!#0mQi-NinwHLpRyau_vfpgVm$yrictLM-OK4c`d~U+YX&ky z=(~EJ+mq#F)hAe_h>qGY*zCjc3E)njbzu?1R-rSQ$A8&8>MlX47E!{mR$R15_VG*x z1#HR9aNxHVF{!>&J}eisH0@XJEhX4@D70gkb=}H+q^`Ro_M4~n0^L{8JI^vlm&~=B zQYpN!Q(&z9>z{g9t-j*pve$^RbS{}{csaZ4W>MEFY@JegVf{ymC0z7GYDqP@b4ZQh z%M3VS&vM*7L#z?JWNt|QPMl!%XZ(xF-^6bfpE14@0W;>b!iYqR?#tKr`$15R)$&+; zm!M{_@tM_<5U*1kavhH60~$J5sklTLN-wk;XP^(P&;8r;ohJ2WJ)e|~euN1({JkU= z*x-gk?C|(oeqksuZy>QYsDG=l4R9~}q&Sf^C2eb8V`UG~AuFVhurw~F^tSv}Gpq@E z6MwL8YD2|G`N4?=%bG|?%9WX^vJUyrA2 z1r@k|g6;*graAJ4AS0)ORU{$ng5n{sa8%X4*VJ0yFD^4nQAD(v9@@gT`5YZeMBE~@ z)W@O%eEeve3tOfeWE0?BH{LJVbodlg8Z3AqZ${TPZixZr2d0nc4$#)2zotKs1B1(; z8v?BC2se;wos1Mvb(GzsnrEL0Hk^Xd2BZ7h$|9%9YVUi37n7H+aTjl z3x9Foh@S8O7utP2OWkIy@0JR`>Gq?&hRpuVrdDjomGc_<+ElM1du#Db;VsRgrP0Xi zr{>7TuyOfz5Z<=`8%N*!@wvm%WFAQOoZR8;z4vfEaLyO~C zZC5TgO@wSjs9H-k-7YTfC#)e7?wI!nOAF*)6B&P&PCuU@w$ksVfn;mJEeL5J+i?&; zCs+ae8zI%TSQ{D0uyKBWOFl*}%%7yDEjN0N1&pW4rM6yWbdYFdBpm@X70D19m4-Lg znXHrL)Y>8}_^L`I2=YH7kk@vk8z01u?=)#o000w()!Xej4FE}s0rN{_GNbWq#{a!5 z=xfyRv~_q3(mXQYcO#u@RXz=M#)J4RJ*IgDBSLFtCesuqQ|ow2>8WH}u~NMfnI6{h zW$CG9?J60DQe!54Z8IJq*j}+w*Aec#t!o^IG>p2-o5xjZv_aL$}Xs{H35Q8g`mB~iCv(J9aQECgr;5CwM!479)41H%#_l%e zX}oLB8baK)2xvvC1!wNA{8f!otRPYU=G0KrIeNc2iB$tMih<%eDI6*AbLI&JV4S{) zuVO2Ifm@30)V(4Uvqrl@sYADE;_|(TUczah}Jxj)b0QK&GZLW({ahrA7 z1~2D2#HtNZ%sMyBKW>rD7O;7K6OVw9q`Oi#Uk}DtJ%{w^dV|MuKCR@!^D9&Od+M;9 zEZm_RshJ;Mk5mq4Q&NEHy}r9KgJPuX5(6HpfUKUeLt=z7ib*Fx44>7CP4-@8G{XV~ zTrj!B%cG=L#xaJpz|p>|6fi*HgH1s~bzBs=s48KgZ{GMtkSV1v7D~6EUVCQ9WyJ2N zBn|dM;+`gZq_%NwyU7EVvP=8brF@B$(x7#SL!WURVg+prxd`u8&#W^ScxO*bZ`!Q3yvpr5%+ z6<1sXFM44?2Y!RRTmbTG$Z$u3T_ylAj*^6GsFal5erkOzNTDjoDDJ&f22|sk%rw>W zDCuucr>`A{pB2fF?z{Wfft)%G(;b$h>cQWDvX|HNDlBIDMS;-vR^@P$8pPs&NFN&S z3HvheUd@A{xer7I4xZ8hxEB?qw0DG{awLW5T#0^^F9k0}LK0@yiUNa>2vwd_HUiZf z9J|y@q=a&=oae+vD5AYpbz9#tC;Cx&Xe)-Ss zSzPKu!Ybklw`yV@t^l74{9Fb0lp=Ns=HbX7zLS0}P&LzJpZMWxKIMt8#DbHVq$dPQ z8VE{s_HRchTV&ms(5hXgmcglPasN@7u69uliE!>JCW?;}!;>aFG{^OKG(9gj76Rj| zaHRkE9T_1q?Zs&5Ub165&&qKlj(Ik7a@is#x zo@wn_y%JQZAd+@yl_zr5`)n0!>1=$;!W*1bpH0LX*FI&1GsYQj5kSso3I8@AMPF57 z912R0=~Wo(DoTPgh|boee0a$v3f@lDR^boPP)f3r?h8~NkZ5e-#5<-MutM51j#*XB zlTu}Q2ThylT=QaXw{|L7=LSz4 zE{)Z_Okt>uWCw}gSFxxI?HT7{L{^b){u8>5eCf>GlG4CW;}q%gDl|Qs^gs)vM)tkB zNcW+Hs{qZG|7mZMP#5Kc&4srDoJ5Ykm${di)uwfuHf7uSmJ@dfDA)`@+&^WuQ)D9S zNY{(cFuFQWBMVbBC!LUxY`#(94Je1txe~*LVA2$*m?K8EE!|5w)$=#8F8vg zr^h?dkS>$x9V7XF!CHx$Y{%f%;3R26AI4N?9qrWJB>$jx7TLYQ#m_$GO+;*yn9#}$ zIX}INmyHi>_#GnTGm`1CIu)ga3yOGLwkP9(f5%kPMI9mf)@eqnI!X{yV7-r2Kv+dmw{gMK~q5 zZT;*zCds_OqB<+ZI3ufDxmFSqGje;gsD#9K`Lho&CY7RMgu1*)0Oz6}I#(9=3n^{~ zklcQem1_^f@66Td`Ytj5!iHZUG_YfY`1yMg&l%>-cmV`{iTzqKx9U{?V6{jW138F~ zRWv0t)KtDLI=4YDb-LkW)E<8zw72W~#npiCY1}t@-!G05Uq*W4nyPl@ zp}ZudD)8~j{y&1$e;TcU^;iZ`C;kB(zb2ewr$(CZQHhO+qTVHU*A#p zprZ%pC+vvxK3djiJXD4Xjh9DPPtWI)Z_X=tjl{&jtGitBm3oJqDpz1WiA~(Gc9Mcr+{EH6m2opKj>oOMizYh+>N9;jtS& zq$TyewmfLkMcWHWUc|kl4r|i`mk#imr*uFTyKoLY%MUTADZULxq%ZS!?q#tPXNJ+R z=mdrX7(BG_UPjxP7IAlx+HNL_d$M)f0@`=M=q2$e&`fAobE6Rj(&rzKYNjzI+8Ii5 zaO;`-F5^C#zJh2uFXzHWpC@TWlN3phT#r}nwqrMu8hLSI#FmI8#*r6GkwK6-Yyf@3 zIl7uzwd)X({8VUE`<#8WwAz!gdo*D$+IO8ih}sBua@TK)_}5>N-No{I`vXqq*hE=4DgQ_ z{`soL^kaAi3mY3xWX`Wbtr3-mf7tz_GA4uO5=JUFUV@j_W*P4o8$t}=Cz>w4g%hP& z&88;614}>`B|=w)hQ$w>KX)|Sj%xE0$7mSQl#WW~kozg6HyT!ctw3P94S7v&aUD1BBq|78{3}z2HV<>H z_tfIz^o)wKEi;X6E-di_q2PfbbgzCU(qdklwV~a++23Ek{#V-6H1Ve?5LNoN)Jz_j zNQo#@S7)F~6}isMQsjm^Slpp5h!4G9Fne2VWWa#Ujo+scOEkaPbVB)n%ROqc7u|KT!ID(yU%?U=c%*W zD~Pzk-4(#3k<*8YxOkhe#dZMx|jsKNbKHLVqQ!?y5Kt zGE?>XCodTugR7`KD#?}6(Lidn;YCEnBoM|H9JmVgOE4W8oLNiuB7F06+aJGEG%4Mu z5D>s^?<00tSs~^q0JgttQMJ0F>@ODIbIosED^XpRjthzR+D|h$ZS*|Tw9a@Ls1z2? ziB*q9H_^{{%0!+mjOocHi_*|CL;$n-F1p0LpMX3qI0%FO0Gn}w2$T^lA7li05z)TV zK-h=Cg*;_Jo@;YJ@Jy3_`(rt&C<{s)VS*q{?W6&^{5PMPvv=IF;C36FP%jm~MizMy z6)Y<1kWjzsdXAp-H&xdFnH@8IjSpnIuv`zrfljW>zyFtRjIBO7X`BB z_2ohK*cfv7HH}$Ow}f$>DG}0yDj*C4Oc<7G3^H#H`J4s*@a)ym?;ER4w_kfcH-7viWud zw%7~*C<37PgVK+>ORW(L*~C(l4u&xF9hCWZDye9W2J9UZ%Mk_QJmVf1Cr~r<6CktP zv$pqnm(ta{zMLd-u=9ZVlQ*AHF%AFziMcm&TE;~mGxS-`!3^Y?q|`f}Q1Z-3Ipuki ztJUxFf2zkKJ(}Rl-0^Y{-^p8>cog#aJrTXTI#)bxQl+V1uA|?4$`;ZU+B> zQwwNzBVCpA>FsV2Kyx*1-xNVGiaF%XM_APbITG@bnCa{)l`I_dHcHl-^IABm zLzi%oQUZ~7f(k@fcZ1uvU_ZzF)3})%1AgrZC&`I(HNKaW$@|Y00&#Abugj>#X%o%S z!0aI&2J1<&pF}Sfr%a0ZTP+=q=PAW^DpFbGI$CN9M6P?^=C~kp_xc&|YX~gf+;}qh zF}^HW%6I(*Q&Ha7k|~-5X5}%O>lZ-)-ueRhbrw)Ys~gXl?soi9(wLJu$E_zV?f$|qP3q|W2X zx=YnINpIhupC`tgmldy-=TaSfOrW>U<^-hhlm7O79xz7!Nz8i^|H$ywIH>pCb9YOd zk6l2jA)32I7UTD(clU|ZU6B_{^{iEG?XHzq^8|+9j1Zx2e#;6Wa?~IwT!waWjpw9z z0ZHuc1gJuViWvPY^d{V#L;<%_%=CyC6PS!AICpdk0UPmqYf>rtnwkboe1d1D96_qm z1!eiX7o2K>%JNkwhQM&N z>gj0;N6n#KVXgA8X^W8d>UD7C3~#-dlFPUpGu61^3hvzQBwcg!M#*M{v$DOA%c{H| zkz4Xv_7WPmHoCjp}P+fU{;Ox~g3iA1J5Q$)b}n zXKGE#_2ww(3U@t0QmA#+G&dJ$-qf@-W93ZQa|I_$)(qM0FDg3FCKTm}CPT{X+ep!> zurG3n^1{g2YW5kyeZia*&_tlwNQvXeaB-%T-?E=-@<336-7g~=H&b4#c(aNBXvzldv5EE~JrtnLGA3!to0HKj4 z;xx11jH|T%$CnMn%N+vkelL&+R%-fisFqFiSz+1EpUf*^gqo_gAiqe4aQOT{}#=vEgk1WN;EESA5wTX}uq9}3yirunrvql|o{7&2z z%Ya0P0utaE&}O{ib9TT&$XpaaGiS^rN>&lXsmywN*!1$Q+n3uO=4RmB3$UFlj5kyV^6_sfo5tY2pke$G z;<_A?3e@d*A?WDTA}|2hyPtDY+ni+XZF<1jn%Ey2)ypogRd?^6*J}3jt$wlbCfefg zre0wlD}+qj&uw*E)db9+>YQFvfR4LNJmMT69H(V>1xwKdr1$G#=um*0#Lvj4Hl{>! ztnHs?KBL3ExnNMwgvY7L-Qw<@5lI$#xa#Z6$oy_xGfnu7K{+GMp7VB|;K9x{^?s8( z54A;H^S2pSu(N4#VYerWISb*g6TK3#(IftS3DF`u-w=uk&tHSmlA1iZl7)+a$gRFM zMzGwg-OWDb9erOnZyEIC=w~K9hA7fZ1@H$3f5&eP>VjxASRoD~aMYD>4ZXB{yVRAVo|7Unv4n?vCA4njx`_0pA)0^qghTEHs=vGnM{EVU zOa;mV+ViL6i(UOw6A+T4ZuqE{;%|}BJGA4^lc2`o3m3d+g0OT+I&t`Gz)N1$JZCdQ zja#&{P3Kp#%Wac)t5QMk36w(e0yenrHEn-DFt%P15u+0S**H+t?Pp zo840W?4R2ha80KX!L%&AZ=$dX-4}7i0_tk&7?${-T$lI+qgkNyA+-jofiKLRcS%M~ zJCwb*DH{aq?BfvT+4FZ5zR{zyR73D^2z1@JE_d}hyUGqRe_aJ|p2yM9C{p-07%ARS z^@XKlnhFaeWH`UCwj_d)NCitu`E!KA4HxDV^3z<4$#FQCj%rg{pQJ z_F6BKDkZn{!rWteT(UgnZH?Wm?bOOneQua{ljPgaGpm#0L@xVG@ipkJ2l9x3p?|Wc zmfl1z+9p*|kB^1AHK1tOo$p&KzsU)_dy|Uge)-6cTM6$$h%Nw*Dt^~)yGfKjW(oNM zJYc()cpxTvX$gOiZq70?L-c3Apa+3lakO#WK;Ueu09~SrMkfHlwQ4q@j@Bm3^sV4O zZ^s&x+2ye}wKer@tqC?8j3z&vfWl9|r6^HIEd(oKC&7@!TLv2jL)J>TaHT1+0W+=Htr57G)0Id9G>y$aEC;~hZ2xdP4cYhO zQNPb_y@FY|2dK}N1#WLY6pal`d4n}Bzud)dLh_n=wm-@xwKBloORN37mA~32WK~XY zjWP~v)RI@%$B=Ox<(PB6E?=^~TNK_9bZQ1wFoQ&C4a_-th)l4gV@`hp1!iZ#OcM{S z{Iw81#NtESKm5mdqBE<8HH?21D*kYR9yhZXvwGBDI=q)|K`kWnCcdb7X!rIooBiv< zdIm%AXXC;WW<(SLMNbv(FU-w>Y3vY+{=p#jZ^OAs7m>c%1e>9+L&~9hXd`wHZr}K; zgDu_I$C10b&pj)N-sR#bDauli4w6ov>*`)uHvbV8jFC}4d%uge{}J*hIs%e-fu%e> z?kcP8^~z5RS9JIk4vT(ibrk{pcGjJ;J4=qrZmegh$y@p)4&l^3OnQvgAWrwqMZCkn zwsjn`-ec@}w8)M0O#aoL8n-e;nbhivkq~bw^Iv6Vb{yS2Jxe5YlR*0V>cKNB5MKoJ zdZyp%Z}J&N4g=ndS0+=iH#{Ba1h0abz_`s#)Fo_xZ;^w#=4^F+mr=ILmQ znYDN(Utxb|5+Qi_@O$_~Hk-`tPSS}j>M%2#WS4?WMF=uJ^%+BdNMZ_wB4P5Vqvy}s z$%A!9xee{^90*9I;F<}+Yan!I<%mOB8SIrAbPmQysl9(XK2kakH)AoAsV=SQa(s0$ zpbG?xEiXwNfWg(AU>cv5EWM zi5JG&!C`C(th_a>KP^)3qSv)H`R|7*JWePMQ&DEWQl=bAAE4D5-Ij)xD?#c3g1J#u zyqOPHmTdU;S9g7oKB3~bOFLbwc|ltSYE&G89lr6*77XBRD7DFGE&8VgCbi$s#(q3( z(FpDkOT{s*Zhe;^>weHi;{k*M@}v6W_VdaM_(a=SFxKZL{4&krzwMa0SgC)eR?jK; zP&>dy{uFf`SM_Kl|4ddP;{4$)uf3)XzjuFXRLdQuKKFmw4PKs2c{W=L#+_N5eA7{^ znMXicK+$ojrPtL1nUvvctlvL{skLr6il$9P;<2GA^=Qa~j@@xkt35S#HemvvH?FP* zT^0cgX{--lH68Hd12{M1?#YUhkq+Th3*n`Wr;b))L}G7^uhy_%8?`jdF*Vj%(`_TL zG+_qiEq7N9)@tuMuv-hB!B^n;f+JutM+=W;(M9Z?y<9@NRwG1JVt zzbUXzuUwehFD0=j!U5QON-ptr2x+XB|Ab#3*}ur($&5}=iojCst%D4l!AEy;$V$yw z032H{1~hD03_9H;#5rwS?*2a2jx4@Ul|`LkrTDr~UBZA&3yL${!(Z7b_!T^TW>*-h zB5S!2iSiG3w~xfkQW#K8f2M?01eSdS>iJt)(~Pe?iT!YUsak%KEE^FDN|)^v<00a( ztcu=;DF-`2VByrPb9h3W<+*t^E}5}FUUC(}QL?ooGFqgRf_#3cKDAK#A%CI?MDuU4tF-i9&RK5 zcfvmuYa&1S67m>?fPIM#YfOL44yzPnNF4#+PLS=1LqNbaBP?ztDBN;cmTMUjmgAUT z?0W=vdL+c!YRm1_SCspmta)Y%OqR{20OzgWC`#A_T~ZjO)tP#4jVQcP%#ULn6Nhr> zQr5Cr7FOfA+Ltg@7IGGl*(cCOvj~W_ zf84&Yy0ZWgj{-UsIe;8QQJ1pI2U23p8sWGpBON^Mli=erI)*M0QzKpbI@r%f@2PK( zgII!JsxhYjtY9G2hl(y4iqDIU5B|e>>n*fSq#gsGpKUG@fdF7N1fuI^$ss6X6gU_D zJ8H1TZHd`MVeIwhgro8$zk$o3?B0l25C!}PvFM$=Gqn0poK*B_z07_j4kM>1!`)vk z=fM-hyK?&m_GHYWxB>>C&9M6Zz$R?NhQ!_DH5jLYa3L#rKhn=N;ME!!ff@iYxY&ZY zZP$c>qa0;`ORA!X8qAkHN1IR08@AQ=(k8yovJKL=M}1^8*SFf`U#^&YXeU4a_xd3u z`4aCYru#be^~Qk6JmWdHyZzAgu*hbjCOMHcLOR-;R{Z>^hmfNLz#-q2j#k3RJRZK$ zb#NrrvgSG>>Or_9wQ*>f7K8$wAYoneaTI%!mm!rZYd^9C)&o#j+;Yx2TVl z=Uu!&Ggsn+RC@qd!)`{id4-b_wY0adVO_1SA6H|L60(FuX-YoE^#0TgN;R9Zsvk8H9R-&CXV@<(^`clWl`tQn7jbyQ{C^{{7b zL_2?Fu14M3ErmVwT6Fbh1Pz~4X5Z5ltm)O~qV7>=ZSQpHd&~yY8Y|vR2>g-9qc19j zH~gHjE?|($>u;UwbGP*h-`DN4B05n?$+k$Q5wNjg88x|(m9;Pj2oSQfH3vzvbh48% z@cni>=jQ$7yA?0~b{ZMd9M|l-Y3_BSx6cjeLYoKm!3B{mKX=FTG3p!2*9BT_>=1z} zVegGr7fVLHzO~D_E*vY1YM!vEIKuAWmmLPVHlfzRl(Ahn1!&!Qo6*M}LEX_Rz&Rd# z&NKWcTn26xnqX;jq~3eL$xflFi-)0oWV6c$mTYO_xmA739P+wPedp${KADtf7LxF; zPreIp0NyGDcC3)jzaPB}g1MY1KVL_kywBA0%*jgSA_Q1bAC)* z&(UE+Wo-rWS`SyhdRY~1H)!1#Gbd{S?2k3!aE~^~5d;Mb_!nK6dO`h{E;hXk%^?(x zMi6ECnskmJbHmLvz7&ViooJ{z@n9ABpA)kWi^m)Z9@|M_j)zJbx>0RQ$7|&~+F;qm z)!Q|KkMcU$$6gM6@l>A;!$`+6RCP4ARE*Sj)O8l&LB)QB&4S%{t{ssL*x=!A9axjML>O5@IWAO*3O z;d$W(+d&%0fBd8+I=i={mLWAJsLvT#Du#H1okKQGLpR(6z!@(RL0#}BBg<0Vj~6Q& zj%muwctZ7MWbKF5v?selaVXv=lcN??|8;3ChX*o1@_(EfS?Uy!l#W`{1#z(vv+b?! zV)`cPm9zu*>XFe;o~34g8w(AYLZmns(-fzYa(5{#;}6%i?Cf0z?8@5${;i5UFg|srV!h3ZT9<5Pz%7wD%`RW|H&VAH znKMuEh_OJ`E!pApdn^~>1gwBo4_j%IJ4l%nc~JVOEe}@PZi8khf!!72RnPdT)SAp& z_8zWrB^QiW94rkT7;vqBCIbw|)q9=$DL>G;qW5baP9pQSDVN)*Q^-I-o%BwOw4R^1(bfaX zjNUm~=TPAh)r-9OaFsIWG4cLZ<(U-W!5QTgc=}FX8`7boo3trlAqKKigoQPswKY?EVvXv(W-CV7PDp{%`lS*%$_ga~?3yHj?=%R^(uMEz4gINs0+RU%y3`D?2f|_a zE@cK=4GtamRe5m~jNM&#CS`Ttb!ByPL>UDGIbs!xgKIOBpgZanhh!%;K)`kLBJ^lek{ zvQ5EP3%OMc59k{%C6Og}kCC|kHEDF?#rlgoJH!SP@bSdQ($En7rZaOs>K zA!pxqkGCiE+2W&&4~^Bm^DIODLU(+IDgWehqT`k|_<>L)Rzd^QcsR0$+nK+t3x7=B z23OxykZcSo%b(lovKBW1R;Z==+}9iDb&v9<{e2G~t8sfmW9J5Quk~m2NvmsJUd}7p zZ5>S3;Ma~A*Kia5lzaz}c-FJRQ&PeC`F@TULeSFq>HjIev;)^5I~%CNw5Nh<_yDpaU9+XaMQx?x>7BWZcC_SvP?jDA65)Z) zh@jXD-sx^{X*w8_yE*>agUGw|o51m@*+68+ve(mgy5dZQp*kAin>6kC; zfdC;BV+fq5EUyToQvd7ZY9?-^P?#8?Pf*JOYguGlv|eBE_01^F%^ir#|3;8u$S*JD z@f+^NqO2>4>!K_hKCEzEKQFoz;!a6?Ck3~4SQH`b85ZUNfe`v`ALYoyk-nv1L&8pfM#e#Z1(l|-K#1X7H0U511$UZS^3xjx3<&4hw znf!?1C_%nxa`}*x@;#CD&Zt7dS#I|k_henDu}E#Sn+Y6=zfaR=MH|6@6amq_q}u$XOT+HBF6Cfmi;(b@2q9iD%+b=Dnl2N(Zqp&dXNj)&P}<+uLV3b<26)%paIn}z7_&DFnNO1h}KI(TEc@Ol-nxhemKGhQ~8 zSSeDF2WaY`UeQ$p#O{KnDE~ z_GtwDWFmamOf8P%Ys;&lhLs6{Y2)$U9*t~eA&EfSh)#RSN7G2{znV;U%_Y@|RFW8a zuGDX|xlj{0_6prq6Exmh+@Ragy-*%F#t2eNslTC~CK1xX9(Myf?sn=u?lwAQV$MjM zAl;gN!ndIw=YlOp3cXMc{O?fiNXCP2#DlNo!!gl(sH-84ZNQ7Y;OiL+@T#}}!}$K; z=6G%@I^;wuYT4C7o+Uq)<8+yc+xp_tRGUJErLzi~YpG(rkLZGZ3oS`!P!Sr`m_E8* zHEe!rztPN=%_UQcTADd}4#sBVa$J&HRFEqA`M#oOo1ZW8Of@>@NK|%)1f#;~cFzTE zY(_CB_RsJ{9QM3E*arY+-WDT;PhA}s6l{#D89yJr{<~A()ns7xJO4s zLJvn+22ilhx^eZu%_^)6tv1vVem${iGG&*-Wi*wRA>eW<0oz!Yx&9lF39-27gr+j0WhU%s2k9e((xPGs(xyX2aNwV%3f*q@X)j z+*#A9VKt~2&TqKuI#?UE%q^-h^s-X-YgI>TH*&7_i&BZFe{z>q!pQAx7fJbp^OSE6j=M=kn{;Jv+b3&Rfk z1FRbRKKWWrGzSi*!8pv5GKP2zjni$UhFMyY`sIF}o1j{Yh508!MFa&IW>aY$HWfT> z0X1(X9tzjjoIpN4yy>xDk>iauOP>h0%A<3r(-!JC!pwYpip+Kzv?SnKIlHGI1)JNmr8oeg8a09cKeh zfs#Nqp=&xlsiGP5%`o%h2KaAqyDxismbr++v;~%u#LRsk;Z$>6-HONR`Ypx0Un(`f z6+~BaGR&H}n9{5oG>t{(l)5oBAP$8(wc`X!w!x3zz{%si6=R#6_-1%;_>^$qTQz`b z!&S}sC?>B^jKE+5f4DS*9fQy1H%mU0Z0Vll8Sm;1;SE0Y{GbDoQNb2V%b;vfOLUsH z^^ziTv18B5oF$=-JYb{3yn!_;1!|5McD7D`5CG5eu#mJ2ioTn_f%~O-D->JZIDZ>; zBh;DBY}kyE-h_zIO9d#$-DkvKgAIOd7aq@G8T4BF&v(g}d30=DEq5PGJ-i}9lE1dF zopKH_knvif5OF0K_$PB_ricA`9u{SuZs2vZBXRI(9vav(ee}Ce+&??Mj?La2*nF~2 zP9Qhgjs<@Q0ziLF_1je4I`7pJc}P5b+sMqQ(iezz&VLsXp)sO~Y1z5+VX$9lMr_aF zk#xymYMd>W#~TnYNv(#SBcGkQ$9m*yho%d4hmL9a7grz;TEX$`4htQ-I~Sl)InzbN z=ONbS`wG|~o+vOOS25q#o0!!Itm3a%Ij^*0n*?q-CUmtNeH>4J(uAi~WHEr6?_U~Q zp?>^UsxyQOh2fu(nQWi>M|&E+c8z8D`bTC5NF9+PFU{(PkGYK2k&PNU6mDC0l}zg| zYL&>czpoqBWxv^TWRh?!@)Q>jFB3gQFzvWa^bgLGS>%%_0t1W;(Q`Gb4z;pl2+i1^ zO3KdlfQ6Z9NU8d%P9FU0hE&K1qd|lAjhcgFPvksGb$|^rm+W9NpHEYf;rclE0wUNH zRsU#{B`a0qNF_nX1c**$npNMm9STnvwe%j`p1NJ_SvJsZIw@X{(-8? z{SdW1&h0S&g^k(z8rr_=qt0!$eQ1-ucg~19F&*f_=kTphYo>#K5MhwQ_?CUH<2+y5 zYHF<5jB`o(_7t}e8BFZ{K$)bH-c$>y>DM$OuqlJBu{&$a!xh>_c!IqEtg%@-`#Y(? zhH$QO-loj))4YHv25yq(a=Y!L)O-dRp4}BJu)IG-s$ktrw@{PvEd8i$5pQebn&GoY zPR>R%NTq7`ap&P+QSuFm1szj6qW>!oJJ5=s5g^?Q&-}^fRC@3SQLb3CZ1YFf)3h-V z4+eOzkwyEDO>hdF+r46i-92@jQUcbis@1I)Z;b#IuWXtvU(d zQ)!uB)Oy#@H4miNpY|=b>2lBYIZTC9=BCGdj4)E5oqY9 zp0W$t)Pwbq(=o|V=j})a6;Z8$lqp=Zhkm2Rq+;nvE$gBsHH`mK+YQTzP`z%^N`i4K zU^%!E?Z4+M2jAZXO<@24s(Aqbi2wI|rM0n>zLCC@K8@k>zgXoV6T)xjJ2Es3cB%Bg z=?p-D$v1`8={OSN*uVig999(?94yW?nOi8V+-z;}@T;+kL^+(*_H*I|p5pCX70cH` zV6)-JQ6e|y=|0TW{inmk*uPJoO@M>sfieix|HAQIVP3S*2WRM4bRaUh0s{&uTy(!} zVBl}?7y-y9;$IZ^CVsf2{{bT=UNxuIk#LPbqkAGYyz^%e_kR-@A{gxn|A^WHHLk&v z#FB-M$o+?m2+fc(r4UB?HL2_hqDo~Djy7<8zymX4wx1?U9tfUNWQO;zt(<@)x^L)% zEKL~WG~w0edvriE-sjImcUnA-Z`=ycKO`)5$UX?KBcjp^XJ>zdL8ZW=9t4ZzKXm8q z>9+kBw*O|Q|J9|})-}{snrNnkex?DOLwcUZ>xgu_ zJhzQ%B0&^-)s=q6&tz2J&+vvVhT(1aYX4!-jZ-aXAigzvF4sdJ=&N>`5MC{K-Rk(2s;;Lfd@{67*q@sZEa^qctwjY9fGaf-Po|YQ8d+C z1k8DPCH@}mDR={a2r(I1@5Hwz44Ve+yyh_UBXR@6a-mwZb)U9VWqjvuoag(XPeXIb z%XYn@c-7#uxu)GVFX2&CLGSNwR^*4kBwZhsiO+tw7mKr{7yG*cKQEjJZ(Ut|Ie%T% z0gTNZ9c5o9Vh>&WR+FnW-6~OlZ~b!3j%RRsu)3jf3X(fL*ErnKxU90R_VJeqOC%nA zPSe5NN4sj|eZhg5?h=>q{Bz?H;UybGs zz?`H{nvw5z4I-tKF>#T4#cyy_A4W0Mj@_Vr(Qn!Bz-0w+kfeJ+jpD{~qcoR%}tSv0jl!e-oH*IZ^{pIx1s zrwML(jBXe-l-8@!)={cVbc)U5tCH>mEBtBmcWlXf7#k8_Iw;rsKL$dh5NFa zhzcV<${YvH`Eq>0xQn*1Z#CThi0#I6zpGkdwQ znA4B1CNcTW?xo;s(~AH!S2(SzhD2r)G}0+E+p`xmYmHrSaI=E=x?4AcL|zfuRqtD- zN_Ao8+8F+6n_0bX$~Em$ubBEE^^%gl|3!DTIVoA2q)V(Lz8W%7w7Y?Z5&+6NK3^~I z)mKiyM>uS2S5^{y)}Oq2?rq!M%O%H02gm>^^aI87v}^09WX6-O*0er8R4_13)LWB_ zL*>!47%0q{i&Ftn1Gb)w8C*FEWi@HSJXam_D(k5GAoumW%E^Dv`RAC5LAX7GBIL6^ z;)SAtvED|Y-k8M7j0{{K7Iu%l zbOfi%u3trbu>E|dQS5km?EF>xf=6c^J80l1+G^(5s37oZTDZPJ#P;-X$7ddqU)N&K zLuJ69Wq_7<#bnBvjAJFK-9;|vJLD6!xaZubMU_Gvz1`MYd2=s(H^@G5i@e8(l4Kq4WVt(_v=WYkTkClK0J`5ym4VWrj=Cm#(4)-bP^kjS!|*K>k~QFg(T zh`S<$6#5Q}Kja?+_1_o094)`;ikf*3Eq67c-@a}igpVQUv?$fM@4ItnDWe=-#q`QJ zeM$f-L;Eub<=2M9F6W+aw|!SFYih93C}V2>xVC!)WMWgmSXtKK31obNY;2oA#NvJf ztWEBWMpi0VizX0MJ4d)czEmkq z50RO~1jLn}BSYoa{v?A-g~T@2z7^`_{t{IiU@8|_kRn@J+2tL+f>jzYW(pOZiA18% z&g20|(@QFeNklqLODl$HbYZ6Y9ECtSk|Odom8?$lak)lD(GlBHca(!4h4i1Pq6VQ;eDejDL z@dwasd(VR;Y?nnZh4a{aE=kif0St4M!_m!ri%djfC(<`YPOtlj7mJ zWG9v;YM}l|2D!>KO1VdUZRL%DCE&9P@`o88pNUZ~GuVmUXREqFSLeworQhcWu%%#j0TR70UIyus)dRwkT1Xlbwrz~qt-kf=_cwo`a*n5vMVDvZ*F^AXL1m<+R@v*%72E^39A z5TR+ljIzF|X-dpP3}FL~y+kdgL(} zA``OKF_Jrcm}uz<2I-U_`F_M-`V{)v z4v5!cqPg;1NqJ-b0_`(+(Gk@f7>2rXoc3=rPcrOFFLJJ-1h z%+q5kWBTosM5F>(rB;4uW9`xm>axD zGp6;9JoE;Zp1eHia?^06PIs2F)!_k5!ZeaVew3QZ$~uMi%Ko8#816$u>_vr^0w4ld z1NG^!WCB!EY~iGLVMhGzLv4fto>P~t?e%-0Lss&D-XhCEm)SmHE!m~lL{VPw@}6g2 zr^?x3OkO^bwtXL(a5!;1JnN9QELW&iVlLH)D}UQ?EM=~sMFllft?Ma^xn`b`;qui76Y?`!| z`Lg4hKh=}sbFKH2| z_)06)Sm3R5s_rzx(BZtu&P902od2qJGjwO%bSB%H^8oKQ*;{)4LJ~e~!YJc4XYK3J zw^Ho)e`Fhz106DOuL@wMK(!O`rKHhJPjD}Tl1o=fBY~<#b~>x_wmFLZ7``U{DMFos zO|;6!#&?ZQM5=>zuZuqiE8aLSn_J&?=KtK{+-zVQ?Velzh1b?>pAbZDoFs(HU}6g) z7gaY;t|c2AGTln7vcojYa+=7 z8BP1@w?_$7Ls2NqQ@nXGZVd=chU;Hv7}@OQo2D_u;t9{>iiyPb*k3DJS%O~Z-+d^M z2}(2WO}+@r=75axrPSZ*4~iUn`yU_`!cLH68!`ZZtPcPH(*Iqiuye5ew@d0|Zu}3X za)s^b_{ns2d!y)PXJ@?*^>=o2t*vId1;=~d<+M z_HfTn7gMrx@ZAMnAV-^c8d4R##K7c_(n-%8KxnI165Y(eP$m`!P_) zHAwy~mz97-R-9VRcg<;HvMFaIT3+C79`8jW0vkkmFH~5o9rqI@QfrD)m%AE= zxv$&J6;WSnp(E!M?ZG`lz+}X|GvRb{^!Fz-}SMt zPF9SLz?(g3W<#1UiK^kI+R4qwZIvy7a_*x~iU@ zQ)j<9^g(yjN;@Mdo4UXHmV4rNMrGU1<6t*eWt)ky=CMMB_Io~${X1GpiQeroVYlS6 z@T6z#sAU-*z2;E#Z*m>6ZX!&Yy*JNdal1;&^BZq8mQ~W;ieiY|F0tT~Pja8Eym2k9 zz0}@-p$Kw|&lEh|rs()^lBCBwVA)CBHOm3Kw?r)=QS65eJZxcIga*!{xdCGxFF`ji z1PQOPY)TryVWnfchdpg4t+hLI^W(32{H_^5LL=VuV3J$!w+I~L0zw=KiHQ_Rp?Jo| zda`k5%5NJ#w7!ug4=ihs7ZU^lNg23Fp(MMP-ryfI%SnS!flM3$j=O}_l7bLT2+M;TOpcoOvw zjp_EGulq`Tq*mf=Zd7b-M%2c5uu_6h4DEd?edV*v7Jx;PC?G8 z*y+lKhh2)y+X4Wl8IAczKW&y&HI_O|&{uR3-#SNCh(%tWyH|RNt5OpcG3emwF9<>b@%N zP+0+jB71Ig_^336RrFaK$8xR*ZwdVDzlLU8uN~P?MR%@e0J1w^-Z|}1AlO(>o3zvF zwt9UvFj?g21ciC%H%nPN&Kx7ine&$Aj_$QPom;q)rd9T}%U+jd>|%l0GL zEp5i*7Rg*@f6?)CbN43Umr!okq&;+VL;Z4lO5@F0a`CE?J2yX1VR&* z?t1%OS00LNPqoRbVzX*Z8wtiMC^dwWWLiPOA!(B(wc^uMOHmg0H?@VHt$c?trPh$qO`5#TaZ=!w78Sqb+7 zcSMc#4RB&a_p$)u8pKw*kfwTG9Zf)y73q-&a&T3dynwp5^iuXJOz*}U*pd#2d1Hy& z`GCfWX7i#9xk=SK$`yn?bsSPU8a%?qXTu1pCY(ofKfaFa_z#O zs%!hf@$n`%f;uqf1=}DH^C>S?7ZxaUjr9+zIdWLe!h}^{YvR z!1$YW-+stW-$RF=gS`tlh)}wlQ|!t>S1gxLZ=yb6JkgWP6Tp}AnJ9;G|ev|-xLb1{a8{9Q6^{vn6>+=e9D|b}DxmL+~ z%}SGdeMbSI)QqX7;sr4dCT=q83VwtJg<*sQC2CxBSwnb55pi#RbRu(qDsz$o#KGNv z{3<*kTqBA)k2$L?ha?Q01gb7NWj;;;1wY{lGd5GBUlm6Dci*oMJi&(Cyv_PJ`$ zOW=I)IB)UK4~krR%IUcb*vr=7^uWLNcOX+umow!N6EZM_rThxyW&-B&1&@GU(Lq~i z$;w1b;@9G0$~=$s@&I+>VQ2sHfwj?4?Jjm}^ViQJddA`XgQ6#w_0xOOP4_0u6z{3m z%b26##WESVfNveHL3_(i>qsfVJM|--B+z7>+Cj|de^B~)JDJP&O_=gl9UkD|tGhr# zA`QfY>%9ba>vjxCb_j%wy&tnaLC9*)vX03>Yz7Z>NKuZFz(k_Bz9oulOIWF6LdSn_2m(Pr8K5iRg88MXhqDa}kAm{# zk(-1@P#*=bs9PgT)x;w8qktyBmn>a`Avh$@!%Jjc_4764%sg*Tk(6`UB4JS6Y_!vt?VR>c9ZTZf=>rr9$v*gKnG-~f2*Ft60?4c39Nds38;4rhzP?siPEgeHP=95cP; z_CjhWLoNl53ge*xXt-g#S!fb?H88wYQiO`iO*?eMUtI1&H zgvx`61CY_O!NzuPOI>E;h#T7LXRGsUexdxnSeW?^zPWEjn7avR|9O5uEd-+BJ2A5C zG9BG&*VB7A&m_;-x5E&bt=Arvh>^H>w^2U_8xc1~sBfi@QlHk&fvD7Hi7>$ym`?fCy>yfA+?1b z?U}v0Y)C*-%F^>GNmr5@dy%a+VJ|xLMo=ZTc&3o}8|13I)Suqcb*;I{5_(yWzZ zZq>Z--%aop6icf(>QsamRuFA9+i2w*EN%r!Zd_|GS+A}dcMzTArsYHlkSz>jUf_#uHc|hl2^~zPQRyy(vse{wboS0D{_k_f?_FEih+{!7vCU!_l>Ah-I$=RZeEq(7!J5` zG02zCDL~rZX|coZ&bYuEH9H&si*yKX4?KqoBESachMp0MM;8k_$*Re23;X*bNv53( zT(G7@%IG^+9lbcW;BgQo;Wu^Ut&_!ZK+#i0Z5{>w-JlzOahTto5t<2kVq~dHF$C)J zuTyd$5uYOuPS0Dsj_g(8MpK8hiXrVy8J)zaDk4#yg0zZ=J&zMtY+4uB<@a0Sl>J0# zKwP=MPaV*cGU^jCRHlvRFYx1vBuLC7%Ikq3$;yQ`&eu+sYM77!bhwua(5K-+Gxjy>~j+O1(i1Iz2z&( z^Q!pX2x9E0O0(Hsh?r8HeR&R7f!w-CBXEs>rzq+Yhk!PYg|geO_y)$=i#>F=E%|y7 z)gqhNWRGGSKmyl+F^Q#!{J2>Fd^MRp`M`2Ei->_^U_X}F-=A<+^6xFg$=ODCq#9eY zRBTeRfRxiLp_EjN7WLTivnz!MAIxn$GB2TK7r6!0=;d+vF5^FvkA!BK9gSHJVf(V> zDQnu(irhp!1ym<5Nzy{9%5e!{lv8aefgI!}UMDcceg|Z~LjX9NJRDyJx zGC}`GscnfTie`Ue6DW~~HfO8W#lW#CWn|w)Ah{2jC>XdDdK&5R%ZNr^rN))#ert3O zeb@YWY=2^d81Z2piIz2k=i||6!HZ5Q(tolXs9xr4j~GY3@hjI`_zfj+%qq?9-r_Kit&5rTA+v#|rqJEQy#8+pk)zi%fv%KgxLo9v+pZ0nm3F-pT0wVmMy)3a=6C7#|B&3hp7PSdO&L;wc>1MW zeE@d?2PwVfBD~in@2y!>6&M})#-OX9KN8g8e{J90e85~=I)etKW;YiAWb#Qak$-b} z_*ve!O=FB;zHrzm16;JQC*;}-SXigKd!4%kXkUvMeYf-3yD1s%JPJ}-Mx0P!&iYkN zSK_6GMbapicZt!&s3Zb!$2-uf6_#ug8-p_9KZGhR!VF|Fsw})&nM0R$%*#7U)MscS zM#%!gp}fxBeW#Q+c{O!VzT8Zcn9?%WrQ%E73pmtxD|gx~C(gF5T70U3X5&+_%lw(_ zbegXhi=@MJoZWO}dYG_;lmdTI5QN0QM0)H$+1v1{Iah-yNH{T_fFjS0iEg2D)&E4^fOt@vfYibcDX^#3%Ol|JTrGAoD2EL z5R0csTmd}sv<2xMglO@h*9gFrlkggd=oE~*bPqBP9-w-XVdVva`tQ@_j)2aAuuICc zu$*mlg0P(2d$Im&U8$rf8wqQGJYM2K!3d_A^!(IYP4QF|Q;qEVY?tFIv=3h6Oue2v zQT(9yRD#d|U*()p0&L6P49AwMn$Ww#e^z{6Mx@I?xB9Y&{<{al6SE#n_TH24=R~Nx znN3MZ$u!a0;Z&WFdmaXo=jud)*vZ>sX`E5%6vcG>3x&ykQP!TD>DpS>Adt75c{mC- zno5Vpm|l3RhNXy^R*fVfM%xvQm~0+r*5eiQH(rl1)uu-HG{d$a#d1`mFlR-$!4m0f zJZmZCZRe5hE9F&KncuCOqH{N^@Yxeus|P$%;6ikM|9hgs<6&X%>CqL39Yr4<6(Hp) zwFXq-e{rmIaY3Jk2Ami*9siXh%Kf|bYWMQsfvmKjMc6R;yqi>Tbw|M%?T#=>fEK^J*LFA_-&?Z)ThK`a$eUrWBTcr1Re2uMNELg6abx_~`~>oEd>g zoF}^#lQu|;gT0I58XS{N+1&erPtxBL9vmYFSMT-M$QGi((BGH)fiCVjXH;#X?k)Zl ze9^0Yi#0j9AoRVuB<)0)T+VbtX7BAtOUe8;)k336KF4}NA~qP?obI9t0!ZA*ykp*{n(DNBWW=Rp}JdqsEQk2vDt-pRj7sD|(1Z79_ECx7!ZsKGs?~MZ$lb7x4Z{khpRT#RS{n{n z71JD9Sd;I-6_JRl66yyRHrc*hHZ{#1!t;6aL8KfcbvyXD<-z#Ry1H$0Zw$dw7BKGS z#7w@ZA8XNi@?Fo^yQn6t4L-7lqzxvxb2X3aL4{=ra!EZ-CR3p^|MsR;4H;Cd)WSuv z%IJWhhUmh;Z^7n>Q+9h2yLB9{fV1fihA#L8j63bOlt-}>fV)3yPrz#V;gfaTl&7hB z#?_u4R*<|1)Wd*$hYLB?fhBV0D>42C1=UND$+I>p(rm#k_*nSo=2ym*`tmD=H z^0CN2jggN~a7kfxXQA8CFOm$e@IMusbZr%GbMf z$-^q&GtulLRfW+sfykdGYCKSeu(JWA7n=EF`)-8$OSQz13>~LJ;NDh!#4Dz_!X$g3 z->Ok3DKA{Q3>-2_cH5~Duf>Z-WLL zc(j`3Xq#F@rgVcZP*qFt!EQW+%qaxI4quuz`-(?p>dg3h7SfG{2M}Za^NhmSa=bzV z{s)Hh>kLx8Jb_n~tMxD?nvtUQ%vjbC^1R_yzTa7Qo#%17L^jNlC=Y z=MVgcG`2#Qi<$?F$xe0Nh5-d^MK&oK0hQr1nxU-ByQ<&q z>%%lFYw2Zm0vM@+m(FBbxDAML!TJ)CSBW`mCZ{^9Vula*z`91=zwlr2ijj4VJcZqT zPXA#ZaZQa%Ck*|=-km$Z>pkdLejRzBm}s%7v`VJDhh;)Kbl0FMy0*-E`Vj@D43AGhE&O8`f~ZORT3j%Ema@PIIte!akWGp z^`Jaa&NwLgB05S5V$B0=hjGHnU^I<)l?0v(rU*0Dtf2++ee&8~q|pfU?WoT=eA>Fr zB9vVPJ(hM{BXo@MU48b4gJ-8kLT+9dxBHR->2ZNvPJ`g1mLkde8kN$)jkshDMB`GF z9ILRO3q$>?2v3pWA^V;WHdg=V%nn{ZpBV~O(I-SoG3WJ!-MnGQ&9?DB+_Bk`@YFcA z)ph>RM&#a+&|&<)BKtz@UzomQ9`1faCKE4uBoE48Y0Q3~CS9Bi)t&kLU;EJa~PzaLoq9m&N_rBm@RWZo!!P@Jh2&Pr{brHQrY|lbH?7uw>znp*kqkO*L zZbSAtiin@hT^05*eg)_rF5r-9-ppt3`BP{%yL@Kk(t4aM&l`~!b=jTFD;YRjXqX*; zEP(X1gTfy|Atp?-ZH=n`#xN!>b4H~Awz*j^w=4i&sMStFJ$7VER-H4nQwCzUf|&F| zF}+al>f@XT4iK(=NtumjzU{z|sHor)WPh{iL>9rEGgtz787;8CU6xyKYOF~T#Z3;9 zB$Bh@CrI7^TF282GbEOTTp;p7>|@q@gJ^FDsc&7h*igfR?@P#{>Di#@yCAEP%(OWBkJ^DS(J5@dzNuB+1h# zlNgjNnfUmMpy=p}8$koCOBVg#P$cDlGI<7}3cBjA0s+ClZ}l-*bWeq#`|8mNg@L}?7IN_UEud4HUBn5l z!MGn zFdtFHHqbBvOSL*deSOR0viaXE(Xs`z{dH8jcwH%YK~XPx(YMz9Nc0Vrjmm3@s=QXU-2YIG$`e1j`La5ae+U=%<)FBb^@x=pK!-$ zQq@**FXML2p+YKHFjUrcq^CHqWoxx{JtHgt_ttlZU*6?y zzt~^eHZgIWYQ~{Paj@6~PLh+}8Aahm$|3Y@f426h_zMj|z=Ee~Ow0o3p9BcX zu$_gTm2`615t6dvfL)SVl#6|>FimWYBB|6UgUzl&9Q?u2ZsyRxm~Cy#Hq3PbqW>{N z4%DR%dU?!oaz^9ZY&SSdY&37TiO)o+{X#cWPpQ~Y#4R1FmQx0Rx=qP}B`_ zuGyB@GwRS0){g+5Jkbu^Y z>fGEw)I8ysyWgO(Z93HRPfz@^gaV zyS~z9!Tk@LN-?6HVe=0@&d!M;+Qoj^{oC0$R62sJF9!GX6O z%o6ROO@sZzVEl0)%I9J6wf@F(58fYPE3l6}84Bx_(OP}j#o3XW;_a7|`MO-H4InxZ zcK_lDk$nVHWst2%AUv}N(g4~r2Hdt`y?a2aSF#DZs1lMMNUPbB?W3$g=47szQov~fyq`+D*a_jpzZENKa5c?F86Ea{+EVOd zH_HZ@Dh_}Jj}jMC!--k9gZ$T-Q8DKGA@UFP&j_gUO<2rbBju}W2q0&#ku^VjKyI1>6RV7*{G}Ls5e+=UfEBM+d1LpfeAS! z|7+^UD&1Iw7#;#d4M>F-xogaJ%=kB(uX0MNnsc9mv1~*%3-qE`M%KqiDiTw{A+KLs zJL`Vih%=U`X~L$Ns>&lZPL+8KRsIbXGSuUZ37io3gyuIZ_Z5$mg7TYxQ%OE$<$hXR zP$L}R#24BBYIFx7Zs=h2+wMu#j{Zz&9wNGRj;`;vvz;YY`l_*> zQ8X3}+c>Tc$tisR83b0#?B?@RnyLEI=Yi#N)BO%xn@tt~a@35(qMnF1c9oh)bTZ>3 zH%<5%GdZv;ZBVZ}B^9*Yw%%ez}=Yh`tdwuB$IPJQ_PH&M-oteHe6$T$e5M zmv2*#`)vdm>e`Wt|>Bk-Z2yM)Cm%JHte-9|w((BG+*MmOG z$@#%)-xs5oAH#1$B*F2J=JR*oCG}qMMZ3h!fmSBiDx3~Q8*SW~nq4Hwexfx+$y+r) z9#KHaWV%U}tUjD27c!^^NsR07!N!HQcI9kzNHLL!xPLl}3z2R|PTe!5_j@^ z@;-Duxw(JwsIk<%*8XNclE-3E&V^LP^P9WF40>g6oN<$1N}Gmxb@y@VN3k*S8SESa zQ~#eVvsJ_cd??SUvN4r48SpIG`0qUP*EV`#=L(o#)ex|d%aFppOLR4107?ZF-gw0#{kLEt;iJ(VmbEk?U4J{gQ`HcTdRB zdHdMgcv*kxqPNR1TmNo()OUO;j$MWIkHT*OQ_ZyW6ycq4zdg-(JDaf3T^L^8hVgs0 zLX*w86KAq6X;Fmg!xGsO3i-1l7TgKO9PO6qD#{NsAo!l>FSp5#g9P&U^I(L9O27&V z%S3Cs$Jh674YK_B*saYLU8lspjdr%W^=vL!dF`gKRB@#7EMbH@-9!=eV*0em^fUXJJ9!)l$B>HV%ZqqI|iD8JZq>ru=)zcG@TJZ zOU=ta$2B#0Pg$uVow0Bqa4{?$y(u!3cZeyZAylbN(Mvt&P5+5XqeJk58_UKB0=hVy z;rFy5tYcgoLv$6fD}P=R!$ew)Ns{&}M!bo`)WBga+MC4F_Z~rqzdCSl^_2aHbyWYh z5`Ukk5-(2E?d-g42#N2uEs-|5in=-0nbsfF)vFb)!$fn zz}vV?;;{})bUsvREdguc!95%Ye(u$YoD^vvDh&N*Cs7;F-PY(bJoHWEkxiFZ>SUFb zUUstzyiCkH90GP4+}r)xSHAu5R`@)OXs{H=ii`N#A%sc5e2OQv3Q`TPHG|<_jo%&_P%! z<)(%kclhtWoPMuT`jV7j>0XvU`Wlx|3Bksx7|HQScPdkgIMX~%z<}%AmioCt@#izA zZ{fjCpKfENzq8#KS)o7=r~?g$+}T(@-SWEWX+Y-wIe|I2$Y0=n8wM-V{cafPPq z`sDeE#;r!|3SUzWPY-;%+SUGjVE{QrH?aRU8%102zTM08OIT|~?^o|`kB7nWU(>Up zlcw_B=uuDJR%lf)N0isYPK2>p!dBm5Ow}0fZ%Pk?q$&@u9rWyU4&{=~^Q7n+tP{Pf z9p`YyTR`3xGG1jy9!>Xg;`CrT2Z`gsu$y`Sa*{c!`2ON&W<04eD<%0nxDD;WY|Cl2 zRMgB*(VZPc&|H*FE9X(P_ed}F zS)^DIo7tg%Ma;V}rOx{vIs*$Qj`;4+jKK3DEUO_FVmhpT zjLGAO|%gn|iJ zgplaKfNsAn9I3(1mVkjhqEMaZ(FV^1%=T=lzj{2|Ei^X=@P0 z3Syh=DTJdDV=5~7VjQ3m=6O-pIsT&W1%b$fx7m*%2WJfjxH90zKL6{Qz|E;P zZR(tR_6t!&r7D2O3swHqitEDF(^q77G^69cl>xEnXytDGAS#);eX2KUE=K&_{fjP% z13~bFzS;O87>6|mIsKWjBWHXM9w{Qh@+WuoIR%f*&N7w%ePJ_R?-g9Ch%FJaE`ytb z8<_xO@Pfy&-EWNiezq(Lc5IX`=M5?*=csvB+{b_Kejbuccq$-1I#)mf0{YS7XvCMp z22C42pP@v4R2O4q?(7GI3~w2rqY2sCVtX|5UqGqb@zK|Wn1izi=#e`w@d4M_)#vW6 zJ#r7gRi+ouL7;_s7JWBZN+*8skqEVNY+fAbvBq_9Vaih995mUMfp)PoN|;09#0B#o zPr#F~hj)+QbyCdmfLY@xOomQ_)t|k}l7q=@)pAx`qJ?+Qz{B0-h(;s$NTMb5u2k() z>ksmrMSOaxT1D$09GcDDLWT?s)hZP$NIOg1qVn2isfPdFym6zfq^MS`AjHB|0X4De z4!4wmwx;x2>~GqH#HIAqr1p3$Y+5cHlG?c~1FHZ-tFiiq84DCD0f!m@NaD_p4&xsl zH{U%VD@uY``Db&M+N+tJ&KBmZc!@4pOm%By3p%0hLSB0vvep`3?s`HBZ?X-*lPV`! zU_yhdT{052`bSEGh`~zQA>ptH21exme6N1O+1po(vkrxcBgF4zm9AxRM0iPmi#9J# z*HOxq5hqJzvS--~Pk@L<3#|?y)*{857FtIm?Jo*o%DvF1L|{S)22)Mh7yim%#uH91 zb3dExb?uZv3zRwyN2{>0k%I(4Cv1m-C+{Z?V_9<`t9&IB;nEnRO6*q9N-@st;P{C{* z5IDX=GP@v&%`OA(4(!D$(%`efh(eyhK1eW$<>|qwWyE+27UG`X)bvSMylA7ivOR9A zpDywE`y%ZBhjM?V?_t4 zy~N!uUK`R|UuAE!`ZjzF4K&+C^X7VXMO%I=L(9$%hf`snm{qARLG*I5xC;81NU-e{kce*E&P0SyTd<)@+s|hG7McG3bPgD(aq?U&)X82M% z!rbOxfUhpRii@;yN?pn}>B?Tn{HW*ORX--I0{a{?q;>HF*2bXwV>YPJ^BzzO(>igU z$|&dbRRH+>JA=1${bv+6fgBrc99}9G>*<+LTE2_@;9z^NS|iD6BmqXQpi|rz!<(r0 z9;xAduX`Vz{cq~b3)fRnIQ8+FE3wShe$wr?4(k^5B0Q0<>SbsepKjVYa*^uCK)niI z3;J>X6CC+9s}~=gyt&pC<`xsJ;ls!ynnLpi?^INs$A_W1Y8Ux_=i*L&qRXcu;BQ+7 zbBD-0FEy@%Cmqucv%S>_GV@>5SH)(22&h?>L(rNh=w(?31jM~_#AxR2+RRw4lQbpG zg|M~Ah3ozEfRxYy4x)L-Rhx|tu*?@0ljEBVw9V&Q@klmnT|v)bJ>jd4BqA0olq_l%k(N&o zOE6U$r-h6Azet%uNEdW0ww#dSHf-y7La&^=R)emh&PSu)Zb^Mj->X;v`aiYHt=FaS z$y_gLj7)>}O^zRuxi#?jlVr)XKW?iAlAS=ss>s8MWZA>Ym9B2 zT%}BY{&0@Q?;V0}1|TL>dZMj&YOLj(98sb0gv4wUXZ4fnuVM@P)k3Lokfq-~s(%`V z3xAB-OJuu{3QJF4iR$q9eSHBgb>t-DkM0(3)&~KFso5L}rrhv!m=GMs+kR`Vw7g0~ z3~$|Ek&c4g=JBQBuaEsuP=qAI9T%>RGNNW$8?$!^UvAmOnCx+*aP<-rIm@oS9I-jY z4r*d3OBs)Qp$RikR+Z2_&Yc|m%-qYerh?C4pqrZA!~u{FER>!0E2h3PBIU#u4L5#k zcw)Tknpb291962SZ%Kyr)MN+vNgR#ggClJmDm7Se*M?V{q34Beg&=b0SisT#ngCOv z^OE7ak{c#(niqvJ7H5e2mVY*%g`rS_9{(&o%Bqs8Z?ODfpXCc+s%kq&Em@q{QFPfc znvr#v;DBzNHZ6>zhv(Z1u|CB@4IZtz_KVJgrLCu_ymF4$o2-L=LL|!e5Gv)gP5MYG zlv(|CJUoTC)Gi>ya>Wjur!9;uQRn4MACRtf*Z}Z0J=v_lzjVVj4~3x- zcds*zB<8`?)cR&qg^uMEk(C?IHVEjw4e_KAQ&0}?>rnnUB_`)!)66Y-XJ$hCwN+*I z2(BH$-l%V*0D=4@Q$VCcgaaem6$_9wapBUqxsb?#_R3#s8hJ$xISQG;Z!42y9TP%m z<8yXP{Qw$nIz|v(tg+<5vt?ztg0gz-mO6nK#);1nepd$-le`9NBXi7m0yaM)$da$_EGEbJtf(6MDoWXx=rt2&= zsQ?@h-UA_GQVTqMT)#h%(`kwamjTi%FJF&MSs98{gdIE%Qo`TJryh!md|a* zjtIdlL_&JbdihZJsg`6V$@%?J`J>MDhSWEho~5m&!ef3eu;ecjzRy=O=s5pP!02kX zAXrSA(!)J;SagVsko6vf8EKh4HcF)gq*^PfQu(y25_~Tlm(bFA-4l5=PTrIU6=cQe zap-Rxl(kV?!k$?zvsqz_X<+v=q&^r&?8NSAwZHMbII-2l)ZzY!&`OL_e?|>eO!AN8 z;zW5PxHwQ?S6w+*+sHWp9m(oKnGoHSL6tEoJ<28Y;UBV%tOFmKm@--zciFp6K{7b6 zszD3GqP+mYz>qm7s5EFTpbfGvW$5xOVnDDgLP8R4MoD4^8O9KSKqo+slE(pmY>@W% ze=$Uc_c@$C8h1B`eJX9Ss3aUN5K!BPoA@lh&Gw2%CDMgC5piX5lC~gJ!iZGH zWzB*uaPi5It2;od#vx8JpY}X8r|>@m_1=z`J)NdB&N?nw=!r}(m5JUHpjLsq_m6+* z!ggul5-#)&AV^4;BF_S(Y2T;*bBJ`5s8l#?v7g>>AX8%-qrMp~Cmp$mxpQF)4!!>6 z>slz<29ipUGK7*6DJ31UA8&sNpp|5gs^zhcsycrfUyEJG0nF>wasTqMUjyxY=ul}J zp}LO-AT{JwV5h_9PlU zdE-#h%o=?y44kBDU*R^f+L@eoniMvA2DA)g7(9*PM;!Xo3$0-f{3Keu}5z z`CrXCKMz9u)HJHsHGWYNwsI;7wM@?#C%;orAbWf%4-ouIiGnu#Wep-h!>vS5U^^hm z{0(z@DZ@v?Ai^lS>9zgz;Y2gIP1x}${yaAP>bes2rk*y0FP+M2nD1g+fLSY6qOl-R zXBqi2%u;;<)_JJ6g$+GQ%j^5*h+l+35So zZWRT?5F)U$xl;_7>>C~lKD4&u5c-nTFxM5+S(BR|k4P)tlk4?H~FhWmGx# z&$uKTKBETk`MN`ZZlog9USU{3SdV_;L5J7DKV98clt} z{z0ZA^V6u&#g&fwz;$Hybbr3nDYH2v0$t+&eC4ZFl(64D*5BK9x!bpMW19r)LOJ~C zz0RQr3%ktBLe<3=Te#HSa$!S#I_@?=;*D^5t!wZsUJ!G-Bzl^4GIau4oKLJ{mpoyT zeq<2vBMrq843=!mCvhwxhIK(SlI>wSrpG{JWQ2pNz~B-3JBEnxLO@&$TP|`T$OJp) zLmn4BI7!GD+3zHf{&KVa_2=AO>&79)m6lS4HzCaT*fhJ*>|E4rlncDSny=0sZNt&D~>)p68dyb9J2W9~!? z2Gpep9yDj99Ed7BAgd=6tcDCnGA%FH$IZvWjHk?PxNT)b4wWWfp)o;l_}I`l$f(;K z$?Nas1;+_ARP&A3ICYPg^Tw7M5Df~+{AY4cY$KW(#uFCtmaeZQ5m)>d&!XtA%r+VL z^3%j{Sv(g~HxO^=$y>dS!n-Dd{z0X1gGtqA$cPR@pjZy z)ai%(YqkhA39*{W?u5TOcns>{2+RQhv%*0VObW%Sn4aq><7WX_CQ<3GB;2XcPB}n= zM1G}BV~=(HE|SEdV2C0~s$R4to88KZu_g zzg_^*44_2IlxiLZg@!bN6|xK=xpsz$st3sWR<)TC8AnxW{I~1~YRu3K@mk5Frf`^r zq_&JitykC^k>c+Dry*mB^BzSf>% zVqypQJHSCi1yRCIhdd34WJAYk!g^xW=*&ieYn3pvJ+0Rd`vH0XZd+a5TNEiXn_QCEg;=2wvO zvn6K!@o?4tR{wbdZJRxh>(RRz-nL*o_88F#{1h%RjgFXIT7Z3s=(}#oN;Ql1lsEC)>_{ZH)GN z4;L4M^>#nAH)(EQY&FcT*8$B6#%;GVqopl2$&y||Qp|VgY{t~i7V^EQ7h38y^VENP zKCqo#hToU3!JXVZVUqeEi6M3EE@7gm`ht`YPaz**s3+!Ti?%NeE~0fI`8|=(yb7F} zvI<|14!#JEKOi=+mX=MZS^F~9w6;;rt_ zjUtFO4FK8N60-;E?S(P>jLw=j%NoL1hJ5$CS#fN?Hl0N8ylWPMeAU+HO9U7VQd;^o zR30t$XlkfX4ktrD$kZAYOyE2|UTgABbqGjcnxa69&^B!%P%!fnIW!D6U4CkkQhf$j zxO*5Ca{m^91soi6zB_pgq#V2#c)u8ejW~X#CI6>}yr{*JB$iKWLaNS1 zV&;HHA}6hf2b~}fOnL78l&-W-GpKr*EblgDZGQ)9Wr}6cG`R;kul3qg!FQbTd@PA6 z!feIyCX?xn(L|wR+U^Q8>ntZy952llB~iSK!5Mgm90YB^FGn_tr4{`F{4|-#l9rEGfznVVKP|2{_K6M=D5>4ecLRwwB_`Fn z>*yyH@|?;9Mj>35nxFM4+xo@|g$CJ~DQuv9+6{#`V}ckTePtLHzm?zSwvFrp$qZN| zAh5!X*VpJ}^e_<=z}HXI7&}cdy2cvSMUKmr-rBvJe~=XTw0M_7SlKO;x$ZK5Ft{}~ z%mqP`mEMAG1hCuE7y}&$GSu|$5hMY5UGZs^)dVqR3PWlA{Zx(}-+{eojqu7in>kxD0aTm3etC=Q?7$ z;x=+E8hUe{xeyks!E@Bo_UTQ;PrR}I#ntfQ7_36XssnQ)_D7if+ISYw9Ki8+v?Tr{ z?HU4n#p>gjqBf^P?8oqoNXs}uSgw5E37u0w_NlT?f1Hrj(qx=>0Il{EZwQz&vqr3M zyRK#-PHc5em-u3nh3zIK*h~3{52_IWW;&Tb69+q+scP?p-lXbhvTCL0xeC^zkp{OvRqxxBug^hmpo6DQU88n+692gvSR2MD%}$k+?WpSpUZ% zxz;{+++;)evEdyN!}XHT=F4(bs&WvIHCa1!@@A1;f(<1ij6#l7k(6p#Y@gfNCUs9r ztZx2Z@^nP#KiCBAiUOCgs~f_$V|l&~6NJpH7}}Y=nI-#aS_|w72zJ`USNiUpOy^QQ+rmoIKv@pt(OLcRhL>wVqB7VaPGr6&c`?r?DQfG1x}>D}*tZa@7;CS@+g z9?y{A>kl%Bw~rWk%C%%oA1THh7|@*0Zqjaybf*TDzR)OFpkfPSokj?;BXJOfn7G`x zX`Y=M>_G5oTqcSj0c$6J>)YMg7c_g!?Y`O3ajvt|V@2%1ac8e02LLmH7mtk@r--&| z-$zLy3y!*($-;M#I=y@Pdb+{QuZWeurR!>Iv-frZ#cjXY+REwe;J@AKfBv3%Ua@h5 z*;A7O5%t#;yKLH4bdwGZy#|xIzaCX@wc;|C9(;xK=zmclT35k{Jow-O$~hun%S zZxhTe)NGvq(-B8m{{B<=*woJ5a~4@Nt9vTkb)Q1|*-E{CcBZ4Vm3x=|(%#Zia!3NW zQ{=wf(TOa&+5d*(xnK;-hDF|F8nNe)i~0Hi?bZ`qQKPe^AHM$HzwX-Xx(RtZe=7G{ z35=9;h~`@t{W~A(gA#Gf+0Bo3s!q;07h$GdO%FrndFZSEfpv+sIq>(`81gbhtg0bV zX&%Q=BNhJgZ8`9M&C5VL?(GhGH9^L1?GDSs_YFK7qfPHm=x-P5yHscTB-V7igBS*% z;+1)dz>^&e$Y&A?Ay^)f!q9*To)r5sc6;{n5Mj$Z3!@32(x28- ziex2N(Add@=43&G|5oDesn5s9>Pzn2PoP$I#&C5Dg3M7Nwb(jiiOxktc3`!tMLGN5c!SV(#2k}*`5T#GYuY^sN6cOp9a&h*VEbvKsz=k}f* z@azx&!`L}238MvTwrtzBZQHhO+qP}nwr$(CtNt?YiJsj-ck~PF*rSZd{IJ>^M>3j- zrvCw1RvY(j0ug>1ucH)!Vr}Wc^Ie8)fZu{Pt^@)x#9iOb&aTQr-N-qZ(sr;pC?^&^ z2gBeL*6?@~g7eCZ4`DAW@v^EdwGx|Fz7Py|h!<-rj(t%8-H_WumlIbe(qw}>CQm4# z3*pedgJ4(Yk5W-km=Wq0pGyRmt-7pHDKQbxp8=i`Tp~s?;AT4{Sec@MUI~y;V~Sl8 zR5l}Eqm`SOwmtH>4PCC1_83l$oB`9o;(SzZk3^j1=NwL_kuRgmq_wf>-TA!5!dX9% z^CGyK+(rC{{DeW#2=z0LQ`PDO=>HMz;UVT!W;RV%ldo~{lJ1JG#ujWWNex{p$x~d#@dsFs_#b{`-BBJ)e!= zB{m|;6*v=LZWQ8LgxVA%|56S^MkJ&i;<;DpN{7`nf2x5=Y&_S*2Bq5SvaxAnLti9v zBrI6$q;O|9(RAflY)Bp>Tk$u_RE5^gn+CDkw8#wycQlA1Iu z;vaw(RkCHcGpZ&PQ|=5NX_6hL#A=xGFh-}%ZN|%_r*Cf2Sl;lHqGDr7IH#7;ddg(#lPJZ2g=iGHNzTxoDYDjMEg4w)b zaaGJt9=fTiX=w70zU{15Qv&0u~MbU7GAsjK(Np$WFP*$%cRGO2kEO4c?7G7<-{I3!v(=JLPG2~=u59$6ujDl0+HoTD?E`)2L3y)62OgX>t zu!>gGp8nRg0X~d##C{;Ukzn**u4>Cd5VklbYKE~>8+Kl z0bj&8lZwC}WWx66g7Je#d4>U12N`|#Rp|kd))r_KaH`_ooew3%R5MX&68k?0j^2*T zC=i-Q;)*)0jJH{)^2*JhO60#Fc^{n;Bh#C1SB6_L$I@5q&<^bG%m32q#QBwicdF$fo~gRChXs4OsORR9vtl%n zlDX4S>UXjv(d=j^NzJRu#9d=i_Kg|-Kcr}Ssc1` z!gKR{^OF1}&_o7AW@R2zR)Q+{DxzSikn*YN*MCR1Tw|uJoaB`I7;TO?J*P!1z`Z)6bV7wm)cCReNm8;y}t5m5=^T}5ZYf8O9Nu`$mHEf#j|F-V~76qdtOC*=j zkbcmB8_V}E<$LD5PPexC>|z*`@RLpwmn7tX-U zXGpw}$$Q{4aZgKcNkAG*3jES?5o=~%6!ZS%D^+uqvWR^2y%NG(x_6AhIACuQ)$pZ zxvAg|-WlokEp=$pS&~DTWhMvN7oyIR4pJQ-1D5=wxDjksBSi5Zx0GG@s=M`M+a#;kO@yXV?Yloa7r_*TEg$A-SLXTdp&$D8+vmFZ)7a=XSvSj;pQk)$v=^>dLs< zZ#9yxo5KkaMaku;yLZ=Bq5P1VT0t2j@FAQ^`&b&+!_-j)VThwpKtFbCxR#^n)Z+_R ztqVaBXiC~_o=)I9?2P1!X~@KA=0wOn*tIE?=lP+aKxSZI~c_z(4mEf z$B#Vp zo1eh9_T^mQU~Yg9Kb9KG z2Cj>1(I-$d2FGDCDbIyt_L0geDNa?}W5r?8^3#qORnNnm@0rs!K4~hrP8X6@seK-$ z(P%a&P0~l+5bD-y&pkDzT6`+WslAf?>Y{EKFof;W&?|ZteX6EiuuA0auW-g)iqS2( z*2cJts!Hx;%sO|PMjuTz=s<%RwT(ff# zlU$6Q2#(;qqv%mDvH8rNRZHq~M~id|=x5?Teor9LBX9l{dX##82Y}2&%2mKjj}|-0 zDey6qp}SQ)LP(zYm-=Ps63 za=b08RgxG>9vfmG^502Ca~YDB2}G(f{vD^EH4$6*~w300q?l z=UQu#t7==n#DMZk(|?44+)N16=fj{^oXOA;-D3*#f|XoW1B%ri*Mb`~_IGFLjyM6j zKQX&&IscF6{E~BatxC9D<32^B4#uMrUVdACEBM1C46wdVqZ|xWghKoVx6e}uJ`&pd%!g&&P)<9{FIk9LsMS9k7I8`k8VdY9QRmiOS zShvLt(`yuS#$B$?99GUA7BBZ{DG;s?6XKFYZ8XbRAlCIq)xh}-M`{+`bgcmiA`D*9 zi8qfFA;#`N7-4*nqO((|K@&CO6kAU+(kB;EMT|L0s(DygJJb-vy)F@{Cl*Z633#JQ zFC}K^62_JDCNHMk5ZPd=6IC>DpVjv8vyOwou43Z(c2K)@3%GFr zktU$$-bJ#Vo1mElOJu_<8;r&8r2{x(V71;U)e#dv4JlT-rxoy^LIeeZ~ZNS}U2O0W7 zPUg$)ZBGl*vd`mw$U~&-a9b0x_D=Bp#eZSr78f4zIl+hH5Y zZ=7hcqJ2!3JH&9qmwm`}g}*K%9im6shpBNot`424C@FIE7On)w_;JV3ckU0KoYe#O z5F{~%$PZ$sSiX?Fzx6;N?^*QlexcImPJ|3R2{7d(4 zhRAXi+-o3H+3QrCj^uuQi|*Ex=N{wV0bNL&th{SR{LS7W+W%X5`jHWSe4xRfKw9 zK-c|>?v_{ouCvR2|More)3_?NUbEGMSL-rSDW+pE=L%;wKkX`f@{h*k7e(f#_Bn7s zc)a$j7=>~kX@4}B@zX0ABz(?i^6T<>d4=Hy{9NIjfVX47ei#AdWD7D3&f$Zz49-}x z8@4`kIcZU1yY0Z7JAsF3F?&O3Iz|pqaQyhddV1ht19Rsi#(Ei`Rw?X6hltwTKbPKr zIz#pW;gnwuliWaVa&b{_l_#k|s0%wD-bK>5C|21*3egX$0%vuZ!zVd+)bz7>$E1Kq|@)a!ppNrn&}H)>Cf{2d+aQNx&d!t z0{~za0ss*HzprU-mL|q@#w|MD&PQwrf7~A^R$RS-+)~1L>vGH2Fo5KSQUO4dtiCa0 z28cYYZPwX4rMEB5?&?X1Vr)(I>vGZ!tzX-#R;}G$3-x+QatM6lcgIYGt)96#IPG!$ zA@RvznRJ+!-M^o_olt9i#^iPf?2_C6Ajsn-M~u*T8OuE-^oIHe4#r4gg2pHG5Z}8Z zFo+!+B=$BDy9wq8vu14ZH*nbHh}_%cFdUJMzUI^gMbrY1>GA-<_XBy*59GhSYQh6BxPwRx{K}{6Mnto0&xnd#O*E*bmX>O)t%Addb zOeWYJ@*#N)_RLTxcs3kDR3b0DZwQm zIST2Phpk|`%w08j9xz}v^HXpLrF=VmV|xN`QRu{iB*ae}woVzez8XLh&#y&;hS2G@ z@=&eRu^3gu6iJSQ#voC*89ar|!9GFLThUw%i8#FRZFy$8_-{r@|FA4TBOc=f>d21Hc=GVC( z8%iKQw4!%GwCI2j$9JLzqLG$X0VxHCXCmBGni(WST%8TI$rbj5QaWVqXxu}G5t81P zwz6pADt7>a>+R=S2*3k`7&pXqW*uO_Yz2u|Ia{Un`4rfr)m7+t-IRmZ>)9wG-7o#M zeHnc)h-K`}4iLMg^N|^c7qWLR6oe!;C13D4RX`I}(mVtO?iv&#t%3 zj$%j(@i#l)nw`96-U_9vi|z$`;2_M=l&>@#LtZr9NTW6}ASJ>zz4|8vI5Uqv@GS(m zCIG3hXm4&dlRROa;Q5q?UW7qvz_S94hp-U25FQfPSYG!>!2>Z13&ZhkIVHJ+TCLcn z5p32XSdi_)QM9~QJDMvPJBIxvB=96YmCid9r&FqnT z+*1+Gw+b4bbq&rz;VoGkNRlf$^ZO&D3}_@y3Y#!k5>Ui4egAsrUsRsTB9OMM2A#?v zoUa!*YC`64cmk5%Xolo$WRRt&9*Enq@%D^xCqE<~&Sk$hd^DEi5i;j+_N9~I4m#Rf(MGT;=ME_EqX?7Ust(Z~^?1qno{aJ0QW$$AUFzZMrD zp0G^P^s_N)dfR>yo$>u|{w=6~zZp#Vvu!t9X(Ixp=FY(Ym$joq7By0n4X9O=+@p~M z`ziyxrM*Ch(Zei~lxmMaPL7B@Px(U6c3U+p`Es&@{qn&NPJ9i3fz4ZP#}C$6voRa~ z3O%z)VcYny0bdgbt9lqFeP)S=5U|{1OTBOf)xQm9XA1|ycISN0GYu7^FSS*5lt>Dn z#j;6t0&m^|V=45Sl%`5j)-V(#m`b0mz0W@3C>7;?KJ&IVB(#^Hs`nsQy?d@-!nj7Q zt$!2u8#X-kYr|ooaqCChr3KvM3Vs~6X?p)27u z%ATQhtU>JBmBz~(QnnZz_@je%QgK)28c$5qY+rXdc9H`pVf@vs(DZ(m7)2z5PA<(;Tp4ueB99K`wOT= zk<(LP!C!bllOh09G?YzU5rpYZ)w!LN2k$Ij?{+9$6Ogr{6Qh4n26G0|C|Grw|xFB?4YIt`ITI`b50V<}WmrgDeZu}Md! z?obSGXntlp1!>=|i5AjjNmVcBsh9fcte=+tM&GSE<9OFZYL|~VzYPa1zMk0c2{MW2He$G*zjxDG1fHR*4_i-!W6s)ac)w% zE$70|NRQ*7jban)eSqr3%;zDa6*YSFLNku}>TYm$c9$kmgrXs^HL&FF>>QVU3~n{A zIp+I%oz6LC2&0qChoi~~)eweG8oobVpffv(i(*gmIw4U7Bji;f2ZfsotfAlzE@_xrfXjZgI_?g33*Dpp7L!9cC?D zz)8jb?3|RvVP}(83AgzhDTI8eyst4Zm+L=T5_GO z4Aks^umJXS=&74KFw7-tY=cTKvpPC)Eh;)YjGZ6VhK}*0ih*?7;rnuuq1R zvKNpf-cM3uDP9V!0#WbclC%DTvw8^r3VInVM7sXcE7G0UD$(hxION%ssEUc?%`fRyd1yvE|KsY7lGFX1G=&&pR{=*_EmKL;R zcVJ<=@lJx|5gm;E@a7f3o1x-4MFgLr$Nk4wK}<@C4uV~r$BIx`F>cmzg}JSMNw8YmS_pWUG7qtEZ1#cIrlvUnVN7$6yvBIG$@R)I;pNn zeUHF31Fu#$FIl~<-Ja6WQAH;bFzgCfX*-0*ZeBMi!b?}8s?Bhr++8UC6!xD_l6ca4 zsxuN&Rc2ii&)W#^qK%*3x5-6h#F?s3u)|03)K;!Hm0O~z>|5Ifj1JxVDaDa#Xt}*=U1Qzy^7$6Z2#z7^5;6suc*+toMHx6sGZ`6K2r?TW7O^yhOe{Nt*2zkUViCK5u_z})F{byw zw{vbqIY2*+B9t$Q#=&Bcna3g_k5^(Gt%f+5jdL&==Vmd^!D5`7@y^M3^|BfDvKji= zjD31z9|gOWiLTRaM02#u*XXBG)~G2obUuXP*Y!bIoiAZtTK%NI+=39E*bzH^8j2i0 z$#zR7A(GE+#$#{1cb?AgSH)seqEOYmAmY$@!j88T=lz>_FE%08>1YfW6?waxbJWZ2 zC9SDwp`|;t{q{lTcO7m}gxx?$GrQ>N#udQ3ddNwu>`(WleGE6-0=jS)k^z<)%iN{uSF?YGwc1Vk zB>G+buR?I?%W9*Kk^erKhi>aPSG_?li#vQUQy0c!J?@uTs9KsppQC~ts%omo+gSPu z+Q<`3-<7!-G=CLtXV$9Q@5f&N)OdxzaYCqmwy z=Ep9qq{#VI2%;;Z&aTZw$H5M?(ZU@gM0699 z8Eg)q!gal7>h^kRJYX~l{iY6{rV69!VvitYr%_%Ig1@H1Z3zAkLH0Lk%r!ro@>pknYI|1VCq47fifRW;iJbnXmwwX*kl%|Vr8i;(gb#DMvMZS=V zl#$nH&3+&-NZYn1bdW1?8>OI$(=OlBtL4|BQri2*`|_Md64Dy|8%5x9^DNU1Ab~Z% zB-&4dCj;c@16t&l@Dl{U;`a%?Iq@F?45EF$VV{4$*uTs;2(41xq`!Y8-fs@Nh?G(F zhu__d`dHXUr4I@Q10dKDb`W?9D`uy{4XrKL1rWd7?tI_;@tfm|}z%{_c{wLG62^Vpa_+5GDdW00hz= z?b`wFU%2regOR{c3sHhn>|r8bz3iLC>F_Q0vigt0Lgw5+xrPwAwgTe-JC?u)bKJc( z3{}SBl%y-6f1yf~?2R5NhDp{6hprM47gD%l(JmBXfkWJ?ohbmw zNDzgD5zPBz%k$G~$1U-C;e(GHUyNCCiu)TdO9cFLsTBJ-E0dmCQ-D}LW4+CBh+LfZ zdxUt|Dsj3;Z`QQT@jq6n9$5!YIG{!vKt@2=;>J93;m4GBfwa#S5)K}Hni#D1-^?H? z^9man7`1#qLTzxe1eFNP;`uv2dxmZgSVi4Ceck;(HQ_l6%4FR}M}$*+Ckd6hxzuZ& z-sfL)ZVA|0a8g*iao{X7(&WL$&qbP1>K8n+e@3~*)L!C$s&5uF64SU+tDGLc*nF%0 zdzD;pkkWq-s?V9PJ{Hne-FPi_kgo{84zGv|sYQijUs_?oKY^bbeTmk1oaS!_i&;SM z6dSuxgaHK_yANCo6d<_kkFHVBft!jCpUXJf=jBft;C0B5A-vTR#m_6YA7d@I)XMi9 zO+%xpYAEb5Z|i;T)*W27tj}t0Nu||d2$zwnG!J6Q{$~%%y#Tru@C1F;r?P)$U!sepCV0cZ}_XBbLMv?<;r~=cL9Nh3Qmz-9^*YpRHvzY}+}v zSUqA=4l9xXT7;4?C%w zSUPl=NW)y%P^K%<6LfE{r=v|p3sW2+QVw=U27wz@5@DqJkw?46xQBS%JG~99-*zot0juNa&4Z6r`C|t+4}@O|ECD5f#;k(;5j3d?ixK zat^-qrx;0dnq6R0daM=dD#&;t@`aFHp>&y`9t}ch2lD6?yKaX;m4}M(QD1CRY{?)r zeGMttzTY@aBQT88L~i;qM6@e%Jsqk2wtDeT|Cd0(!;cy}7%B8-8Dl*n64eo_>n zEw6z>DjIX_(&6r)!mn2c7y#hd+OZsAKO)>~%k1me!Y=+5%b9)54udBwgn79ugnXdY zf6du()~5>LZgf?iPW=JCpaedZl{fn$m9Ea z!%qm0<@yG%gA(HOs71Le)uo!nb&}rqCPO~%aRyOtR~b%L?n7DN6CEE*v4W`57wkoz z%w~ufJVjtuVYH+-X>3)!69~K6IGY)*g>Ajot`_$f=TWTB8Yy3iD5A#y`Qgy6A7ASE zgzTM+G{*C^#ES?`wt0l!iToYrX57U`g;R&H%QD|CQhF}6W3aST(Mn}C8(u%~nw|q_ zo6xF3T!YGcXWLtD#e@QZyVL?6M41deZzKRyGJL!qq1iVG*x}j*X30eik_**c?#}W3 zdSUm3KzueXjo#-3{~2%bp~H5n&JL8VoQ1K$DtfIfBCgJ$;q8spDV(#~go&hfnm}LfBKG9q z;={R!r+}p+xArU$EbPOZy=)|U7XpK(;TsN_rX zedeo>JHW#=Dy4Bwuh%MR(>BFxkS9ho$e;?Hjc0e`klb{q9stw+nkGL&>=E4MN{I~F zx{Mt%4Zf7L#S{oBLKosSVHK@+_^ z9CoaERNH|s;jh7qt}CoN6)U|+hkaA3NzY0V+r^LGpC*;vna>x{0ud&&Dv~D?>R0v6 zy9bJGEruPB$E=3b?1~pht*%lV&k)76lv14l5P^AL^!zYK)3YoD2Wl2k$dA`6=O7?s z=tJ2CMiN&{>|sI}B9XW%e5hNmw?={eeo^-Ii2am~@?N|q%PXHHHa^UgfHp)-7$)|1 zYCq2~Dx-Kia#et7h^}68Jz`4=Mu_m}(D(^k$_v|nRgp`P*9v(vA}fu_MqMyi!-^|1 zIphwRqMuI^FD)^Du;`Xs096->*wT+LuvmajA%esyaM&zOA`XPMR@)6l9hr40?3KEb zCoEO|rp#q)|!_tZ0mGEGWUq-@`w{279e@zK7kO}C+^ z!Z?)gFgiFL65;A4OlvD@<~=gYvnd4IjoFxk#)Cpd%&MQh#&H$OhxThp&hD|0FKgaygOC4 z+p9UuDy$M#M?b<^NPlctT_=ymURsiK0U_xK@(Q^)_gPY{_o_6Qzu(?;KFoY+W% zm-x3BRPGh1GlzInJWbxSJ@aQ*q;`kkzQO*tFeuNg9}0sG0HBfdpE&q`5eEN{Ab5*w z>3q!c%>082WR`&f^d1$jX+UPXY#Y`_DLKVB;E^+8$$K*7*hRZ;f6hA@cQcW+%LW~~ z2_sJ2D}BGzOhTRSFB6wu9nR6!DJx;@BLO43&KLTJA+T76=LWk}&nu=rzF}bP>VW7h7)PA~1Fk`t9Cii-_PN}umxkDEjhu*0bO=1f7h>J z`Dni{GHnB&y?b4u7LTu z{}$<25XJebqTt8R-61EuEp=f-Op(b!7;cY`pFV;p^n}TQQHb-|^uDPXn3s0_uwnUL zUq6s&p8K{>C@T8(?Kjg_b;PqO?zUk4Y_2#ZMp;NKU3*CoDgK9Z2&v;la*?s}a6 z60S~eyZ;0D@auyY01BACv-Qw;Wjr^>bsijII~Wv9srQGL$@$v&>_+A)g++FZdR}hj z>WFF2#W+_5u~EOfC??v6rk1YG+(O-G{W^Fyy!%UKx0de-t$gRCZa!zB|CYVJOBlb7 zE5&$Fw?v}rY=2Lmz}rhaT~rn$qqWL$U`Qq^3o1uYUY*Sdjnqp=peZG^GC{ zFIA(j%O0Sd4m{nrHhR3{k~UQDW#!r`W7Qa{Q45wRZn2dPp;)z|38R;e@X9VmYqg?9 zhOKdmcud*q=qb!D)>v|Ag>HBuLXjTkoTB%_qj!0EFdVoEzAk<4M6=~6e}A9F*KKmL z3l`T`-8OJ)-)nAK`6k`1Vj+J1i+2uyxcw!q@G{jRecuZqysjGtV4U4%+Z`rMFN}V| zH)B(@Q*=_b=JGT9h0k%m>lQh#RG@cKT$`$46UtS7OZY8OnPQ~p9v)2e1Njy#(LpU5goFo+j9$5QpRO+{y?057Ua@}Y9D z-Kqe7j(dFI1f|b;vPc!Ex^X^v!r^}mKj|rf8u~BWzpCZ?SGfS}+G%(;x(|#)jj9f; zSAATZ9ok~Z!K{3u`tQjl{r<=iyPrk6aTkDf;GHS~>$gR}sM9^o8p)(#wT;yh>?#`9p6$|TUpKvZ)70Cqf3 z29F2@O9JEIQO@U+mVklGBd{@Ryc|Me13_Ef_2fI$-VgfE` zSI*OJy)8O2d5`wPCJ}7bG>843biZ35*C*E$wo88N@jx1{5dDcM*#>Zw@6LTl3fm{; zV7koP`|rPO_v+RA3mLaf%8-Um;)tsN3$Zx|;qVC|X*bJmZ#{j~<)@3nktT)>M?Eq0 zQiV3+=-M|5=C{s=FTBdi;h<`e#ZxGN?ak0g7m`Uo3o#~ZlpS-?nIPGDTzP+6vjwbg z0(hubv9jUG#X@iK{boUFK_h_A8Qsp>vOr4$t3gkE>7VH|6{sgjFVv{m(nuu;gU%E` zR{oD3>*&DxCmdXL9czN> zh%hGv0IBDWI5xs4NHM)*AbH$~N0Y=H&qk3yFkQ(_yX2G^Io9TY%DJ~syBduwdfmjI zBNy&aKI8SIe|6=|8{&3JI(Qw-3i=eMw_qNq3l(buSqwtF)p|Gohtgf!No>MFiz&f8 zgR4=5yY7rL#^!D)8~H^`+vaXa+nNV4O~-x&i-}MG8&W1NQsdX7^{^HLs3CZEOpd$_ zgBhd|MVMXhr4i8u%z>8@SV!`;fK($(#u7!5$`XraJFI-JL=M?`UuO5~B5j8i-Xn>OOS3#M(F9O+ zI^YY1@sQ^9&7iQY$^DmbdU9zz#}fkE3=T0bibQYT%uwb-=E(3S{w{(jL)M6203JO{ zoT)|&&D0y=e9mp!BZ{kLGYvZn~|$Pf6&p;kbxDa9feq&L&+@ zkqM*iR9Hw$PRPF{Q*O{WGrmTQCR7mr)A5L2V1wJAGZzT!D(}Ct$QG&W4;i3~UmIq4 z4xc`AA8h)@`iPK|ObE;QwH)J(8@YuPSs+$eQo!ytWQ#z4!Nd-PkmDnp;|DO-DBSQV z(jy=?blDN~^$1ZY9}pnGQ>w<2hp-`x|I*@CKxXc%ULS^@5?5`990IA>@yIo0;nWnM z*gmR_o!$^iXt8R605T5c{f(@j)hoaHC^7kMeov74d4=(;Jvk9@Wa9kbupT>mxR8soy})em83Fcx=z&1CM= z9P2~%!DzZN!HrpJJ3{T$pb-=5WV+Y06Z31t*rz*Eo*|V5Xg(Z}J2q$ptDcv#BzgOz zj$AXKl_{N~D5H4lE6Z?g@G7=yr`dT6q)}VRr|8ZOl)DJnL1^tELl>J~uw98XDELlI zQO)^i-o4Kq{z`@?cZ}|8_-pD7TErBYutFDw`jIFc0BA z0%FW#2Ha-RYA5V_lzo@2gv%(qyPvS<6ZhM3*j1Cl4Ak%gtZtzu(B$v4QS>EgWqlO&y>f^!dq$hJv`U`n0I`iFR%GH?EkfPaw~ zYZLDrf1U-FOF-57^nA6xri>>VduIuew%kOUzI=YRfet=weOd86ljNP9?<&y1-o2j7#O-x35r&_nJ@2}%8D&yt;Ys2WHiw@6e9L&LI%9HvwVi|saG4{j@gLn4aXk}Vj3hPZp7!-z?^kk?Vm z8g)9W;bsdFqAd=+x}OJrZ8B>mv36`aY4u=-h>?n*;>D#a3p9YYg3YD3Q)+|NDA2k2 zb?XgmyA?;O8Lsv+D=>?6aGS^#0i;7HU*yBB*Uq|i!^1CxzVqNew2>Mq_GBU3p(Ts8 zQEMbij5~no&cY`H(RfE?(>9r9ORHmj=+0P0>B|(a(o)Z?)Hf+Sp@QS=RWf#-}B?}YwV%K35Twz>8B8X}y}g+K!sRj69IU66 zem{L^B*|4&lub0Cmy!-`I_xG=ujpkGg&kF?bL}V$?$sWK9A=%pcc%cV!8__yVn&#m zPrxy8)>m~IO&DcV$kiHL!-hAN=n}_X0bgKCSx(6^jcQBqzbTAa&a-X zY1opYWZkB*w_{L0V<$jhdYx&Zk_=Q?v~N(yC`J zzUh@8}RU<+lADeWAg|KKGT05VP7Qal)bNndK4!tc~i!$ zt7BCrxU96*cFvADBPLnICzq@~#pu#XN;}O$P1?D^%N(UmY)TNTz=8P4_=82NiqmG{ zI4Rdxr0M}u&FuiFhU(blltDuek8-vM7@CG} zj@W5NH)F_q;6M{q0~8Qba`S%_73C!7pCOkT*Y8uD3MWv4^arW}LYR_NQA+b7O;EJ= zbsX?_i2OUX^DUL;E=l17+uEy6<5eNfoz|+}b;T9=d&50By#s6%AH@attnMcD&bWO$ zAeg#EfYa*rLZem74xuH#=~esLKSfm|b=C+Q*9^D3 zN+B`U{5FY^%mEt8csRXrOp^B)ok5BBaV5P9Uv?->rM>b@>&nyBwA@qr3b_bKbV~JJEaztD z<)E|t;?kAmyeg~iTnD~Wms(I|+f*Bnk|a?DEgnJleQfxb^G{ijQ4QrPJ~zq3S0CnTN7z9Gf*FluusgLQ2<~dJJk5|ib+&^wxDt&ahGc}>%92C zzv1$dG+{Ht4714=QrJi6c290f(nnctsxgy`wd##2^6bq7-E@_6s{}Ny*q|9w zn`(g~`vBKEa6_~#8a%d(;f+H?@P~}o@Zh2LAG;~94I#r3(}wuPeb;?;cim-_`LFUB z&h2-fJXQovh5IF9rt1t{cgRB$qMfS3mKm^B8M&#%Zz{r?RXDS9d!2R+D8No=LOqTi zW@p+`x9K49`TSDMOe&{gk;*dI(6)&|*%*%HwAM}piBZl9KUt>uVXy6&~;?pT(=WZb2 z37SD7QPh|Pm-S93g~vnzGD(WL2ER!HBUPia*GeRW)v?Y1_8fTT17(ufig zLxZHm&&A14wrxAOcEvcc*lB=P<-K!|Oh0@9&(wkME!AZ@KPut?Rn( zbw4xn+-@YTkvO0+m_f*T|=g$OAeEd%l)Y%9xvU88f&2W~m8;E8)I#{X9BgbAtG0caaIHnk;QNLof!m@2zxFWdj)nM}e5u7_I6AEz9v z>hhI{mR2_6`r4y*45_iC)IXt@joI$;CAoAkDwLiD!}gvKqodhQzt!m@@FK9Dj4|0# zR0-AY{ut@#F5VHH%-$0zQtl7@co+go`y^g0PIM#H$$)Be!gKS|LMvzW(gPRI?QwXA zc!B_Mi)^OO8H%&tJnPfuHANU?vQa+utR>Icfmxq{{Au3)+ww2znrw93=uww-mR2tB zzY{6Gzc|A6@W0)nxb{qO{jU8<)75!{J2(ozIKO*&5}O z;k&o2@0dw_CT#*J~^{#zZ%6*3j|Pz6Gh_*!?u^>3p6@PAyg;{Gm$9=P1TTx{W9P zx}3je1~L2;Go$%F%e_F06_;rp)Ta8z-*ZTmP)Yrn<%jIzI)}4P4^%tFatT(A{En=m zIYyNNt!&D1#xVchuR*kd+qyANJ5n{Fla@%02a^(<>PgqM7v`|5T4#kD#?bq(5BUD| z5&8ocZKEVYBqS64|NIEuB1zlYev21y1HW~`8dlmfB~4&A_T!wQDzniyNL3xCJ9@a2aa%2Idreb6EJ z`rctKGHTE1HYxX1?Kjf0Ysa!1jKwib*$Z6T5WSLX-Dh6aFXlsT?;BM~uuu1;PETmVGU-}OQa{|u2RQS+JhuLvtBhGF0-T-RiLudrS(1%VSAFE4nA7+dcwX$@!;hah`iyH>@mD|@r@LCY_Wb90M}!!0n% z-Inzuxf0yYY?F>=u&$H*gATI2PJ4gw)2i&vu7w`Z_i>KYib<}9nkQN^L0Qk21Cxd? z&3^eWMkL{*lUiWqIV-`3=Ep~l?6^@M59l4<`IK8Gj07I3&9{?YoB@>u*0kK3YwACe zyxC-pBU|cZ&yTUqG2%1h!9wi=j_CH*!9Nqr&|a(kviP>F%m2Hd`#7pA{mo;-8MWs{ z@<;8Oy<7DHXH(rO*u8c;j+;x*cw3&XL>kJvw;*Y^=ZnL3T(K^!TjHV{ zXpiQYB=SLZ<^3wOmhZqQTkC_^^aLv^B-Q@u?WSZ>6x$J(d8eh%r6_(bf5hKW{?sWX zFRSKnLW18`yJOCVAC^SX5Zi|-s8|vB6(=S&O;MbJ%wBUyy>2}#lZ6Twc{s51;023S zK`xu|J0D`o7w?kuWrwOAJ@e^HJu6U0xAYbQ^#e`yR%E_Hj4i)LLAY@_m6m1HM-=Ik z!>Fuu>F+7IT7vW>Z;kQumP^rM13#)aj>jY{~ zFq|RSA$$Uj;katcPJdGW&2v!Y<<|hRwXBxQblY!!^O3q&5S{|V zjkqrCHKd&{J#7?Jo=)X+ck%dFA1N*cc}S7Cn@_X z+QynYYSe^#5m-=t1C9Ey-gI#zy3(Xn{jyK^IzAn*YtGAgiaGkwLUFn@QDl@xy? zMwtZ^mXHwRS?kf9f83rB9BJUfLGD0Kz_{s`QxdSE6%q5e5g$L?*SL~iW`bNbL8ffw zB&nsOD$n;>H__;6%vB1)?1zhqx9sUBz~>`RGMkALW@H>H9_m6=&u>y!-xg$TopL z(+eZhr(@nmydF`8_Ng3dM%6zi4l-m?i4M*xh-Qm4VU9+_k%=+V>#^v@R1qkb-Yr_E zH&fvW*Vs4y^~9(^bc3!SpC(x99mkJDY!Z(Ze2SIykV5f&%9Z)Z>NTHJ+|prf$Zk*9 zcTurQ2baN}TE8R$ZN8dYs=g^QDCJNx$B^eW)6A4GyhWJ2oV`^NEn9JCpP5;hVmO@$7(wt@v^Ak0mG43j{ zy+V!$1s)d~lnsZWzx0gQLiQJee5IX(Up_s@$^S}%ayZ>NORO&J&Fq}GvWFR^EH?X! z23+l#qkGQ%V5KBo#)FxFCn#PfiYt>rPIL>iL`D>)nQD>fn#zM7g&5e#&0&|MVXti?D%QWipkUoK>VG{wn`7J)+3 zaUVGmesL)E<5R`7Db%!kGUNa;2_zhxH2ja!v)TE+L4_&zPLcAgQ8wC;RbntqQM!54 zDZ~WaqV>kT20li9fM2Kq|2xB2dLBVx6gjJR&j`EGqQy-Ntacu8<7Tz{h?`I?Dd(w) zX=L-imUA=B-cTu*oI;DHR|&s27MoX(!4r|^L&XzOiiV~o5kyY@l0Jz1=WYFl+2$gv zK=@VKE)LyQ^;7~A`F%;REQp5$QerkiW@iyYOTP0&zM2E9NH>6xt3vpkKaH=uo6XK$ zs#Ake+Rh#ILg?+P`m-Dk@MFpnt5mbRc&xp0#~#^-ST#@iv0T)A-&G`Ix$-!|c69}; zzU1N?QnozL;&6VNYxF45g*&qBS4B@-?7ouA{MpdCMa5Okq>vYEYjQrFdXQSf;7jbs zaeFW4*M$bD_!J`$a(zes>YumkTLmMnkR-cxT=(sv&a#!Y`xe;P~lYfHKS zMIQ8HHcZ{zHQWO9S>4=W;eCYI`OlbE{9F}j!w=D=Ai*C(-_^t!+zQ1t$nx2o%t+ci z${3GgJwy^kiCs%lgbRb+0=|;o1bwd4;n2FNhUD!4BEEHp%I2_?Wk_6dqgs5y$5Cx- zqVO}e4ZRnXaK?**^gXAfTNTw>+lrSkG|5lvv?=?j#FG@?;l+%K8kZTFhb(sm#3(^UC|uJFr2)9!V0_3VTFuVr`A}Bvyg=J?cShE$}4^C z7BdPWWTZ?piY^zREkjhCg2cIMlPKum9}SN>Vr`>gQR6HAY!Zi0NYE6%c3a z0LfQs=FF}uuZ|0!R~|&Y@bZ8xH_JZg&9U8Wdc9rY#k5VtU6=V;Pp8Yq8qcn7U2hK7 z{O)HGDc*uHE+~3C{FCZ=RolX=N4?20qDyA@8n{23XPBN6T+T*&8Guv~*itRjOWK zL~~Wxkg*UF{BSNaVuZ+y}Ns=Mo$Vugun|WluZ0uuDT?S)kT|Dc&!jtK& z%cC)?PW$#(x`y6@m6ccB9~#JX-MHJ34@~%5>wG@bpRG03krMs-?wcPa;%EFzf)76f z)BiU2{9NwP%vvY+7t?65%`QOpArnJJv$A;&4nq1$?w}jq{L-$-?{Id4A^#hPAMPf6o6w)^;+(>0V3hBbV5e?OirB0^^@+!#ek7 z4mMFR?I}S>7Q4U7!(qs#-^xNZ24mZmAn)w_-;d9SMD_O(@m^}ePU(-sy0Sj76p~E# zt6EQ45$mAyki1sa2Jw)nt77_(web|LXr$R>J;|OnVhDcuOwv!?B%L(A1MLt4>?c>2 z!ZIh;DxJ4Pq-e>HH&zovH!aSkrE1OpmO-wN38)_v{Qfo117YA#f?6Y}=Ia;P7n)3o zLze8P8`%I%2KU+gw7#F%WDlUW?$A_WJ_QD=CiJFm5%a3i!o?PlF>U@vySn@CSE|n~ zqjvQRkeGEI@@f4aoX7MeW>a#)PG@IG|zGQvN)^Rl*M@1lkN-w;#8lM*9ZKQ4 zy*-F&melJZ4~FKp5Xq+MhggLqIcq!jp-HsNLtWnXIlTMXy6s^2KoWMY@rXPCsb2I4 zGf}2$#@LRvzeZA&xxXTdorgoT*J#HoXNt+SG=Y*NuzVqQtf+`jLhY$yg99brA^SC1J=X5DkNUOS}=m!I45^KZv z*j>vuE^n4Ffsc|G0uloru~|TJcs?j2I%d;RZ_-u`?amn5GkMpe>Ic=-Haq8fwb9t zGG590UF}JHU!trlIV6jp__oxQi%EHHVri3;kSrlkG+Uk`mz)Lj63EN7H`(R*WTs@X z%yXu`7P^8%^4RW$hqq~w;?vjW$f&$4n0RU*uEr+O+Zvm%fY77v8UfK`ZM~6$@>(;s zo}sE=sd_!?KW1YV!f=`rAMu}mB!oVX=H^$~wVD_F`q{jVULo;BPi9eCZ1J%NH!8M5 zIuTFqx3_g~Uu~hQjb;X*y~jt7#z6Wi!gbkTnq%Rb^&OYinb}C}iP~mJP(}-Sc{NFQ zUJRzQtjy~gMW=V3iv1`Y>b&cDj^koqSC$XH^b#+;fH7?%Kz4nIJQ zRFVA*kHqzg^YpArjoLifXWq04E2Hn4!hJ!|-b3^=(7cuvH~H7-4$WvKjdk1fJ(k); z-V;(GE*xVcdZAXn8&*DKF>u>d!>5s7o!NWVY|~{h7Oe298fx|0d$n1|8Q1xRB)iN7 zv#3vbC!}g97fQ^(!fJ7s-!-EED&t4z{kM8~DFDG#GG~}m(XtTzAV-!J+qrZZVnF#5 zzTS7gZZj%czwAOh$z2N=_}RW%u|3ie^u5NVHl+^NuQmwAlfpkpjefN!XDild6Om)8 zxVUAP;6VS%#W-i>%}y`CFw{bw&POJ=`pTi8V>=dV%lUjAbbb%hWu6Nu-7>L=g;@#P zVODu?2_*iU+4WO!qp>I7)?m6c(l_S$DXIm{3QQksat3k*yp+H-f!`@L$h7{`+@=MS;t^mS> zJJDr#G<2V189Y*$lAQRup*;L8yMAR7Tl1~2EwZOwIg_ZG%Gs({*U^-#W==L5S5X1z znLWK3SBXfED)mOn)9>VtUoWS+wqUEcAE&VFvV%*eUY|dYPsYlPO1^Jm8DH-9!A?C& zcDZAL?^$YcrfIRWtwy_n5+oXs=JX?{RCP$>C zH&ojI#j-!H9~?6?NF1A>$sL->l*Qbhpq#70z|0WfcZjQr{j%+}jt<~iFVUZMlP_f! zlocH)z+QsO|9k|g&p+k*fp|KA0Gt$%*|~1(IW)s6RE0gZQ%hXou zBWi3XqH;>@FlEmlWuNpCgWf4J2j*9jjHa()PBiLTN%V#$Ej%IK84~>UDDBYQ;(|2o zWp^iU(9bSDpJ6pF7J(U@=t+7Kkx3aEo2Ni-z1)Xb@z_WgoC(%it-EP0p!|l&S9yWe zd{i}mmgD{x zGQTt+@gq4w9G7s>``-cMbk&46m~R0Ocv-)v)D;-0Bs!Y@4u{mzeXlk$W}6ItXb zJN>0n#HV@yQN3lqJ~oM-Kl1VZK|>cYY^KO9ek}8+lBH z0G*z?lwRG9@P#a-i?AUdGKlPgxi6WKg^kn4ra!ywzqi$z*@7R?tDDD<|2aTKkUpmGRJ zfN~&5Qz!3;T3O^;(bdJHu_@b#C{DB#pY$bEfGMSI#us9%5Y5a`#xoPhoFYRxt^VcX zUkL|4#py1>y_MhH7x|bDQkA}3`)PUAJsNj_f=wCuiGSF#KI;A_8IsjUonKPF>y<|M zIv9;_9lPkpRLXox6N1!ju+pV0Ocw5$0G=KxS%ECVJdX3;ZfP1m?J~jJ*LboaQ}6{< zn^l+9T<7x%FZ{;Zy~mhkC&px+YH9C9lO*REe-a<0A)$u`+#izuLRwd_u+R>Dg%)>k zm}v(8kj>8Wr)omiGvy&+4dMdF6;)KNZ)%i&{j92A6|xhqgJej*1?1}1`^prjYPEbA zx5vD?xt>~m=J*EoRfq@Ug)iaQ9h{U3&lvS-=+32~ zc;wFl5zVUi5=HUZ)`c|WRQQ$wp?h(8NG48e(G0RY*P6PP=lbM*#WR(Y!n1X@R33by zomEpdsn299Cdw8+&25%$pVZ}B7f_zqRwO)fd#frnTbH}J72cAG15gfvrUmVc=ewyK zy2-!xG}kFeDFErX7p%n#xU|xL-L%i9v);0( z*({}js9VP}{yBB4Z|%E&?^&DKwE{!I z7tZ+SKl_}a<=vzMY@>wN@}xx1Pd#g()yZGv8g%WBb$5AtuEA5h-syIH=sc-K@24^* zcPrXrTSPS4^!vs`))R}E`9h3c3j|KxFKayt&Z_-9>sg(x%D5Y-#IpzEq2N zXc0TjE(#g!JHB3>PPTiA%2S+UGhQ$a+us`B3Z7N0e`#Qcv!^(_aPh6lT`j{WZ~qhX zIGRHlG-aE#%yae>{KA{x!14X$YEMgd5x$_7=Z3jPrfg2+;?q-F*^xJKo^I(;=X{SS z`wFi3zA`oxV=9jK*_dx%7g1F|!FID;my3N|4BNk)dYUczmG9bS@)39}QROSa`{XRG z1}@jwtSz@leQhQI9tC-RdN2jCV6x0 z^NmHq8C$N#NC@b1*EsoDM(;;TF>Z)%o$lD25IgUHoqmZkDb(r%%-OJ zef{}$Nt|entBV8Vc9g1cj8;{-x1>1A!QL%7o1N|EEcS zh+1t|ZT0$O&nqeF3!3+-W#Lw^*~qIwEpL%n4jYhzkYe@hE9(1Vmzsh^G`;XkW}E4h z1OW|2iFVIoIm|sypNt4_%uzGHF3b&~PTV!t?*A}<)Mhf>xwjsIUVfZRxYD#dj6eK3 zNIX;ata3Q5&&Xcpfl9LEhMBGuz{;X}PI$a!D*k<#HCdmlPX%Xxz{rWCVC9}3+Q@_% z=&Qckf@>*V*^inG%~!*<-r?**xvsZK8#Z0AaOK=M0%cW+&!arMWeghPAvyW-2`PC2 z{X;xOWemwfh8*Mxe&N%Q@i;#PMVIQV=NB?jS6cm32L0qbG`5cvVOVG-Kx3rbVh zb3X!bR6757#K69GO{1_e&h808W@W$wRig)%7Gk=R;g7MP=Elbnz8aYhB%>9HuC)v; z-wq+R3aXYLEWVWCmy;_hvzd>GW5*|Pl0*?QL?+STuC5%{jI+H3YbrgjYh`46>iY^n z*FYa6`++m5O%XHFNY-uh5%943EoD7-CjXglz)VjkJU;eC%wgo3zpEL?!%rn&JlrOJ zq3q%5Smwq8+KMD2FeO&h38D($@Y^w<-j=f%s>^ME|Kc!eSAksh#R(nwM!j2er~G~p zH(8(wJM`+?PpldGvtcE6U@-huJ;VW>b&sF8cD z>UV4Q%16uS`|_VeB4GF^OjRdo?C61^1p-#ZC#f0*&nOs2#$$K%Wi8AH@WjUt3)+~m z;MOrlBu>4&$vA(*+dE$ z1mTCk9uQb^;&q7pUhGaLVzKA=h{eKW6pkQ^m0+T**h!GC({RUkd>7U#FywBrh29>L zmT%|-B_2UfzWqd>p)DVRw`fa^U3P!mO8V?%pz94+h3uKbk|B5Rx4o&QWO<&K$>dG7 zc1N3&x#B5uwJlRcA+;RgkBqmq714qBZ(~?dN?7n1BHz*AW-qt=MLNOfbwZ!I-8R!E zcAsk53-(9$%>Cd>7`0z|B;C*Nu*|(IO^>}=1Ey%j+tEiet^o!8aL4;xv;J4K%Q*tR zI&kvb`*CWV?QGL1;B;jz!G0CK8>=YEzQ7ShYlN_tf8p|1&uH=IXbzPoB9+#{RD7SE zZQw*b%}K=-d2G2qPYheato@}9e>g#UJ{UsrF@jY+Ku&hCwjb5irRE8CY!ArUma_5e zz^rJ4!1qE!<6|D)i<`DDfhToe(4nLn!8n2=b_v*9dgOsac*Pi`33X)No{15=9A^?$ z5Cq%h;Ea`xmQnTP|8d7yxNz?nSDElYRXk8qssHhF*XV6oaY$;VDw_p;xXC;z)|NZ2 z@q_x42jZaTj~M-a+=stfBK6l#s)vbww=MJiY(Sa)&C@r9w=+lPKbxSs+G|rYt#7ld zF5<~Ajc9Js4`S8@0%>cS-#ojl{xK@b7$SMkff18>?q~VON3G|v2m&-T;AJ)AL9eA0 zsvBHJKX|J|=;_+1Fj6N1TGMZ->3AtWMz}J*Fv4L9dUoIFF>UJfPs)exEoj<94EG&w zkuqL9sPdG24AqRN0s-@=WMbn<%dezqG}s;SB-TCY`arKvbLChGk{O+6p`bi*e|Z2WVs1^l8)dg4zu zXc9`B908a^=T1SX=XJXpdP}oERAS>QE@(TmFNk!*XK7RCV$nBTgCyWV8+SpUZ36Cs z)&|c)yxB$i2P*asaxF9WIP4DzAvzb?Bx}qN@O}^BNuwm)c8glH1tcF5EXgZDmm3X` z__6`3YTbTcD{30JUnHBc$Ds_NjeW7`Soi?CSATi*L5B`+GoAJ_s`aE*)UyHeijM4( z<8gglys*K*W^yX*v~KGx+$>D6z82N9r)c4+(`iS?`6`B+;fsjVMJBo*oue|V5)pld zolKPNFKI8m*bXQ6j_Yr2#UX~ZiKbhCV-gOw3gpaQV*2?zEHI?uWd#l)un4t5lU51> z1_Z;g2wiur69GTF;m#jrT4R!1Q5Dk-AA=*IVK8SWk4GoWE$JH>m(qDJ18~D}zag$l z#9-hsdH)(FIbYAyGYVa0z0k2k6^kzrt8ZXe9z-GZFMOyBNteozX2zSs4oZqN#-7dC zUk4bh*YATlsQNhHhq__`Vs(5})`B7XchKFZheOwjfDTid7ll5z6(G^J0TXE7hgOT2 zhaY;2JC`ZxnaugNuc})_S6Qv_rQIb8gC|nSL?j}g!VXJPHNk$JxxY?6U<(r(yBH}{ zn~1B(gXjzfR$1RgM4+hsBSO*&{;jRM2t7nZ@iMHc_^J0xYMn9#N|QNccpk&(D&rLx z?C8EQ{OERhKm^o&W0mC#>1*s{0=B;dUV4Qe*6qViv6qLq)jHxT0wFq$fxjc3bF}=9 z(9ZJ5|0`nfE@EJAeTK^DPkR$EbQaRET{Aa-P9G}zhp=@ZU~8}gKLrdFY2}0i?e8r+ zvT$_k0*|geU45zI4BvRV1Or$(c~qM^%?wwf0VW#&Ptgt+yW(RH|3izIe3M?C#>yGY zP)?0d4{w8%H1sC`xK`<;LlnYZ!GFR85MXErFiX!50PDeUep3H&F?U3RT?@|*aNKbB zjRMzLjaNuGjK2Y(H}yhIxV;>uB0^H3B=ICnMv`0{j&h;ESE1zwSNZ29_FxWuoe@M| z=%nrL(f=mRP9yej(pW+Wq`Chh&0Y29b+g6G`0bhhseIwcTV-j5VPgeLV1N}|0wJj| zp*?ew{havfwpyu>8DFX1F*<~3CVk?i;G$_>vhUtwmmG8k>N=7b_-41XIn>kMng}LibM7HlMnr@MMVv&y& z4Kl8&!X-IExZ)#Czb%n_(UnK1Cd~|(!VXO$Fu`V(-g6J#cQ;7&L|rc9`I2vP!fL1h z*KwRYyd}!Y5$NQhg%6YIq>1A>|Er4@K*xELs~v;><1+t48)mhR4V}g~J5*_4EF9pJ z6q<+J@HPrcg)(!R{uhe}jaTYBD(%mIN*>zMsrqlozv)aCi&G>PudjY;P~DZ+-m!;A zb`R{sgp5l`CFcl4sRU@*&766kT~X~vmhUUR+M4kQo~tBU7%m~|$UWcbDVW9<%=(NC zNtRJaJ~()Z?F#VK?@bc^=I#Nz)*3yxQ+%^^jIiTW|g+6Pez9=bN%ERyLYh~w#0 z{Q}KoR-%baHdqm*)Si2Z$O8s);BHZm8oH@&NaPd*cZ*GoBQZb7DXrS2H~h+`ZaFFX z#B_+7RcQKHr)Tk@*Bnf9V84UVF zABdW9XnIGd=k1Wo4*W(oqpP`BIpISUAAz%&p~h@*u?P!`Q(3?{`7Rjn`c1bC>OW$d z7|(Xu$s2?Qg4+hhC9{==av34=_kfi0pFP|L>T9d}Xe8Y_@i2m0M=>7awHy=d#* zUar0kXmx53)t|pL>(3E}>u(2)wS}d{LLLK$&TO&!n0d(54IbGB^%GgK+(C5COk-M*p|d zhCpCc%kOv3oxT}fRsS8j&75x^PsMVizIH8QRd{N^m|vv933N--fXG*hTNwcC@pjxYfxI9OZJNrPSfn8p-!{6E724t76Oj*PPOyP0x1mP z=4$bRpn2qucP#wDRV$t6=O_1F)1Vgrki|by{I0C3@?(KNFY6AybMxsrcZ}upeYue;2qu6xGvBdAB= ziA6C|w7|F)`I~xcWsuW!wJV!f5T^g0b4cjVh1&<5^bJxNLha#DNY5j;zhmJDu4?@a z1$>hqWHSDj7&Q7bAK;kF&UwwOJUN1W)+ekM3KcKlMjZCrh~e`@at7Rp1(&>wA+pAy z@Y!I{WTpQ0%}n_*wAA=;ef(99-B5)g+*d-3*;s%3$}@!8Nf2sZjru)N3?h_U)46wD z{pW)Ei?hpa^&T;QkAM}+E?|bx`NZx~;3Wx14tx^pWspWNsS^bUJ|ZgNX9g>f%lU1`-SNpf^Ya#f}imW35^c2Pcje5GQ=Tqf{Umb03@J) zL!7IZ?)iMKlkRjZgBP4~)uQvrjqh0Q2UlG&{x)M8#OlcI%=qrakOh#iMws!y^6js^r6eqktIu6*`9DV}BWYu^ra~2oP)&@~ri=N1R8vPePiLjKLZ6CS54gmd|%-g=J2P0AFZ);&W+5Qd8(B z9hUqd5vntZFumg#0?e-qy5Tw`6HTu!nbwFH9A)teOtvGyBIEV7HLUQbeWkPn+(Ao( zWHiA?@QvIu=EOmG*|+EsZTIH@4oFq0u_caLUGohH@0Fl7N(;el3zM=-Wt7B?Lk zT|#6h6O$F-S@reRc_4VX_R}FxrGjYt408Kc3`as$Tjx4;!P7|;6zOsHR61!=rZAcI z&K$(tOD-KcGXNM^7TUiqOYGqOJ3$riQ|(lA(Fr&G`H|VnQyB%p2Pc(N!4YJ6S^p zMAenwqCW{KG!T&rVN)fCTr~y$h1^}Diq#VPb=J_1|Ck8gA^OB-_)*RZ0CW^J5n8i- zo}&XW@as7->18!6w8O}Z*9rBwDRJ`^<}iG7eZ*w^4l*40Ce#KKemKoDYP2{z7Ok2p zhvK%|lI!MBo7mkmc`py>n=xKF29FW$_}ru4j#b9b42hP0Z1P48erS@$p_kq>4;{D` zvNP62kKOEu(`oHwHEf+Rxr^xa!T+ZS$-g4F5D`5;6nh-7mVtlB1GG>xQR5kK#|Nxs z>$mYm%ud= zpd%IlSOI_{Xy9zv+zF>a>m3aMLqzb$1}ZI~2pZHXbT~X*7KAIIede#D*z`NCi>QVQ=DN>5GGO_45J-W4oYKP@ zy8VCfrrCmrlNtWxATvOV{=BUHeaiZEOuGp@QCJmf*chuNw^PACpbkSo9d^giq2Jm@ zwCCon+teAHp~X$62&_5OEBuFgS*1m8HHDj~034-WP$FQpjHM)}H18+)Ic1c?c*U!| zau4RQUp(?R{lHeZf0LyB{l9~O_w=Fk`J*qT`sAmD(TYr~(Q-VYa#g8c*w)JjV652) z3CTHO$rb3RTCJ%w{nn}+LaWsA|ARr_w%-Zu8F}FFj(~x`ABX&9a+N5A|73FiEY;L) zA^UC0(Dnaea?p;pp;lqgSsR3@2Z9h@xJ@v9?n<7~TIY4IgL^Odn4|+yRd^L@_!z4L z_wf@@Q4l@&`%|>=jSzaZl{>CdOc8;Ux>Q;^A+Y#m!Q}O-xg{5Dwvho~MPo@dL%7-8 zN*<5H3jSGZBfh7@n_vorZ^zRoF2RRPt2hBiQ755T&lGzH51juP1GlW7g$k;fIiq<- zqn+1l73NV~U0&67v>J_a+y@?b*pM(oFrvUgf*uxbdnIS~fUDTn!*EeW!w)`*? ztV3iV@pEXC<8xpH3qfc4dTz4!?jlxVqOYK-6fXX{A{Ld-zPF?=kHE--PHv3m?@6wG zBO<%b{@46)D8SDu77D8wtjy*{b9j7~5%A%9c9{fU=px{wNmT7*qJ?jJ3D;L;PW|g2 zLY4*L&ebu4+_4qIpWqsmIo=8ZO%mR&S#Z;_hcR9k;RB`^!=(RZ?*n^k=ePsF|71n> z#-j-wM-SYMFKi?Y$m5sH@0`_1QjJ1@0ffT^+A|Lad!|;Ll5|YKIZNS$MNy!$WU;0g zu1yG{GE&B-7$ODbbPh?$(MJlDGKD8aW(Gj$&$&9TOP*~X<919S2>3tNhypr+^Uv|l z`2WGb6*&J61(Lz8Rc#KGx;d#Pc0O?9r|7HgQn6m@q~8hhp}$<}BoesOFNn7dqUJct z;ke?p=8|-5(r~`{#{>i*2sjhFT(wuhUk~4$*W+{+G-nAwT=tHm3H%5s76R+}Ii66+JfRd-sRC3zLVY8Y;i8IgGCB3KzAdy1%8cg|uu`Nzkm;?Y0Yy9=2tlT` z&K!P6xo~pn@R z2qYh~f)PeR<%C65pmSug)(8H-v{*VY;#AjmHxKRL8)|c7sv6 zR*K7qk`<3Xo81iM24JMP7g8AxpftaN?+p*`24LER7lFE;(gOCqq2o{Y>!5p?&J8yQ zq7Q237Kr-?oZOVIF%A4|-+W4@WnPISg5NLAz2XNR!`kump@ol5kaR>#xFprEA@mYB zx9X>h?$n+KixY3-<`-%Az@DD(o_i?x$-fEEOZFzdIqF#^Eu;4zE8*!hr?NJfO(sF2 z^PIwi#!ET``GW`K-N_*-X4DPmyYAGtihITTJ={Fbw^w^tKixH-8F-!DfZ+dD{Kli8 zWD`{sZa(8)&BaYTm$z%26(^QkyjhdItR^BCn%75Xl{E3EJ-HTB2qWRiWa{sHEo6Oh z1KRhz`X(aLlH$x~-@~goyEks~J?v^~iu96nw#D{Aa=gwvkFAo+)m?{sl!&n~8BtrN zgxW?#LE6Z{^7(x2G5nn+-q5Lz%ie9Rv#S_SgYcr%dF$_Cy~SKv4Sw%fj?CA_sj1xy zy*%CZ4iH26$vR>vzZr}cUD;4>5tXSsJzS@*KOIXPnDaKE_G&n(OTYI1^n^QDn;@X~ z?HUOxd`yuPxzem_o&(Sz#uVB+o0H^5#jnDY#JRm9@jir7m)5%}i)OS}u+$D@CQWqI zCtWj6H1TqF*GGtu&IWKNRE>4!QWY4?QIT>Z{tuozeoAv^<5vYs$D zWX8@P!S>-4@$#hgc#n2@OEU+3%F%5WSPLHkQ1 z91SfJLgThN6JCMa3*^_g@19f`4zYG;#Os70M*2^6KuyF*uYD)p5Q}a)N8%9jEe4*o z^B+QX>jJyiRA6}fh1W=gs-;}HowgD4T=924G%#YG10xJ~2Vc=u^4pS%L|sKm&v;`c&7A{Oe4Sm=tf3^xNoRWJzWG?MDrU7IS` zwZ6%LQXxabM2RePl8c1rjOZsrP-SBhDFr8-{KN^8z#x6UXTfRGM0xT0O$J_{Cn~7c zy(q4)!r|3juaY2DOJQ(3$w&OI?h|5>pApqP!&g+1{AP@(uKg-y4QxOKyV*IvAlJ=A zm`tWlG>EH$3UM~TbT>IboDELy<}IqBXwV8X70;-=TkpQ5i^txG5bG>etmWG0NC+@whF7HC%JJC4eczL&bAx2gzge^_cCmaRpwq*vm$%3K6IAB;+()!Fkd@GV} z=$P>ZRWO3h?1Yb?9b3d_?F$gN)_?DL8BAcf)~)hlPvYiB4*2(vosz4CMRNWYP1e{S zCdG72{q53b&elu*R%y`Kj;rKmzM`)Vdi}=%?GuLN*W^wioyg8gl1A6T&f zS2X;P4*o3^7lcsU?i3BS=%#lh2E!FCymrnll+trGdFBO1IQqYrw1*@WCFpS*{!dJV zz9^2}$tliV1=jKtmwDm3L>w80ScBo|!hffGi%54j8m@pr+^cZ!`mIZHs`d49Wl#hB zc=C5>zj~NN)d43W;BT@1rnTF1`cj}CEox&tP7VH0;!TNQIT3WjWEa_4|83xjsl+P_ zf;I+0oKi+#a+NeQH&pLKN>)$UVO;g;?ua45?4={-WpB#K>kf5lYR^Kwg?_BdhyXzIWaPZkHkOo=h(&BY|f1|;OKtu2j{2+_q zJ3IBdn9?w4fbR8(qQE6{Iu?r)wf$qSCv$!U2-jNIjIV43W0aYl;%}`PMk4mrVZ^?w zn86g)`C0+4HKKU9)-L!{M-Kmn`@r8%>pbsqI!9_Ra=k`~!dcrDqPu3A3KOMG9f5BK zbWT`wvl)^JRm5HJ2XGpbkNjld58yIn5CbtuP>v*>27Z3JKEWF=<(B0VrDMmIWx+Uv zH)Mdy9)RP1)2#;R`v1}GBrjcm*u+b@XSrMf+%f)#joeUaX}Gmqw2w}%DjgBSlk)!b z>NTcxOd$jJb5t{+JfupKEBn%m1Hkrny)qG$kx?`7Zkfw31&@Ob1=h*4l1XqR;$;;G zIR~1did?=SGN<;uDgT9f2DsQb`J%E%FU}jV;z^_?Lf-HBier_2V#Y1AaKFArXZS^b zHm$UNXPl|MvU=GY`qm+7>iVMck2q+&f}W<)(=riZw62fZqQe559ucopJk3X*OUZiY z<<7}gxq8VNYe#nU?I8~E=v&9L=N?Qd)e;o%&!N*+q?0CTH6t3*ReSfR0Fe`V3Y&J7 z!F!lnkq-^NRYA{t+w-qJgPl-9Yr()CPk+e+6^FB-b^8LnmtY83$$)HCgy4;d%p3@~ znz=XwLVb@Rg2uD6T)Q1(*$unMrd4t1o)C-jX_Y7>|D6q?ePLNk!xZh3Cm%t6a!LtP+e^<++Li z)S@yNjJY-J(L4Gb3^Us6Nji71xWhCa9L-2g8!mErW&0Cr2Y4{F$&xt(^0mQ+Umu<0 z!L8c{UuBnwV_%;JZ%*mXu}D806Os03#}I;5IHaJ|hN2HX!e}B0NMU!7Qny8e0}3wk z(%7az->Tk=C@pg;yHbntw06P(WxXJ|D*>%^j_r-*im@l(+r;jwqeN6!oEbL^uZ|L4 z-6p&`%3Mxtr(f+4v+qf2w*ySsROj9^KgbLgansrU_zO#j`y`mA0uS#IZ6vOs3MTUk z8gmZI5tzl!>$r4!|3;!A{hst(L)6foPq+4DdZK`M0G^ z-|9EiRckR|So$;1xen$3hzbrZ1U$dk&P`2R0EOey*P(y|n+!9J3-|%1mWL;VbHyV| z68ga5U#=uu`JtAl_&HoU2Rr?*C#{M+UTSD3+d?^ z_p3gAoO}RzHyEV)l9ul!P%qtEx9Ln#f-I)i(+MT;hbORm$4_WV11Hn-Hd|@o#<^rX%?E8Nn|;6@`2_ zze3yaM$8dQ%=uG=?bp(UJ7+e_`18j(!jS6-Fh~jI#yKE zSgBXzvk{+SB7I+)vJ7#3E!lU5dY6dT1gWO9+yc%TZ;gYsYZ&OX~sOtJX(+P<&}?W|$Vnc+>UDO#}C*}r*D z7$vg~i}kFS2TSNTq>D=z8sNU+8;NE_r47ftJh&5CBVl;;kLxF=>jEG=i=GZZh)(9o*`F_xlU$`0c#<)uHIQ-9ugbMUyZOyhpMzyBlv z68lm?77n~W=A64@sW&&Rg4t=ik!Xxa@mww%S&5s#p#7;^cZ4$@Xy0S2yjqBtl)_ud z0N->C-`GTQP6%k4vdFx~l-DzVbQ=FA#(u9lf1sy=1&7lZs!G$vN1D9zMe^-ShYy3F z|MD+CB?F9ATmoZy$zS5;-QsO4hSw${Gq+H^! zwTNYMv4Jfy^Dy&lm~YK@xtGS)y>YiYyN79**Ex`93w6(xmW9?D+!NQ)$e-cb#1%7*_c=ILV+WVhB63*9ZP|#nG6m#oQv;)8|hWo_Sca?TuuQ=@XPn zo|YvQsoN2y5eFs{+(Ei8CPX#Sb1^Z#6&ym8RosT zx|2lii$mAMNo zBhYvIR|`=4^AFknT@9(dY;kV2u!j|dv5{@b_CMb8i|{wNK@(Y$`D2~CIThtE6{iR0 zy}3IBo#hC!xX4w1oYM9`YU{8o*fw#lR6%4YS9wqZq-#)V9hC+q*%P4_b0*{3Q#I}~ zo0fUZ@_)D%@m3f>bi|RyeN;Y370!dShx6(+jZ`X4g6>igOfrb|p|(Z)1~{P-*9sMV z`FKVvF2!i1)%~MK{sJzDXGXYL?x=lcvIKZbjA?&y=w%}!7UM4VUR(6XfPx2k3x@|c z`}1z{7>=jU1)qwz-tcjE*1FE?T~7!B{xBECW4aCcY=QHcDb+DDF1&<$PBa)YWTg+6EK-$c z)nhx>2I~>4m;xaxfVD<@1{6%@E?l>4ZbEOOCO+2;P+dV=`8Cp>77Bakb&#^p35}C$ zU)bnky+1~GJ+t4@-E+=oboYBqgI=Mq|IN$O8ol&9V{!L2l@L(W zhtXbYQRkXK$P?v&d(GR9wX^$gS`X2SpQnZ|zZiV1pDB-vX=^nRD$f-Ge;0tFh3_W2 zn;0JYGg)hYoZt?0h`O^}n&Lkum)lZZ9=`eolGVj{R-Vgsk{C_l4mOw=7*fGrntK&L z93b&`e@iI_8kX1S1*lnv?a9LSJ?|%*ucsCzBrq1z3@B*fb^MD(AZz~;WlrY5u-T$2 zt#Lk^-U6w+mFVlp$?fZ%y*+&#It?4U0}T_gGHO99C6QCKDUWG*kQJrj@Q3k$cwkoI zpPuPSovev{HRIPwHYL_VVO2yW)wi&YR9XR1aZ`x*E~nFO_}ikywx6e;zElzj3L!*6 zY?6oG^|QMbZ9DpZ0Pv#z0Z@~drZ8_EtNZ!y4+F*eUl-T=PbXgw-^~gM)J6ukQTV(# zcs*{sT)8`Z2`{S&M|&9cCM;}_B^#xB>9rw$uhDI;To-j3RY&S}W8$BLW3m0|J8{P< z6n6`2xZ!os(#iQ78RYslR_Y2TTa%-`#n#|Y@pzOlZ?iiszxVNh`6IIf$vYHQXau#l ztbh-hlN-CPnp~9p(okWq*3%MNnoFAR&#w(zsy_ZUB`s`y>V$9mV&&kGmbuGctj8RIQ;MGz@`3|S ziY?CWf)5I&^!eS-0q0WcvRzIcS=ob=H|A#tGd0gJ{7=RBCFL(z1T`M#k|bU@3?4VpNN-ZhH1r)-|>2y#D5I% zy14}07D&9s-(w+zsD1#E*nU_sLZub#O8f)FQ}z!K4+JT<1iK3{D46FXpta-LMfz;? z%T69zju$z>0y|k%knQ!_Ti033QzKW$2)!rWM}&rs;lyU-e5qagR#QnoE&%o)eZ?Bo zWuC0QBW0GC{9y^(_^v; z^RZDC7QN*0x$g4haKo49dse9T*RO(r+R_O7w$i)iX;P-RSByx?c{)Vr#jAdYz)#Y@ z!v*i_)yJjgcAxN5bWir9`c%x($cwJ+koWr4`sMU6Ya-$L?>}{7kEU(HM_fV4uY_4C z?4&M@V;lV;SP%a!8D{o5m~P|@68 zxVXyLni^5#sz;MKGNc4b%$RAXXwiH3zaZx%!k#+-n809cxpUBZc2;m*OE&*rem@>A zHstgV*9>4Pi;A@G--9B-;7K1N#N6|%3yVBI)?uImNQV|J7GaqNP9cZOFqw21m}%WV z#gsUdz4+2fXdJduMmbMhkzyp6occ=E~3)pr#EvpmpI>FI90l=$Q}05^i`MB zvj}m0^UVfI1-dWP03KN+Z#iA4l0xq5-C3jZ#8CdKJBqx0Nspz+?y|?_lXvGtxNh{_=UrJ%<^dp?fEmoXuDWUicYiWZ)aWr&iW0Dc{h z^L8FKmcvx6d!M8}fxDx`5XO!H zYp3sS*-KKI>|rh`oVR0}&FVTdJm=3uHuBTAh&)fVYX$~>6Jj8`RcJ@2Pg%qDW(RrOfC}3id=}ETcs6MWMt}* zBJR6(O&T6M!e`PA6-pOt#f5a^B0>vV9wKF4t5s* zi({TJ(hr!s#hfsG%a?hvJ1MSfx8{@>-mZE%>5rej-wK{L!ox9T$&u8+CRRRfG6>R^ zTnsQiS8{_r8;08H87=OtX@1hv^lbk$9;wF33Vj@bA{~)pXJ7>e=J|xnP0JH8vAggm z&>ovyHR-022Uzf+g-jPz@N2^$0A-UGYQ5 z=4QzrT3>QjsNADi2vl7 z2>rf@AR{V6`06#BkqBIc2e8|e-ge4j0tA2$FgedzkiOlcz%V~Bvd|(B_dqix$BF^y zZ-h5OfeT*$6Xd>g9`Y3rbj(b$am{Wn>!l3qpP`6p0Ef5Y`L>I?!3)-1gbKip7)}N| zo!Y`Zo`%{Pu`O<_9G#L=cXO5INN&y#2x)}6n&k)6&o$i zj*((H+k{gIzAPukU;EBq84&=E11tk;caB~I!~8FQP@TIcm?EI^MV{h+dP`-jTX zm3-wA-LS#Ps`0|5GZ1JHCs@$g`FT@=)BH2vHu_CSM0Q%JR%D+UK1q`BvITh+!5_!94Txfo8?Znm$tOXP;`4DYJdAh=-;Sh^gN~({|^T^>nwxoGW zrQ|sD$Onc9pFt`hyjD13vU?4_BnS^IMr!Rba^6&}>XtY_@6MC)_WRBK?}WWrVP|nR z5{NxrIcr(3MC8o3g1x%NpqrD02zs@W9VVlMkvGZLex&FvWW~SjwyaKHH*$Bfz!}+l z8>-i=@@dHBgnqW@t4)Y4tA1;H-tH2q=v(5uS0CF9IdsDlpHXf^l- zVzrrV0C|uqWb|mTh86D`_UtQQ(?qMV@>0JZjU8B)68TQqyPY5I#E&1yvkoK29FH#2 z^QKh6k02R(r^@C7l}{gy^U(WV`}Ht}blXXSFysxF#)FGpwH^~*Am|X<^*VUT>s^A1 z+{4Q}CY0YJ+gO;H3-?Wx9Zr|viG;3wQ9B-4fwONlHWQfqyn@>dh&dhpNm zj}LSVbFe}jODh9MQ4SRhvxE0Dz>?w5GsW14eZLSYxcNh{s)d|pSv6DNGrz>DPXCzD z7R4G-=TXt0ycj(e70G~{^q8Q5IYPnOPGPPJpc`2nUXm+L=vy{re2GXVJy9+r>4i9jvuuLfZO9{V- zvOjx92)%gtFY!2s$DT3%?$CQ$JU=Tfzeo|K1D|gANY>>ggWRiXmdXEJ!LO_pB~}ql zubgoor-8Xh%3D5JI+<5SI>u9bOVhgWbjAZ`QFo*EAtjDHpk<#SjH2dW+KL{lifvHJ z{_hSbWxbR$6@(IaE0)UJWU@MAN(>m}Y)c*gp`ZFeU-?VH><2wlpS;Lm}tB+(*)+^VjTDio>UQ_>6-B#EL^PP&g!M@u5%C7B}U;QvH5L2k0J zv~Z*W?lH1326oPhxBG5aWh!8$z7jhQRNJ0Du4cksBBb8n81K64b|5cegvdb)u*;AX zxA<|otG<}QU;-4WYiNf7(VBp#bD=ItTh7hrLus<3)D!M)SE6J!Z-g)vy{P@foCx`n zj~C1NQ%$l@VtZxrYVJ!if1}c`W)It%^<|ksPZX_y&(UQ(y)GVZj|Zgxy$eK+MrwHj z*iTy-VgLZ5|CjDEb{1}WMg~UaCbUMA>h7^~{K(&0yo06TfWp=S@B!({ zh3l~N5*Br#Ej}*W(ojODfRMPOq+D6<$JaXj8x{H4?OzwOgN*zp4FP9=s2Ah9h|Ptw zZjdlr^NcV6owM4->#PSTyblm^-0;GjTY}1Oz@QhzET?tch9G+#t`GveTyedax#vW3 zHsRAkfUHm-fns%o0R@=(LyR^Zc^VyPIKQDCR&Y;gEmp~ zVbSWGmVr@4dn&)g0W+xr1al^Y+J}Sz7(B{O`^VE_5+j#SiWt+#(caE!;lZTPWJkde z!}BYeWCR$|_c3H|FfvUMvnvv|;MEh!*2L%ai2Q!%o}!&OMS!Lt73S74&NgjX6-v*z zv0~`SF1CZqKo|%L@FSQz#&EsZ#P{Sj<8k@aDF2nfnTMqbu<^=G4o|@=i{zI88}4~nE^b3Y@nlVWaN3MW2P;;0 z-+yktcd>b+EJYGe`*&U;St=i0>{TnG;01GvPd;wfedpI4cV z;blIzLXKhEV*G(9%%GIAF-?_MmWD2~Kp7lNeJ*W`6>SgNk9J0{0GRQ+F=%H?Z`NRpMr*(`oAI#6)aQ@L>S0cZg^_m&=0YX5PIo}QG-&j;i}}i<4QZwm2ZcdOI_5} zdBWsM@n+O%Q(6RPIzMo=1zO@BEa*#fL*W$K@1h$Vyoc{iUGriVD%m)jaD?2UD2M#c zsiD4k6{*yh;#SlVT~rLn@dsK!v{J0Y<;V?y$pK_Ql3dezm1ZBgWL^b?h62Oyv5CRRu}Z~ND)$>SoR$Y@oYI|ap>^F zy!xZ11D1rprRPS4%d@=ErN4OfUO{y*41KcYx8Aew5yjY>AT8M#%?&tJE#on3-GVF8 zu@WVz6zRhk(8U(b$^6!B*990gLPFwn$*+s_=jh5jQ7?JBjjLO7_k=H2T@(%-k}CcCmN z`nWbSRLBV=d;=@#IehEB5G6~-a{6Q}4b^ga0$+~;X=K8a9X#*GV>h|P#@rIYqK-cYnjSAK?6+S*$agRA0Q`*2P8#{Ob$mXSdQqBQnQ;n1Aj{(Ki z%A~MuE#03tEsc7}9~d>^1OkRaywSyZOVxBy7F21DaK%8j=;m@LA=<3T!|5|j+)bVq z>Hq%BHmxG(4Re%AKEnY>M}n$dHN&Lr^?#pcf##D?Z{O92D9)4$p_kvlbvdA5%EDL- z{EMO%^{dDo0g?CeO)n}B0hG2lX0!*HPCH|heS7K`)%b4WhUI$?ihjbxky9$9x-U?j z)d;ttIyU7vc+?5v9>hi1wa^7C1w}ShIqGd7%-|N)jzntlrUkG0B1u`ZEh-T&<(mV^ z_p0r=%3U6vwN1lnIiH`TZ0jb-*k<&4ivd{$6t{UZ*6@uFUmF0g2Q&Vtoho2!pSlB+ z{`qxCg2gA;?SW}nuALL2fd91xeI(yaB@wuSN@atX(x*T>fm9{k zHe#VGE>D2kyUoC+c^fv|#%rNV@ZSu2E{6e0 z7fdYLLGT~i8M2CjB6dZ-HH8{*aHs@VGt@_k3lL#!Y|?%H`BR+IANpK4B|OjaV{CEs z*{6H?1a1!1Y<=SPy`u;t)og>rz5ohP(`7KFipM=lw&}PkuYatwA$*dHwbER1=YxS3 zfySe}CI?PW2M>h@HNR5}X-s(;G2Vtv1o|kbxQ0FhUY@7%URLsZm@-d#N9^mkV!Ni1 zC;ML>Y0c37a&jOJ;6Q;$TUcNZ69zQ+x2^b{3Ke4toWu(`vPeXi2QaW`vDm;zC5nnw z=b3jw-f_jYSeDJv>?PiFm|U&N{qH%y&k8R73J3t;80!Bt=bI;~Z2#nZc%Nq9L1DeP zIHVb2q&*=xPf2dLUzy#ytWvI$Y!q4>o4C2RzOF9oR3{P@DN?CfuSXfSrmj00XhW}0 zxrdxhGvPUXwR|Vf`e}sPQYsg_lyr$Zsz+zP`lx|onR91zyM*i!_*1?p1Ta_5ysBP7 zN2HkvQ@QK7s_lV8JN#0qB$4LSY1D#6;!s-=ryXE2v_}s3xu?V)3D{DonOT%wqR=T{h_g!C(e|C z3s;T|+AK)Vui1D+f%zFkKG$gc8HcpA@>?^38(~sO{a+XR2Qthi`={K74Wq~Q>^^99 zI}pKzeM|}|ReP22;IY?*VRUoD0$G9>Myw~@XVWVg<`Y{Jw5!~j!ctER9bM76-QASm zx*&k%hCng7eYS_$gWR(5){fR`y%%CPCnLwmwTgXKoO<=}x)lXMj!7dd zWmMU4c}{tI70_ZumK6*FSS1G}a_=xbo&I%I_=!H%x7l2DKZ{yEvSIwr_1%1^^af&H%Xi9)9 zJ0uQgA+uig&c^4zTmL@kSo4#;DfO1g)$(C2Eq@;5+mW^@e7rk*zVJ2!R;f@+aFS)K zh0GpBo|AuY!s3K;t&w1>vOeZR>nMWqy`k(_tmK=DJ0ENIvi=CPp2@hY#I9sYFIzVM zREO*@9FY{!F;m$Jp?nD9&g8|?deYZj$&^58uiSrI*bCB)JmR74y{Wu&8|mvRut2g8wVl{t9AUND+DxHMVL8h)a?r zl68abov*y!*Q~qQe|>diio2J0E^}-}r36@YRKB5*G;j0f*q{6TB4eKRglB%TR7`aX zoD?T<1NC3w0ssI#g;nC`t>C{e{GVSx+lkKQr!yQK13f#v9i4-Tqph=pk%^v@gMpEy zi38n#NrV4KdcYf=weDxAd$|(;0K@-*w2P7PPq#V8|I$WlbfD#FyUq&#&Gm&`849X+ zL@e8Epi_@(heXDdzLJ(@b@Dero|qD~eEGrdPxF@9HjYSoz4W*X8g##^Rh9_uwa@d; zX8hcf>xcw0AL-U6J5h-BpZ+HSPqZ&itN3#UA~fApzPJW*I2@|`e7jgDuN=F(L}F@_ z(I5^_n0lb^o?mn%_K2G#s{A`88T6uaBa>HEK{yG+6W4Fm0yOrjl8>Uj-# zB*bCZ)84?m?4Wn*f{greb;RNl2X~?OUoaeI1X9#F+J`M&W4(}tYSp+@t0P1rNX@Za~LLG4p=wb|kc&Z_#*F5x7G(_%W8ymI+ zQ23{w#-IP5Xl0>27S2qV_ z>T~X!?I$|jB>LqITh85FnDGt0aZV#DW^S8YZEYveql=R_zv<7e5Eu=i(|!eV7PM_# z<+k@Tj^8Wgz4+`?(KUW<7#xV<5$SI~{sD+?Wb%qfe!2Z!`|C z>V%!Mbwt~Q4K}m4O%p(GE;<)W1KW2ekmnbiwhCahCw}mkV!WpnzN^}Hv*_i%HT6E% zg*(iQ#0XW7s|ZX4p%7bj0vmXr(U0*N{Ns%c4XrkJ1uhMlJo-{>7w0xVyeNx2)$SgV zrWf|&E$-Fn7pQz6rk2S8odVoL5H^GKz&>KZ1qtfjQHlHzbb^&Fl5y*Mgc%)Y$l3{0 z!cKD)I5VZ2^e^lg;zoRCeTWZ=-BoWDV7R%}F0d;L6lTnDzXYJmXmeNg!axEMkZ4BG z2EQg}4-Wx4v14&Ibj-=)G6URR^i!C(LU*#WA?J;t zLkLyzZTTchEy4?YuBHZGHygfjxN%Fz#x$~u_QJTo8c42Yu30#+V)2xwmpq^j$py2? zONnbC7xu{qOLV*;7Q0mI*h@4oQ~# z|IQ)BNkiN#iSmX6xUp8$7@7L!+5iVlg!s-UmVo0T2Q(trPwbZ40|XdT$&yPU7D&)* zhvDy+YK-wLSxs6Co_^Giw@tSQk5xNCq-0U8VSW6RX1}ftjA)TXu!a}aN4B54%UEgn~Kx=dsh?g8}!%BqS?m9^IF;ef($>4 zr#A}I=$buBsB9b9^5QeN+&9-W)>`+mAKY@(eDFHJWHCPCos;Nuur=lDK$M4 z;yu(i^Lr>6j{^i)){`5|%8We#JvZ0(5^Ek6)LeM2ijLw6( zqp0KARsk*!|}UvLpl2Q z-w~lC`bMdkA}<936`iUuZ`IRA)OLir5)iP(W0h$=PjhQ@YBqK$%?^q^1#wFCl6$d$ zHY7k@6dFEw{`Ky^NqP-xKTa~Cu_@f|i`} zzd@aptr~wl7t6?>Gn!p7S57sw3#{xgl9Z$lIG$UmLWKd=w0`;Md&*Bvv($9TnIWRd z6Kv1Sy_FrF8XqfOY!zO{^(o$^3aaPK%YwG9OjqPW9fsW>#5wIcLuzgH32R%)Jv3IY zEm&nb%W5epD4u?w%xxFH8h#!$KmDO;956TQGS$L#{R9SY?d&Zz$Z~diZoAIsW%kGV zj_gZ4J6s-(x3PCOhn#_i5VlsuvfQrRDd!PH%62A#<`r^w@6#J8nTx*e+F(~O{6Nj3 z&ejAz1<<*2V$GXmMD6&M#(Pg#AY!;ayHJz-tQDgHEIqB^rIt}AAC9OLqbRP-Ip2mZddYL3zw`AoYpacX{$X&s>fO9<847wy6B$7h zS&D}2dd}j5DOQVV6Pn??=;mfeRHKMd#4{Mb^1{3cFoQfY?%Uyk(+Uoa)jSgYCm1|* zuDUr>A8rS;RFk{vw#x!P5RG+?Wkac7KWX-4=VoI;q1(DYq4I92(pu&GX_$BnuyEu- zgTH9uQ0nmg{BBgE>%H4)|RnRMRzxJw(369&2xBjoi{HeK-&O6llPahEZ9jUmQ zo-o^`{S(}L-dMKYNYXT}JR!l5CtV?sGMwE(cU4QhL}fNQR}+;14@6aP^4sM^;^lzG zh7QWZ^JAb9g>!+bV`Q|-uV$U3wTdXc9K?D1Y>ruPaRzjlMp!n{I3T0!OXCrF5!3BYS9Vd=4#@tb)C!`0NwiWZG$DHVu2R>b ztR)Og+fpT)MKw87#}%EmyHIA7@JNDpb0jW&-I*!?W8eCn9w7C=y|DdI}DmvU(|htc8jq=k+BGgs9^UP`X>I{DqDRkY zA@t-&#ZG-+H1B0^cj}jP*xObK)|igrRUc|)XAzf5+Q%Qm)tsyi4xV`+{qL$8w-2sx z>Xm?8M=8L_h+AM;za^B8935ha!@UZ>#~g8v{v-%|SGvMh(4L-WAmC*6h#7r4PVT}& zcCX}X%H4H%WRx%(47@xgajA?;8l!8+ttC&h&oLW?OKYDjJqA%f-iaLe>k6eMQ$_#?axlCpLQEez92X&z^uiHTqkiI69ff5bX-peV z(&44Um3|PiPmj7?^_x)hMJ~E{sN-mM_JXu6ye7V}WqS|5u%nc04mTL++<%DLzHFLwg3Zo@3|6Wi zNw0IOT6&@Tp$z_eabxz86`?sX} z6;0}){!JfhaHqfVE!=9x z){ezf{d4s*W0&`$2;C6spe%ysvRW zu$$UY-Ayy4siTQ(f&B{?TvXw1NPXIt>nChW8V0WT5QnU)u!Sesii20Oz$FdlxrkJ; z5Pof8ELhvNtUy-7{Ov4w@rw_n>=d)w&VkBc%^Fv2Km!7Kg>zP~11lZ|AjG<5BO-0N zAC$n2L)#F!L}yS&uT6u;0Sa3za@qKO?Y?(xsvDPltLro_RIm^-M;ZH;(xZRG>8|&S zkl3Pvd~iGeu+z4Yq?ZT$nPiV%0|knqyU&!~3?D@U$6u;Ld4(IZrUgD=Az2$g^e`Gm z*6Y|Qvs`-}M?ZAvv$iyYu#U{>=_v-f`(&vRCbF$KTp_?}|NWdQ+QGCDuAvG86iIks zq6n8Xq}@q)qcBs?btlc9qv9FS7c;OjiBKGZJ{XNS1TWfw{2=Pn9?_D}N2Z~nZTL_Y z1xv0?dBNSX0PKnfd-AB6?q1@;(VfxJeTE&jOi8BiOcN`XH(>aPmnH=K24`w!Mc1?w zJbb3UrE)gtXbYPOEqfSTZ<#l_O|X~chGOHO)hVsy!2aHZ<+*11L+l3lP1KbKz3WHJ z===}Xt_i9+5((MLwL7ZK!73BOnXZH5wb`h0QU*p&4o@X9I}`heWpW-xf*`=y8&L_e zt-StxigvkZ5wVh0NdrvlHmbkz{C5$|>Nnhi_KVc~ZAt|XB-&c$Kv5Bi74#^-S2mXk zN)kxLhRf#*Dq3WxytA-H)ANg=Ux85Ets>Ds*FXWH^c=?iaMVzJ1iau-9np{(6E-4%^scZf2MTuuzBjs6S>dj(J?mR zi*;2=RIhh+0i~C*?QhQbhbU1{NPXz`9ck*qja2y8xmZk+$)Q`! zIr9BU%KG}7UO^ba4nM2hO-V+*>P1R*)M zybMT}SY|p#6l1gQb`!7JL33sw!JE}pwyS-M$?KM&n&QtYN?Q`ow(rvhU3A0+I){Q0 z#}sr;It)J@4k}g632VGp3MLG}T|ODt-x^%hQz^e~mi@I>db^xR-(79%bm-KCu~Z2@ zP_p#*9SEiqn1y_jCf6B^zM1@De&u9qH{dVLF1qS(Xu5_J>vrnDdX62;t{ZZ$*n!;P zdjqCmVWH*uACPJQvvz*JtNMG4=)tNfQdYsnGTrv7sEshooukzO*!q>9G2^%PGIhs) z1^aU@45DA$v1;!MMbeax zx4k(UDMfyJMbH`r%sqKYzF|{Qj_q1Ii}1;2R`}Bljx^T7}I23wYAtlLOV0{ao8JfonK>NQiJDsQv21#`eTW!OSTb z)%8_Mpvv%DN(8EtxTK^YJ=I-*R7mX+Y#I|;9hWrz1`16}+Lm^z8( z`mU89qhWJ7Fq?~Y2mUh&el)kv)3X__pn|be8gzgesi-@yhN_SPNBvk_TrHU}?9(!H zRB#h+C$z&&I~xDGv{F+Q?>9+>;|0H6eAiq81#wJJKBBMZez98gFVz;@RhW4`vKzM5 z?|4}Z`|Gg!6a%wxt69hLD&+tixlg;_VF%~s{!Wqu5wfn>#3uv#Blucur!(lnz#y~8 zxP$~YpM+ZU7h~#@GOr;Jf9I-(`4{-O3#G0w`ZbGd5JhV|VxW)tGQ@MuOoJcGyd{ib zVI~)K=-&N62&E?X-BQb;yy*Zq)j!9DAtXoVSS?aj(XyK!=ocj#0K$sp=SPV;4RVF9(0a03#95>5hWA&k-G^@(Q}^3g1KPhGWsIdk)@+e&OcnpO>!ba3o=J+;Vwa--*J5(3V8nba=3;J{D|6SPJ(vmIkTACsYF!69@$* zC(hc2-do!~+wtp;ljAC2OuVN4*)x@{x6BvsZUK0&dH)oGG}BVX8T)|Uk56S@qhulO z3lwpX2-R`TOh~;#QT8>()iy9CY2z^e77Chq`4cGbphM_H1A_u$#VKaVI4*i`%9NvLn810>3$MN*8Vjpo-|(?6je z^(-lodo*DS3(AS{WhbscXR3K~()y+={g7tB9RBvVR zd1-y|aZpEL|^@$(XV-f9c?SGb7-hX3Vgo(yM*}umR71x&+$4hvhN-B%A93xXay+}OJc6}2~t3c zfi6aHiw$zZg)hiN7b9T8lp4Pw<)oJ2_kHDUHGABPlNlFK?da;{Odk}2G=9z#36d*P8CTynC_ZZHdimy3b zh;s~vQzXK>9d5bGUfYSxyGf8#rMpFiGfWw`{ZByg@t3~hzF+5=UC(H?<$ghtb$h7# zcEM7x6Z+?^2hEsAuXZj1py@PDCZTqhM;rA=N`3k3a9fDl8ag)GBB3?<;rgYFj%%d5 zi7Kq_Brrb&zJVM0!HkYC-Aon07U)bm`{L-Ppgt_`H*MwLzS&!G`zorPQ&==S2oc6z zo{pp_`xA^FueP*-RRudriw@4YcSuDN2<5?3Mjey^O+uTu05sCLQGkVqbjOMIgAZeO zaRd_V*vMu@d6{-}is>Xcg;!)Z-U* zw_(2Cl{|+qQZ#x3t{OWbSYc0D_-OHkZ0uxHduzK$*ljnL))~qz0G8sKyZcdE%cTeo zr$-yZoz3n}RE|)^Yx(ORn<_MV9en7*vE`Y?HpIFFO%{A{CGrUx^hR@4a!i)e`B?12 z;G$Vq(kVY&q(E?0vMVvGS{SS>pjebP2#c)v`waqdusTGvHU8pYY1W{96J$6TcEg<+ zV^k-_j)xGYlRQDB68fp*vV(!Rf_iW&=45ce@qKsXs=3MP#8P*-c7DKn8NlU7U^0^4 zENVCs>j~stv(Wt29YLQbtl$8zBkLpbYvm?F1>iRlJ81Jprtfr;>gUDPYRp(t10el?69I@F_1Qo9SD*s9ktV;#2k3rJ8w=uy`)xke^dWez|Blf>mKAL% zMXI+zcH#|2Xg6&#GbTpKZY1I#oY%(p68{v}LGKu!U$JoPZK`(QE-+=-MecXpMzRBh z$+}#J5R8igbJVpO_?8Ep_{97+pv$tY0Au3`h!v`k0@Jr{2jH~nQoSPM+e+lUF`sf{ zt43$biq}&7p6z}rrn{!s#w7YyYR`a zd~LEE+}L#>ZG6rHku`GK*YeAP(yNxx8xjGCK&5HL!$jlC(=tu9Xn=4!JXXY#;_OR3 zNpt>SdDJWN6&wQmy?c5?XEduu{#MEDMtPTloeTD~dO#YMFXeyI_{xx1L$K`<;oC zFSL^HB4+25?QwE(m%=J~3a`HvqDIyL;KEQ|PBF6N^+T*tb9Gy+xB9*FTxjAXfxVF8 z{vd`FO>~x=6IgJJkc;`~^A^)N(1M;F@IH_Jtrf`0P^hqcs$|0!0F_FC=1qfx=4+qC zZm?Br9{k(gL%~xpB`1As|HHswtb6-^BFR}Is{{q{wiMh?BmoBp0ATt5&Lrv?*jdn; zM=Q%X{>;bYNztpD*CtOOrQmspOOTT2XNHOLH+7gpw}@tmClSMg|MFIY&A||2><{gD zf0|rx(bRLvH7id_y6+Rp@b$l1Y^kVunCA(V@V6s#cJs$VY8>fce*1-3lpDfTdon{S zuicm{ghv?%OKEw;O64EZCIW2c&^bu=tx#a?UWAO1{TR zWqwoGf4`}xlQx#6ah`_%EIpqdWscxp;ZgAq2UE}vJ=__$B0M@SXu|rg)34D_B5q=f z^bI-O8i)%hAr0*vsw8SElAluyE7I>MEI1fnPxD(eNyL0$u7RUOaVl(qqu##UAsGgc z5K(`e7*Axb{~(LbJ27KF(*X>H#V3NxrX??TX#xB5CX7{Kbz5bPYC}!qO!B^iy^hgf$+2_7^JMT^dcN*6J0n=e>8gb$U? zJfv)CP#E?c`%{WonA|0k0I?C+1M&!(wfyY}zTJ+0d7pBQn$?Vwq>*ou_ggG`D3e}l zGf^aK5}C0Y+Sfq_fMAm=jKf3Kl&(@RgGppx?K1UB*@Lb_-nJb3tpx=&r{%IUD#G{DEUxEO*OHRIcU~0p?#O)L=*Pbx=?z>7Xoa$IKH|K z^*{Zm=h)8Mz|1ITVGyWty{(L}SoWct*Z5z`oaUimN?}Vj^zBr7>u6}EbW0anHc_rp zr|$M+O*rKWnIgeyL@V`OYteK#$0lj+UhOH-mTl|oA_vNg#a)Nm1pp=wnaOP{#-%6F zO>yq$eE;QP0093y?8mA8`}&zS`9DlQ8{-er|37R0ucrbK|8HxJjjjHBJ@|igpIEOG zH$ejcNC^P|VEsR?|Hu6Q$k7^Y{xJUg!tmeiugF?)@`@fHu)v6UWUq)n3{~X7r9F3} z!=8-M?uvo+GkNUw)Wj91CD$z#Pd<{u;?mQ_gss_e)BdCxS|OTMPV0MZjJW420Uh7> z-aXpQ`5{T&QWUff-&f!UaNYGvJl2cazzsLyh)|!#$P1BUwdTPuAALWpKQwT-t(^on z*AYyjeflV!4IJlxO7Kag)1`vpBgsrxJ3Tus#*ssnYUUqomhS|db1O{G6 ziF+lrH)5_wXznpuco?J6vfF`!q>e(PxEXPO@!ui75~TDzXV19;V#a_kPY^_s^|MYB)R1o{w%D=jt)#| z2!YbkX)Gt3Fwq!kTa(2JZSEo?nGD8|&|`_sh#sMBT-5bCbjnEIm5XmHk14tr^mm(} z$>U#ENH)BlPFW<;+07TfKP8d89$KAB_uZId;`-kTfMQvDaFs2u`9QGp5n58Z8DuZ3 zB7v)3##4aBI4%(E6qj8KSjl;HMcuTt=S_BMHozR>+wE65xrlDup|wM`sReR;gcTf0 z9@WmJnFQ{_J`n(cyl1Vm@=oaM3)qR554x61967tsANf}|RnI4M;$7ak$?Ao^zS>EG zu6R6dCGA>xYyp|5NwoVYXT(y(>Mm!4aTtGd!Cs5M!2;fxJqP;4!jiQdS&1GmSF@ilQLq&7=$IC}T@L3MEvJs}3-s!N1yESXC(EFRTam>rpKLPH;Md!wt z9wPxI2=9q@ryF6kH(p61-18RFD*wY#mc(K- z4M%{wZWCDZwLYMEmki3cpA}ub2Y5bgw>pe1Os$89`zXERCBK*#?5p5Xz#M(FZc+D7 zXu7jSkJj1U=7u`jmjkY?|Jwe0pd;|=EC|D|l@WXey21;lMFvEGqUxCdk%8}{!(%PX zdhwxs>hX(+ow3LlPjzN;E;{Zb?89Cec-}57Sd&27hB&2KJ|E{U&KJtpFsXbB)Q`q0eBQ1 zjLj2xG*M^?t6C6d?C2SwqKO$;j-r5zm#JMomTC6`ZqrgE+LvV&#S+iNL>w>?y5v=y z2}2VYf|#-%4@2nC&Q?4r%7V&mqM0C%+BpPUC_>)G$aB6lN3jhhj^c2y$4mO=sHLKN zGV=~1UCqnPt}l{;R;nz+)%QItd=90i;SJaOHcVLZiW-|j>SRZH(;okeqFrB&?=0RGf zlntXsrR}joHt(#=Ss`v-AUocNr0@IqGO{W_zslIFvF62c!^8IEnrZ-?WH7R1GGtT(G6gY^=KjkP0xxoH1OQk?l)Xr<#L{gzC47#y> z|AKSdamL~bdADq;rZ^#{T*Bj`CQf3D_*u#n{sb|}8a&3R#M~Ck_=Eq@H8B6Cqn$<7 z$9Z`Oxvf7Vc6$QL&^Zu2etW~*ck)!>;5Bux8)A)OmQWjc!g`D9(cJ80ALuc;0+@z8 z?@Z+XzQC7It~3i+w7p?kq%u}rYScyqrG=7RAel1GHUedd`6PDa1gTWSP@G?>0ko2G z>j!;Z*=~;XChKr}!VxCzA*$SmV3~~+tqML#@Iuk6KSF8_3nO+tP~|49`pB>(WD|hV zl_N{-$TT$QWwcI{td-dVtr72h-^4;c$h#9PdUWxU#+H-CE^Mux&K{=`51GbPzh{>2 zRncNsP)p`ZC^^{%N;)l*t@pFxME>Zw?nEw>O{fjUFIpsNP5kbr_kJCrnlCxXs=D!{ zcuHd}dqUo@LYh<=GkV$$xj5s`p|}U>J&5#$>9HBRPm0$9>x-ik zd78@|#Vn{hbEQ-zCYM+50!JbCbqOIM9to5RWvx&tNvsGJQ$AA^;w8so^1<_T>eJD1 zfzDno5}!}DD^C;mOP?uRb9>U(L37YQ>0__zE?wH7?iSu32Z}m>^LDM?)7B>nx4(8t z_z|k92Q~e?_Hz(Eztgy|C$YIi$&y_hk>&Z?r$0aXyWv>s9|Z`lP}q#pQ*{sO^c1D1 z#Y#sFXVKHZQpO=;RryiSIU)~#B(BMs zmFenrMp>s?ghy`a&VhM1aruvvxe_GTkPO=3r>gay6?*K(N`naS({b*b-sT(=x{IOO zFhU7u+L@MWRYx%Yg%LgFSq#DOdR*|^&yJWP2K#r$`$wU^AS4(6)mKjhCizQ^(*4iO zU6E?#4rI#?$h0S$HF;i#kI?2}8lEj2?x@V)SJZOXH=Vrsg&0n9ohR6x$FBGq`x2Q9 zPC(e5G04UkPK+4c4cn3>A|0i;$*h~f`>04f{Y(apx#zdX1*SA6ZF4RRbdRw9oCRPX zVUj1ZC%_jWSp|(_kgj~R9nU9g+ZtUp_j381`sJJG^PD-}Z_6D{TK^K5tOMQucRKpd zX=g!5a_apT@iZd&pQatNL=|h>1v-RpDc>PLT@{dm3pW%Pa!YO0Io5eAGl(&VKc;n~ zSkb>Iln>_#k#;=GUQs&7NA?NsPS%wp9@MDvV3MgAq0 z)IOC%8j`&ej0ghXv<&}!;smT~jOQ)D&n$mo?C7gVJ%Zh-_%uNj_fwMiH&nAd7+l2c z6iQjVK^8fj0AR%CNL>(}%fA+39P5FnR*-*)WHbZF2DCYyS-Sn2xb|Z}Y9<$aZ0LCd z1&IT}6Ue|pdCLnF_Q+NjDlpQXg*>kMT~kLS9KFgIdejruLFKL52=X+0BakD2iX7)P zKoJecu|=B`0U;VdW4C>cw5Ta8=ns~!dTPn^Ej79X>TmSWT3LkMvGkWuh0t{7PGAviCkEjh;a1D0J$jpW(OwhTfQm zNoWYbW-ds}BL%aO+P{}<#=DT3jyKkdK_9Hes@LiD7h6Vg2sxyoVPGgjKL)iSjUEpT zV^6}lE@XF5Ka{&v?&6|JLb9kwm4=k6uFJTXByA%~S&lm)UbMVgN1ejC3NtjkRrUFZ zU7PA*Gxs&KagTApLzEPiKy6b-D~H2xfyGPM>acPm8Ild#!1o-*Kd!NiY)LF2GT z!0AV?lbCoNw;Qg_pS6Hhq}g4WH1nF)=U<75l=DW`A8#~(=;-s+_)-zA^su7iiHH460Tkr zRws|SBPNEb>P#8157q8cknYe4$qbp|l!^${8l4zXb%^);Ag)3w2QXd_*T#M;5mO_V z6DiTfkGJv_$)rhaP~nw3GDq#QwpPSj{JWMiJ9I*-BlgE~Ar^u1N?1Mr*09s*I?!=$ z%0ew3sRvTpz3S-x10-CgVid(e#HTs}5G_iuI>qU6Whf5mAy;d5szBUQ>wsLDZ`7VE z!VZoolY=eDf1PUZlpk&;$SbLzf`8HP%An@Ca$w1rr~-?`@D7+hx$ZHRleeIIF$goYtg zEHn`aey;W0;{S2kGRVRHj3&Kbst&+a8{7v|wxd#c&TYAJm?2)lbaqg35z z)M3c)y?sSY_Kj8t-NCPV&L#bn@Jj4&u{tg6CxN8PGR7`*anQCxklZ;p|)nZWgA-dg;MT-6p7+%?cL zIUHd;io9Ei{ryM#m^E~{bKIvXN{uXY^S51>#^>K9Ao@-U(qLdI=lXT!ENn#%+8)Q_ zn_aA#gt`HuJ3Uhg4w_8DrcstG2O0U#yhqGl0Y15w#(mnqWY}-qqDTSk~B9gQf7)rxuNOL^=#YW1Rp2% z!%SQ`Q69z0a|&&m&{XpJ zpZD>{MPYd@)dDFvsRqy3ike)4=vcd~+}QBJ9xAAWK(K`Y%Tj4jBObSW1B`BTbj%P` z;eX?W0f2kT)-W_r{c%YR$Q#5MxIc;0sq}++H=}TXj7G_#(2YP`45zJZ0?v=VM&Nbj zV*?j@6Eo_{E!vTeLD{O<96lYf^*0#sBclE$a{?sqEQ?^_IVfwrMB^NL0#?8vYl89N z;tQAOAM=-2k{-df!IQQdB|PPX*I&abN#X=L?wlH^dH|MN=O}+Yl;z^a+Fo{e^T#+@ zV_$XO4j$#|Z0MYM^Xn_O^?wh0P7Db0^UBK1w-Vd!@gH3Nax23N!mjKY$ey#nbSBtZ z$}M29`Q`@dr>Ii0uN>}q{LGssgRWt<`t#<5{J~2m8&0*j0f(?l64iO|3_M78TTq7{ zU?2G~W?HL{&@O#Pgp|pffgFGUZ)AsL;j@K;{e1otine4K6Zr< zvAvzZgJL+;G^Uuz!ASk;%A0vVlW>v3}d$OGPqzsHM|{1&Te2kgK5a2($La6YYuh~kJNknoGDR$ zR-7OZyYnG5P`7Hj)u2bw%4f-EDK~8tjr+xm#;Y&zDFh3U{su(=$k2r|AZ!qjghR6R z(5h&KCdX|q+sPSTkOUURdJuJO@VGDZwjUQ_7ZwV(kY|Yram1)pW|e-vUQHWjE6WS-vk+mTpXrV`GGBb%B30=sNV;!(1{-|zYmG;-Tjjv#mMb%lBe;n` zK6JQ&1e8~esId2IESQbf-|t0@J6i{sI7mW6*+{Y~C=T(ty2hbqik^!!EwFP}xCFs) zK{>mO8t6&cUaAo0P$8^=A0fkKJF4mW9My)kHL{CReT_;N%#DAZ( zAoZMoC!9dGTZ)4N$D#%u-sCP!?cM$Vi1Pmc-^Hh<`@Vnx0IGh|IPm^Efc!s+tR^LC zSuA=4?uH%%B^rWozj;Yw8BLzQ@}c+ggJTZM4eAxqT~DH?3Qs+*mxZ-NP_rsg4!6@> zJ?=Ma9pKt*^v;GymG`sc&%39$U;6OFDE&!`dz_gWxu7rer{1GU0YOfBb9vgit24Qh zzU%lni_4Q#Il$DC5fIaf-`Sd6!NVYAt;N;?9JWVHZXjp=miBs7lToq8f?RbX53>QJ zptx6?{^Sb-Lr)+yas@|FVEW}o{7}$~aQgnsaeQpyUU5TaON|vo)Yo<>P^m0o*IZE8 zRUpk;HjIyjntqF6`3%hS0UxFBItpxxLA$juHZ%;Uz#{>F4+})fc zwKXu#_WqI->@`V5CP;>D&#-CHFgY{9q$!QWKZ`x*F*kns95*pFGa`T4dN2gw0=?L- zbEK;831CPD`le2;@brSv#lv=sX2%mb-O*0llx&PY@i&r+P}P7w92~}FWNXxTP8%eX zuN34hHY+8yOYsr5siFFU{ClsK*As=zmcBwDK~KY7Wo9fpWo#)n*H^ zwwWfNy(6C7f(Nyg!||%*4Qdt;Gg|g&8y}$YnFi`ln`XO(9kK%i%dY|ny#>|A_fc&4 z)e<_|>N(Z7!|r;D*8{(i6!#>$IPdXc&Yq{NX@|1zYWd6?Qs{8lFbeutMuqG!ncF9G zUUN}F5C)WEWPW8Tzaq+|6|NpVq3k+gvklRHo~DR$;u7t@4qIVP+-C_O008^Hes=u- z_RBG}bugwe`}aF><^L*5w0wuOXv}k0I)E%{rnECEYbn^b$0L>}h_N(RBn+DPt!8Ln zHf&Mlpcj+L_9q!T5=?pCmi_*G>hX03lo-9mM&bd|mO!4=YRD|4*!TPPnzRLf+yM=c z+)+sHcQ}s|$mn;bW>Wug(~{Xg`)%ZcT{(a(EX6+>JAg`FxRjj<%N;@E!kFpP+?hJ? zRC1d^qlBB`QqSX?1-RB*sb_gnKZ6&`@6--PbSM^ z(+-!(eIXqjZ`!NXygG67q98*A=V3f=k%8<->WO*fu9vXtR})r|GfnEE3`lh_X1cfF{!~LJnaZh#T>mIH=1g8L07ah zM?-VYkH%og2|`|Klu_D*voEhkhe?wK#;otnUj$ZO>!<@}z#TDeH&y^AZjqSQ3bW2bp?>@u;X+>#o592&3m70yf;eHeWRPdo zz_|9BgP;pGP1o~?N$;oho~$6!2-cThA~i-g zA!w%mGEWL4N2AWJDwUQwa?G>FBtC)u+F?lX#brv|w5F{HhLS7nCHPh65STxj!p0wd zLa+u~-EB$+8(d~$O*_J@%||bT$dZJ{ONvZ zwngGzKGlm{6JrhOk;cEA7lOxOm(+?Sqt0dIO>t8bt_Og8npNz=ENv}i$%6I|FbijO zJafL{2V+EWbvSvg?Lg*Ri$;*}cbaNFUQCP(*nh|7<`6#C8#HWY@He=E@c2x zQiwm6VWuV?9C~v_8DtygTmESy7wlu$Xj^pb_kC2RBxI@DV7{e>2O9;m>uKkQRKo)x z@d#3ov(Y&IQ#&KhE^JUtwZDreir|hf+$1}0ryh7>ZX9%zRET!Bu8u{Ta0oHrdKNhU zjDOsI=dF=oH%a2<39c%}mg^xO18U?ILdNBs0v|Y(K&Zb|Y47g8MoSJTtW`?D)dR*L zD#SbTCh}gF$HS{s$sXkil-)qyhK;|VMRM1@!QK0?uL*RCv7^6sj>J*VJ5w((sJo2X z14ww}%FgK*M3NO6RtF3che;%=>^Kp*yD4l%cz*-ZEyel){I3_9lKe~c4FUkb9v=Vz z;eUIf89O-GIyll82B~gD|AI)~H>#1lpa@hO^O7p~M67AZ5rc3t3Tir)^Tk#|Ey7(? zmphCuf>|s@Vin5gj$S5Sml&iqx_&+HZ>=;vJJx$^kL*s>8!I)Zx+la&uAo9k4lh{! zOE&BoRufD2P^$)j$=&|Wb>z$NLzm^Cw5Ks7iCC{~I^Mdn*Z#OC7x{iu7TsUW>S(rm z_Dz9jM&b)5MBChk^(8T^BA&j$R2)AHi5$>T zCJeaM`RYHK$x0IU8r5u|+{l)(BoH`6W=boQBSzlIicCzbuER0BJR2SI#ObP#Dy!~w zp&i_3a1o@(MJ-&A^S6enFHQbYnqZ_`ZijIsg$wA`kV4+*(^B#&-% zpyUk+)}>I~_|ixy6dNrk96iUOS|b}MeS@d>2XpPOQO7D1%zzY=2Ppss29-sAxDO%| zwMiI-s{)wIqst?;8m(`>%UI^1Y>2n5Dna{hS#VRQEDYJG^mcfzSC3tMOnqI1IIt{j zjN}Y0ZF!2i-P2{Aty$%{Y8KeN6hhAB%4Z7t4R|eja8Mo})%)qOc|3odpP#e4Ytgju zW_t?}Hy-ugoK%$z87MN1F?AOv%yZzEE@EI{5+jc68%z@7njIANibZhY<^!3rVlYIf zK`_DRIs*L27{&>pZd%YdWfOLqBLq!4g{R>XUcuq^zr_)GwD6Obiz`zo9AXT?&4z6I zAA`Zid7}!W^ZocL4E#!Hi|E+?xc}({e#o<8VX3fK1T9@usb zadUCEuV<=Hq;MP@+fnMf{=6OmPb|Q2nU;{lSn87`fB@faWAm?}MJSvS^~3aCG@qN+ zxhMgXBlKP@>3jNMpFhcZh+^8~S++iyW8aKe4*<_N`t2+?mJ=BOIs1u>=+JIUR~(6% zD`a>dVCpT22^yNF*TL)+Z*iz*(#skqzv1O-Te=xk@*YX8vIzP)QgoqoN2ldaRQGR^ zSG@Px%Oe%IF6w!eDP^b5@~QQxCyBWi+}iJihbh@QY_<@L!qA9tbVyf{1|PPO8EOK8 z9~RSR!AaQUJX@Z!ZCvuKiFluK1+`?+AFB1YGF-(NB4<)1w`Os)w98l(kv+!6(BsQ= zp(%q;Q@1Qsk$-j}pookr{81iL^Nlq(N$naQHy~MsFhpL0)mPIQIAD7&;!oo?Y6Su$-M=nkTmggu*EaW$LGNBv*4rre`_07|%f`Z!; z6HEWC@aUFJvHaljClTRTO%ExgdLZxe!znkX?Gb$K^?Q_bZBu4RAkI^cQtz0_4>upH;z-+V?y z3B1+T(nRG$jpwuThi^_RsJ?jHP1BC*W13I)I;!v1k~GzuK2CIaZF6*K+X{S3vIzy= z8oFeM78zIN2xiiB3&&fQ7OLx$eWk%b0`F|% zrd{o4Z%V^s0W9El?HeTnoA3|2!s0gOoTOBem^oG%N}E!Bo`{H2*j8!cN?E5q! zNdz++vO z*F?ZJ>ACka;Zs#)4)LtvJh??8qrZ z@Q;nz@GP4pjz##yg*S!G6^g6M)Pw4W5jqFuD*OSY&~~6G|$n zsInQ(8OaO>TH`QGIzzFo>ERi6D+^HQhQSALS!QKyaf86X^K|c#(eUY;V6Op0d4!E0|7FfBHuKWFTx3gTK3Qcgq}zD@&eBY`Z!R0 z2myfaOCz!)OC}h|>zT64EJ&0aglzSp`PtBrx`%xDMReT|)UOc_SCNb_&8{Oc%69gu z3aR0)NWdvY+wQsm?wePzDcFW-qYkzQY^k`u%KyASpYMB$E~P9FY^_i3n+#`JGZY+K#UbjjZ5SR-lCe9xX+~OJ*@R(W*oMSS&Osf7cft-U-$q%}4|}r( z2_Mdy)WY^z3x_%gK=1gI*;hr>yr5C9=bTSX@Wtqxhom6e4AtzZvu6~zCr_N==7xz% z+!%dAi_qXZk+q9Tc+je$xX5wiMnjMSDuv2nM>mD+7GLaJ6@zo7k3kNl$;6sy6aN$X z$MNyEV&r?%G7hY~Ron-z*=>K5G_<$sDtnsd*?6VBUZcQ{%%pzt(J_6gflEDL zmjPMg7-`x;i|C0lT8$MQj)UCHmt|J(K&t%)fwbcWVgC~5lg;`y37`Vv-}QJ*3r8(L zTStLqqT~ICbg03DKVN9y=F}Vwa{RUyOVg`nSJO8MBFNp$yDF8m6+YA*inN)9L68bk z6GXnQ6iuj{%u%$RXnFDX&Gdy@vVKa_`_M3QM*}A(XG6>mSL$TR?lbBE6}7LO1}}AG z1T>DeXZ(eD@n9fNUcg_Y*A4va z?rTHG&~9-4XbE>Qhbemtz>rl={N$G~3c2DZ~qfQn_) z-{mixMZXzRliQ;n3Jn0>5WH;7YIWEeNS`-2^6mpS34X4K*DI6TLf>_Pr8g`|eW?Nn z3Ts1ioAF?*t~1Q_uzL!HGYRpRqcE#!D~>N14`ZkmL%(Phj8f!wc{Y=DZGl}WCrkFx zDmL&ZhnOHUiMdGh%huuQdrEl|J(F0yq#D{2GNew61atXRS#$No+?#*sX)-jIZ1G|+ zwX6k$>GlcYo5lBHo0sAQ^!BWtgH_v|hzVU7e@Qm9;;a|c2}4T%2ua-)c?MN7a&KPG zY|?E_t=VPJY7Qu6m9AOwKZ*4VwVJ-|?&?B0014_kgp@oSIlC#W`E*Z^{YycBE@qMS zb0qE>Z6N$-qn4fsSVw2r)&N}@7|>?|Xti71zE(AmGQC4KJjJsc&kPcJLVHO)*)p&z zyfaLz1F#@x%hu10Cf{sQA*>)!r5e|}(AN#-Y&5G_BPu2Am0>9mL2gsBtB_=k1Li_?_{ zX8^oa)GSvS<2owmkw@@HeOm%81ybPs@M9|YD^`CYGdCqO*|pYFV!&bV4!`Yiyt`qz zK(Uh4Ee~(Yv4v-4lHf6pRZB#*lI1+}|She4WhW48?J}kll2V6T;oL?BA?X(mzHSG&Q=RvZ`GYWtF*SJxrS-wd#fAiUK{0+Ms?H zXcbwzl-G7hNM>*ek|1NLI*=EbB=J!ve<;XfM4IT*_tW-J792))ZB&qfv-^7Q4O5rB z0MaGV6%J6Mn`fW{Q6EAq^*Cqk1YUF+o4yMfMWw~dtR8Pi&Ac5z&HDN5E7POmMUd%@tkpYkykhg^}=^hT&GG`Gk z14LB?XzJ4WM&|6FXJ_>MJFTKPs$}z6lxR2$)z>?TN=fAcAAub!xu+7JgkB^*Zi3oQ|e(GxXEHUN1+;ZJ>z$HQao&iN7*EWAb;Oz z(Y-J4IAuCpaabc@M+qgo7I-V}aL`bW5wz=01axye-fzDZh$?}G4zCwugfWr&+WC8l zc^Fao-p-JC5$F`9ynl?S@kx!lVH`B3eUatzz@BqYw4a_v01Hd-7z6bXae;M`1666u zCq+!{=0wlykPbvJI>uF@^ldE>j!gg=vcY`I4t(uVpF1n#;4_1s5nEx1IMMKsu9IBk=PrTOu1rG)KEASEm z(N7O#ztWQ%-#jmZJB=Z1d{eQsk;S;h=mXZFX26; z7?R>3nU(M;LL5@ux+B#ayr=Vsy8rJh7(SM5tT>KYPtF_Ge}zl5+1?|(zyJV1vHy3B z`Tt>C_zx?>|6?uCH8FRvcGdsIfDOCUeqnPJlcUD&D=wGJCa-H zxUB}}VS8uU!_p?va68~Yfd1q@l@Ar}3j=j(P`ydhlRCNQaTiYuV5?bQq;4-kO^AKPmL#NC3|e0yF9)vnQ@w106sa z98bsLIuTTL>mz4c2K9H+`lz zcI&2-nqsn^GRPKe{`2Gx$czvqOBBE|XMnwzzrp#LFD;TVeRumQgq7(O{SI(*JuAzh z+q6ek48&BSEFqu=fqy7O`dO|LfNH#kVCA3gTtIL7UL`i5+@TQ$P^iA*UvyS{*4K0a zHDxDlr5b?|iqpe20CsW`?X{So}b4FK4~LdKL8llL!UMf?h(ooT2aJu0E$TXsl=g8U9PS8%*e@(6`a^8#8a65wVuL))W` za!*Htgo=_uH%?h5X0V07gz7PGZ$7%oFS=m8!EAvcsj^q70O9M=Wq9RAcj-F3Uh*(7 z@U3=%4Idr6UNRy6Qz=uYhq{;?e0z51?E(ZJah&-HrdhD;}u&9&^lEqISI^4I!TY@o_drU&!kcFwnu)V{Z zCb1Z@1lRntFD}gxls>UYA~6>04`so4ecl{!k`@oFsVad3wg!HaQud#-->9%cm!Jj`dtY;^~BS`mCQN)Ko-c$rT zi)!Jq*`2Zbfz-j+X_l4rYyQpg)1e4AQNJGyxp~gK*vX!@dq|6ILzF?6>1Cl6X7;Zej zVBc|1xP0r!CsUh_A46n~;qDC_vm4#TVs4$TFM{QoB*Ll){+_>eax z_F>&q!YZMx_aLStuDPWemGRf95T|nd?(3_Neif^=mqMu{o3#B>&C(plSv-@?2KeCDfD1$K#lX3olijG4iXbg0kP>WS@5h=d3?&cHkos zy@FQ8spcJhgBXTVC#=RmrndP!&HgT_IJ6||IBMV~Z)YuSun+Gm?gFEiB|BObsT#j9 z@*vB)90@M5I7SYkQ8;64|9_^t|CEa2X^f|~{qp_`zc1Kt3CI7<>tz;|z;CzA#EsZ9%4LP9@!a>OGD1)ZzfU09^|&jB^{;ga zWS~KpvOyANYdF^Ig^p{_e8oxtoiIAIdUt;*8L_Dday_g~GC%Q3u3W)7zAfi$As$9h za1(_}_z_=Dm;i`2(eXd>%YkMx0+V^NY zn_@2JSsqq!0!kr`$~d0Xx-wl5YSS<|3#su+V??50QeLlA8UZ`fncG7!e@@7p41#4u-1?9T}fuQwaU&fUPvy*)gt;VN~l_J{jc7tGmG;kw|Zx_}pEKL#BZ*kE45 zj+*z_UM=Lr$%;@Z!?5=g$<1s)V$7r5rwg@9n94`ZHoi1$T3nSBYaajFbn9%1U>_9p zw!5Q}UwL=1^Ot9wB*>Wl?y@2GY-KjtIgm$VQYQ&4cTZ(|=iAu_auwa$0#J@k zJL8m0&C0r$l$tFeVz;Pj)J#`(-D%5h;Fv>&CUs?6kqHC8lB5ZW!*bA(YdS=#W)ZT< zSo2Cl_7t)Jwx`mY-Rdpr@op)e9Of#ts2$d%x7o;v&Rf03pUu2bxhHXYd*|lm!gg(eRUHvk9 zymYUSnnQD3F2GMmI2~5wV7fN)z#x|#2Q3j|&*}R@$ z*w}$jLX!%y_$cb9!ej=nW5E|=^Em-Qiijiu+~I71fa-tl5Qw2tX4d2p zVAgAAwgC!H?ogT?U^ql0`wh6mN9{qaF;Ot53(k zNI6@wdpj~2v;b#dSedOxFX6txWWbI*+tD#xL`DVi$pNq#HDavcIK2p+zfTBJd^an+ zEy9;fG?A{V0$Qbfu!se;#B{SBojph_qU{)wMdOv=zH}1nmO#|8Z8M?(@T@NXQ$NhC zi*{$cR^fRXoP-Cx*mSCpee&o6TYesROgV2U-Z~K)$hJt59b!NPHNb}NGo@I=uz9it z=cKw0X()w)NE#V^L6=|vb=F^%t*A}8FsA??P~s}OWO`7j_|#!fr`b%+s*c}jeJs2f zk2@4xGP!AM#8!;qtG8jc2N-f3kRxIv>38lO4bo-8qGTWG>`jV^hh0Ro@6;*cN}me1 zvhaY6Za5563nzcCG#I1@MSbX%_R-gE7*;%JS6~;YJ0TRF>uXRYl*y@pzk=)e%HDwi zlkuFTpIHr?FLv>c9l3O+Dv-sN&^8E=u094^ThVQ}l2B1~Sf&sa9S4IUtCYb~#xV&6 zfaT83Lq1VgeatX9f7vU*om~Y zmCo3S_T=*jMN+lQTWkhsb zc`(RS_7q2dqvo9Gcu2c9a;j1*yg&y!o=LIKDzwSGKeMPp-25Sv=o<5C$ZvsDDa9a< zl6TR5>)96u^EVkK6H82WaC#);E5r8#3Qv|2W;U#2Tt0hr`{*9n7@%*NiaWE)s`U7z z!!%&BD_E#2l660n$M9p_83kuTbLZFg07RY6 z-3D0x;|IDH;gTIJ9*v*&un2D#P#-2*Zh8+e9Zqr5z--pv=R3uM2h(P_m2qk_EM+!7E!`S2!=h+9QUQ#>Y;uq zTuM+AwQ}$?!03o_l@)Kx_D|`k1Cf6{U{c9Z8H7r&9H~PyX}6rNTq*+})u!%gQ|`9* z!?~XellK>t(1^#YKk(@G-9-Fd#l3LYZj-Ptz`X-Rdbf}E)3W}O<`Kd;dpbCs**9}+ z$n#r=ci^TCZ=&H}VL*&#&J91Sw8WYersg+0%E$hqw${#2i5F@W1+JB+yp=+Y@>k<& zmCN`7(=_i8Ut2Y}kOVwCLwL3Mv#C$EUPWr0yV1xS9!=BqZr7n=+4a*%^G1L4=K5W$ z#{^n4`b`LtpL%8@PN@qca0#p-2SSSIHYhShsHV~koaNF$r5vO?N?pAN7m*kN9tFfS zu95&j?*V${wnYbeVj35U9k?WajqdwC1xvcvU1<2}RH8u9&v-2oS$~F^Pxm?qaKg}i z(`%U$Lh)T{Z6VyizE6nTq{T^inzXe9u9D-(%|G6Tz9wk)*h5ASY#J*3&isu>%6jO; z2vOe*DE7{#!AY2d$TeJqjPeQ8f&0I*z{|o1^X&0C9d%Cm|-6iTg+a7N=P5YStOx|Rl!K|zTFV;ayeQ9%T}Gb$y=~b# zf9$HuRelR+l!xm)NN&`<7iyuGib1l}XtH_C{#8Vjs5r{9Z@eMku{SS;7_MZQ^ToWH zn63VOm>Q+GI(gL#<5(wYr!eZmEMSGFDrJbX>nr3_8}-($XRU14=k2oyVn`k4ezTuB ze|C4ZTFw26iDnnTXm)oRxOYF(@FEu=Bt5KI(^ZDGBf=1P^+SBkn)^-$87O_-#k6>$ z4%yU6o`pq#A%Er8oQB5rhT9~bnIKu<4Q5gcW&1x z;R@fg_9cGG7G%9GDQD%-lC=j^1EM@HX0w8-#4FZy$n7-(!=2mFN+I|qxoDEa<}Y_> z>k>tXSgn9dya8ORa|xQsd_qm|=ih_LSCtcF3kg#t?$1!I8kk|71swYf?<%;CI|Yhp zh@eFYjh%^0MUu^DOJ>lP8}Y=M@YbSRcRiNv4W(UBh4g!DV{yQx`#K7 zWaAB#+8Nd_0T;MyF8(2J#!~QO0I_`P`-uX9)ln~545UOWU~qxfShT{vS$WCd1S@Bx zK!~P4f%%})@?q9^Q+Qj%gIHx>s?4s&gVgt0;gMbr`~YnwoY?cQW#u8s>+r~b6{b0s zQjRHRGzhs8#cLb$8A|^ti5*iQo*U(IQHtA(@qYFzmqjb@r2pP%FCjuC;L(4_Ly&=|KZH~Y$e$FTBk)WehCgrr6q&9ek~s*9@HIuVOpo=DokqYs0CkVd;{{Z;Nv1 z^R16U63{gtm!{<-E7f^8UZYrZDqABK+lu--z-5!=mjXc}z3N^tS6bH+ACgq(Mi>di zD?}n)5!d)L`-Ku(uSGAZ!o$#Ja5gv)#%oMVNoGHSxEUEbl>^zSAn?-^PL7sj+xXbT zQD1?Reui#*g#dg9YjNL8>VV(odIL)hiGy>+3?kpzJQT$U=6t*(ozmQN}7E)x+ znY%E!kSMd@;*o55rf+_}K0n_yG=mkgr{SQ9rC}z`-B^sPAqihq6ylQiyTV+`LR`xJ zxs;J^6lGie$5|d`x~F;G@_Yk7<=(WB3}jFglKQSX03Oc zsZR0Vj>C_+`JC|IOl(lDxW7(xY;GoTy2+9~F!M{6#o$z4!A2J4uXlAu8$R0B(duK8 zPN|`HyUOsJq`B`M>4sO7#3-y8ky|<>Vr*9iCM$3k$Jx6 z<)%r50?pz{9|-R8gcc+buGv`##!qp}#vuGr2s$JdKJ#&**zGOya^;T2eWt{M2!ama z?svtei4DeS=FO+kW(D|;N3sH(W)M5wTHSdc1cMSafL0emn$ zih`Y3caZ_65s)Uqp!dKcBk>&3RWXYB-q^lX-@lr8xD4Zkv{)1}v=qH+?>?mjhUIy~ z1xNFN#SYTAxBT$CNTlrMjQz5JXRL_kmFr*==n*kZhSc`22{5>tmy#}r>N{| z**)+;&+Q$}t~~7!*i_(pyn}L$Pf!C45OH1M{kFzN4p4>sxac&%iICp!PBdZ{L*~aaL_7n}dlDXPuo3%W1 zm_6y8DrbS79)==wE|x)@Gjl-vN8!{D+{rtMHj6E#cA*l->Yx1*j!OE3lB%2!$Jg+a)kW7m)hOgzOYnL>tz~6Ead&3!DDl3$D#797YJ&70(5FvSipR_D!YZ zs+rx0vHnqOV-~CstiJRs+^^M&$}B&kdlt{hcPoPJ1NPBQmuN;2vrFT4oq(Yq<{S-l zrDhyljTya%K08X8n|`%xgYRb(-sYW7Fy{%}e&*j(L zE7p66*DRG!DNYAm$6raxH0 zO8}suHOPa#ljty~V=-Z8V3GR)QD0TBKzgd7(u&>e5sIzCXHgh%JO3AB=MM;=f9)RqN9KV|9U@x5`&MkC3`Q@5X*8G>ABFR9Z`JWwad9f4%qXBes8zC5pomNbar7Q zRS9V4YtWWo;N_c?T>pbd1Upsv=tO=e#wa+HXXuH%(J*$n^6^-gr41(6?Ke$*Jv z=S@F)Ad(hPu$}?r$~@en*AcB{5F0*FryKa)xv?;YvK0{eH4JWcQg6~5Ja%A#7ngL8 z)FnkGL#xOy2QeuAb)|ryWZ-^sdgLf3b~S4QY{w0<%A(VUKPQ(_20y<7ZjkG*GPWXux zKyn|OaNDYYn18qYjZEI{n9}Y;OoK| zUOThM{zIP%A5A{oY^f%M`?^aQi@)rz21aN2skhtdvwgb6-dPn!k%oX22~@J zoE!THOO8{3_6Rt0Wn3)aJCuw@%LIDM%+QFN%_Wr_h6{bpu);<8w2_{W+BE#WHmTg^ zw&}y%O|L`JqYQ^`uC216{j~tBAdNE-n@+uB?|5=gDL5az&G(rMO%<6T8QrtM1!J1C z(GxXlg9(+l)=+HVx|6|%tk$S-o+@^`Z~B4E3XMjva^HlAkkoUqq}7TQ^TRy|?N6yt z#*PPtF4K08GgAyE?D!)4qOu;;Y=J53k5`D=T#CDIQCI51-83+>I=KN;>ds97!(TU+ z0cE?{_V8(F4})UZSmZ%WbI~tRKLc_-o`M5u^&C#a!Ux`m`#8dZA}=^T<5TTVQx zEh8+MOrLJUfWU{|Et1S}#&SnEOH>fKNBv)wY|QEPK?R++9RZx^wu%qHMcx4w6$Ch1 zX&B5JkxJYpo*a6$ibgaBG0Y7yHj8x2AJ0e(=IOSUFYS+zAgsK;!XDJgJU#&>Vvm4l zfD|q#^=h8BwG8zQSZ~5j+cG?z>6hIY zYna%ki#%p|goct3Ktt~#Q)9iV|0Oi>o7TUWy;#SxUw)6{V_6S!J%nf5~Qw`vmauI3;O?}uMIn`UuB?ik&&`R*8uiE(UwuXmNu-Yr`|>nX3Y zZh$Wk%42b$v5jOnY7KRo@@vrgPC=WXKZvOdYdVJgCu+|2bv&u)1}k5i)3JT&&e$wK=lL(BuLN3({T z{t55fDCM%}$(34=-l4b~6}xo;$-M*5XFZou2h@waUI1T7lw0{g_}#f=AwqT#B6YtB zpw-kEkY#@Oa}P}{id=Mkmx*u`vLK1fDJR)w z|Nqq{urRZ6FmqxsS=Mx~{b>{Y%l3l-EwI8igCUzxv;-AR!Ej{?t?C-GBt@Y#MVt7z z%F(M$U%j^mYH<=0AP#WQ|Mq#j$DOx@h-xxt>_2P2byXj<#qfx4@Y@Aoaq+ zTylOODgkAM5g8h1NlA(+;yHllKI8oa7D>n_i{&UsCH8ny5mvLTP!%Mk_Q zC-nzC4YiTT3L0>RlRR29#JZJT2^8ySs&kN^%!m1!0IUlW5SBKIw$R3hrpRE7O9@7h zlav3A6yPWiMZIueb%LW;cxMCBq%Of zgqe(Z?25V_8YJyHBv$WR*-E?jG;KbfUriI2%eudJr{X3>EgP#r_$U z79mUi{gv?{3w4y%DaHrh5f2n`DLBN!!KTS;bV>i&VPYDrqmiOokb+? z3e@RJMNW*+MQpHm3skCc01}-&bbuGUkI*`@I4{GS4J-Lj)^KVl#i<`XyJI0`zkjvv z#m$%VfS$-isyyfH%{;RBPTHkQf3;q?lX-9A9W?qlZ2VTxs+mv2r01y*dJ>DLm&GSjGP=>HxHynje$GJs3F4&CDgc z-@Gs%3M-7ZrsH|yGJaB041TY3jK9czR^z6i;(2b(%mmYyDSvvXkKsd7U)z!u`Xu8r zMGxaG*G0g>BA`iO$Yv<-=(4g{+)N|ZFXjTiU;x6ohoQLagl`Vqh_WD^$}Lma2@x16 z48xOWMXpYKisKrk4B$QB5zFAfr10i$CWtM;3ac(fAM{ZpjXa@uRgG_} zmr%YUr|hV{z+3$*fAi<@;JSc0QRsY-N}3aYCKsNYP!Ue#$ViJNg}dcqfT;|h4V@C| zkkfI$eV_L?{CKz;x-^CFk?HN6=UlP?u#|=cs2y7LL0yh$q=)_WS~39f?h{*d?f}}a zPQRx^uXpsXIu}8^bhrhtts#duIAtIfTfjl`0O1_gD8DnjJV<(V#;?iDsR%ZF$8&-V z9D+ijhHXILWyoCU(UCfrg#B5ePm;O)8@4^9a9T;Suo?nZRAzPAW+fi^OWf}jfh;yB zX=a4Q58OOZHEZ9JIhxT%$8(+AiP6fl8GIL}viUjIw?3I)ozq4=D0A?v{ZV8TW0(Te zV&YrH-kU#D{EZ&Idr(=5Fwq#?{Q~QAVH)I12U3;Bvg*_8^OClD3YuOzs$aQMQ%)y& zcXR1vp`f$sB+Q&(2kb)ETOi6y1^7$9MbPi*>-7n3AhqqK55q5{k5L$boLWFK%U4OH z%3m;Xth>pF$O;&9St=DZo3bhO^+db9&QEcl%Z*e~Rfn9!9L)EW5U_-ZqXXFnk0%LE zI5lS^WLh~)F?x6?QFeue5!vi8t%(K%5>-z`{D{2Pks=%^%DoGVijq;kNk7|RlB>G2l&ld@JHEBjR7Q8a01 zDXsGPZrChab#T1>BAQ@S`3N(XYbu*iZI%;7X7Si=Eb{CH7sL2h*h2j;sfj*D%r;Oz zF7;fRH>N;(b>05K0-!RO#lD*{TL`~nATLfvW)$G{{XG%hy*_aubx+vj{pwO}_4MV6 z;Wv9WDiG_XL`ecfBx`j#_HiCWH!VtD(Cc<(I?vc# z77Yyo%SCnJuR-W52X&K3e_WZ5;@=5r*R0lZlu5n=4HYdx7aQsHEVFb@%z`_#T*dR6 zZ`iFSFp_8>Y}w2olYt8LyHr!rK3aKSpTwSO4aAPmx6Fy?13y`;%2onk(PZ(T&H?q?ZyI2NVx~%iG|CsNkUpeq4Fg}LKJ~P2;O4Ap|@qB zUQkO^Onqv%Lql4q;68+Vd?EjHjgeMJfPDDF<{pLt0;2yPLkyO7E@n=4Mm7dNb%&qD zhKuJ}0on*D$LQJSZbVYkytPr^fLWzt~ z2HZ1q%tZvRQT$mkkOC4%O#HyBnIx%{RqYfv7&K|Vk;^g>hE}$l(Ejb4wZQ>ny>4Oy5pK zTNky!(%d0;tBC5l&Tg`jo-2x|YU)MCyC%pI$74`JcN7=H?n1#|=%uP~M_mhe{wT@i zjF}igC0hbvys0B`y-YQO+yMdw;MZXTkmd!U9V{&@dE7%2{$Mayw#N42@upDg1){xe z5j@_n9miqT_ciL?K&t!(pU3Y#4h~Ntf$d_H!Ejt5gCca6E%L}*eV=sAaZnn^tW*f* z8x~ySJphLNN^>&_g?kyjTU~bGyc#!m9yM3piELSqpIOX9Iaxk@MCuUzp33nL{YzX( z0F@o)!}}a_`csPf|rL8>S3LuxTKLhYAIac0mW$l3!FcSmuM?%~;*FG9z zZgpel%;8PJ<^g}>*?ezJ#f1j{FUK4~x~c|1Rdw7f#UcLb z+0zn@(?yPfW;chXyjial)g5C;pW*XGm7t-v^)NuE=5hUy!yOrxaeViA?A2YW*Ts>h zncn|(srTyrtGr>e=LxOleagAuj^GQjW8SJdOEcJ$S)-y#@f=>`*Q`S<_9p?aMU8j@ zO`=JwX#J(#F9W=)&vt$VZuJN0xmT}nH7euB&dEcR#U?@$6eY{{k$=#UiUMr|#eor7 zrJ0&`+smF>7itQ!u=IzIzYZYr~mqOMZx9!c%6;$$<0T+NKPuUs&F&zneY~e-Wj+{p*Ks4$4f#S zt?4nEM)&Yf0s#F)zt4VyBAeVr&`2alaSjg#eDm4{>i#qA9 z4@s;A9@n`Bgzp3SSf4P|Cp0ynCK?3p--b0k2L7mJ;dw-n>0JYlw=oru)ox-02A8B# z6s`)gyIHggVjY1@pDA*JD}RHBog)dMQn^Ggd4G+xdPh>uGio0|5_Du0J;aPIz z%^DJH^sxX(4XUHZ3*84l&%OmC@Fex3eU zor>1{!DIb36n*wW3ns92!fZq6U&k|tG*n!AUX_x~?E@^e@Y>t0|Bm&7Psv(yga@{r z3m{bCxifJiOg8aw7f!mB9|w^Qn8!jx)pC4eXfFA>~ zXr2sYcRl!Lw{Y+h)|nS#=-$x92ya?kz#os;@Sm3{0UHkxMgu3b@7s%Ftz#$L4c44~ zHBpqJE(C2Zy!po*KEj8f3CE%x&XFlca32CT3arraC7B!&5dqABFcI)fjtJR{6Ybgd zls3`z{nFJTNfAxkzkePd=G9oNMNN)j$Cw>JsDb4t=h)815XMpRLw#~Fkw z-A|^o%&mecKLP@R6l4CUkEKthViRYlWN{v1PUie%ty;+WEEdiz_;AXjX=r2vW>GUm zK@Jg!#7H533yi5^Bt%Ul{3|`R{fM0744DBWqdoGw5rA7^Gr%?>os7HR7^p8j&3}^n zS;Tj>D^InZet@b~O;=+bFVKwH&LfFhcgw)PpVJRi&6w5sOXnRyivVG2o^`N(PZh!E z3ZVo|nbB$Js|z|J=WhY2BT4m+2M~4#j}4zUyu#yM%xr#h+cyal4j257OBW1}fj;)c&Ryz0rw{6gm4LO5~*WB}uD*0x3Tx2iggrFX~fN zig9bxZOBg{!=8nPDv_lRtxOXzhPRF3>AAckUP-xFO7KW~B4`XXa;iAs{Ij3;;YQQh zsB;+RnoMG+hLf@XJUzTgg)Wj#rCHqlHgb+uiOHlf#ldoo%f?F2L*u&CviG7IQfk8g z?U|AKy{$;|mLy+%b*J^Ni#AEL9o=tg6{jSU>jK5gyY*NK zAa<~sl7~bjTWf#j5+F}ZeU0t$wxss`A?PqUNc{Rtt>1TFQJCgPqvR72Sfvx`9^Zx$ zbLpxznO#4n{YP%NhiKMknj5%jicGrFH1vy6LjXnNrwy&c@UHsQ2vEnF@IZX*!{5*c zACh%Tcp)BGqFrZ$njliy{rs@%sw{3ZzSnPqioH6`IBR&-i=W|&2N7B<^S zhxBqCE$sS+T!Of4G^Nw=PL03`9J%ScX}rHQbzgqBvdxptia4M4qPu-?+{y&c6t7=r zn;<*TSd}leMA#0BkNCxke?;=o2~XS=S0cU{XTWg}OwDO;80b>!gBWL-Z|ZG7D0$WP zYct!dSkJRtvMOS`t~kSZ_wa(i?OWr?o7nU*m(dp(Lc;_-*0Unmmjy$1y2t#b-t(2w z*4jdomEevrU*97VWoemjMVskdyt$))PYvxiG}~@~?jyANc$X~dA{sJHOL12syYH){CK%+LvOt3;kP_@#!oh`0m+{>c zTZuJS2^s4^K~sM*jak1UbLOiVilsnHTtZ&T&$%w(pj+Zz=Dro@`3b^_w% zDIw8&y~KgU{8yS6oYxB-d%Cq~v>w{Hmz?mHF;)Y*ow7EGB6CY2th`hJ?(J<_;J~Il zNVG7o%D^fxMdUnRRj@2b`5P`lO?@uz+rq7(0cgBCfQTSnaCm`sMYmqlEOI$|8iT18 zj|BOe=-%WTVpXyQc1k`;ct>K%a-o1NX`TKKMq#xq^$v^jDU`r{ghoX)Lp=CQO-V{( zKuXxFSPdn~fm+z>SshiSF3GU?SHka^mj@(#zHTqqlxHj_1Y7I{(SR#`)oYdEahZ`U zqM3;m{<|c(1SUvfhw{j6mCve+I z((XV$hHrK7gJ9O{m^&_7g^Gw5+Q)Y4Oifz$h^Vjy>d+M9J(Fei zAxqw?pV9%=Gxe6Nh&4g>z}MVK6h$ro`cG5NfMz-VC2d!Vfc0 zXGm?fQ)$V{{E-hDP6W-}%3S=ObMN&nXyV?-LsQK*DW*=7rnlsaBXw%`#iWXJBl1vUW}m8!K6vo)OFCodM-DIO2%@Sy#C4@t^7SJy*AfMimh*# zOr!Ym-||b+fesgfKN|b_?vdi%kN3+S>|P7|`jPk`LNI952`SgNrQyL>iCL;F8%h_v z^gKY43uwebnD#Ag)}MV~;gO1J9$sxTCP%8{P(!SE`3>#k0@9W`%NQ{GO8-7`1VFuB zRv3;(!t#s9CIt%)rHTZkoU&EP?rxNuT|^KhVVfvS7vRjLwYv;~KA9Unuk z)Ch0ASwCV9sho?1*-^ZFWv|E^1s-KS1~zTQgTMp35q453$#5Yr*aoR?q9lXI*sN{J zGM|CIcF5V*cP{#9YPAVDYn3Ih2^A%y+~rb0&s&)}#t^!NOS0Q`7ZC8~m&o z`1cHVjQ*v|mI=F2JSHDr9ctlYBemCe*sYmQTo*X?gM~A{hRRDjUpOaUh2-(;^{<*yd*Q`QqNk`^FMINY!J`7^a+y9ty}CY~RGuCw;WjAEhH z%Z!q@3MxO3Y7bZ}I6rXe(dR^ggV;O78XEXShWOkv;`peL=fW^7mj}MoPCq#vj2;a8 zNoqk=rXBAt>lxUi{(|$r;TQAF^aKlw465z3>eR?|Nh&Ni#B97HkaWD4{0_@V?l`}9V?q@sI2(na)9 zI;mUw=X|FVjPK247K|t0I>8xGACs6&79^J0miIwQ|KU&9T}L!dvvo_2uk5qEZ3X`0 zP@ngd{{8lmFX2V??G^iPMJRE@qI{by4kcKMR(VfPKMvw6o^q`g_4C9hXCkx7olnNv zA61S8fSJMu0ex=@V}_p4%Jv=ehI-yc_0oGEE-mvxytIYGP_e zHu{lF3r6Oro~%LNyhqrNspjL$WHzj50Lkcp^FZtz!`^<~;mO8Un_oRb@(9WKl?V|Z zW>FIp!ckXf8b>kU9~A_#GE1PvN>q0KG8HS46eFtRYx*Upe0h{b-XJY1ofgqz>6$5- z$e049Jg+oh!bL93An>Nu>@^KXdfJUhkeSXido@_>u2_^DPavPP1h0eVc+YhrSXQRW zQmiyZiUsGrpcMyyPJiz}lrgAv5deH_%sl*zDBo|ML_kj~DU^p%n+xAsG#&9yBahzz zqxZ?9L%vgWBy;^Hg21b@gq;)bm~;33{&Q<>i{Yf5C=g4o1qhditU@od<8Z?D?Aq_) zkcfJI_Mx1&f?tFKhm8(S^1jHg!PXO9FU)bUYDfbC4{Zm%T)t*cQ-Hng{;bAsTuOqD zM?qbSAe#6y5=EkC+cGmSC(9gcbZxof=Co)R4vvqLmG|xxyyJ2F9(Svxdj)Zqo|h>c z3l*;_Sqlhhjt?0>X6ba_vTHeWWN(5o#E3#^SnQh`bmERzQ_ZyY>&`6-i5LK|nj^7p zUws3*hPBpqwuhoefPb%3fh6b_dYiZ1k1dQN6k}4~@Gxt+pVXfqc=hnA?-w&MKzEqa zPZ;`guHC9wL6W=Cf0-x^>Y)$6*mjMK>n%K1VwOEjuG)D$ zI9+NfS5^^QM3U8R?9p_42dmuFBzrd}D?Z7q-jo&64i8}hmVp+=&#r`%|Ngz-DY18D z=#jVLrtG;Q_Xi~Vhw43?K{e45{@eOy;*vUv9iGT1U3+RqdR2L=(_FbhBYzEHO%xmp z!>sN)H8D0nuG9e@)pvfv);+xEkgg&oSjVEiWy`5vn!#a&h*~Y@2IatnrHc_17&sIv z9AH7Vl`tUWt*|VONo{<=Ey@x{16b(C>BUMe8hyf^{-N>f;0AG_~VoH!%2c4=se z!*3iN*3;lu0EMS@jEQj~r`S&?TdoX=u|)Ns^K}Szv5TPg(9Y9rQs=e|-h4OT0kNal z`lskyT+HA4w5#O5e^y!shTpcx^v^px->zzuiC%xMO~wDoGw2UXxTG9l&Bk=s6S3Oc z%yly;x^#8K_CC+Xv>?~tl*?`2OL#qTroxQ8f3`eJsZ7qeI?~A zEX_JFk&>(b_IT3x4NtNCBG&nr8NU?1JhX@!t{D*JF_($uiUFjPTA&UpNJ?#i2Be)F zv?44BFkV6`Unx~y`(OonNkw~B13I&&KD+$9Fj3!pJ$qhcV5dUG_+b{ZTuchi6lF95 z%{4cb3SxucMj90&tz}`gP=u$xu)zeNO`=nY7!LcwCswLfGy_T20|hVxVSodbh5q6E zL_;OgstgE^xF8D!q3m2^nj^I1bQ?e4uVF68`n@PHW$2qGx)D~`A1>coZEQQeBG%}? zqHZtj86&4ovlhbcwj6;OZT_d#EeRGTd$fAOv68qg5sw3=zk1x!nz+rC%WgaTZvw>L zSs$ZfxPIfJ01e~?NLy|C!p%zprzldgekVDE#KDXwBh)`s-fRj$z*0=tu`+?X*Pz{B zsbgM0X|8xKuG^PT3Xi9Vv75*(;>TJ#x9Ea{fqWM(m*ywzYWR&RCPe^2+xtzpWnm&qB^?m@Ko!dejYNvXWc~d)lBXOc4vnZ~G1WA2j)K#XL zn|Y%0p#N*Lh3Q)m77xCqW)aMdnDGj|JXXUe{C}RtPE+*|_xzx9Ir#ry1yoxz7b8<6 z7o(qq$d97&zp8jYqrWMYgg}ZRzQP*dpNE#vEZq) z&p|7y8@9e%gB4AQo-InTQAsBo%1jB)Ao-f+Wduc+3D=pkN+~R`3 zLKPN5Hq@Crp}RTjlmZ!S@ZEpQwt9x0%v`rl?n9KpV>p~%FzE4Yn93yRsv5gLP=@jO zW@T|*YBGRVl2&*}3nH_BLT1hTlCYPrke zcg_vqg;WIv)#=9s3jVXftyZh?uSWe0{U4%raj!eyVmK_P<$ZK)__L3EmwK~y{fVMT zN}){h6w_(WDEA-pP}o1xvE!?iRj`IhR1)Ugj{(%kx11LmtvSowoEQgTwtUB-H%|u@D_DN9D{Pny~}>m5yGoOflMX=c+0SzO2wJz{3ggRH;K#bZnb?MJ-Ac7 zzp9~kdcQ&(ODlyr`DiVMRN?Q{ensT76DZh81fNe=qg-qTfi4kj>A8D%&q#*4xMhhO z|N94Q{I^K91@*Lf-S4HI!mD(5WwhH)C(^m6_Wq6Ao3rAnmxL8P9?W_+FriuTVZ2#( zB!VB>1(_&!R4xI4V9Oj76G_C5%WOdhKRG`bQ`V5kw+9z#403SBd|>HsTS(*4D%;J@i=+w z0>k@zZuNZp+--Q@kTp@8Yascrkpv7a-S)f|SEYcPh6v9xPh{J_97(CF($h5q3e%lGy2 ztrou&1ZV#g_SOogSsiwysObYr)UdGwjBUU-s({<0-jP?cQ+GfHGm!J92VFyW5t3?} zSF0H|*^C!-6G)$%e%~&mQ{3_uia%g{^5Z>VG{uG@43SD@JqhGasJ)N5GgQsyg6K-E zw0bws_lx{daG7U;bih0*Z;TzBc}DULNjqn|CVt~KDYul;^@53#JQW%#m#VDlfmewg z6Rq>@laI$S1~U812xEM@)3~xmUF|Q4S1SK~ZpV#|f1>um8VMOTKkHEIpkl}|lRB`* z5UliyRzNh;}daWUrmuK(BWgB*$;w) z)Z0STB&{1hDf5;#4R3B0H8!$sz*ErdNz7A_j?$oA>%CYy!1j+3V)RRxJO=n#;ylhY z`rkCMg|M7kAk68rFLwx8Kn)sfxkXymSlnxOpxf}!izWJku~uc#$&C6wx<%3cO_RX| zmrza`n}$`-#8!&l#BgPmuVo0|TINm9zF* zC9(QK_`<3hpKuhQOe7l`)uHo(F)o=r9XHk(PH(0d&h@ZJC}n-e)6lRw1kC+}(Z-nj zfBk_L{q59Ie-9(s`wO2kazEBXFyMoYN)1kN^0$r8$bQ@NNt@ulW~wkgjFyy3q+dvi z6~#hRD+Ei8v@d?VxifVrQ1t;Yqj=F@G;k^oRWqh0nugOaa>y0ziiZd*$;!CgH0KD=9Ws`M_wi2BeF)3FmW%Tu%21zjw!xF3Py0Aavy*6V0 zFd4dTw{RAEyEqT5|?pD1syc|R{+B@>iWD*Sj7V4dQ4kXqP+Xb%xT8Weq$ka z4Rr(XJ{oDVX0u#DmQr(9XB+45B$gomMm=}7=%{mwaRuIFs&0AAtyU?C(}wit#S!}R z385m&GGe!IY*SLJbLUkZ9N_Kk;VVF|8gY+3A9C*Zcd;K7iW0_3(zr=dZt^Hu`H@iP zpOJw{5YW#^p$67-|8yt?uCPK&}j-4Bc=3Qu@GgI@RmrD-6(k8L1|YS z9n(>?-G8yq@7`lRzxtWf*0<|K)s5=_SeHw_1-`$0P38?u94QJ%nBL6w4xS{zwJf4Bi~FfC+1@A0mK2o zWM=26Q>_tC z;FVT&eYwr#+iLgK`4U-~{Jm*E&FgG@r~~bGYES#Ls_B!*=e*8yi6_n@g=;UXHBww5 zF^Nh)0B#clhHn6gM4v!6N2EKOiwE%lm(kLfY603fK|!uy*7%(<ZBx;$q^oH2!cta*Z?B_T(w6{EvuvoMVo>S z9ilQ_swJ&d^;%8#^CxkhGHkIsgV5glQD)Xks|Z!!z_nRWogAZB4yLGoMXETPL%D`} z>fu?#fDGyg^uSU6YU@Ya=}}4 z4-jg*d&r}X5qmCPQht3ic^(hj?Z$2&G1uQDgu{L|I-lC&-Es0>F~9738~*0^+<3sBIG50oeXTY1!VC#)6%%03-_G|(wn*^3 z4yZPmwVc1?JJT0%-ed4ttt8HqhPQw(q+VOs>JgCW;{!_Tm5BXDQGD0>m=`LZ6gw^4-7B=mDKG6Fv;mq8ThC$&>~gXw6KVAO<-su)xo1c#Gi=B@LjI+Yvb)j&5=QqzR@ zn}ZP6bDX1bwmfQohdK?Kf>`qA*(Gj^S2yrYgCo*XDuv+yt{bnAcO(V z%uk%91V$pDxo-YIJ10qR^(QEpRFc+Om1fmVGMjP@N*QLiwBqwLEA)09TkD#yV>%>g zHtKuR3})H;cR@{TTgEilSrOk{LB2RRf>CPEI^lLzMa5%xEoknFro63w|5s5&MY8hs z4*?L+^C%F|kGJ%HAW{AA?53sJk9y(?@4xd{kF;wDR5pc<27?f+vB1OXC?;{&>+&5p zu=#5)BvWa;QZre6-+$u}qm`-nl{@t~Y|c>lZsJ}~?j?`KP+bq6eNlF{%**(#|Ew|^ zbn}J~*8VO$rx*HS+VBxAy{E{6)WVXWKcY{M2rQ){rk1)H>v9dqxuV0rPisxRb-0 zPRr&Jx>Yx<*&C+O>u!TRWy#sDmAY)92hQ7>KJnl;IFJ*k-r}$JXa;%svk}n4C)r2@ zO2BTfPx`??j-8i`4Z&9{m9)JoG@7k7vNJ76tP}=tOi7H#wyHUGR$sBiSQThlqOh&F6= zSw-M=E^LBIFOq~J7)=2C6^lD!T1`#BHK!x2u60qCFM-q%y~+uzVdP?R0-rys2wzAC z&2+{PbIRTkUziiX04lj!o>^5?&W*1rkaKuBZ468W{qBlNVG7P(EfZehK`VL& zpCmlDI{WU7sp`=%telyJ$^fDXB9V=rS6f>g^4ZK<+lH#Tq)Y1|iCE@TZJNizMAmQ0 zSucxz@}!8m7Nmp-b2v_vkC^>*PCqp#Lo(JOMqLpz7c78aC74RABE@k&FC_Os9bD%C zigaQjHVQd)DJ!&{U>wlY>=1aNAieePozm+eKnrYYrN(O;;RbQ`^Bzl~bt3| ztd+7K4|04u>|=Ow1o;mc*(Mos$A!zU;fv?L-8 zc7(4KZ5(HE-uk_-jl0#Dinwub2nTQj93d!UV>=E*8K@$l;O_6C#AKE4AGhr$yh;%N0=Xb}`;s-T(0Xu@s1!i9)OMAJ`iBgJCNg&YzB7#A`N|W>P%lV~uOpEhJ{wv`6k)FJhY7p5T zFrE`&q(NIpA$rT*Nk7Ml?~UmvUw#>1a+<1Y_x2$nb2>%%W>R}A7`X!=u0yl8AQ`Gu zO~`){@Q*L;h9$)CPB6b84pCAxHV&dp&y5o>swI9{UUQYXiu2sgD2m43$gv~Lwz228 zZs>kj9)CHhA6Hjbf`&eM<&375P13^n`P$|4g~5=aX9rrzfU>HN>d|fX=w{pU&#q&- zZ6e*rp7C)z3Y=yKLZMPbcEQVEGG#<@W=1z0N-LKu{8h8cpA1;F6B^9h{@ zEC`IZ=k#l9{S+$%sL^cEW-p2uz>RTg^EX1d!UB$NmE{Upl#N8>1=8nn@^@>ue|Lub zVLw9BJETK@Zu!C*_rfr#m(`*?5Proy1mxD9FVvwAbLyjEMsLMPI|0BZXfzE>n0!(o z8msbZCCmVVvo!S9WV-82VlaP@O5*mRCNh2`he~h!%ap$}tyhtzdm}tMs`_*tYhX=^ zNmvT7CYXn{)r~1S1N)tN1UdDGgf5;+_*2j~H6rBdWW9jzcP{0Ax%|=EpT~CllAmF! zu2EBt0RcBsOf3?u=1LR~{57{@q;pTQG!yE@DJJOHvSYgGCJoyK7_8`(OUd+AuuVF$ zlW4E=9$EW`Eb_(C0T%hEimx_`aSVEiq(itjO-AL)dmsc|lmqOGy1ke*Xeaeo{Di6n zQgzT%I)(;9XPC@8TD^!;QapiaAB=lbDEl8hBm-3 zufA!QX)lKZWqZ~-i0NaoVa6JE5zHjq3>PP3adScS?J}^CHRZbHb@Cy>@$3UMS2H_c z1fRV;p@~y^@h_#!C9>9Tqadw94$?jmBCY8pp;7q^BQ#lHhZb zqF5LS31hO@IY5VU_%Qgeq0VpGo-z`)L`)rS3RJ8}TV{2Z1?pNOh+!&NUaUBArG6T4 zHPbEwm`3pg<`??@7xC>98(-%5rPyKg12JUYFL}xh%EgeVzl=PA_M;R1U+9FZu-T5A$(FUltf@aQ$Jfd;H$6qQiiq1arb zGsP#C`NSk%8tFj=CrgBjY%`%8Y+k8*mdKQqK+>snx-<-CeGUwERVjF|ISSG&L}+U* ztXY!SW@7vO%ayCcVrFc{2>B=(!m}9uf0g6}_6xG$&%+l0z`|X2sR6|X6$xh<>o=G8 zeX#x)uHEI~UxDrmue<8KyszCgIVlr|(AW=yx(9zkbyu9fCwB@wNxkm5{f?~+In6)Y zYV%vEXO|h(NTYCAvO?t(3iSaWMyfYMS~}prsY=mUaws$M5{EXo z@e-D4Dz@WWt#O7UbDzNe$*57QJgjBI&|^nZ+mW{||Dnk?hWR$g!vC!|gY;0getVAj zzZg5G;LO5qTgUF$PRF)wcWm3XZL@eQ}twQk;;H>+x``OZ1U zcy!!6YLZ~Q>0uHhj;cD9Ca5T0RU%%C1RRTP^N^IK0v%Mm)O6uJVa z*-W%OASEXz`OEHQ2GG^2{xyz+?_|$Ab#X{Ipf-G2y5rU{hEKfVeRTKhQk@7vpQy5~ zO!7LwBK_&-@zAf?A?OZUs~;%J7h2+MsAoEA$aJTo*3)oH8g1s{^84CyCNr5|8qV=Wk2Lh#|1?)PnWvXkUlO_ zCri&=v%*)@q{RFa{61(qh3CSmx|GfMWVTA5XCG61g@-LU+$AcUKhkI}@d&QTq6js- z^Y?TvI&3zN@r2RA5{Gpt#F>`1a;PoXEuF&rOWG7qXMK;#b9E9)9cpO^D$K?~K?n(E zPr{vPovdn|xVCewbZ)dED@8W_H|bxhBpVlw&_KD)h@G2XpWXt6yWIVB++tRaZVzslUlYYkw6V?45!_ zP_-WDJaGf0u}{77-1l878w7WH?mvoaj|jwb$-YU2RAJ4a)nlg$ROLwG*2Y6^WW}mK z%NF5r^;Qy7NLKyBY^J?4fgQ8LF}=%xeM$m-M?^6UcBj+eATYXHFS_b$Nr`qU^{ysY zaKyW}ch%T@Bxi5*V7d?GSQA55pkFrHp4(b4<-FYIZ(JsomSBp{5lbfQ#pIK=ZmstI zp`-dB9$tV-qPX63p#L(Z>p6T4tcwgQDM{9uuGIlm^sa_a*&T!QX5*opgTp9ptU9(q zoQuIY?42BfmhZ-uL5o%9y&KnrgNJ{G`K*E?-$v^_npCN{kb8y>C!5E=L_wsVt++w_ z>N_UbYpFhem99e+!fxvADf^Zf%4I`#cyeb?$RglO19|wXxRz-sxUAPcbbvBeg#0y> z#zhB_PczIKK+@HWE0&AB1yz-Zz1JJZni7L743Y5|;ZB$oi8W`D zXHsO?Bp$$wBqi#ca4(&&)Wv1kQ_*`3h;}$}*3SAyY0jmRKT2iyooMYTx;g2(CvJ3)s;X$t7@Raj#2?kt4g>2a4o}FU4<{7oQjWTIstjLy-ENB3 zeJ?B$$aoI)6}0$ocGYRp1TD|z3YIRPWi;bL)(O`=l?^6(_pw;(p zvV*{hPFOCNVN7!6za`Fx7PZt#^P5e_+VJG^9+MNYYWcNdFI}3O}tk7%@er# z))r;G{di-Mgs{`~qNok5h+C6VrbwQxcW6JtY{rbWu#3EeK5pDAP`yD&jaG2{81j0k z^W=O_V_w@Oeyf3VA;yQMSZ=N5^T*~=U;@(BOnRyv`r%#J{dA;-E%$Ic!pM;6t_Jj0 zE*Z#jXYWI|zzO!Q4Knu~(EmF7Q*E62&xm1xol4OiQTMs$LvS3-bFIuXE}cxH1Aq`G zc^Jy)LMbH|7>d{HH57y_-Rdq~lSR@jtFP4|vjZ=g@s1P{s1{&`!G=*#fEK=_MA+fp=* zMx$E&X9Up?2KZ$O9?@Oik#CI&e$IQUMgW~NQu>%-sC|*IVbC|j!n#G}wZD~kSv-{1 zny*s3L}7laKU2h-Z8?h)O5A}PaeT08Ve#5k+A75z;wVvHjM}%BTZ4uqE&of^Lm;MV zTtGjiKGu~jbLB~FVLOH1rg%n6G&fF4!&$Ik$FN(a% z5wF`N(M)QbV2UUr*E*oxkC_|^(376Di_Jlv-zWZSuI59l%`bCiFmrOv;*wx^sj?c> z+_t*_lqIprYeu&x^n)p^uVw1;WYoKIzJHSqMGvk+?dto&^)z??^uz{VI;x|34?eKG?q3`}t%QzR zAz2pDRT2)W0^H{GQ)Dz#L_YtOo2*~wK*hM!D!I2Gx^AA^@{%)wQ1k=gg{t@7(wgGm zn_-}83t}G9ZD-Dy>goA~rJAHydlND9z=F2UA7{MeGd3Aer#)U^(2gFQx7QoU*0h%t z`PRzn;EM$v5iL1KeCoH>aQ@C`9Jr7CJpbfeM&nFSO`RwkBaBae%j>XTULasfoJEts z4JRU*QvlqSfs*^a`OpMZS_trXc)q&h`1uKkmh(G8D88D!ti-SQE+3dxDJxT=70g|# zce+Hrz5R#h7Vf~SR#dfdc5??JtN z;-qmsv&AJ#*w^27{Lm!+p{HI`yoEv|XWmf-aTa9q$YTOP8bX{v1>VcZ2ic>|&gD^Uje!>qnzN* zfq&g6(f8Z(c9#x^=u@^)30l{*%JEW6vxNAL-(a~o6v<{ZS1o=W9YY=^6&f$y5BVX`St=d>+aS=-mf`dz!heUx!y!0jR-*3 z3-Ey`JK>y43*(Ym7J^#!a+cSsQeZ&1e9eY^2H1c4Z`W4Gw!}B&c33#QASK3qHSiW7w}uP$PwkQ3K866`j;poIXib7m(2_<2am7ZLVun} z@$x%*6M@5=r`EOA9mdgvZ3h1G%+_O;%7&7?Md_GYqWvVep|OzI0ZQ={=%0*j7YE5z z5F<#sfXHeS(wv-0d%Q;DQqDy81|++L#VXQ{gYBmX#4(}TI6OguW=1$7`D<|-LRDHnQoK&q?@!} z7?B9(n)l)8A=&Bt=1`k8qlo*42WfszTaqartX0yR?>0^xa0nC%&@XIVcE!`Fu!N6Jm1~nazQI5&M9%udMBc5`>m* zAa8@_1B2I7<6Ax+9-E0gf&&EG#jd=DyqtHI3$UWW>}YvpM=9`D;jFm@qQYAQ!_xf9_2n2vzD`+P$U zgNY6R-5~Ir8ayn_PWSTFxCtgaoZU*CpE$q3Xl*YsmMbw)r{J?EKEcx2NxG?nGY5wl zP64-gd5)MZ5}XszA9xp-CqrT56ZqV1*a(dp3WN%z_&5zFRR?bgS_@8>68M!Rr`ya; zw9rPWiNgaWWQ6<6>68|Rdt%}>C-S71;%n%ys#7Z_uAjqBfW1DW)J?iDw;k?c%>poh zi%Lu(csf?9ol8-Nbda$XB#?ZDH=At{+`7^HW_qt5igsG0yX|0KYllJ)a9qloOt;Tc z9po*}lXj%m89dQNIen)N4d+eI;TX|Atjsz#sv>M&r9IZ=Jfwm-#jQDVHG8nZ?DGUj z@Yh?h>xeYdPnEGBMi!%8NVxFKNmQAdLyl~8v~X~Dqd_z!G-nc?>2>GoSULQ2#GYM` zc^eI@V4zRz8NLyBAz{(R4SBMBd8)$?$q>SV_hJHfH^im-2w;BZ*^=kxK?7W6I+Ext z{hfZh2wMbV%xRhE{klq9n7!C==F z&w5*5N;rWP$dIj>R9b(V=&MnVBJ)2Gxd@J!<2wglwH-Om`-vR0k8e!BbD;fRpU<2K z8UkJ+Eoa21!}p-)f_)@icyNXNu&qPpT?n&U`O67ug_SGmEHU6=**F-W)qv+&=@qr5 ztCb=fmr1s{JCf?XQlds!n#3GIhl19f8U4}AD=WjBbPgWJ^gYN8V+w{a{>jkUA#)gX zl4Mv(hUJyvF-DdXKtkl;IGU~%6o6rvFY8dM8Xp}7x8TA2yu3VMr~dQIJ&;&ieIyaI z*$}YMVN~n3c>g=tY{^|+3dP-b{m^Q1#Qu4IQUAZ&=db zV^Dy6bf$TgiYzki5AbQr_7wrijH6v-Pk zA0VvvT?T^4Vu^V^y11xVp{uEJRppkw%|lvW&m(4{GuLT<3bY0D^51Y9G!%Vh9;TFD zgIuGXX#5px@aoCL0mWkYLv3q2wE{!GL|GUgITOcJOOso8WB>Lllh99Po)N7Tszt!) z7$3S+CaDD}9Bw!RBP%r+x!dni=iSK}K;^ph%Lv)wQknUB-*xB1LrC1PX6$P|dY8#| z^-PGTm)4=sfci3>FeFw35$s1rG_f=Qg{Hzi)eLx1`Hc)wHwqWhXB|LuQ@uR75N7x8 z*3z8Azvfh#KxrI|pO;?Ana_!L)!}(Fw7eawRf!0Cwo8F&9&3h>tI(C^loWt=Ye%z_ z=DuP(vJ8_!GMP5G+-Iqnwq_mm>t3rTy#5Uz3?j}3sYp>aE?Y7se~G7)ON4~RBZsAQ z4=PjTLuw(+v43cOxR~FeC?>5|^V)Tu*8u&keZlLko!+}!@!y-}C9~MjUPN$N_l~)I zQrcrG=kDp4%X;c2n(#DEG|5<)--3y#x3ei1L04EuZPH>dlHB5L4iEtUOsAHFi|GoH z*ut{FANuA@eqltE{x=(|zpcuE7*44E`i>(-)D0Nl;cX#aF$Noh2O;S97%vL<$K@M- z@E6PU9;SyB`wcwd@cyl~uL-k;_Kye4vA3`ws6?7Uw{N^Zw}Q%4HX;bLCLq7W+Y?+_ z`{Yhf@41KUBKz$N?f6CQ?8YF%Na)vi$-p+s?v@mJpqoa&SKC%M)(0ucNl*0bhWu^a z-rb?+LWbjlcasHx!5xcW>!|;vuyv~sV%6e3hGu7`f_?q(%F0TTw1KAKZy6wv%8F~u zSaX}!nK5L|s2CtRYJ_1EaUr>`e63Yx|NaIGuL%8CXKUqGiXupg2A|6PiIEd-|D-c# z)8BwzfE@NSziSGa8PdWz)kf!sFLeMqoh!K#6v$+AcY0-&M!4xYuLXdWY<78i8ee3d zyTHQDjFf~_iwXRBM-%2ov-qvxt(BGgUo&Q(Ob23ZxMDcxP$vHRH|$1rIjaC)dd3CQ z?7FFSNHO{jsLu@oGP774Nhn#tu<+voC%?mG>CPswS`PJ^8yFQHNX1909e4Ui6yxUz z)tiK+pgDHR@!q6!i73Q^gRvMwy|*j0w_t2DXF~DHcW zpTd&bL{<^c`W*rUbOKG=v(+40KgP5J`nek!S5~sALsaZ8No-j$0`Z`v-6bav16a<{ zooQr@fgCq#<~F7(>rP@$`Lw&1_aoSDM12{Kzqvr3viVUsMixSd-jh1Eqe%J&>e49a zX(NEAtwxCU3vxI1nG>NFn6t%NKfB)RETbsd4nah|Fi3;6LR^r6k^?{jC`8}3)8s@z z;IskG)Olf0H}Z0@1~~u!vE#=4%O<(}cFRu)4FtqR3*4tAW9&z(O zpuiucJ4%6t+UC#!y@TwmNy_Mc=)i_d`xVesYHFjBHcxlQ%~bLq1d0o^ElefTZJ*C$ zSubaxpSdTOvzZfcs7?RZa@VrX=Z!DQuoJw`N?gq@OSsPnvh6N`(8z;8qB!Dxco_9H z?(!bcH&GBy9}}EuUK5ZvAQT{sDl=q8eQ2W&$+(&tXB~?ZG20am4yopU#4Roe71ird zVwEgxRT>vYI1AD@APUx}{Lh^)t=H-LVfKEPr~6hLhqkeez(M_vK?rn@Z;Y5S;HIjf z!W`Q{#Ob z-S^ItDRg=luk#EpEUWKT2Pa~Pr&p(YUn;pn-IGpA%t&Yg!^$~>1mF@jqf01#Vo|e$ z(*p|kv&`l>jTN(hw}isuxPcq#GE4F`gE~ptd#g}*LDV1Qgcb!>5zHKKEx3WlNWBn^ zI1qozthV#28`!H8N3(C-m1s6iJpq5-`;;{G3s`H6MW5R@KjLCTxgecEVo_}#z#TEF zBLsgCGk}c>kC?5e_ZY1#k_MAt3`x3P7<+h^4U^N!85mnQ8D84k%ZoU(_i?c3yo868 zneR=}=o#w@{~K_lV#x1k z)?N7v_^`fpWxJUQ#K2?2)w)t(uG-Ho$y-`KKhm-k+eVC^AKu5t>M&M!!$lfJ+_>>a7?j8@@>ofDZ3wA@cRV zI>;+C#p^26YgmQBbFD+?u`H);uFaolUe}pkNwCt&PE5XpT(B4fSLA?|wq+0uzDJ6w zF&O_P2|Y4m?>KMvwVk_xRbP^{uy7sk^4@g<`uw=n%FVP#J-@=l*2~C~E5Fi6*}B-y zmEyOx9E|D>NtMV{GtYMY)KN&S@aR2{l}+K|(Y7%*!&UItMmeB<0dd=>-ccAy3saAJ zpQ?9+;=(ZxSzknN_YYg5DN1%uHhDTTJ7b#yDWY%ya+x9yfls+QSg_Vyffl2-ChR1p?Yn4Bn=;lvs7~rGkq>m`)w~j zfYst$bE2+d5S`=P975u!_3LAB+z27;y^{G-5~*LxMhginf6A~|bDO4f9r0Tgl8<+~8Nxtv1Cxp34b&y3f(N&@* zgW;)CBbnoG-6XtsUkwZSpeh<*H58F3y0JpHYiy}x+L3~%#zNX0Qk zc`uWG1yr&M6+Zq;5;#|o5S2#j#?>!fw|7n;s)DJiQHH#e8U|!|fEEXlL*D=eBoTP< zt7QDQM)V5eH#<^ys_bE%%tdt6RHPu?g_QpRa(0sn>f)*srAM2cjyu4hA5Q7LYCl^+ z#Aol;Un1?QZ4-m6&x8~lS6XC>Vm{OOZW0m5)c2WM2_8DiXcS{-5GRP3yOwoRQ|=jn>9U6kN4t_cJt*}%Xs(It}{>p$i7 zdR64JW0i%p4#QK)tDkR3qyxd@KO^8>1 zD_|)eb;p}IO(wKLVc1XvlhOqKNE(n`BWZ&%H$&~6Ewmq-6Gl2ud>xuSn|u*t`PZN( zEQV-h{EM+7KV;bWH<(r+%7=s!7M>47YETkuFvr=y1;Vg}Zuey8lDYPF7ZWxj%JWCJ zg8~2yC1@t;e2Ygh9i#1#sUydJ!EwTU+W-&U3XUx6m2yhnZ;F<*?aE3R*=D!wMcM4M zZLsp!O@%riU70r8K9jxH299vzRPEp|AQaO>hC*#q3F<8nXj*K6#{NjQf;BR{b=Y4J z=QSYwzSSL4#D8po}GGlFvOPTij zOHqMn&4tcVH>x{rue)T=$%H@PjA~krK1lCXwis%B+A41%p7>jx%JY@dN~Edts0hT` zud$(HbZ5F-TT@Fi%Bk!#D*J_Hm9e;;IlADMq^~|CwqachG@+GKz?wRuVw{l+Rj8>T z!y1wF-VO)qjipH_i8!0|nkHS#ewCdpIwQ%nZ0$}Njy}d0;;s4lB^Y;va@S{`8tKhM zdqG~E8{Bn7zv(q32Y)w*jOE^*o;clK+(bV2z^?gqRC|*H-^;ip!Iq&-?}LjG2Wm~w z@c5h3b>_&sCqGysFi^6L_bLfB*m&B0*7OD|b5CB4(IVYex!!88()1 zlwDSkYJ)Xk~v)!LfFE(BNc|lc5;t3F{-#!1k_}0 z>WyK8yNO#b*cH7b*qY@jA9WS4`jK9}ZJx_D+lK{H*11h6&@vV4Ip1tr*i98*Rdi;x zE|f{_S~imhXqFbP*}&P}-0quavNUuRM%QCqPJ6M3aaJpErekm>Nka{ND9 zVuc@=<^NB6WuB$D^V41-`lj|6E)H7D4eG@WhQWa2NE6v8%%oZWI271cY{y(D0{(vN zWYM}|%q~Ep2)Uhn9B10O9zTIcpI`NrJ`ICR@VdVoUuCL2zBD7OK@cgnZw(aMHleC6 zc>?)r2#MSE>Ia#IInD;bzAFS;>RX*RA)(FIF@(=9hIFArgxQyBjfNDnlwn&fmN!9- z2hQHR*yNTMQNb4;7%C(DQg_s!Q~tFm>Xtq%ot7^~ET!I9p?Gx2AihO-Im=>LDcvQ-Db@V zStPW^;Mt;kvNw)?uOf%U7oY)S_4jixu)zbPlt527k zHmb%!kk`L+X>lV+dZq@+_i~*tfPSe1VkpwHPHWQs1|7P#WYQT)uUe01^8G;GO)VDe z^_Ls{665I#)2S9T)d6v&3aX+NVW|Zh@DZF659ro2UMxsrKD}ES0QlDdt#>Q<9VOdC zkBd0pGjordwC4+6n`u7>%)u_tvG^X#vBfK|{?rU#rIrDS9v%&w4`Pv~m2SlGcn|?E z&@g8DbNFfBgi<*q{hzTDG*e&HDRJu?U~QFrnhU_y2SXOk>j_~*&?vW&Tq5CVt37Br zkeC@lHB8VdUf6Cg0wR5ZIaCXI3g4eML-fg2Uj|H$j`~oXcOHk|W}vs)k7LUeHZ^Gt zy(4`iN2t%+@$p)%+oi|>U3qM-O^Lf=Te(-mQ#jPoE(=1bEA4ghcEJHr`AeKD`Tf4^ zszs!Un-KzZi9bu&`LaJaZ`GUbJB}GK*Hb zUA_obkXCv01^%B({)57^MHCbupj;^+Ak6>w<;KF;=szG$k01B$f8S}WsjBoZOl^#M zS+=Bt<7q7EfY+{`XGd3!YL{0R#baGxI$pZ&b{QFhE0xO>(1w_AUb~#OWnQjun8MZM zBpLLK3-{O}%5dHhZYLH;o%=>j5Rc*xd8UbH#sWFG$i5gz06e77(i)C4od;YVpx-|+ z?};kNGbm<~yK?*n(S>z6yd2QnL~;&)w8=r(=p`CR(vGl*1;qfPUO42&SY83&V2<{` z9_xaQ{Rxf6m`Lkp`01)|M!}=h_k$1FazX-Np>)uTqBk2z!2JhBJSa$G`%BKL1cYOq z`*@hV_V=fec13_H)!SwWBQ}Ty2SsW2(SrB^a0>ijy8tX=kMU2QMR_p9q_~2!AD=hn znV#Qof{z1-Z_oELuO4?PH|XYdm`2>Ps4;_~{Lkc5g2Nce<%;RqLQ#sK0R-;uKTlW&;Zy zQSWZ}4?*Dx4GU4j2X}W4D4#eYYbV3>19z-PEQfU(-?1T-8$`oTQ1ykn*WQ>}zsy$_ z?aspX+?m?jij&UVoqYsjU#B4t)cMO#*gOW1rUA(cBM*rv@X*GnAj1PubH-e_3lo{J zTmMAq zulPbbbIB%)MlXn&4KAcnWj*HhOL>5DM|Et&Dct zm8xeu%8Mal_oCTS zB##KviQXx5t1mAR@ghWvqEJ7ankZ7r(<0Q(`DQTstVd=yv_h={OEZ*Jb~y5z=i+I} zuHBtkk!=-B2GP)iyREBaU3h*t`ZHtq2yBkN(@>!*c0#$*C1z(F?6Pg1vK5BBoIJ)1 zMY|z6sye)`l`~g=(a0_7f`Zj8oq=;l=y9Ei+8A5udn&h<&T5jYW-eOL#nE8-#B{L^ zE6tA|Xqear+lztCi+@{%O-Ze0-1d2Ts2D0%Rq7Vgx>)A(%=GXK$2^lJRID1FX~Cok zeeoISkT8>#KCh5zAXMQUfq4d}B!ot34pdo*Taw(Pkspgqqu?r?I|^zO(g-Y8v~I^EYQ8>0_5nwwp>r4T+0*(zrW3ssYOwN_(64`|ap7v42uX4L(P2q@k6{o0 zP95*hp}<#=Q;#G?ydmcax_g#as5KIqMQPko&Ew};+;pJagIb^qft#F;hdGOxhm9~? zD{R(jLG{%nk%k~Htag1KzmocMW2)3zht^>>AX?mxRWzU1U0aN-M8MM)2yB&pM|S9YK&42aEgqKSAogsFV0aV# z`kEUgEs*Sn>Ts1VUtpv?HKUSaW9*K^U%YTh5Dl>OBUWgkk%{^(XzYWUl72*q5L(V- zT@VAJ_cz(NU zHy6ggaWRTmY%88q66@+KDXRXq!xX{WjPj}Q%^J&CUU8xb#e-+?IuJq^iOgAZ_loSx zmlmKAl5f;J**r`t6}WHO;4tT|Kw9>gnbkbEKq96>)L@P;A_GS-zwCJhF8f_X{B}$O zAKfwF-t}nSxqpX7PE&0SXzQ1;hlN`GRYM=y@U7y&)NdskU(9*1a?~%f z(%q%%DyA*G1#keVX7+gQEg(2^>M7Ai#h2vH$o77fK72Sb<+|wEtRchNFY<>t`s1J1 z<=UYE@EL;A^g48n-rwZ`hujH9b6Sw5f+izdTva)k;<0OuM!9|ju#M zgup8iBv{EGnQikQjt4O3-jvYoZJj@%?&-kQ-!Jfwmdr6yegN>Dj%3ljaM5g02xgXjdb~3c^}iaTBOk3%?GP@e zl`AN7P_@q))!4EUe>|HTGPZEs!QbeP)OJ`1(3&cm@kcPWQ%X`?{)L^}Bq(|Wf|B6;47+;&1%CWY+yIGxh2($gAJ;t4} zfy)ukDVO>4j@7l(ftrqrp8lMU3bmF2SlCo6bz7AO*B>>|&we-d&AbD)ZQ**IA<@zA z!MBypXX&W8O6wisipF5t?DOIRzW>Gaqz7oVL8f9$0Z4fPTPKSjbat72*ZK>RV=0y= zy5T_)KmZ{ItVA^1>@v{&^HFUxx=t}UGqvk^==NP0nEnUKmpe}Edy7BgqQY*7q>5-K zRYCF`6dzGc(k)U$L6%c59xkgrWG;12|4UGF^V53i)wIR4-NHOmDC0x3D2GGZwhd_b zyD$#B%$t{z{74r8VyIfRzLa34(shM_mGaC#=~IQuo}{`rl>J@oQa-zxEa(h~ewW-3pdg{veW~e+Aoq8~QFA{iE?JK+e39*GcSu$-!VQvO8_T~w zPo9p#IaeOjwVq(TSd$Nz_vR4X=`4~|P+Pn0u!Jc-b^8jtS(S(zb+Bg_{zAa9>cR1h zr+>Yj4~W7$CEy(vSG_v$EQa-q`DxuogVrCc6Easnqr>44@*z|PCi^viG(eyjwQQEg zj1>4u*sNO=4OK|0LG@EXfvX}!H!x>HXnusjm?An2k~9x`)D zw24cr#Z!L{{*Gwic8@7yATX?gx^>UBgl(d6Dz!+m92BOR$)F(+`S?~6N1kCvt>xLa z#Y$`a=X}#dx?;%*Nlsl>E-rahvOr9-Xgu8khZb((IDp0;L4oM-gU}1v8BltOgcf}i zMXnl{2u-4P)^qzzgNdr1j9c#%KL&*kj$~2l zD}36wYHP0Ih8M{vY*A6-;(GJ>4Oy2}Ukj&hA}i()HREC$EB!ZD^j>9|LViYFaTtSd z2s9ayjwvBLN?r6w(!;7pNb)d4nu%U# zB-lX+A8WUUG}k~-Q<-N%J-@q4IQp`>$|l{DLVi2C-yBBhCFK0lxwpf;sMbHs?K#F0 zNO`f$RK7OC#+sQAD`EPydZ{`hsT z<2)awV3Ko5_gyzR6tG%DMq?Hkwg6ZLj7KKPUtQY2`yOsVEHG&bELMhUVa?iRq@6-K zsHqA@K@aoO^mf~^bb7M%d~!QFGV~)YH{`>{%;CRhTxse{;Q~-N@>Et91WY0EckgJM z+O*SF(Ek0={UWvj-3w>??Mnd&CM&iYT`;2JKJSq@YwCj^Z1)II0U;eP*fDW-fhw|kPWJQHCQ-juvJ9i%3@N9gX>7j{9Z>1+KGy{N2jdFlA?_V|n|W=AtMjTk2E<|~8eiea#u z5cU{CAjx^AiVE2%wc8Zs`4!YQyH*1DI)X=FXck^J4n*w1+_dfUu&IRtCbzBJI_9n* zH_2IhHBA>H2$Fz~-NU3pbNQCe{H<(~SvJ?hppWFJ1nyzLisZ@t2Jh5W!rS{r)9!I9 zfES}JNUy=Xmj>L}&C=dU)NOs}{PrDJ>aX1nf!2YEkbahF&sh=-Qih8$(2JvE(H1gw*Fw%1&@B)cSa^}{)$s%q`(Fk|h7eG@c+>mzNnD`h0G1qmZ4`;eOkP6Z zH8mho^}7Vr8`1p$@YdQcpi3Eo-d~k>B5YYPwCvoSwnh!+CZ$ip!!7m2h(rxNi@}=9K z@zb__%m?v!jd<5aGAm$x&gF%&D_hnjEFxd|G{~G@XnGyEY8mw%8JU+A;wM&!l5vk4 zj{Jgb0l_$TT(1WDT2sK!Gtt*L2k}Mc3&u%Ha~ccBF@{KOf)*{|!D{P2>5F&E|JL)f zMO}-w8_aLi3Eg!S-aumV%)I$Z$Eb8qdH5>)uzBo!d*#=Xl8al&A<%%evv=*uqa&$7sjaI;DFa#$DFgX?Zn>+|9~pxcKE@GQxSUOFK_u0j?ktT^FdZZ*ijFT6%Tmh8^Z^SEdQc?R@qn02mJ zm?y_rW`Y|h^FrNq2|d*lOXubxyQ0s&)D0Wx4O(raF~_Azbii%FEL+9~B`jk_El^cv zefJ;K0(rnQd=CTQTYH&%wKQaB8NdBr`LrhLI|<%vOm_nZXVH_1nK)w!B1cuGhTW&H zE8wYwXJB{vxcHShP2L3cviCMNGTCqYPeH2?DmumkAx$M~_++bRkjjK4j~%%1+7?|? zP2RR_8}zovWCFxM^`Z!3{+8+A;38?sDqdb8{LevJK*er+03#4kWghVVHb^tC%<%e; zIAG{|S&lIxA}?~ip67tL4_rGR1bA6Z2D>n5Lt;agQiq+7uVcY>g?N1-fo`x;;D*!f z+TKse)RkZhWu))TJi{U#VG*H%>ex)N)A8#{jS;H3yCHnD*N>w8qDf+a z{dY1B*6_TCyVj=CcXIDm_yfZ$E*(!^cC`@Y5Sh9tMwC1s`rkfP8jS8l&TBH5Ex8Q| z7o3BAy$rZj8*s;wgIJ;iq% zN<%E$MIceyJ85kYKcBag4omY0Lnku4yECRH91>7~2`Fl5B3iHmcmI=8RKu=zIe8QX z)>B9Y*+~-WMvS)2%F>_^cvQ>4+t{l!U3PMIe^?EGxfa@>Z#i?xZbscdQ$UvfAqTluc$@=M?0 z^YNW@Baf+nQI`rGc)_6MwI+99a%Ifs%#$0@wh~rji;HcsBsTO zv0+-ZxmNpFOEr2V>PC%>WaxGjLsl+j~R{vGEh zn#k_34(d3Ff*cARNk66Amn<*<9yJ}$^hlXXTndnuW~SEqq3PiA$R?l%Ta2fxw~^&U zNxh1P8+psIQgYU2;qG*lf8g^D1GzCH5rU-f+9Lw4Dd_2m;RO5plRDB0jIa<^ADMtV zx)uY9uTj-0D|%3V#hG8(4T@tCGgaamrI2M*Z!Cu^5~1Cz%|l(QE~(EYLt^V=h5Xwl zWH$9DTN--dTde>-KklnPWM5^xS3RR7+;QX8J73Q6$7;-8nBRNma(}jGd~tpwVz`Ot zz+|d++2XBj>Do~_;-5KRM7Gj1$Rq+86+pYoey8Y{tAZ)qGW2N5WLBdHp_Z4qav%qy zJ--;nvtOtLylQ!f-X$(*l{pkF;=9S&)ehpF9(@dlG+QpJ+|{tE76Fa|NTj06)daq| zx&5m6y=A&qbiCMZ{+yioBs|9ck?t6s?5m!u!>&TFr4HD9TCZhEl?ud@@>?ngNQALCEs+r%ws^86(v35j zTl+{w=mJd5#L06J$5^2`%}U!Crun%LmM)kM%=}Eq+;iuwCzCuCORG_(71^eMxN@ns zK9i1tdPHr5q7l-V^mKj$l#$6mWCWNQ)}=Saj_w7xa}_-;R?FltG3oa`3h@}vZ`ga7=j zZlU4{mo2t3bcql*Rlm*@n+DpT4lFK%WH*6vYzZK_%D}p(C=I#TVLd-@{uDgLM10F4 z*-LJgyfLzv#n6sXV!sdg9qBYaQqnC!HH90U2(eH;XEOw7*21fB4Hr(*+#J|C>_i85tk z)269zW*4O%#;gcV@wzoQG<^o}^By3NBw5_Wiv)$tCJ{l-lkDC0M=Jg2BIK#lXAX8> zf?Q59WoNSR^Ls+qAW*YA;E3P&udlI|!xf>0xkJ#cHpRVT)Tcg=N(# zi7=4)s+GF=`AG&;&b3x+ru+i}f%Ft3bt!Df^4<49Q;!B(ZyH;?z&3n$@JijZ^jC(J){@Kx`y%@F5 zgj}oAEVifx`+1_13S=fsokvnWb*L0?y0yTNzTx{znP-`|)pPP*SM5|Wt)yjaySHSt z$GhMFuZQ5|QIZ}YeRG>A6_DT+6uOivU;Haw$$Gxj_(o$&!hulv?Zmj0rF!)qwJi8Y zg0{i7mWHwbl9Pyby#MYvURZaM12-JtUoD7mAKeK^RPXBj6vN^@?}_4q%;p%GOxykU zJv$J|5O=|Ki1Zef;;vRNV7o9v1zXc}^ulhhtz9@h7ffu z!!<0pjvG?S!cC$zRk0N^annVDqU|DH-tj7+<)_lVozih2u+VHSVkI*dXvh)aIE;XD zz^{C%ov(K7bCy4%zuFFzomYn(JZ(+5BkN$3?e{FWLjiWPk(^_ffN*%5XK;@o!pCdnNjVMB{Fx!J53iwvwE z{*V_70NZSzRf4UuBT88CS0vRxXT>J_r*rl3g`~4P8Q6Vf!MB;RY~BA6r|V6Fu^v`_ zzjk&57y#)=56PqN2yo!Sf7$L>vS)&jHm*-`2uANs(nwuxMHeo0q!%(c7n;_p7#zdv z%yt^H6K_OUXSy|1{E9CI$z(~v-{B{q`$RXd)mPVS$SiUo$mHeB1|?zfay$(7TqbGK zAhuw&O6*T9{weVjEB{j>n6-ZDaD8`7fwQHutk+n!2;>-{-c*`eUD_heu(NUYFiSEA zBt*N_;(pwiR%DRTEnyK3&xyRLwIWyGoEp4_HTWvBoi+jX9kx^Dd6ct&u~scQ2LQ#7 zw)$!j!8ZkYR*0w?S2V0LnAE7$5jNoqQ$yD1)v7HC^jY~fJoaEuY4H?FPAM~0j%BTK z+9r&_Lcex9%GPtezQ1>G2|8HTOY)~^2fzFCm4jcl@n7eM^M_>W^_g6{a)o$q{UZy( z4WF+scMfXQ28}eD)lN|Kf$gR*64UdE!1acmP<304UPv?v^R-Z7YOl!5$jtRV>+~bXgSnnbP~DM{WyIgZ zk}V21f=+!$HyaJ-am6kkd^$^)6bs==QYrUwf~O9S>OnNe&%T-gKtI3Qm1 z^&f7;XECb#Zz2_4o+uxzQ721CBbd|$1mRgnL8=B&;V670>28Rk_k&vSA^{(v4;H8i z&JqV$s5DpDA{bjJwfF0cXTIQhlr`b?F{j-M@jlE5YDM9a-549_=LK#lyHD<9^?&-Q zXuV98KVeil{ZAN=UPv~~UAI4d?yNz(fAycp=~s|W`Ps(-;#yH-}Lpi+Z3J7>CgAt4v`+l_QJDwS0e*ef}jef%~mWOekCkb z1j8qcq~Y%Pb6i(o5c=PAF$DU>Aol$bSy87-St~CkH8>jR@MUR!L0&0lzM){cvY-B& zU@a*N_%Pt!+_`3)vx zW361aI@!Ssr?)nN`q*jvsUp}6v)TPKyys(rq-YGO(eW%YyUepe%H=%pc*Dk)L_J~U z|2m3^%ahy1?5$;2EU-b9oLEifSe~8S&B#Gin zGp~pgkwEuv1_dnN3gESk3BhChQ>Iz?Xn$ilHcc-!M?0ql(t1F@c5+BLK#U!z2!Q-) zyI{^;OtMFV2|>~nSbHE_$tlf!dyD*c)rMTFc58NRXV=!ib&XzSt-|z;rvVf8dTb{Q zN5zO@+&|6}3Pd(4iUp9=WL8>Kvi4I$BE{#lcn23EB32g(F~g<$=xvQ_hmHhFBtFos z_ir{%pS-QIhoML;W8oz$Wb`tV)We=lY)IP|L}4XH!J(W^tvcsytA(?u0VUT{!A8J1 zpajhO3oi{Jl)!f!sgYu8gl~0nsP)2hZe|8Y9#t2@M!m{E;A?!7ou$HX7pBmh1&V{` z5hB53hU<`?WBpr%;U48>I-o;$MMY&M#F2a`IzN6j;=V~XPhbY&J4Pa||3lDrdG5;< zzC2X`Be(KaUG=MrVhy2Tb3NGVXprT*%^$IB`QW7%|q7zndsm|m&ua46t)&dDq;u^_D&V;Ayeg3f%08Se5QEXQ+ z(eYRO5iuOa4_#;kFB<{vSL(>p(z;eNF+Xxxb&m4~r2}5nU|Kthw!SYmT!f+xE1y(#!y$t+NWjAlGE6!ep)qSS-lS zV(esr;;1k};#64&OU$DGiYO-@NMA6HPaaI^CC1+F-!L49;sBBV6A7^y_v)ZOYtnG> zeE)p>eChAoxOA@Y^k@IGDA?#bGM39o4rYo}uYVCbe*3PMT;a}FG$0{JWaox@G~(^v zc9fZ9$Ij!h>wdqzOZTO2)<=MDMT6!O#qr6E z)EuVGpk{h{_M8hy6-7a=IN815JlX`iwpJZQ;o_;d>2_J?M3tQ^BPpL*@j(Zln`Ugl z)(OalxkEs{iw01^U{u{@$9Tm07qkV=p4m=cNec6sTrdF`{=!2OD4C{zMi@gPxGWIfpdq zQ4yR7@TI5ot}Jtx__AZl5hf+I##S81<(CiB6Er$ZLA)-Ffq^@2{fXZ4qlpbJEJPDi zBqT*ngEqgi<6SPfuubr(&a=6&H6y2fD#F9bQC9FWc$;-008p$-c2O_OXX<~qFqa!X zVm~*9pRI_ihokPWz+twzp|@w%ePUUL-l}C6A5I@OZfs3GKdjA}Y~gMsQ9Dgdj(l{s zaa|zcETM(+OArf3>X+dR{Zch)Z&wA4PmLjkz$ubs`*lY3(3iULpt{sXSKcepA5EsLKbZRj*s3c^0cA^?O#&`2jW&usiCb924*@!^3bG;t$t z`0gTP_U^r8>cwU^{SplQbBBjMn*)dYWgv&m^1Om3xmfp~F@c3aZOQ5S{N!=yX(p+r z#OCPUqqX+0ZR=BHIp9A}eU-Fb^wS%x{_YaFpW?R!&}E&(e;#>Kx(G#de^5tpei|yTS9mH}3&2szI?I2_t}#ugc@#~SOs7LklI(bpq)=s&K2V;z4G8BL!(R}f zTe^oMCGm!tuETT^gmOyN7MR+15eZSu@3HgvZGoB5UN2c#B14ef3uv9JCtJ?`PgK)G zK^`ycdz1HTL<~PNpJJ`0k6p3kujBTfq^Te>**=WtR_iV9h=^XySiXn|&aPXe5NJeZ z&D02>9ItW2z;H_5QZRhV-gtr6XaC+_FH<-vX6Pkq^%lRr^ZOZIX%(g`$;oNZ zv(zled1_X~Lgt5C(Bgd(;5A9^*?{**uu_2v;jvwOZFMu1(+!r*bh!bvds`fM8X`ie z^VTxO9;Z~HlD2pd>E|sXEF2nVX02tX`!VO+RJoVGe)`;+I89jGU$sCwFnrxRC^OJj zV9QHjttN`T5yS)R;(~leh8%G3Ox1NzreK)OzB%*0{#zeWWLyo`x%B6; zH%K5SZL9mp*y3O;lu-#5q13Z|d1{cenqnBs(Y1md%s-T481{$F6S#}(U(Ue`8tIt; z7Eeb<0)j=%)5tC?8MbC0rh=TzwtB=njwUBQFi<(_g z5v`DQ(yb%qbgh`+b3t1Ck z4d4D)vih{h+c98Jh|!QK>a~7560{iF%Vz~T_0lo%pMqS?>AIB1Tj3) zbOI9`LOl#daZS~XgN=1AjGZ_Hp&D-wgz(lCT>9{8?!UYQ#vq9jGL)$+y7^c%UDvlt zI%2(t>!JlcVoLl5Ag10T3XQBoR%ZEhM_435-$1dAS*E!_?f1Vb`+-6j<9_OOK+q>R zJR7{+I2Z^Ba8BfdhAmF{>#e1keOcxWamgX4j_(r^7wHW*Y|7x_?o%Q1JfK5M57YCN zKjkIP`yU>K?8UzjC_UhxwW07oZvJ~%(eF?)X`#F z^hBapfI}=MO@N2o^q_>76Gil>^#q|5J@PsbdKap%D4;{2I96(2BoOm?y}EUeU?E60 zMCp0-TWZx?vf$<#O)n>c$&!zUruIB}AjQl$<$c-TPa=N9-o`C;FW(0=TQ6d1g*;wlW7tzBEemKXB68?HjG#=>u zY0^JlgxH@o^vPtI=%`s-TC(gNYElY%DoeN~DBK+ev8iL}%_%Q}+{YyXn#6oCy(q_L z7d=_O-@+k>ygXiisb+I#ZHXYi{tw1+kU}%iBAnDIYTl^l5z3>%} zpwBSad;|IRAd9|`nQ3#t=_#||As|7u1*s`x=uxLb%_df87<3d5MTcWh5Ti|ILRH*{keA(*E{tMyS zy6Mu>!Ehji!gFl>FKa4~40}CMM&F~uR%^Ap>e=ZY{&=Oks->{_gi;X*rm8L&LuEUZ zEP94YkEYFtU&mF@nS-Y)6*6H|+o)0zD{^Qr#Cj2iZpNpj&vjHHl}Pjjk}8oJwvFeF*u1WB@G!m#&Sd1@BK zfgI?x=h8gniqD8sol@grWP1-h^sah+K- zUgp2!7y~cK+VK-pfF_$>T3_awZG z8NxK5++fbk_lo+MS}-zpwv)cuT9}$jb*=Mp4=8fW1r0UwhF@#gOkFipj)4Yp`UOn| zchRWxi1P$!(~n@8?qBmRzqfCuf&l-v*8Z3P_WHkB4Md3N^OOB3P3qJv-!#Ma zYV>f$q{u6SfnrAyLG^D&M7I7|P_RahRjAfAOjH@XOdm(eFZqNBa~_lk&_;$vX2xN_ zCWwc-s6}WHv1y7v98m^de9>qh0jH5&-IyISc8?^GidA${g|YfaAOolo4EX3N0hp1v ziS8_~%`+eS{uOyLwg7Sc8)(l~{5P6WuYc#BUs4H+p&zsoswobUlg>mr4*xi6hCFZp zHW%j}CPrXO?$-IcBQY)-5o-*D9imr(pW;o9Y8HWSk<*GF$ZTl-{njdXr`fR`*CA_6 zt0??ESW{RE91iRX=ny-*NX%R#swfBhjOBNX&vS(K1>f*&T-nfBq5W+kP7B~->f*Hs zJ3o>U&kf%XRriH14w=H8IBmNOdFPsp*HTUIQahh<=ip$*H5k+ zJjJvbt_N(FTBoM?+a~5yoN_J!4}8}&&Qm&L!`g_CnUkfZwXP?$W~O6^XbayKON=R* zg7H4@o50T3pg-mE45Gj(zIc?=Pm~P#npvs}hZYPut_Ko7sUCu*4^8OZa-f~0jptr8 zhxFOEw67GYXTwWfO%(*jC zQ6{Rx!L#lM-_R5hJ&X9Bga&F>httTq>F#NcoD6_~$=O|iz|MO@*-=>Lyw@rwgW1=L zF}6v~t=HTd68?h5YcHjkgI|LbrwKdnek1=Ka(sMr3PNSkHMAKDq$zvf1Mw`Wa(ciy zDMGu5<X*eQ;v)|YS$y;3y!aaf#J0I)bVC4 z`ewse=`k{~IQR|eSS#k>C5w(sH1KV4G$~HbwtkP=o#;5NF8#XuP`PMbP8uMYYDd7D zJII{DLfok!mHCTCN&P`lgmwrnZnyRR0K4GOj7Ii*3dTa?t_!q|V}JMKKwV(n3v*ff zg1-vwr3GH1)U|IL5{D`K_=6P;+fLObd;#y|$dw)}?3ppJ6ha*mrtZZ7r~RB}L! zSvT*3-#K2ALH-%a(S&?RkfL}tXzF$ONskQoM<8+#W`0ZqbHN*mZl zoI_JFSt({ZZ3EgY1FmF6+N>t9N7g)>7)72eR6y5KVBtKi?qp$=bJx$5oTBi}+FHYD z8-V|htDp>y(hbCTCw==5Nu)BNU+~V(&%{hqt2bN@i%Iub+fBM!9F{-RDX=A+5I!V~ z7%}CrVF$oN;8+SP#<^di69PrO&i`ln_rg0Tyy%SeGrAjs7@5av6Xq_Fok6tJ%4%sK zznEdBP+6e7RfK3bV2qu>L*Lsj*$u=hW{zvEx7R)Qm6TOI7A1XDY*e!b1Wlk4m@;?{ zEXi2(sQQFHvc+M%*lq44#g#boVyn%tkywc}>aQ`B&(RxbEQ=%a-6siB>{t>^k+OVdsJYvmWy5c$B^Io@4|3FD& zF4zX(_OtzU_yCIi1A5!r|5)0056bgwImc2F*~t|?~m%;h6U`tS&agJaTz3^IEk|09pD%3^mn+avLY zUrX3}+LS#6#pSa^Ck5nmK<3{aE4C>N&YEF7)p#?Q@3F*q!$Dldcr%szDIt#9c2`1X zdPit6LTk&P0k$^(6mL3f*yP7zcjrmuT9$vmG!hu(^ZFJ&@Kvdu8&fd2_C`#IK0NRR zZhiV9?zM96g0_2OtxkocV+_{!tk72>ER@ck1!{`&TB}&Pcbm`u^~7A?QBuo~sWdS3 zh!EOt?Eo#>cy>1ge7Hm98Rqic`xv#+BLD6oXwSR`FAs;mNdILNYo3KOYB^IL9#r1; z<_$c5Ae7@^<`@HWiQ28519`(nx+QV7U4I!i7tmSj%~1UH8DXQl#cLIuIGwNxHSuox zduT@H`QuC9@t0V4=syo;(hTik8-Ow4my0{5Nt@O%>=pZ|FNn^{;s!|3NZ83gyc8W( zgVnJ#b=u9Om_3!cu+VRYj6D>toYN7{0mAo{DAsWdcpltHK8*F=s6=#0=I?#C!b_Po}p; zD?x(H2)*9K&>!#`(KV8DBc<8D(HbtZwjnr=*#X$Qeh@^5-@G{Pk}eWy3?wVFO6~a@ zN`asf#1jw_z)*NkCo8m+dV~tI&P`78yEGOmes$~;79BcK0&9?`ihjrED+6!6fBq2W zX*l$EDc(k;w2Z1e^HZIutT<>VB?Y5^-h;w}p3eX#uq=(ool;HzRlEfiRM8|YhvUgZ z#(&<;Nd9x;ho7$|R+0zdD3YW~5}_NX>Q&BOKJb25V5=t~bl&7rAyZ4Zzhy^^4kotG z?Zp-qbxHAb1VNcQHLR?0)%v;Ec30!Oyr9PN4wr*b2GsK%o`q4kxSnX`oU1N z8na1ZM3In&>*y7FLEb173k8F&E771mtHKM1rzH~YX zqRq8*MO47@Or`j9hixm1{J`jUAEq&~YVom}A!8OIXHF94@nc$FsZ_G%! zlU^rpKgdk*=C(--U<}l|K7K#=_0WLd)>gV#KRKU%dcT2;haB-yj!LC+-GpKq2*}H( z@G5K^y58TvY-L}!ZeAk_#F%NRkCFbne6;IZ{CxzSflL}W zhF#4|`^F;^+ijgzW#whj?5$w0_BNm z5fWqM4+>HcT4AXt9^rN(%EIsKCx#0_H+^KIv$RU=I z>I?VgTG0?+%i*RI>^ad*xDdS7d`uxBk@cpaO8dnw8&Qx$U)SzmPg1Y&(NuCVz&FJL z6j`2!ed7m~?(lEGh3^>XMO%L^(Rc~Bx?s-48$MeCu>z}s$L6*0+uj zJnu`}Zr76Vp!>VGXvk2hdV&X*!m0~Gstd@4R5_elF@W47%Y*GKYz4>IC92{(&{ea| z)4S>Q%foA4FV~bOJoGO-&wUf-d{$4GGlJA0S4Yv$uVeS|ovbn;j}8xT>Ey1Au22?* zkffPe$|gW2uEWN;X;dy{+m-E4BdpNupZ(U*lYugc1cF^(&wmqfIn9=d%@^V=N=v&y zB*k(_<0RAz|0+13*xw#DdVI90yizNhh&IE;XnLPT(Sm}>Y%cAPGQ>DY9srfc63E^E zS`R@z1pP3^qH&e_7DBD&Q_*D&rg7ifH}1=^Q~VfRH6TOfH#wiLRsDE1mKr#Lp;Y$&`<8 zgvlirhO|4}%-)k2Yln;+UPUoZi33cHU5lQU@J!-4TB46j6%9LPMSLBjs|S+NJF? zv>**750;5hQ0@{o%OW;_DuzzedwW|>^f;kxktT&~zpamzY^nrMtbO~|kU`3DahwKd z#UMpX7UU`=l}$N@JEYuGBjl9y1@^=Sb>J0}#-hJM)a6K7b$(gnf_)nz znspHsJQcL>IZBmef`4tXERHobX1m}GMJM0~JEyh5!u*!t zCPObsXNGo4I9y=vX5S5Q~2u`vA{kcg!B3$`r(Hr(iX8z z00%9xrPZa#wNHeGC+CTYfkk3ZbMOXdS{O|(W>%)?E4iqDinBMH)(D7JtG>wBmXK&S z=E91u@;7oW&Xg|c%$gHRza&VpQ%NR_`KB{HONsyYNJMC%S_6P<{v zpPFsh{$&m)9IA>9pHM8(+wk2}!pUBZW#r(F{JiTze5dJL6F10eA35_I?X+h--Mym- zbXF+oP3MJkGDZQ<#ghXMKo`&3R(ttxt%)zuT zmuRHl*a07R-Wl@5Hf>>e;yKYi*>Njn_G`9T{yM*}pp9pOe2lzBEOVl{zh9L@+OgY` zcK-Gft9N7%KO^ntDyRdGXvewz#zaP~2)<$)p02&W$ccNhh%g@du-{%yLVzaXEAQ0b zP=m$d(g|OApkwA<;=1wE>(LfWLHtx+!KRC^p9P~bUQ2nkUpPXcjGh~(z)lxST=5YP zDPWLIi|JCAM$vVhOnjX?cu9vV;61hXWR*;tqL3;ns{Xo_XC;a(jN@QDRjZdbtBJZ* zut2k$gRMCWFhfW4pqD=$jSbNwMEN;mjU}?0sAZRV|251Jt7$@>EOv2{CaJ(nbs7Gk z*N0Or`vO2MQng|!+c!j{QzWaelX}1NZ>yar`g@pCbL&%5kwBo^ngYJaK~jg6X2m}R znvUBb-g-0s-Qv)iJpdxL>ISQs?k2GHqnp5ypP$&q^Z$M5c%$v|$G#V@rS<0Miv~J- ztJ}d;jKlV7NP9>W8rjs2pcoSoDMyFGnSz8R>@?dk=jrZM1o=d@u(!otJAHa=!#76* zdc`;Mv6H6e(!6?-eLLBOiTd$^;2U;A3Rc z#snA^q9D*kryr0VlG;YV2Z7;ny&HINJ$gpu&+1#y*9MHif^B9*9fZ&0uU{dgT*VvO zj9Lpstp#xS+*%{p0c~Bo@p*0^+RL2Tt8dFX7*Nq=AH!#l=&=k(odYo^sUE4ZdZ?Pa zG$X@kkcGP3KzAa<9|FT0G7x~d8NQv{OYO?Y9}1D#Lz|z*&xA0Nt{fctP<7s~ku^YY z^z&=Y*}!O#g+)Fbk(DTVIMC8zT+T)>Ut@RV{vbo0YqM0Jzch*q`iPc57|KXwKNaDr zZsJ_H9&wurKj^H^A}z)2TWG-%!NAo4#Jc$pQ8-+4Tya!&(>@19Y{i zlTZiD!32x=5E%?kTx!v5Hy3(;DAP`&YzQpA4F2YRKzOyfuz2&d53Ru&Yy12ru}kO~ zV7}|G=)UXq*}ZwnyyAcLr_Z3zTHqj@+U}3mo^gotSvULb0~Sjg008*t6B=LZ^)m&c zFcnes+J#Yw2QRaXUwSBofoVHEWI zj+h^^HfgDC?xG((Uoes8b`D^bvLWS2;ujoW8f~2FVOR@H=Y|B+`sk0vQx@)ir5_x z_ng4}lzYKb;l5|l{vCKRcA|Fbc6jeno2r?sglUnw5y+*rHxrf==HobP)1i8e-&NHL zjP)i5Gy-fxH*cU2g3cL};2lqXi-zSEt`Smdd$VQ}pD7|^84vNHkB%12iL%iry@dY4 zWA+!zm0n9_$}omEoP_HekMAp={9)Sat?haV5eDQvw}BpBcdop&tSz!6NZ~*ZSp4@& zuYT(TX4x3JA{Liqu7j@$vmCp26U&46{p{iIQ%#;0xj6Q|VM~?3@51AB_bKGP#6ji} zAw!yP&QU^-*i-3y%2mJCDqX0Al6PL-%mB_r97Q_l%V_0v^?ou23V=3ekXO{!C!A%? zLZ`Mh)lf*=)x$H6jNPPw71P#*D7!qL!GFOWe|RT9aK|6y$$wphKcDPe>=@mDh$oC3 zEKH7!&SowSZq6oV2CmLVCN^fyjQ>mX@gL(G-WB;2L?ECrMIa!i|94||6H|j9kN?vd zgUPn8m&?)*RAuWMEry55{Q`_qagzd`)&3x`qN5)E(HIcj9M5*<=tfpbzuR;3+oLC0 zoz{+sJdcHbz3b+)r)_O%GJ#`UsJT0;XG%=EQ$FDet`#!pc1^xu8Y30Y$LKi-PfY7< z^A~2Aj_KJ)Xc8q^IdoiIW!DM??kypcC$!e+f|)HO82_w^v=qwBk_}I}&k@CBq)9~o ziMJGv52luMR0ax@6N%(U;gZG-2w={b7a}xg-YG^B7$#>NT+V zBFKV;x@F`IDqj+svT(FVUJn<5N0?yIhZJ~W`6C3Ct2jEd6%If0<;;ph)F(uwJoH*~u=IZRjaU>{hev)mmy! zL1S49a!T>cAeNa+1#=k#!K25D2+;iHx4*QT-%a{)ROf!V@w`+4`np89#ly4fHzwfE zy_ZI&4RH0}+E>n^Lwo!}$S|fFF7qZ{M8opUN=a7B+|fzoqyFme zmC(9UTmXWzQ5}nbTurdBV7)xEt6sUN&-CkJ)daCa>K7gGJQ&~2Ht>knr95TK*N!Lw z-J@fIn5wX>MdzfMo656LsPe>^*B^US9U=o*)!^o-YfFgqkc^hlEVA}+t=F<#Pj1X^ zt?EOrYppYH2oACguYP*hxP*@DJPa&D{h4~>f98X3fh|)*f#~V$d@zL95%IW&))1qwRrE7 z3lU?w&Z=uN?#E4CW)cDQMc}(eZ6uJOW@|U(E!vlj@+-E|m_H755s1_qj#;vB} zVmiW>^{DY#_<0rT!~!)hsP<*!$%#X8qsm|mqDXoQ6F&&Kx^=J6ZIQp((p4%oh-=tD z(!zZM&o^iR@c|iUt6K;b?CC?%;my?SyK-kwE0P~z@$mfyRi@!c;}x~}0Ly&lx5&2y zk5V{q>|!;1K&e8$H78D}qDXs*oxn6dvTlS*N!QYr`KgkGQrUZZ_S<8BP%+I&&KQN0 zTCwymK4iTfD{6>9MO{L|3jn~jJ>~1MHQ(7<&k)C|EBs*R(!nQ zDriZnmM1JXHt6)L;51lNjd&PkNdOe&nB_na@~cU6ACTM1DVv*s0}UCTTpjp4O?B2! zx|PM`p6vH@U*7r~FQ?*!4|rdN;b7>Z&#WD8g1^m9;+Y*H_6!>`WBNC^@krYXSJ=y~ z)tnVhno4nG{ev(#Vse|(Yc|r1Er-Fep0uF&Wva_ayLzzab1o|(5<;r?EnAUS0wcU) zg717#;D)m&q@Xdb)EXO&Fz6=BI#wj5tgO6P#M3nXCJ)|Urjaj_H5|{;Rs<=@Zjw@*i@1g~(V(n!s3lS_EbZdY{0y%=x7-pIWJ5H&-qd2l{PZjD2-XU| zg5}8eKAvd}D%r0o4*&&zEtF9u7{LyIP3du0-C1U#h3TR`@@=Uu}l7 zzioa;km}p5Oy8b7sjqPR8f)OUssHNr-a>zE%?VbZZSY@CZM)eET&*3ld`WR<9?5+@ zXb~HMZbE5M%2Ur`&Iz?SrXjH@mAb)^8JKK@BXQ7R$!OV7sAI1BkU8oocACtH8rNR* zw13m^=kR$>H6-1#Ilx?KYJ1OKH0;pemB@`n*ud*g@6#KF2jZQE`FQ6)5B?@_pKL<- zpqQfuy%GfPpDndb{5t^j@@^j*bYpB#5NMrSYMxS1lhJpeh5`HQc4*-)$3#?c9nLvZ z-Mo3{q$L5}Jj6{llxV_X4;Eie5|&#OH}CRfK(8c@?@K(m@cq0jtE1e#kT4A{@a%mYKAtA-ZkqBcTBO)k$*eEa%a0UApo*(#k0O_ zTfbA}1wk89W^PQv;OyYdL9DHkSy&kwL;Ifqt>Kh9_;OZa+bfdvSgm!IXWkF3TzDYR zp<#CJ!*?3Ca$>|`xFrJQCEr!UjwP4#oNUA0H3=<2HkHVED#Gx{@wJsGcH50KNog@j zwuhRynGIO6HZT}B^)Q2EzGW_5T)-<@mC>QOlFcqSd69UW?A>oLwUPyog$Ll}mc zo?s$iS*1D+avP01HVDb zyMD4ZtaX>+-}A19wu|kUFuXF;M|N*S&W^*99+|RHN3w4#2zBu&QQKSUznSJmr-xv zWOfouO|N3dYs@zZRLeue`y=mhS@gDFkqOC}vkC*H{mRFkGy96=_ zHpGrr+U$>cKONcgL$4%pV;ye|IfONm|2m^V+RZk$Cd09z6zsHDl^uN+jA?i}%aPAnh@B86GYWc5qT$X}GC|gE` zv_)j4W|T6+4xuB!{d#PvGwW=R7azWs<(MrC@2eHyZLOP&i+kRi)P!a&YO)$CxaQY^ z{)lXR_~GHg{(FZ)!;bz=+WxAf2eF8;=D?~waNvv@dTU9d{Ut~GeZC;Z7&_0{!F7jc z1d!ONyW{A`xx$vr8bL`gnIPklZ~bc%X@QKoUW6wZ=r)#xsp?@(_Visc@+u)TS(epL z6@s)PMLO?SErU=wdD${+_(hCg*(hL$F8-!n>7GUM`E~;rWa#Lq3v%oyYpY^tKlK3% zD^PESGUprD45qE*j-xYlWRJ5K?>#ige)$6N?^RIKahXkc$7n^~Ox?v~ko0%kl8nS; z-pZy%Sw4^J^Lkq-o9PnX^*_Nf7DY*Hgj!w*&1n3d%3hbrMMM=o#1a^XJn`x&2>9wO z^Rk1Di7Mkr^#0?<$+i9q{*Rl3ZAQGF){k=SpymxoA0SvLctBJohC%w{i_v+A(*W6;YjC^y)$vCN>|MBPt@2+UazshFl zY|*R<0|H%kq?|OpBr^85&b00d@>2%mh6LPalhK5DD7+VP%G?`|EjS-h0~MU%7)~J; zE8h{KRXe*~Ij^Y;zuuo~FwYtk14Y{0#fBRlr~jdU((!?(2DelRP) z@>mLy=@{=ov|+`fHoE|Q5P11)|DaUNHVe8{5SNBfGQ7p=wlp;s3&It?~V0X<3V@4vL07T_Xb*p^V*YE z417p*WGx;`TK)rAIN1GH80{A$*buCWR=b|!X%9G1AUMKj0a+$IIl+o1Wz5}yoN!v8 z)h}90bem#wc=8_WsS``zcXQ7g?|ljA<5+J>BswrD#|cUZI4Aco(N^TQ2Ft>QpMqiM^aJ$=O4EGPT0#Z09)MI&zr58Ouw<=hZTJJ>e_!Ccn#%ie{jiB)A^(3Z z@GZks1O9_5{?g$eIr@}{5*{F|FqWm!C`_W&oIJ-)nOV#m40n&&q9*j0=CZ<7Go4N z3G$9BRtn+POC^HUJol~jf@qcnkf3=P`#ZQ>ndd@hAlX&l$-ROjaPz7v3UL5dRzr#L4Qt*T?fj;;;$#hN>@Srq(1Ioz!W6)XEk|x2 zp!anenujmmLP(k+p+sA2PfOmQNh_5#2WXg!$mxXHFkT^0jeMOUew|@hs`3fIbWebJ zmmuk4br~IbREThd-U09uDD*)MgDu6R_KJ$gSN^aC3l5oSU*R~c5=@Cg%LZ=0YV1Vn zwdOIy_DopfxbtCz*}tSYl5MrGfn+0rpse;jaZ)9L_V1R87v3{4oX8j3s);rB<5b;dd}PW|~# zT5>rMkQJbwg>P7K6F!N8*M4U(MtMm;WNvo4>i6~X4&eJX9c#txO^)4$%XWJoHXCrY zXdAg=y9P?O?yE`811w)tbdB?(*}rNF2woOMZp?V!6E1(vq@DJh{6^idiCG z#&qqY91hiO`xjN$x~z=uT&tLvoh>4^`e%=s1iftC7!JLljOrVlE#n-y)xlZ6{Lc~2 z#m6yl%a{?p*t9y>ywObNUbx8Dzjb>kr`n{fnMv&?G1loT`v?rIj8II?^@717I6KW; z>C({7ymuo7ywajzBx+LnQ8s6y=f+ za_T^Ufc$?D;eh|o`)meAj#dnoaVl~yn@mW283qkYx+vkvsRZ8R6J?1^azV`HS-Ajl z?Xm3fWYP(W&yQNX-a(+haD>J$J!4xHPj0yH<+@sLxjyYj8uMLm-Vb5?-uRL~2&iAx z99Y@XG0QR~T}ag6@PC5DB3i{4?1XakMH3OEZSw83f$&*lpk__|v$VUz(tZV2WLpYz zI~*6^LoJF_jkGihoup(Uhz+>0S}*2>Nj2)hYuOp*xcJmt$^5k!ys}aP0B&}kxuS;Q&Z=H3m-F8 zt5QlLVG&47e3|A80{nx=sNzeU?p|51sEVpXN-PA^=1jT6NCSZA6s3S~q#qgo*wTdUJa{HCgc1rTruOQQJu=w4Doq=~ zXQvx6D?JnFv&EwelhLjZhYALwd5YH`!g{j!_dW>bm~vA0Ic-d^RGfdXGK1OG(nP+s z9fp52uTBaOtAr~RZCAvj>rJP(FezFdGtdG?_&R=D0a^A1coe>`f?65W+3UD&vPd_H zPF3BroZep*|vdWV|C0LF9;6VI4a~{d6ujMnmNv%UnX{J2DVij{+lbg-?hw`EN zo~*F{KsNx_R-HO62DNhLOVZ`>xzwav*Q6EYGBk3qJ-L#)z;8s)Pwutd*M67#q6&yu zRi%hYdA&K3qGh+yGyXHoY!sznX{#gd5VVk52~yVV4lkDW@D|8p`WoS2u7y@E@C!%; z33u9_E8AQ30kUU$(ah;dnl>Rvy$e1!?qrzNJ+V!dUeJb-hpAl* zZNT7Jq(5<-lyn9qzvJ{MSPe68#(8w&)V=DitaQxJ!V@^B|+XCJj7hvP#u!aLE=uIUtpti;bLVMaYtOQfxeNxM4nroF zxkP1{NpG+JIbKxR;;LGk67+rg7R0$TuD;kX|ykCNq zdLbz762t<)*qUV-vG5hHuAZB7=X2yB0%mN&A}4Hv65J-aGw9=YB=!H0T9o53t*ZG< zuD?t=o3^(8_EaYP0Ugu)Q~>=wJ3C9+*PMr)Py(9K(=b6sjw--F!w08&4V$=Tj+Ish zaVe!KR85}fNDr$h2QAq@;{(a`zEj~nL?OHC(WMe0U|-hV?6 zBk6gEo^Q)i^{_@strk#;DuL-@f(SW*nunms;KAKX2e?q10+-sADj7zrys#j*5}v%b zN3stXFr5Cb%!uyFq|V=%eGw{p2)zje8%U3Se50u;S47csK(I^JhGqf2hCnE>MHgDDMF z2(1sO5jp#GTD-iCe*%E96vE3Z1Y)CaOa9bUBl`_X&B`28Pzol}!8TCgD7=GV4u+r8U1c3Zn`+qP}n zwr$(CJ?B16#EprmSW$25A7o`(Z~1^yRPm)z4j9YY`hQR)~NC@8pZKwTyphZ|iEurLvvE=a|sF;a0`n|0ho#x#!%)P2BQP zsIs=6WC=MOu>i<-HZwY9axL6LFm}HZ6BFAFCS|kVAv>vlj!zyrf7Fy#Q{QtXTh=~=63eR{E-BfUPzVw6 zBauJ%Z*NXlwoEgBD3Rr0&{VD$F04I;7kvuNFEpm+z>837iCYyPXNsl(m@sgkR;g78 z6OzR2Q!s^K251x#8>|+;6?3F_u$J|s&m|9k+s&g(Z6$mO%9;D`H+O`i{8nr+3VY7tjJgD89*V-FGav(wsLuPA49a? zf3PdrCJ1>Ny|*rIJ(fK!;Zai`Cu=o6i{`7Zc|DyS^QGAbC5#1FgsfmMB7t&|fDreh z6_yB^NeKh$O*gKMgUe ze7Ny>DylyG%Q-WQC1D`~P$uHay&1|54rYzCD8w31zBoE;2j(de<(mD3htd3B#@Kui znFb|Z7`#7H+>JvZ*niDbr>&Y$<8ZQ=n3jv zw0M|JYgi<);Axg$$ zA_qSQ<5&vSA&?YwFenvr30L9^J+o$7qbo{6#gO|d=B)jvZ{s%#*gd8j+4m*pl6=2f zu4Dvk%NT@T*~tjJo2Xw3QFGzPh-rn2DUPA|1br!Z!SH>LqbW`*S=f|-CYSB_eb}MB zc|kmv{-Y!Sno^hHV=vq?A+|~^POB@vPgt=9-FN&EUXFiY5-$bfE^1|KW6f3kix{>ja4y~?s!TD5@Q!QBauExVrG~dxh%woV6i0}0 z$&KlfNS$E35Rs_DZMVt5g+17)PXOhS)8ub4L|#)(`zqLl#jk46*Pu5Il#ZvP9zn+< z)bxo`{I*z*<5gI^BK_`?{xazOo!QYOQNA%>7fgnie{CC8kxu0AWDGX53&VrbTN>3x zekO)`qN(uErG`L{>ELBfXjZYCDl;Kqswbor-e5}@7BSqBRpJU7W~!2TnA~|jl085gw@ePT~=2qx(_tz*V&7el@*>fx_6 zy#eG|=i+Cgf$}Ck$}Cvn|ELplRVng>JRA`A^xomw^3&md#%#l`qQm|GRX8z`<}@sS zg;$pLq10Rq$3fP#YekUdrcbA>PiaB91o+m&lOhgc#Imc+@CUdUKuU`xRMCPSr0dhr zY}H#$&{2<`GzR;GW}#YJC8Lc%CnO_M57|l~V)96`e-}@#{?bTu^AA!!bLE7uAf{YGeh@dHTMIJa zp7LwV51sPgM6Uqy!zG>NcVk$~BSlTIZYV^iRO>y};5oLssWp5~Qz3Qyf(IbMF z41cS@^#(4Ip^~QK93erUgx6euydcH=Fda1rIDU?S>YU>xVQ5IDyOrLkmU2~m8j^3^ z&3?9=13I}f+h-CK&kVxCvA4SC=uk!dCCo$oYc(dkV1-=u8M?WpEGo>{l#)_Txk8FV zLx(;AQWNph-PGac)tpinm#*=r&{62*ktyqXw2Qfi<6N1ryj#0M!XL1e7~>w7Z#|8) ztOVfwXnO546$V=PlB-bm8J&+hVd=eS(gSV~BB?5WGWk^3kiQ(?-e)SfIf85^_%@u~ zCM3|2c8~0}$^}tfm6fOfxUv5g6hxXXm!r7{350!-Qp4Ds)l%D7Jj~nisfAbg8E8Q5 z@!MzcLR>F}kaoAs1*I9+76m<6EcH?TPT6Hy1DK(domthssUS zU7L{qd#}%8TdSFN_j6@@SO2o3Ny+tGIi%;Vqd1WAepq|BtEt2~@V)pjeRv3sta*%3 zr%546lYvBHMz!On_i}a4cBC-*UGEnZ!cwiqGb>CuRo$wbQkA=ECIopu1|T?2nM_sL z9sZ~CD*Q+6IJsxyh{pQVv{fboxjbbYzjtC2>JJu1r#?Z* zJ&|H%fR_OiD@*vF;wdgUZ)JCf3L6CASQIu}KA882Pns2*W_$6Aw=^bxi3k9ZBde1GOt!ZMl(K4wkt5y!F*QJwfYNH;dfVm3URJUCp0 z>4Z+IGq|2}j96P0Tbru5%>F+zOTlLiI9`wsV#2IN#^`qpvgnQK zfap!Fc`DKj;wsR&lv0&h`&{?loC(wP`bmnxdOp35O75JhINy=d>EOC&Fx9E7f2QVX z!Ux8}xw4&R$zH6UG6yz|MG$bfm*dT&cS7gdM>6SJ8c1JQCf9z#+s>=oxiZLpo~*#jS^b;PvVr!XSne z?$9bB$d{50Jm=sV}etxUfYIR!^ZH)te93WrlZBpW6As@JJ$imm|^6 z3WSAU{MTE@&Qu0nqvD+$#C2oo-OXT+Ja{sAsH=2}JI~8bVZv+O)!mg?@v?hFo*wW5 zXH$|_`jBw>Bgo|qoNC@$dM{7Vx<{G_I&7Q0Y|BlE|d%V6PK zcauy*EpWINpQF6e=zh#t=k~-eN5|()f&BPow3|0a=yf z!s#_!xhtev`U$WI=4WHiy``Q`p#ARE4yoLWMVl($q?7)9c6B!4?OGrt*oEJV|KM_a zY1Vl=iJ3CeWoxM0A4Uh&(_U82*-jL3 zLOdGZPH5WON2*y48;vXA+&oMwq(pJ~wkaFog*Y>}Mf4CoGDx$Ao9SfB%8&cBlhV!v zS3*DR-V%ymHwBerO|kfJrvq*C-zh#um0FB;_g2A~^oo>%kO<$V60}DrX8B@vlded| z&bcp!x6@H=v$F8d1vz!=obLqlFG%FkiKBLA5NfZqRO->S8?2H#(X0B;y^Yt zW6!otZha0Wm}do51|^_lN2ycyt8Ddi#Pad#%>r-j z-T|Aqn@BuqVq(9yE7AE4J+7doG9A7fEjTKeS<1kX>T?^DI79k*RcWJ^hc>)8Y`iC@ zWoMW8i%D^|;A>hs9z?F~PbCvitrG9mTgp7QC!POPV^%mzMxq{$1_VCssDe?HFgWV; zSE|v)GwHXP=1i{8FW%N07k$fMHSml&l&|v-@sjeY*U`>U@7!Y@8JP^HruAUYCp+0w z%sLfwb^ZOY3BIcDuUxCB5vy*bz8g zQEG7(+qh`4?e6t`ay;nQOg&F5htnsO&OIG3(}KZtqDtRoX+a-ReJYsxEeB7eUR()R z{H12}q6cEj>U%+}vZ4e^xxJ^lYbyupPoL(ECuPt!OcX!nep7skLE6?=dqooWu8zIs ztw6+DTpo;4CfzNPvCxVL!d)75y6e|EKtMs>x%OT7DIyknJ~!IDWBl-IgJsqoM?S~m;T#=d1o zIG|;6f|&x+i0lS-LN_nMrvwS=dQV6GV!pZ+%<^e<@gnwFK72AqQ3)mu+x-=~O#uZ` z8EwK2U5y;U{yjKE6km`{)~-I0FRoFkS^8Slu^esYod&QzG)GC)J8K*tf3{LlOnKxh zxrhpxYjc@strlI4r6!d~F2C=q=q#&OTJx7t;V0<0k!5Ry%Nmk4&0mCQKZ?KAL47Q6di||9pYw}vz z4agEA0;c4wX>~5BQ)O9p;B_X4pvTE{!K4b}ym3^5sDOO8zt5>uyA8CiyOa`KgYCph z?%;wT{?#kRrz7$YOA!FkpW+_|)XpNRHNV^7WC>kKyA~{RsyeM(;^Wfm=6i1bIv`&4 zzS{I>y^5O6!Tuyf$a`r#hQEfrUcug}<#p!4YxNT;qG4b>@$#RP&56m@YFpW^5oF2P zFgrBX*l69!H&aP)k%q=Ia|fFN4ewV0*ct78_wYjCcr8b}W9}|x0x8VK5CuWW3m7p~ z=|C~X4ES0A+)P-%dwGD0o*;7*stfXcoA0dl24>r;Yn?7J?hl(Ic_mE1TGw>K7dbIN z;+J6bpLI%Hvjhti$TW??L=L0+Zh-u7AinJ8V2|q9kIAj{$!ueGV}zCN(-lBW^~_}X z?%rOK?Mu#{4HvpbsCo_1Kf*Zi2Cj%Q;}PQgZy zrS!!VUBq{4(C>s8Zo3aagGhBnH6RT(%ZeZLM%yHXwNST|Bc1g-zEl6gt~A7-s>kFP zqy@DcE`J6iOlD1_L?6uWR!F@n-5$1(L<$bv@f&mfTs3;>enoEXmgD3qxpH{Fh9B!X zVzfJJ>ej0{_z79};KyHap5D7MRdAE0G%dmcz-Kvu@XZuZe~0_I!+H!?Nk{(48ZNs6 z=Fs26SZojMb)YvYQJC)^LxVlzI@-iUwD=AmNyIuDo{5}XL}JAu&#VN-z( z`an9&;$0rB*IXh=x>m1S{t;qx`iB8}v`cBuaa4l0#fVCtb9j~PS9Y4$yN=tq#0=U_ zc?lBbO3l#;hnrj_({#jG3c;=DndFvRxxiR{T30|&J*2|?^c1vqv8+D}=53$yL=_tn zQSuM{N<5(FAutTzYdD+tM0o_4g~Xj_{wQrKQVo~?8azx0nWFD%nRHj~XHo4W_n)L- zibaG7{>jr31e4J~xl5vF@cDMy9$o3tGaTk2)(K@| zY-fl%lRgES-9MEo;t`1M5fY2?#GtSt8o4O@Qu6B)wkMrba!KA~5~1y2q%2*~e@ALyVjw}Ijysw@jl)v+e@leoCABz3 z^H(9ZGV*RuESuCUO?6^bS7a0G zk$M6AFQ~Ae0404H3x{gmwz{W}29N83qx{kXodbCB5K~ubCr|rXWRKwj+rapm_mGRH zGO}H}2_-B7vcIP#krh*;J=%L)nmtFT@Qh{(v`-GlgOT3z5v@re<$Z>k<>iVn3DsFP zy|Y53)7W;M5i71)XkZAr9P$Tgm)jJZEgq=W#nj2rs%~ONNaawKl`G^Qh@b1SktLc4JOBjg zNf|E$i*{GV%emhd|MFz>(^ryB-}(rd%!~KneAyh)e%20HTE1jbKUgYLe1&-5|7l2j z4}x`&nj!zS=y?hq4J9f6AofYL=UF0NXP!P!n#^#OX_w>?2?asp=$iwt0@xS+DNL1{J8P5{Ic8BFeh;vkXn6Zgt=ap z-0iK=W%d0)Zm#QIw6rzf>sF$S0555!zK{>nJ0zmCn2HdG{E01{#VCRanZzRy0C2ErK6Zeq#-AJC`ukIL&ElPn5&bZeJbTx6AG~`1HDP<8Q?L4JaV0 z(%ALVJF?J0VIKf79Qw!Hi!SecHI-oSF`a#~6N5T9tAxXP39WBA8_HpsA0r+Ld)1X* zm$$t>F8?Y$!?SK+**dS$b7fOhAw!l_mpBq{r~|z#q%CfZ*N?S{Ui%GNeMK~g0y#8T@-6NN%`&&^W-rWWfuwWC5<-c3fYcT_nX|ZR%g)M zeA4@l;^m9;O=y2Zs<-ed$8;Ni6Sj~4t*W{mBE>pGaFeR+@;hbfqu*HINO(4@?R|Cx z`bw%m)RVsAsH?@ya?h-#qGK!t5(U;bChAR}+1C@~m3PY5Q_o(`#wQ~FdIJ_gGpaiJ(YK7J<6%6UpSo0l_No!r!U{88tU{+WhWZ_8PwS z%T-cX^4he1E6NVlh;v zwpZz4eRbS^c!_rX9l%GsAytQ@irFHTtRZZ|!}HDOlfzAV%V1`nc$Rsl>~kEL$uzM( zI`q%Iu3r%htV(PA+%2O9l@yP$@k9t(Iy@)+b3vJ!i{$Iz#?>W}53ulf?q@+gNPVS? z)d50zbEk!sdkD!>QINQ@^aJVdR@&$gvM41YRNQ$j;`C#lnn;h54CywfSIQ$bhSe`y zfFrJg8=!-hMP6~#Y^PciWuP)BYtf>-K#p>^?iUOo4J#lF7k%`}G=7yLgqTkuohPjz zj3Rd{U_gfSnp%#XV`f@g&7{w@lA_N2iY@~2&_gwavETmdNU zMmVJGX1EP8SoI+aU-GJc%ZX{vL0Qf3y(gxB7LnGW1KD{0T?o$S-V;S(+XP(ymd2bg ze2TmoL$=YiCuf6_?x$yg}lN6Y-;VcWv-L6>|#wRfB8_6huYuP7~qg>B3O7Q?N|I-KP529 z=e=9>lhS&q4RDc_9r9t>!7e(B{X-9GaSl__oW;-q)r;&yQs4_ZXfJ)H$hG6^qN09R z{kmTOG$o!t50Os;uwOJG8OruSUqE-?if7(<-v%@9aeE@@u=Q*|VR}>AW}DBdUt+S1 zIMO_+5+N*|7zI0#F=UTe87c%;LKDV05?8KoY7#09vF+Slc(O$xx@70@cjTkufVsT2 zdxz0vh3AeKhE0_JuT0J|2dEycn{sNeR1#U^p%(SC9oYWEb!716`7h&NfP%`c`%sr8 zJs$quEV67k4>0Qc$Zv#nUXth2FcFbk@o6+X(JK17SOCq0M?s6J%l+Ne+EpL%UqE2m`|rxHH*L1v<3m2HT(u0k2L&7gJUc3rU%um`1ca` zZjlKn4LCS=ogd6TBXKfRgf;XaN+L#Js0AGm3IG7cW2HZ9=k&DZlTZbFi5?@=tHKsIhy-_Us6Z8W_qJEy}>=Y76HL)S!0w z((6wltgk>XFa9%8BUHS;$*4ED3TC9x$9~o_b#^30OG~wCmPkTd>e;4Sf#bfYEd|RjIIVQ7Uvuf1vw0H(!TlA-6;v%KB897) z;%Vl%SITf?*dx`g^UP=bw7V@YYBro!CG({O*S&XT*DEkj0BSF9kyk5gTMhIL3kTn- zq_y4=vS9kr3wymAS9f>!Z?{7WyR>l%mjL@w1{ zh7}%PPh#p7)_Ws~u30{x@6IgIHqKOc8j$Z>Bma*vb>jOPY}Q#PkgG?;X_T_P)XyR}x`6vt>frFz(lp+D z_Ocm$1z`TrPyy6Opl^=$9o59qN1CLr#?!v42SH%w^5{HxpuKe57<--vXvyl=Ib$b$&wEXLauJjHw#F#)M+p*S0T; z#pp-#Ubj-h4aYJMK+<`sQb0ugVA`@HKpwF;!v6wmJ>^G{cx44q@lK2KE$?G6eWh3& zzm7zKW99$nsI*=bGfF;Dw?bs{SKf;4Q9)HD`rk@8aX@wXpQ^5|WjGy_j!$5RF#SdV z6|}L5&=)w!n;FZ`7W0nXx?s8pGnb&uL&aNXzZjf}4kB2`Rt+L{g&$G;L~`52(6i#BX^8-xiWJHE5>-ip`c4n16WmvV zhYsZ38}utwc7vsY7WZE_)oUfDjh0RLZbpUdnO757^GWlK6X@4UGKJ`=?6emBae15V zz18bgj5+mPPJYDKEZWzyl71B9&@)L+6_65T|V494(CmUd0v8us6z<|iZAl; zIN@eWwQ+`&;sc!8QkD`CO*P*a?S-5@+zOU+aB4)4my|k(K=lt#?GMk;uiI>Fy{dDR zN6zNoGKoM!Dz=~@h1=v^%ODHW1k<^b@3wwqFv!>tJ@tLwzOa@oy5Pr!uS*x7pY>2nQ-2lj^uE$nu0 zzyPHRpjZGGHypT9@~MupN^W@%AmW4&)~wGouA(3x)?mmY?T}gBf=Y++{=Ei z30`FH!6}8q;p3ljT&g$v2u*N^xuHA+`poL5;Fu&bK5|bDhE!jsmewR6v}dUoWr`ph zYu4ImowR*5iTlgHuTw9B!m|c0BNS8-kTzVoe}${b$V5pP#dO{jFjhYqsIq zF;@6kSzyR@5Xe|OBZw>qiw*Y^l{x&|8da*Fq0x;dz?&O0q73Z$BO{7jY;;#EByP(5 zir$4oLX@x%KSVA3Tt|jLG7;pyx=AfnE3RU;C{@+r5uWDCdX)Ei4IU$*E#w5`uM1g% z7-X$^kq73(`lPVL4qc44#J|9R)v(33I5g4 z2`q&V5JL}Ak)@nddV9W{m0>w}^Zv`cX{5rpDYy0$^D$wnXzVJ&)2Fd}63D%}$;ey{ znP}$^BpMHmh7J!)%5X4}C#$quW zg%L+L1~7)2M#X=ZWuprW&S*USe?hZdb(rC6=aiIO#adm8&;pmPP}I?Ly12T5ZLdfA zorSxc-N40Zz1u)W=+@f%a74kPsP1eEaQE?KBW7Bx;?r|6u78=oOD9oX{$NZh=&L^$ zG{m7qt$!bEzV<+#e<@lw-^}`S7czE7%I8nLH7*uT?%N~!QiT4&k@)zYU8t$$u*M7% zh?O_E?@OpxyTqStO0CJDmPHG&kk2Fr`v-p^fp*ryf4BYG*@(A!&*k4zu|(d(^ZB#E zA2?fg&6duwRUtC%QOr>6DENUz82VcJYFQxX`igz_rU-{nCni<6Cgv(cmUHo3>kv8` zML2eXD7gou(#_KE9Qjw50)Nv~W_P=_-K|J)I@7E{FTIB?xTe~5;@;Wc-(farI8u;K zG@s?>+DyCCbO4P8tu?O!A{%7;clq}iWoe3&h-y2t;J^g*qmay7?IDqRnS#kOAmu)d zV#8&p%9cmx2bID5c6h?MhJ6dZv~(Mx_}#TW744D$Q|MS0LOab1?x>$xLFJ!7Pvje< z+j!niSK)uktwvBvsem=sxToaAr-fn@$-{a)#UHvMtVpGndLDk?L@txANTi}`_0j%l<$ z*)*)?Is1q8Y-KxiO$MXR#wF3gM20OHh7cHX6Eu>LKRWqcOTO&;FMnb)Rsc} zYok2uWu+HWAu-WfQM);i@M5^Q%$sX75>jCL>nn1(g527W$|C)~>8B@FSR;?U;X$qd z%j{5oNnodiFv_=|lUFA^YWhX_T+a}r3}<0)=(%?hH*PL}|4QMd+saTnQZ@4W%(MpK zoDamv=b5`TB30=roc4}8==faG(H@^LKLMxoKGM-Xw>E0G}!1 zPSSoxA=S}Wxuk842E&|C6ao|3jPef8pA+UqNBu2s-32C`P97A!S*hS3iM^L$wo3pQjW_8v^E>)_>8ikt#kQ zH3oVaD0>WPjG_EGlbCl;{Qp1WMW zGW7^;;^7aH&?Hi(X;-5u@?B|$jI^J@x;gj)?Z*GAQIkisybk~QfVD0OcfN)5&;0pc zXm{P1LUHhahbO~eKtLq_A4XTt+{Veo!N$Of{-3v!fo&!u(l@Wqu;llGm}-Lw0gJ35 zw0XP|0C}ONf;@7ML<5wk5uPsdW!JT&X?(>6!2Htbdb^X&hux=gtxe|=9K3i1H*zb` zCE$AbhMNFlKxF(4k1GJ$z*K*YXi6|)NZ>!T#HTEgpRk)r;LE-mkPJggHa-9;ZANT zF3BEHMUrQr8vX^)4;-NQ4+%LLZFj)k)t52@>6d%Rw{KSjOCyJK375q(`s? zm_-?})AIL*nc-&k-ovy@=l;zmo@Itxz=iYxKIkiWw5~E z|Jug0VXI!kr6UW(Yp!8b8*DBS4r7yXGLowVqrqY4Un>`-h+P@KBG5s7A1biX^bY3b zJ)?!$&qw|Czc%5+rbyl7kz6hv`2Sr-C!ox59v~R?_Nt&{5coh zDv;TEX~%A&{-b_U!lV- zCE5SClZtC^Xp+3Ci*^DeH4 zfTlq4{m)uhHpU%(v*txC*g&iq!4BaLPjahDF0D=PDsqy11IlMJs8hrPXm7p*D?o;nX;qIW~lz_N(e_lxjuM8ebqG0UaZwk)80&c`biByQxo=a(zDUc zA9u4=TfdkV!F;p%X)I_?dfeq4Ci+(n3>l!%76f}5Ih=}f7s=3L#g~(l(=y)>x95Fn zX~ylq1;^WhxMQF=LfyB7U+6oh0$Dg&501!&f(?EmQ;JS$MV1#xEAIIUT-|Z!DA*Ei zxd6nu!cc^8(^2VH-%r=yVPAh?lm9@%Fv$w|>F^IvcykFPl=aof5)_6qZ%zK$e8ak)%%FeshxoCOnn#JO)MUrsh|wouKI@~VdamQZ zU5;=sY4S91;KqD*j>e8O+Lp@k-S^v_d9CAg97@tf^q+NbTzaN`te{PiaDBjn4S;Rc``YHIS+ zbP*R@y4f4YY=M72oK4#=VscN5~`;M_~GSi(auE=3ND!p%ne+1Ha9$08<46l1_ zUo)w;G*ls$iu}wztfQg zL$)USwzQfp6|^n(F;9>{dy|vl((W-VqFDht!4?cNGyif!ED^FwQX3O!5s>?dwooTc zKsU>(AE3=?6P4@HeE@kkT80G?PTP2tcm5;N6i#fP0F<6_!yBLawl1fVn_;)3wE9FE zVJ;``RYwfGZBe))3!8F1@K< zxPD%Fa)+*z;^)OlGyEYW0}QAEnV@Glil^24(%yTLvP#$=PeO+v`v}&mL|AW=MrAQ?HP34|wozO<#;vS)O zAW(=ghg@-$uW_ShPKi*%71mCFj;P);@v}|VL2f3h9e8b{#u0c|u+bSHbxDnPmG(sA z!_`(D<1LBj_DKN!Vc>lF?GW${;Th##pZwyA{({8gR%GGh7U~@<1r=;mFBR(<+5M}R zwVc`GaIL}=7qjhj4)~Dli(6l}UsfWdx8Z_T(udN7_DinhHaSOKS~J z8PUAB;2_08&RkKtr5an{*I-s`S-@K|Ov*iUvQpXH>Zg;_?9s!$jhTix29L=lcIfQv z4!ON#;(@+q7@jEQL{*XcIiD3~8f#1-Dl}lK?#0Z{hmAWrW+;s-Luvg>+|e`V(6jxH zyu=sKCzAIa6eW`9dJ-#4txCGqUEa=kI(B>$1S2K^A;~4irUgaVvf6nP$GTGM(8sP0 z;$=4El8tAnIL{U7U8T77bQ%&*jf_?)CSL<$Aw``0XcMtbcgN5qheV1FDDn@%Zt2Fy z>K<=~FX`6)9g6G6yj(lvPqE6vS8b}*;ZN4oMicpEXtx~dT071+?=4!+X=E=gNQSfR z41g2MmD`&rj#wQ#$pCN-D=ANiWwddGPOItVc3!7@g{zcy75hZy&f)%`2D+0vK_n3d z-(TO{dkMgVa+_>i58nxOGNwzZ*d} z)E{Gi_Z*|V?e%Jsl&^e#XR7H`ixkbXej>~@ZR0XR1^!Ek*A;q~%sO_kjs{3LZUJzL zwE9~70e|SJ0}=iZDzR$W^#rnHc{y@6V(jGeE2zxKJ( z8W+n>8dBSeAiLH!R2GXV?aNre2ut(%r!63Vq)(cTsuL(* zc)L5YDFLX~djNJ^(gZ%2)#PJ_GpX?KE<+bUp z)7or-Ou4DCd#Gu_$?chzUPNf0R>)ax&F4KrriFrG-z;x^3V3oi+j)g*659*?;m%dk z|3rm?=95#jq8FOV%%?#VbO^)QP>A=D%FQ&204|M0YH;PPqVa>Rlp7Xb3=A~lJ#fmz z$fxFb&<14aZ0B}xxJ=?`j4~kQdZ+#s1T?%qALXhG0|-g}liACKyv^n(P`Bp=_LG>i zlcuxwQWH?)svA1>1Y}sAJJ!kH)!|v}h?~r-3lQ!Kt;kqISW2ho2IdCVp_*?ty}}DC z;UtPk+=T^c_=dB%!{9=Z^y;@i$4_@WG&^YR*_EdMCBQc9VJLoR|Y)EYBBGz2r4$nP`gp|t6gy0+m;Ny_R|g!ZcC-yiNrJI&){;NdXQSk zd6L@H2qs~qFUIAhyGn}raNaiEW7eWz`|2|j0Gq)HPcTxuK_!V4LUY`RL@Umy0oAYv z1E(@#gk0UcR40bdf%cOODm>J`ktD`v;fKlvc;rXuD@djfoOl&w=SS<^_slKO(LBvd zZ3Fa(<=uU%dJRn*Nyi)Mtg6s6ne;ohv~9dmH4R9R$KS`4zz>X4OA2^K+nCFZ<&{d} z@UKs@N&>Dpv|rz^?^Oqk90TQKQ5S1Mb?`a$=n2E-KTY5~nD8ezc8r;wdR*O+8`l-a z2?4#BzN1}zy2>hAg|x6{MRF3xRTTnktaM5oElzR`MwI(%M7qgyK%Kzx{zE-abE)9Q z1|>?mFX)5q{FFyIQU?E2SLOM~wMxUFilmQ0EFh(T{UtWoxfi~Z7m1UN*r@*~uN0CA zV~t0j?mj-*lHe18paT_pOkv%O9hLMTkj-yxa;=;E<;&R}M=1J<#5KH#q?Db%JbHA- z=67qSz0Jmve*B8d_;5}RN%{k~eUd}u{Hw*OaysYTPe0nhu;@fOW{Mqxc)P%1em0ll zhbCWv*zssy8(Z4oAc|zVBP+^zi>%?}sy4Z=G8S)Bt+L)^OY<%iKqb78irQJ{P4Z*X zP@;lV>=6OUM>~A_t{#}~$=0I*myN)dn2?=Xz``~Ojl_*$Pyd3(4h=#Q~aj*=t`VHSRvs@s1QAZ=`pE7d9wYZL)I8nnWw%}eHJEL&88 z2bTXBHf=Ln871ep8>n%p_&ZrEZy9;@u|j0amj%-s9bwSoB)}C0XzOqV%hPY?gja9R zCLDKwWEziKY#dJ>1gLVJ=v^(KuGAWi%c=)KDd@bl=)CTXs3+jk8b)ZuQGB!@Wq2p> zD+U-RtUVfOw9kNKUhWoiCOw6f+Gy+XCwBTF@)XzhL0h+r)mEyq7uk)g<2aefIGUr6 z+9dKKpC?te)#)d)PI|(MQK==;dO=|0s!gvj`S3d<=}aia!c|NlwrG* zLUTcYGwBnH89_OvN~$dB?PMU68SbtHTGXlrza`apVM(}*C|QV(R$8DP-4m&e=A5^m z#}&7yr^~V=~=gXgqmzc$ZS1`92R1)rBeEcAcPT=e}W0E@_bi z@5JNf{R5I}30V#y9{L24quUMuV3E>f-ek5)W)jhjHZLYwLn4z;BYtpQKAYBY&hk$J_g?WPM_*d$0e@&Fc#KX2C0cEkfsJ-jAw={RtBiy(Fc)kG5208Jd|Yq}0Iuy07irKjufP zsvq~at9Xfy_ufyLEl6%Gy85MhI(sB7@N2J8~s-6_W0v$AVk|X;0U*FxWig_hLDg9FjdH*!-A}%-3>s z*<4Plb94MSL8?MnVq(gC+k`Sg0xs3uT`xIjDw6&4;Hkapsja84B}>h{AUJU9Y#I-y zeM=2yV^U?c?@X9X7OM64h-8BcAxXG+nN4Zdt>C+tkl zSrB|``oDN4Y8zXOs{3TL3hdWE+RLA{H#Nnr=7dnW`|27JgmDVsxI(zX76E_$3FA^v z3{yvc#tCO~o2%~4vK)$=9;UBbcV`l}HM#sZ_`6g5UAmupnL{@)4$#M(#=F>4Wd6`s zS@f6(oA=;G8M7}#vc_IciVT@LsF5JK!+i(_FOw+-bmt<02$|e!3M_0Y|A($~3KAu1 z+w0i2&e*nX+qUhQGq!Epwr$(CZRUJQ z%ai26**4dFSxEoCLDTBoyMZIsO`}RX>pB8l?WBE}yZR|_-dJmqnf+iFGBmqUsC=+? z(O%BEWZ@t3GA@5}Q1T!tGFI$CbH&yw;gyJ|V=$TS93+-GnQ_1e4ha;$N`t}&h?Uy?#+WpNPzDSq5 zb@9OIw#XLLI%)dNEPMDdEa|;mJ+|NO(_HC)6KLurc@m-Ak|oR7ti*ZjTu@HDM>qyN zULm_(NE0lZg|R#QS6hG%?;xw95_$Y#C^DV5uJLv`lKru{?S4hq8k-{P6O4x1*y4c( zO

    j*c{vo9YW-z809g4mo`f1DVc}z_b%&QPRXn| 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 literal 0 HcmV?d00001 diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c index d9bb4b9e..ca70bc0e 100644 --- a/drivers/video/msm/external_common.c +++ b/drivers/video/msm/external_common.c @@ -244,6 +244,7 @@ struct hdmi_disp_mode_timing_type VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9), VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3), VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x1024p60_5_4) }; EXPORT_SYMBOL(hdmi_common_supported_video_mode_lut); @@ -308,6 +309,7 @@ struct hdmi_disp_mode_timing_type VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9), VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3), VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9), + HDMI_SETTINGS_1280x1024p60_5_4 }; EXPORT_SYMBOL(hdmi_mhl_supported_video_mode_lut); @@ -829,6 +831,74 @@ static ssize_t hdmi_common_rda_hdmi_primary(struct device *dev, return ret; } +static ssize_t hdmi_common_rda_audio_data_block(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int adb_size = 0; + int adb_count = 0; + ssize_t ret = 0; + char *data = buf; + + if (!external_common_state) + return 0; + + adb_count = 1; + adb_size = external_common_state->adb_size; + ret = sizeof(adb_count) + sizeof(adb_size) + adb_size; + + if (ret > PAGE_SIZE) { + DEV_DBG("%s: Insufficient buffer size\n", __func__); + return 0; + } + + /* Currently only extracting one audio data block */ + memcpy(data, &adb_count, sizeof(adb_count)); + data += sizeof(adb_count); + memcpy(data, &adb_size, sizeof(adb_size)); + data += sizeof(adb_size); + memcpy(data, external_common_state->audio_data_block, + external_common_state->adb_size); + + print_hex_dump(KERN_DEBUG, "AUDIO DATA BLOCK: ", DUMP_PREFIX_NONE, + 32, 8, buf, ret, false); + + return ret; +} + +static ssize_t hdmi_common_rda_spkr_alloc_data_block(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int sadb_size = 0; + int sadb_count = 0; + ssize_t ret = 0; + char *data = buf; + + if (!external_common_state) + return 0; + + sadb_count = 1; + sadb_size = external_common_state->sadb_size; + ret = sizeof(sadb_count) + sizeof(sadb_size) + sadb_size; + + if (ret > PAGE_SIZE) { + DEV_DBG("%s: Insufficient buffer size\n", __func__); + return 0; + } + + /* Currently only extracting one speaker allocation data block */ + memcpy(data, &sadb_count, sizeof(sadb_count)); + data += sizeof(sadb_count); + memcpy(data, &sadb_size, sizeof(sadb_size)); + data += sizeof(sadb_size); + memcpy(data, external_common_state->spkr_alloc_data_block, + external_common_state->sadb_size); + + print_hex_dump(KERN_DEBUG, "SPKR ALLOC DATA BLOCK: ", DUMP_PREFIX_NONE, + 32, 8, buf, ret, false); + + return ret; +} + static DEVICE_ATTR(video_mode, S_IRUGO | S_IWUGO, external_common_rda_video_mode, external_common_wta_video_mode); static DEVICE_ATTR(video_mode_str, S_IRUGO, external_common_rda_video_mode_str, @@ -859,6 +929,10 @@ static DEVICE_ATTR(format_3d, S_IRUGO | S_IWUGO, hdmi_3d_rda_format_3d, hdmi_3d_wta_format_3d); #endif static DEVICE_ATTR(hdmi_primary, S_IRUGO, hdmi_common_rda_hdmi_primary, NULL); +static DEVICE_ATTR(audio_data_block, S_IRUGO, hdmi_common_rda_audio_data_block, + NULL); +static DEVICE_ATTR(spkr_alloc_data_block, S_IRUGO, + hdmi_common_rda_spkr_alloc_data_block, NULL); static struct attribute *external_common_fs_attrs[] = { &dev_attr_video_mode.attr, @@ -887,6 +961,8 @@ static struct attribute *external_common_fs_attrs[] = { &dev_attr_cec_wr_frame.attr, #endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ &dev_attr_hdmi_primary.attr, + &dev_attr_audio_data_block.attr, + &dev_attr_spkr_alloc_data_block.attr, NULL, }; static struct attribute_group external_common_fs_attr_group = { @@ -1001,6 +1077,8 @@ static struct hdmi_edid_video_mode_property_type 89909, 119880, 148352, 119880, FALSE}, {HDMI_VFRMT_1280x720p120_16_9, 1280, 720, FALSE, 1650, 370, 750, 30, 90000, 120000, 148500, 120000, FALSE}, + {HDMI_VFRMT_1280x1024p60_5_4, 1280, 1024, FALSE, 1688, 408, 1066, 42, + 63981, 60020, 108000, 60000, FALSE}, /* All 1440 H Active */ {HDMI_VFRMT_1440x576i50_4_3, 1440, 576, TRUE, 1728, 288, 625, 24, @@ -1205,45 +1283,33 @@ static void hdmi_edid_extract_latency_fields(const uint8 *in_buf) static void hdmi_edid_extract_speaker_allocation_data(const uint8 *in_buf) { uint8 len; - const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, + const uint8 *sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len); - if (sad == NULL) + if (sadb == NULL) + return; + + if (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE) return; - external_common_state->speaker_allocation_block = sad[1]; - DEV_DBG("EDID: speaker allocation data SP byte = %08x %s%s%s%s%s%s%s\n", - sad[1], - (sad[1] & BIT(0)) ? "FL/FR," : "", - (sad[1] & BIT(1)) ? "LFE," : "", - (sad[1] & BIT(2)) ? "FC," : "", - (sad[1] & BIT(3)) ? "RL/RR," : "", - (sad[1] & BIT(4)) ? "RC," : "", - (sad[1] & BIT(5)) ? "FLC/FRC," : "", - (sad[1] & BIT(6)) ? "RLC/RRC," : ""); + memcpy(external_common_state->spkr_alloc_data_block, sadb + 1, len); + external_common_state->sadb_size = len; } static void hdmi_edid_extract_audio_data_blocks(const uint8 *in_buf) { uint8 len; - const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, + const uint8 *adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len); - uint32 *adb = external_common_state->audio_data_blocks; - if (sad == NULL) + if (external_common_state->audio_data_block == NULL) return; - external_common_state->audio_data_block_cnt = 0; - while (len >= 3 && external_common_state->audio_data_block_cnt < 16) { - DEV_DBG("EDID: Audio Data Block=\n", - (sad[1] & 0x7)+1, sad[1] >> 3, sad[2], sad[3]); - *adb++ = (uint32)sad[1] + ((uint32)sad[2] << 8) - + ((uint32)sad[2] << 16); - ++external_common_state->audio_data_block_cnt; - len -= 3; - sad += 3; - } + if (len > MAX_AUDIO_DATA_BLOCK_SIZE) + return; + + memcpy(external_common_state->audio_data_block, adb + 1, len); + external_common_state->adb_size = len; } static void hdmi_edid_extract_extended_data_blocks(const uint8 *in_buf) @@ -1407,30 +1473,37 @@ static void add_supported_video_format( struct hdmi_disp_mode_list_type *disp_mode_list, uint32 video_format) { - const struct hdmi_disp_mode_timing_type *timing = - hdmi_common_get_supported_mode(video_format); - boolean supported = timing != NULL; + const struct hdmi_disp_mode_timing_type *timing; + boolean supported = false; + boolean mhl_supported = true; if (video_format >= HDMI_VFRMT_MAX) return; + timing = hdmi_common_get_supported_mode(video_format); + supported = timing != NULL; DEV_DBG("EDID: format: %d [%s], %s\n", video_format, video_format_2string(video_format), supported ? "Supported" : "Not-Supported"); - if (supported) { - if (mhl_is_connected()) { - const struct hdmi_disp_mode_timing_type *mhl_timing = - hdmi_mhl_get_supported_mode(video_format); - boolean mhl_supported = mhl_timing != NULL; - DEV_DBG("EDID: format: %d [%s], %s by MHL\n", + + if (mhl_is_enabled()) { + const struct hdmi_disp_mode_timing_type *mhl_timing = + hdmi_mhl_get_supported_mode(video_format); + mhl_supported = mhl_timing != NULL; + DEV_DBG("EDID: format: %d [%s], %s by MHL\n", video_format, video_format_2string(video_format), - mhl_supported ? "Supported" : "Not-Supported"); - if (mhl_supported) - disp_mode_list->disp_mode_list[ - disp_mode_list->num_of_elements++] = video_format; - } else - disp_mode_list->disp_mode_list[ + mhl_supported ? "Supported" : "Not-Supported"); + } + + if (supported && mhl_supported) { + disp_mode_list->disp_mode_list[ disp_mode_list->num_of_elements++] = video_format; + if (video_format == external_common_state->video_resolution) { + DEV_DBG("%s: Default resolution %d [%s] supported\n", + __func__, video_format, + video_format_2string(video_format)); + external_common_state->default_res_supported = true; + } } } @@ -1500,7 +1573,8 @@ static void hdmi_edid_get_display_vsd_3d_mode(const uint8 *data_buf, struct hdmi_disp_mode_list_type *disp_mode_list, uint32 num_og_cea_blocks) { - uint8 len, offset, present_multi_3d, hdmi_vic_len, hdmi_3d_len; + uint8 len, offset, present_multi_3d, hdmi_vic_len; + int hdmi_3d_len; uint16 structure_all, structure_mask; const uint8 *vsd = num_og_cea_blocks ? hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, @@ -1624,7 +1698,7 @@ static void hdmi_edid_get_display_mode(const uint8 *data_buf, struct hdmi_disp_mode_list_type *disp_mode_list, uint32 num_og_cea_blocks) { - uint8 i = 0; + uint8 i = 0, offset = 0, std_blk = 0; uint32 video_format = HDMI_VFRMT_640x480p60_4_3; boolean has480p = FALSE; uint8 len; @@ -1755,6 +1829,66 @@ static void hdmi_edid_get_display_mode(const uint8 *data_buf, } } + + /* + * Check SD Timings if it contains 1280x1024@60Hz. + * SD Timing can be max 8 with 2 byte in size. + */ + std_blk = 0; + offset = 0; + while (std_blk < 8) { + if ((edid_blk0[0x26 + offset] == 0x81) && + (edid_blk0[0x26 + offset + 1] == 0x80)) { + add_supported_video_format(disp_mode_list, + HDMI_VFRMT_1280x1024p60_5_4); + break; + } else { + offset += 2; + } + std_blk++; + } + + /* check if the EDID revision is 4 (version 1.4) */ + if (edid_blk0[0x13] == 4) { + uint8 start = 0x36; + + i = 0; + + /* Check each of 4 - 18 bytes descriptors */ + while (i < 4) { + uint8 itrate = start; + uint32 header_1 = 0; + uint8 header_2 = 0; + + /* + * First 5 bytes are header. + * If they match 0x000000F700, it means its an + * established Timing III descriptor. + */ + header_1 = edid_blk0[itrate++]; + header_1 = header_1 << 8 | edid_blk0[itrate++]; + header_1 = header_1 << 8 | edid_blk0[itrate++]; + header_1 = header_1 << 8 | edid_blk0[itrate++]; + header_2 = edid_blk0[itrate]; + + if (header_1 == 0x000000F7 && + header_2 == 0x00) { + itrate++; /* VESA DMT Standard Version (0x0A)*/ + itrate++; /* First set of supported formats */ + itrate++; /* Second set of supported formats */ + /* BIT(1) indicates 1280x1024@60Hz */ + if (edid_blk0[itrate] & 0x02) { + add_supported_video_format( + disp_mode_list, + HDMI_VFRMT_1280x1024p60_5_4); + break; + } + } + i++; + start += 0x12; + } + } + /* mandaroty 3d format */ if (external_common_state->present_3d) { if (has60hz_mode) { @@ -1866,6 +2000,13 @@ int hdmi_common_read_edid(void) memset(&external_common_state->disp_mode_list, 0, sizeof(external_common_state->disp_mode_list)); memset(edid_buf, 0, sizeof(edid_buf)); + external_common_state->default_res_supported = false; + memset(external_common_state->audio_data_block, 0, + sizeof(external_common_state->audio_data_block)); + memset(external_common_state->spkr_alloc_data_block, 0, + sizeof(external_common_state->spkr_alloc_data_block)); + external_common_state->adb_size = 0; + external_common_state->sadb_size = 0; status = hdmi_common_read_edid_block(0, edid_buf); if (status || !check_edid_header(edid_buf)) { @@ -1977,7 +2118,7 @@ EXPORT_SYMBOL(hdmi_common_read_edid); bool hdmi_common_get_video_format_from_drv_data(struct msm_fb_data_type *mfd) { - uint32 format = HDMI_VFRMT_1920x1080p60_16_9; + uint32 format = external_common_state->video_resolution; struct fb_var_screeninfo *var = &mfd->fbi->var; bool changed = TRUE; @@ -2000,7 +2141,9 @@ bool hdmi_common_get_video_format_from_drv_data(struct msm_fb_data_type *mfd) : HDMI_VFRMT_720x576p50_16_9; break; case 1280: - if (mfd->var_frame_rate == 50000) + if (mfd->var_yres == 1024) + format = HDMI_VFRMT_1280x1024p60_5_4; + else if (mfd->var_frame_rate == 50000) format = HDMI_VFRMT_1280x720p50_16_9; else format = HDMI_VFRMT_1280x720p60_16_9; diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h index 43741541..feead43c 100644 --- a/drivers/video/msm/external_common.h +++ b/drivers/video/msm/external_common.h @@ -109,9 +109,19 @@ #define HDMI_VFRMT_1440x480i240_4_3 HDMI_VFRMT_720x480i240_4_3 #define HDMI_VFRMT_720x480i240_16_9 58 #define HDMI_VFRMT_1440x480i240_16_9 HDMI_VFRMT_720x480i240_16_9 -#define HDMI_VFRMT_MAX 59 #define HDMI_VFRMT_FORCE_32BIT 0x7FFFFFFF +/* Video Identification Codes from 65-127 are reserved for the future */ +#define HDMI_VFRMT_END 127 + +/* VESA DMT TIMINGS */ +/* DMT ID: 23h, STD code: (81h, 80h), also a part of Established Timing III */ +#define HDMI_VFRMT_1280x1024p60_5_4 (HDMI_VFRMT_END + 1) +#define DMT_VFRMT_END HDMI_VFRMT_1280x1024p60_5_4 + +#define HDMI_VFRMT_MAX (DMT_VFRMT_END + 1) + + extern int ext_resolution; struct hdmi_disp_mode_timing_type { @@ -185,6 +195,9 @@ struct hdmi_disp_mode_timing_type { #define HDMI_SETTINGS_1920x1080p30_16_9 \ {HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, FALSE, \ 1080, 4, 5, 36, FALSE, 74250, 30000, FALSE, TRUE} +#define HDMI_SETTINGS_1280x1024p60_5_4 \ + {HDMI_VFRMT_1280x1024p60_5_4, 1280, 48, 112, 248, FALSE, \ + 1024, 1, 3, 38, FALSE, 108000, 60000, FALSE, TRUE} /* A lookup table for all the supported display modes by the HDMI * hardware and driver. Use HDMI_SETUP_LUT in the module init to @@ -206,12 +219,22 @@ struct hdmi_disp_mode_list_type { }; #endif +/* + * As per the CEA-861E spec, there can be a total of 10 short audio + * descriptors with each SAD being 3 bytes long. + * Thus, the maximum length of the audio data block would be 30 bytes + */ +#define MAX_AUDIO_DATA_BLOCK_SIZE 30 +#define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3 + struct external_common_state_type { boolean hpd_state; struct kobject *uevent_kobj; uint32 video_resolution; + boolean default_res_supported; struct device *dev; struct switch_dev sdev; + struct switch_dev audio_sdev; #ifdef CONFIG_FB_MSM_HDMI_3D boolean format_3d; void (*switch_3d)(boolean on); @@ -221,9 +244,7 @@ struct external_common_state_type { boolean hpd_feature_on; boolean hdmi_sink; struct hdmi_disp_mode_list_type disp_mode_list; - uint8 speaker_allocation_block; uint16 video_latency, audio_latency; - uint8 audio_data_block_cnt; uint16 physical_address; uint32 preferred_video_format; uint8 pt_scan_info; @@ -233,7 +254,10 @@ struct external_common_state_type { uint8 spd_product_description[16]; boolean present_3d; boolean present_hdcp; - uint32 audio_data_blocks[16]; + uint8 audio_data_block[MAX_AUDIO_DATA_BLOCK_SIZE]; + int adb_size; + uint8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE]; + int sadb_size; int (*read_edid_block)(int block, uint8 *edid_buf); int (*hpd_feature)(int on); #endif diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c index c8d3ca13..476d1435 100644 --- a/drivers/video/msm/hdmi_msm.c +++ b/drivers/video/msm/hdmi_msm.c @@ -57,25 +57,40 @@ static int msm_hdmi_sample_rate = MSM_HDMI_SAMPLE_RATE_48KHZ; #define HDCP_DDC_CTRL_1 0x0124 #define HDMI_DDC_CTRL 0x020C +#define HPD_EVENT_OFFLINE 0 +#define HPD_EVENT_ONLINE 1 + +#define SWITCH_SET_HDMI_AUDIO(d, force) \ + do {\ + if (!hdmi_msm_is_dvi_mode() &&\ + ((force) ||\ + (external_common_state->audio_sdev.state != (d)))) {\ + switch_set_state(&external_common_state->audio_sdev,\ + (d));\ + DEV_INFO("%s: hdmi_audio state switched to %d\n",\ + __func__,\ + external_common_state->audio_sdev.state);\ + } \ + } while (0) + struct workqueue_struct *hdmi_work_queue; struct hdmi_msm_state_type *hdmi_msm_state; +/* Enable HDCP by default */ +static bool hdcp_feature_on = true; + DEFINE_MUTEX(hdmi_msm_state_mutex); EXPORT_SYMBOL(hdmi_msm_state_mutex); static DEFINE_MUTEX(hdcp_auth_state_mutex); static void hdmi_msm_dump_regs(const char *prefix); -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT static void hdmi_msm_hdcp_enable(void); -#else -static inline void hdmi_msm_hdcp_enable(void) {} -#endif - static void hdmi_msm_turn_on(void); static int hdmi_msm_audio_off(void); static int hdmi_msm_read_edid(void); static void hdmi_msm_hpd_off(void); +static boolean hdmi_msm_is_dvi_mode(void); #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT @@ -632,6 +647,7 @@ static void hdmi_msm_setup_video_mode_lut(void) HDMI_SETUP_LUT(1920x1080p24_16_9); HDMI_SETUP_LUT(1920x1080p25_16_9); HDMI_SETUP_LUT(1920x1080p30_16_9); + HDMI_SETUP_LUT(1280x1024p60_5_4); } #ifdef PORT_DEBUG @@ -675,7 +691,6 @@ const char *hdmi_msm_name(uint32 offset) case 0x00D8: return "ACR_48_1"; case 0x00E4: return "AUDIO_INFO0"; case 0x00E8: return "AUDIO_INFO1"; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT case 0x0110: return "HDCP_CTRL"; case 0x0114: return "HDCP_DEBUG_CTRL"; case 0x0118: return "HDCP_INT_CTRL"; @@ -690,7 +705,6 @@ const char *hdmi_msm_name(uint32 offset) case 0x014C: return "HDCP_RCVPORT_DATA5"; case 0x0150: return "HDCP_RCVPORT_DATA6"; case 0x0168: return "HDCP_RCVPORT_DATA12"; -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ case 0x01D0: return "AUDIO_CFG"; case 0x0208: return "USEC_REFTIMER"; case 0x020C: return "DDC_CTRL"; @@ -705,14 +719,10 @@ const char *hdmi_msm_name(uint32 offset) case 0x0250: return "HPD_INT_STATUS"; case 0x0254: return "HPD_INT_CTRL"; case 0x0258: return "HPD_CTRL"; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT case 0x025C: return "HDCP_ENTROPY_CTRL1"; -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ case 0x027C: return "DDC_REF"; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT case 0x0284: return "HDCP_SW_UPPER_AKSV"; case 0x0288: return "HDCP_SW_LOWER_AKSV"; -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ case 0x02B4: return "ACTIVE_H"; case 0x02B8: return "ACTIVE_V"; case 0x02BC: return "ACTIVE_V_F2"; @@ -761,130 +771,63 @@ static int hdmi_msm_audio_off(void); static int hdmi_msm_read_edid(void); static void hdmi_msm_hpd_off(void); -static void hdmi_msm_hpd_state_work(struct work_struct *work) +static bool hdmi_ready(void) { - boolean hpd_state = false; - char *envp[2]; - - if (hdmi_msm_state->is_mhl_enabled) { - /* - * HPD will be controlled from MHL - */ - envp[0] = ""; - DEV_DBG("%s %u\n", envp[0], hpd_state); - return; - } - - if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized || - !MSM_HDMI_BASE) { - DEV_DBG("%s: ignored, probe failed\n", __func__); - return; - } - - DEV_DBG("%s:Got interrupt\n", __func__); - /* HPD_INT_STATUS[0x0250] */ - hpd_state = (HDMI_INP(0x0250) & 0x2) >> 1; - mutex_lock(&external_common_state_hpd_mutex); - mutex_lock(&hdmi_msm_state_mutex); - if ((external_common_state->hpd_state != hpd_state) || (hdmi_msm_state-> - hpd_prev_state != external_common_state->hpd_state)) { - external_common_state->hpd_state = hpd_state; - hdmi_msm_state->hpd_prev_state = - external_common_state->hpd_state; - DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n", - __func__, hdmi_msm_state->hpd_prev_state, - external_common_state->hpd_state, hpd_state); - mutex_unlock(&external_common_state_hpd_mutex); - hdmi_msm_state->hpd_stable = 0; - mutex_unlock(&hdmi_msm_state_mutex); - mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2); - return; - } - mutex_unlock(&external_common_state_hpd_mutex); + return MSM_HDMI_BASE && + hdmi_msm_state && + hdmi_msm_state->hdmi_app_clk && + hdmi_msm_state->hpd_initialized; +} - if (hdmi_msm_state->hpd_stable++) { - mutex_unlock(&hdmi_msm_state_mutex); - DEV_DBG("%s: no more timer, depending for IRQ now\n", - __func__); - return; - } +static void hdmi_msm_send_event(boolean on) +{ + char *envp[2]; - hdmi_msm_state->hpd_stable = 1; - DEV_INFO("HDMI HPD: event detected\n"); + /* QDSP OFF preceding the HPD event notification */ + envp[0] = "HDCP_STATE=FAIL"; + envp[1] = NULL; + DEV_ERR("hdmi: HDMI HPD: QDSP OFF\n"); + kobject_uevent_env(external_common_state->uevent_kobj, + KOBJ_CHANGE, envp); - if (!hdmi_msm_state->hpd_cable_chg_detected) { - mutex_unlock(&hdmi_msm_state_mutex); - if (hpd_state) { - if (!external_common_state-> - disp_mode_list.num_of_elements) - hdmi_msm_read_edid(); - } - } else { - hdmi_msm_state->hpd_cable_chg_detected = FALSE; - mutex_unlock(&hdmi_msm_state_mutex); - /* QDSP OFF preceding the HPD event notification */ - envp[0] = "HDCP_STATE=FAIL"; - envp[1] = NULL; - DEV_INFO("HDMI HPD: QDSP OFF\n"); - kobject_uevent_env(external_common_state->uevent_kobj, - KOBJ_CHANGE, envp); - if (hpd_state) { - /* Build EDID table */ - hdmi_msm_read_edid(); -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - hdmi_msm_state->reauth = FALSE ; -#endif - switch_set_state(&external_common_state->sdev, 1); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); + if (on) { + /* Build EDID table */ + hdmi_msm_read_edid(); + switch_set_state(&external_common_state->sdev, 1); + DEV_INFO("%s: hdmi state switched to %d\n", __func__, + external_common_state->sdev.state); - DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n"); - kobject_uevent(external_common_state->uevent_kobj, - KOBJ_ONLINE); - switch_set_state(&external_common_state->sdev, 1); - DEV_INFO("Hdmi state switch to %d: %s\n", - external_common_state->sdev.state, __func__); -#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n"); + kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE); + if (!hdmi_msm_state->hdcp_enable) { /* Send Audio for HDMI Compliance Cases*/ envp[0] = "HDCP_STATE=PASS"; envp[1] = NULL; DEV_INFO("HDMI HPD: sense : send HDCP_PASS\n"); kobject_uevent_env(external_common_state->uevent_kobj, KOBJ_CHANGE, envp); -#endif - } else { - switch_set_state(&external_common_state->sdev, 0); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); - - DEV_INFO("HDMI HPD: DISCONNECTED: send OFFLINE\n"); - kobject_uevent(external_common_state->uevent_kobj, - KOBJ_OFFLINE); } + } else { + switch_set_state(&external_common_state->sdev, 0); + DEV_INFO("%s: hdmi state switch to %d\n", __func__, + external_common_state->sdev.state); + DEV_INFO("hdmi: HDMI HPD: sense DISCONNECTED: send OFFLINE\n"); + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_OFFLINE); } - /* HPD_INT_CTRL[0x0254] - * 31:10 Reserved - * 9 RCV_PLUGIN_DET_MASK receiver plug in interrupt mask. - * When programmed to 1, - * RCV_PLUGIN_DET_INT will toggle - * the interrupt line - * 8:6 Reserved - * 5 RX_INT_EN Panel RX interrupt enable - * 0: Disable - * 1: Enable - * 4 RX_INT_ACK WRITE ONLY. Panel RX interrupt - * ack - * 3 Reserved - * 2 INT_EN Panel interrupt control - * 0: Disable - * 1: Enable - * 1 INT_POLARITY Panel interrupt polarity - * 0: generate interrupt on disconnect - * 1: generate interrupt on connect - * 0 INT_ACK WRITE ONLY. Panel interrupt ack */ - /* Set IRQ for HPD */ - HDMI_OUTP(0x0254, 4 | (hpd_state ? 0 : 2)); + if (!completion_done(&hdmi_msm_state->hpd_event_processed)) + complete(&hdmi_msm_state->hpd_event_processed); +} + +static void hdmi_msm_hpd_state_work(struct work_struct *work) +{ + if (!hdmi_ready()) { + DEV_ERR("hdmi: %s: ignored, probe failed\n", __func__); + return; + } + + hdmi_msm_send_event(external_common_state->hpd_state); } #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT @@ -894,10 +837,13 @@ static void hdmi_msm_cec_latch_work(struct work_struct *work) } #endif -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT static void hdcp_deauthenticate(void); static void hdmi_msm_hdcp_reauth_work(struct work_struct *work) { + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return; + } /* Don't process recursive actions */ mutex_lock(&hdmi_msm_state_mutex); @@ -915,17 +861,20 @@ static void hdmi_msm_hdcp_reauth_work(struct work_struct *work) * Therefore, as surprising as it may sound do reauth * only if the device is HDCP-capable */ - if (external_common_state->present_hdcp) { - hdcp_deauthenticate(); - mutex_lock(&hdcp_auth_state_mutex); - hdmi_msm_state->reauth = TRUE; - mutex_unlock(&hdcp_auth_state_mutex); - mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2); - } + hdcp_deauthenticate(); + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_state->reauth = TRUE; + mutex_unlock(&hdcp_auth_state_mutex); + mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2); } static void hdmi_msm_hdcp_work(struct work_struct *work) { + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return; + } + /* Only re-enable if cable still connected */ mutex_lock(&external_common_state_hpd_mutex); if (external_common_state->hpd_state && @@ -946,7 +895,109 @@ static void hdmi_msm_hdcp_work(struct work_struct *work) hdmi_msm_state->reauth = FALSE; } } -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +int hdmi_msm_process_hdcp_interrupts(void) +{ + int rc = -1; + uint32 hdcp_int_val; + char *envp[2]; + + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return -EINVAL; + } + + /* HDCP_INT_CTRL[0x0118] + * [0] AUTH_SUCCESS_INT [R] HDCP Authentication Success + * interrupt status + * [1] AUTH_SUCCESS_ACK [W] Acknowledge bit for HDCP + * Authentication Success bit - write 1 to clear + * [2] AUTH_SUCCESS_MASK [R/W] Mask bit for HDCP Authentication + * Success interrupt - set to 1 to enable interrupt */ + hdcp_int_val = HDMI_INP_ND(0x0118); + if ((hdcp_int_val & (1 << 2)) && (hdcp_int_val & (1 << 0))) { + /* AUTH_SUCCESS_INT */ + HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 1)) & ~(1 << 0)); + DEV_INFO("HDCP: AUTH_SUCCESS_INT received\n"); + complete_all(&hdmi_msm_state->hdcp_success_done); + return 0; + } + + /* [4] AUTH_FAIL_INT [R] HDCP Authentication Lost + * interrupt Status + * [5] AUTH_FAIL_ACK [W] Acknowledge bit for HDCP + * Authentication Lost bit - write 1 to clear + * [6] AUTH_FAIL_MASK [R/W] Mask bit fo HDCP Authentication + * Lost interrupt set to 1 to enable interrupt + * [7] AUTH_FAIL_INFO_ACK [W] Acknowledge bit for HDCP + * Authentication Failure Info field - write 1 to clear */ + if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) { + /* AUTH_FAIL_INT */ + /* Clear and Disable */ + uint32 link_status = HDMI_INP_ND(0x011C); + HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5)) + & ~((1 << 6) | (1 << 4))); + DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n", + link_status); + if (hdmi_msm_state->full_auth_done) { + SWITCH_SET_HDMI_AUDIO(0, 0); + + envp[0] = "HDCP_STATE=FAIL"; + envp[1] = NULL; + DEV_INFO("HDMI HPD:QDSP OFF\n"); + kobject_uevent_env(external_common_state->uevent_kobj, + KOBJ_CHANGE, envp); + + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_state->full_auth_done = FALSE; + mutex_unlock(&hdcp_auth_state_mutex); + /* Calling reauth only when authentication + * is sucessful or else we always go into + * the reauth loop. Also, No need to reauthenticate + * if authentication failed because of cable disconnect + */ + if (((link_status & 0xF0) >> 4) != 0x7) { + DEV_DBG("Reauthenticate From %s HDCP FAIL INT ", + __func__); + queue_work(hdmi_work_queue, + &hdmi_msm_state->hdcp_reauth_work); + } else { + DEV_INFO("HDCP: HDMI cable disconnected\n"); + } + } + + /* Clear AUTH_FAIL_INFO as well */ + HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7))); + return 0; + } + + /* [8] DDC_XFER_REQ_INT [R] HDCP DDC Transfer Request + * interrupt status + * [9] DDC_XFER_REQ_ACK [W] Acknowledge bit for HDCP DDC + * Transfer Request bit - write 1 to clear + * [10] DDC_XFER_REQ_MASK [R/W] Mask bit for HDCP DDC Transfer + * Request interrupt - set to 1 to enable interrupt */ + if ((hdcp_int_val & (1 << 10)) && (hdcp_int_val & (1 << 8))) { + /* DDC_XFER_REQ_INT */ + HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 9)) & ~(1 << 8)); + if (!(hdcp_int_val & (1 << 12))) + return 0; + } + /* [12] DDC_XFER_DONE_INT [R] HDCP DDC Transfer done interrupt + * status + * [13] DDC_XFER_DONE_ACK [W] Acknowledge bit for HDCP DDC + * Transfer done bit - write 1 to clear + * [14] DDC_XFER_DONE_MASK [R/W] Mask bit for HDCP DDC Transfer + * done interrupt - set to 1 to enable interrupt */ + if ((hdcp_int_val & (1 << 14)) && (hdcp_int_val & (1 << 12))) { + /* DDC_XFER_DONE_INT */ + HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 13)) & ~(1 << 12)); + DEV_INFO("HDCP: DDC_XFER_DONE received\n"); + return 0; + } + + return rc; +} static irqreturn_t hdmi_msm_isr(int irq, void *dev_id) { @@ -957,16 +1008,11 @@ static irqreturn_t hdmi_msm_isr(int irq, void *dev_id) #endif uint32 ddc_int_ctrl; uint32 audio_int_val; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - uint32 hdcp_int_val; - char *envp[2]; -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ static uint32 fifo_urun_int_occurred; static uint32 sample_drop_int_occurred; const uint32 occurrence_limit = 5; - if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized || - !MSM_HDMI_BASE) { + if (!hdmi_ready()) { DEV_DBG("ISR ignored, probe failed\n"); return IRQ_HANDLED; } @@ -977,42 +1023,18 @@ static irqreturn_t hdmi_msm_isr(int irq, void *dev_id) /* HDMI_HPD_INT_CTRL[0x0254] */ hpd_int_ctrl = HDMI_INP_ND(0x0254); if ((hpd_int_ctrl & (1 << 2)) && (hpd_int_status & (1 << 0))) { - boolean cable_detected = (hpd_int_status & 2) >> 1; - - /* HDMI_HPD_INT_CTRL[0x0254] */ - /* Clear all interrupts, timer will turn IRQ back on - * Leaving the bit[2] on, else core goes off - * on getting HPD during power off - */ - HDMI_OUTP(0x0254, (1 << 2) | (1 << 0)); - - DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__, - hpd_int_ctrl, hpd_int_status); - mutex_lock(&hdmi_msm_state_mutex); - hdmi_msm_state->hpd_cable_chg_detected = TRUE; - - /* ensure 2 readouts */ - hdmi_msm_state->hpd_prev_state = cable_detected ? 0 : 1; - external_common_state->hpd_state = cable_detected ? 1 : 0; - hdmi_msm_state->hpd_stable = 0; - mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2); - mutex_unlock(&hdmi_msm_state_mutex); /* - * HDCP Compliance 1A-01: - * The Quantum Data Box 882 triggers two consecutive - * HPD events very close to each other as a part of this - * test which can trigger two parallel HDCP auth threads - * if HDCP authentication is going on and we get ISR - * then stop the authentication , rather than - * reauthenticating it again + * Got HPD interrupt. Ack the interrupt and disable any + * further HPD interrupts until we process this interrupt. */ - if (!(hdmi_msm_state->full_auth_done)) { - DEV_DBG("%s getting hpd while authenticating\n",\ - __func__); - mutex_lock(&hdcp_auth_state_mutex); - hdmi_msm_state->hpd_during_auth = TRUE; - mutex_unlock(&hdcp_auth_state_mutex); - } + HDMI_OUTP(0x0254, ((hpd_int_ctrl | (BIT(0))) & ~BIT(2))); + + external_common_state->hpd_state = + (HDMI_INP(0x0250) & BIT(1)) >> 1; + DEV_DBG("%s: Queuing work to handle HPD %s event\n", __func__, + external_common_state->hpd_state ? "connect" : + "disconnect"); + queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_state_work); return IRQ_HANDLED; } @@ -1065,97 +1087,8 @@ static irqreturn_t hdmi_msm_isr(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - /* HDCP_INT_CTRL[0x0118] - * [0] AUTH_SUCCESS_INT [R] HDCP Authentication Success - * interrupt status - * [1] AUTH_SUCCESS_ACK [W] Acknowledge bit for HDCP - * Authentication Success bit - write 1 to clear - * [2] AUTH_SUCCESS_MASK [R/W] Mask bit for HDCP Authentication - * Success interrupt - set to 1 to enable interrupt */ - hdcp_int_val = HDMI_INP_ND(0x0118); - if ((hdcp_int_val & (1 << 2)) && (hdcp_int_val & (1 << 0))) { - /* AUTH_SUCCESS_INT */ - HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 1)) & ~(1 << 0)); - DEV_INFO("HDCP: AUTH_SUCCESS_INT received\n"); - complete_all(&hdmi_msm_state->hdcp_success_done); + if (!hdmi_msm_process_hdcp_interrupts()) return IRQ_HANDLED; - } - /* [4] AUTH_FAIL_INT [R] HDCP Authentication Lost - * interrupt Status - * [5] AUTH_FAIL_ACK [W] Acknowledge bit for HDCP - * Authentication Lost bit - write 1 to clear - * [6] AUTH_FAIL_MASK [R/W] Mask bit fo HDCP Authentication - * Lost interrupt set to 1 to enable interrupt - * [7] AUTH_FAIL_INFO_ACK [W] Acknowledge bit for HDCP - * Authentication Failure Info field - write 1 to clear */ - if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) { - /* AUTH_FAIL_INT */ - /* Clear and Disable */ - HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5)) - & ~((1 << 6) | (1 << 4))); - DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n", - HDMI_INP_ND(0x011C)); - if (hdmi_msm_state->full_auth_done) { - switch_set_state(&external_common_state->sdev, 0); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); - - envp[0] = "HDCP_STATE=FAIL"; - envp[1] = NULL; - DEV_INFO("HDMI HPD:QDSP OFF\n"); - kobject_uevent_env(external_common_state->uevent_kobj, - KOBJ_CHANGE, envp); - - mutex_lock(&hdcp_auth_state_mutex); - hdmi_msm_state->full_auth_done = FALSE; - mutex_unlock(&hdcp_auth_state_mutex); - /* Calling reauth only when authentication - * is sucessful or else we always go into - * the reauth loop - */ - queue_work(hdmi_work_queue, - &hdmi_msm_state->hdcp_reauth_work); - } - mutex_lock(&hdcp_auth_state_mutex); - /* This flag prevents other threads from re-authenticating - * after we've just authenticated (i.e., finished part3) - */ - hdmi_msm_state->full_auth_done = FALSE; - - mutex_unlock(&hdcp_auth_state_mutex); - DEV_DBG("calling reauthenticate from %s HDCP FAIL INT ", - __func__); - - /* Clear AUTH_FAIL_INFO as well */ - HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7))); - return IRQ_HANDLED; - } - /* [8] DDC_XFER_REQ_INT [R] HDCP DDC Transfer Request - * interrupt status - * [9] DDC_XFER_REQ_ACK [W] Acknowledge bit for HDCP DDC - * Transfer Request bit - write 1 to clear - * [10] DDC_XFER_REQ_MASK [R/W] Mask bit for HDCP DDC Transfer - * Request interrupt - set to 1 to enable interrupt */ - if ((hdcp_int_val & (1 << 10)) && (hdcp_int_val & (1 << 8))) { - /* DDC_XFER_REQ_INT */ - HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 9)) & ~(1 << 8)); - if (!(hdcp_int_val & (1 << 12))) - return IRQ_HANDLED; - } - /* [12] DDC_XFER_DONE_INT [R] HDCP DDC Transfer done interrupt - * status - * [13] DDC_XFER_DONE_ACK [W] Acknowledge bit for HDCP DDC - * Transfer done bit - write 1 to clear - * [14] DDC_XFER_DONE_MASK [R/W] Mask bit for HDCP DDC Transfer - * done interrupt - set to 1 to enable interrupt */ - if ((hdcp_int_val & (1 << 14)) && (hdcp_int_val & (1 << 12))) { - /* DDC_XFER_DONE_INT */ - HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 13)) & ~(1 << 12)); - DEV_INFO("HDCP: DDC_XFER_DONE received\n"); - return IRQ_HANDLED; - } -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT /* Process CEC Interrupt */ @@ -1314,7 +1247,7 @@ void hdmi_msm_set_mode(boolean power_on) if (external_common_state->hdmi_sink == 0) { /* HDMI_DVI_SEL */ reg_val |= 0x00000002; - if (external_common_state->present_hdcp) + if (hdmi_msm_state->hdcp_enable) /* HDMI Encryption */ reg_val |= 0x00000004; /* HDMI_CTRL */ @@ -1322,7 +1255,7 @@ void hdmi_msm_set_mode(boolean power_on) /* HDMI_DVI_SEL */ reg_val &= ~0x00000002; } else { - if (external_common_state->present_hdcp) + if (hdmi_msm_state->hdcp_enable) /* HDMI_Encryption_ON */ reg_val |= 0x00000006; else @@ -1402,7 +1335,6 @@ static int hdmi_msm_ddc_clear_irq(const char *what) return 0; } -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT static int hdmi_msm_ddc_write(uint32 dev_addr, uint32 offset, const uint8 *data_buf, uint32 data_len, const char *what) { @@ -1598,7 +1530,6 @@ static int hdmi_msm_ddc_write(uint32 dev_addr, uint32 offset, error: return status; } -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ static int hdmi_msm_ddc_read_retry(uint32 dev_addr, uint32 offset, uint8 *data_buf, uint32 data_len, uint32 request_len, int retry, @@ -2159,9 +2090,13 @@ static int hdmi_msm_read_edid(void) return status; } -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT static void hdcp_auth_info(uint32 auth_info) { + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return; + } + switch (auth_info) { case 0: DEV_INFO("%s: None", __func__); @@ -2196,6 +2131,11 @@ static void hdcp_auth_info(uint32 auth_info) static void hdcp_key_state(uint32 key_state) { + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return; + } + switch (key_state) { case 0: DEV_WARN("%s: No HDCP Keys", __func__); @@ -2239,10 +2179,17 @@ static void hdcp_deauthenticate(void) { int hdcp_link_status = HDMI_INP(0x011C); + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return; + } + /* Disable HDCP interrupts */ HDMI_OUTP(0x0118, 0x0); + mutex_lock(&hdcp_auth_state_mutex); external_common_state->hdcp_active = FALSE; + mutex_unlock(&hdcp_auth_state_mutex); /* 0x0130 HDCP_RESET [0] LINK0_DEAUTHENTICATE */ HDMI_OUTP(0x0130, 0x1); @@ -2264,6 +2211,11 @@ static void check_and_clear_HDCP_DDC_Failure(void) int failure; int nack0; + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return; + } + /* * Check for any DDC transfer failures * 0x0128 HDCP_DDC_STATUS @@ -2374,6 +2326,11 @@ static int hdcp_authentication_part1(void) static uint8 buf[0xFF]; memset(buf, 0, sizeof(buf)); + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return 0; + } + if (!is_part1_done) { is_part1_done = TRUE; @@ -2446,8 +2403,8 @@ static int hdcp_authentication_part1(void) /* 0x0110 HDCP_CTRL [8] ENCRYPTION_ENABLE [0] ENABLE */ - /* encryption_enable | enable */ - HDMI_OUTP(0x0110, (1 << 8) | (1 << 0)); + /* Enable HDCP. Encryption should be enabled after reading R0 */ + HDMI_OUTP(0x0110, BIT(0)); /* * Check to see if a HDCP DDC Failure is indicated in @@ -2642,6 +2599,9 @@ static int hdcp_authentication_part1(void) goto error; } + /* Enable HDCP Encryption */ + HDMI_OUTP(0x0110, BIT(0) | BIT(8)); + DEV_INFO("HDCP: authentication part I, successful\n"); is_part1_done = FALSE; return 0; @@ -2661,6 +2621,11 @@ static int hdmi_msm_transfer_v_h(void) int ret; uint8 buf[4]; + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return 0; + } + snprintf(what, sizeof(what), "V' H0"); ret = hdmi_msm_ddc_read(0x74, 0x20, buf, 4, 5, what, TRUE); if (ret) { @@ -2753,6 +2718,11 @@ static int hdcp_authentication_part2(void) boolean ksv_done = FALSE; + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return 0; + } + memset(buf, 0, sizeof(buf)); memset(kvs_fifo, 0, sizeof(kvs_fifo)); @@ -2945,6 +2915,12 @@ static int hdcp_authentication_part3(uint32 found_repeater) { int ret = 0; int poll = 3000; + + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return 0; + } + while (poll) { /* 0x011C HDCP_LINK0_STATUS [30:28] KEYS_STATE = 3 = "Valid" @@ -2975,7 +2951,7 @@ static void hdmi_msm_hdcp_enable(void) uint32 found_repeater = 0x0; char *envp[2]; - if (!hdmi_msm_has_hdcp()) { + if (!hdmi_msm_state->hdcp_enable) { DEV_INFO("%s: HDCP NOT ENABLED\n", __func__); return; } @@ -2984,20 +2960,16 @@ static void hdmi_msm_hdcp_enable(void) hdmi_msm_state->hdcp_activating = TRUE; mutex_unlock(&hdmi_msm_state_mutex); - fill_black_screen(); - mutex_lock(&hdcp_auth_state_mutex); - /* - * Initialize this to zero here to make - * sure HPD has not happened yet - */ - hdmi_msm_state->hpd_during_auth = FALSE; /* This flag prevents other threads from re-authenticating * after we've just authenticated (i.e., finished part3) * We probably need to protect this in a mutex lock */ hdmi_msm_state->full_auth_done = FALSE; mutex_unlock(&hdcp_auth_state_mutex); + /* Disable HDCP before we start part1 */ + HDMI_OUTP(0x0110, 0x0); + /* PART I Authentication*/ ret = hdcp_authentication_part1(); if (ret) @@ -3027,9 +2999,6 @@ static void hdmi_msm_hdcp_enable(void) if (ret) goto error; - unfill_black_screen(); - - external_common_state->hdcp_active = TRUE; mutex_lock(&hdmi_msm_state_mutex); hdmi_msm_state->hdcp_activating = FALSE; mutex_unlock(&hdmi_msm_state_mutex); @@ -3040,6 +3009,7 @@ static void hdmi_msm_hdcp_enable(void) * after we've just authenticated (i.e., finished part3) */ hdmi_msm_state->full_auth_done = TRUE; + external_common_state->hdcp_active = TRUE; mutex_unlock(&hdcp_auth_state_mutex); if (!hdmi_msm_is_dvi_mode()) { @@ -3048,17 +3018,13 @@ static void hdmi_msm_hdcp_enable(void) envp[1] = NULL; kobject_uevent_env(external_common_state->uevent_kobj, KOBJ_CHANGE, envp); + + SWITCH_SET_HDMI_AUDIO(1, 0); } - switch_set_state(&external_common_state->sdev, 1); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); return; error: - mutex_lock(&hdmi_msm_state_mutex); - hdmi_msm_state->hdcp_activating = FALSE; - mutex_unlock(&hdmi_msm_state_mutex); if (hdmi_msm_state->hpd_during_auth) { DEV_WARN("Calling Deauthentication: HPD occured during " "authentication from [%s]\n", __func__); @@ -3072,11 +3038,10 @@ static void hdmi_msm_hdcp_enable(void) queue_work(hdmi_work_queue, &hdmi_msm_state->hdcp_reauth_work); } - switch_set_state(&external_common_state->sdev, 0); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->hdcp_activating = FALSE; + mutex_unlock(&hdmi_msm_state_mutex); } -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ static void hdmi_msm_video_setup(int video_format) { @@ -3188,6 +3153,9 @@ static void hdmi_msm_audio_acr_setup(boolean enabled, int video_format, /* HDMI_ACR_PKT_CTRL[0x0024] */ uint32 acr_pck_ctrl_reg = HDMI_INP(0x0024); + /* Clear N/CTS selection bits */ + acr_pck_ctrl_reg &= ~(3 << 4); + if (enabled) { const struct hdmi_disp_mode_timing_type *timing = hdmi_common_get_supported_mode(video_format); @@ -3592,13 +3560,14 @@ EXPORT_SYMBOL(hdmi_msm_audio_get_sample_rate); void hdmi_msm_audio_sample_rate_reset(int rate) { + if (msm_hdmi_sample_rate == rate) + return; + msm_hdmi_sample_rate = rate; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - if (hdmi_msm_has_hdcp()) + if (hdmi_msm_state->hdcp_enable) hdcp_deauthenticate(); else -#endif hdmi_msm_turn_on(); } EXPORT_SYMBOL(hdmi_msm_audio_sample_rate_reset); @@ -3626,64 +3595,59 @@ static void hdmi_msm_audio_setup(void) static int hdmi_msm_audio_off(void) { - uint32 audio_pkt_ctrl, audio_cfg; - /* Number of wait iterations */ - int i = 10; - audio_pkt_ctrl = HDMI_INP_ND(0x0020); - audio_cfg = HDMI_INP_ND(0x01D0); - - /* Checking BIT[0] of AUDIO PACKET CONTROL and */ - /* AUDIO CONFIGURATION register */ - while (((audio_pkt_ctrl & 0x00000001) || (audio_cfg & 0x00000001)) - && (i--)) { - audio_pkt_ctrl = HDMI_INP_ND(0x0020); - audio_cfg = HDMI_INP_ND(0x01D0); - DEV_DBG("%d times :: HDMI AUDIO PACKET is %08x and " - "AUDIO CFG is %08x", i, audio_pkt_ctrl, audio_cfg); - msleep(100); - if (!i) { - DEV_ERR("%s:failed to set BIT[0] AUDIO PACKET" - "CONTROL or AUDIO CONFIGURATION REGISTER\n", - __func__); - return -ETIMEDOUT; + uint32 audio_cfg; + int i, timeout_val = 50; + + for (i = 0; (i < timeout_val) && + ((audio_cfg = HDMI_INP_ND(0x01D0)) & BIT(0)); i++) { + DEV_DBG("%s: %d times: AUDIO CFG is %08xi\n", __func__, + i+1, audio_cfg); + if (!((i+1) % 10)) { + DEV_ERR("%s: audio still on after %d sec. try again\n", + __func__, (i+1)/10); + SWITCH_SET_HDMI_AUDIO(0, 1); } + msleep(100); } + + if (i == timeout_val) + DEV_ERR("%s: Error: cannot turn off audio engine\n", __func__); + hdmi_msm_audio_info_setup(FALSE, 0, 0, 0, FALSE); hdmi_msm_audio_acr_setup(FALSE, 0, 0, 0); DEV_INFO("HDMI Audio: Disabled\n"); return 0; } - -static uint8 hdmi_msm_avi_iframe_lut[][16] = { +static uint8 hdmi_msm_avi_iframe_lut[][17] = { /* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9 576p50_4_3 */ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/ + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/ {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/ + 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18, 0x08}, /*01*/ {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04}, /*02*/ + 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04, 0x04}, /*02*/ {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F, - 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/ + 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11, 0x00}, /*03*/ {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/ {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41}, /*07*/ + 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41, 0x01}, /*07*/ {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02}, /*08*/ + 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02, 0x04}, /*08*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/ {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1}, /*11*/ + 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1, 0x01}, /*11*/ {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/ + 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02, 0x05} /*12*/ }; static void hdmi_msm_avi_info_frame(void) @@ -3746,6 +3710,9 @@ static void hdmi_msm_avi_info_frame(void) case HDMI_VFRMT_720x576p50_4_3: mode = 15; break; + case HDMI_VFRMT_1280x1024p60_5_4: + mode = 16; + break; default: DEV_INFO("%s: mode %d not supported\n", __func__, external_common_state->video_resolution); @@ -4160,23 +4127,27 @@ static void hdmi_msm_turn_on(void) hdmi_msm_set_mode(TRUE); hdmi_msm_video_setup(external_common_state->video_resolution); - if (!hdmi_msm_is_dvi_mode()) + if (!hdmi_msm_is_dvi_mode()) { hdmi_msm_audio_setup(); + + /* + * Send the audio switch device notification if HDCP is + * not enabled. Otherwise, the notification would be + * sent after HDCP authentication is successful. + */ + if (!hdmi_msm_state->hdcp_enable) + SWITCH_SET_HDMI_AUDIO(1, 0); + } hdmi_msm_avi_info_frame(); #ifdef CONFIG_FB_MSM_HDMI_3D hdmi_msm_vendor_infoframe_packetsetup(); #endif hdmi_msm_spd_infoframe_packetsetup(); - /* Set IRQ for HPD */ - HDMI_OUTP(0x0254, 4 | (external_common_state->hpd_state ? 0 : 2)); - -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - if (hdmi_msm_state->reauth) { + if (hdmi_msm_state->hdcp_enable && hdmi_msm_state->reauth) { hdmi_msm_hdcp_enable(); hdmi_msm_state->reauth = FALSE ; } -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT /* re-initialize CEC if enabled */ @@ -4191,17 +4162,15 @@ static void hdmi_msm_turn_on(void) DEV_INFO("HDMI Core: Initialized\n"); } -static void hdmi_msm_hpd_state_timer(unsigned long data) -{ - queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_state_work); -} - -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT static void hdmi_msm_hdcp_timer(unsigned long data) { + if (!hdmi_msm_state->hdcp_enable) { + DEV_DBG("%s: HDCP not enabled\n", __func__); + return; + } + queue_work(hdmi_work_queue, &hdmi_msm_state->hdcp_work); } -#endif #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT static void hdmi_msm_cec_read_timer_func(unsigned long data) @@ -4210,6 +4179,36 @@ static void hdmi_msm_cec_read_timer_func(unsigned long data) } #endif +static void hdmi_msm_hpd_polarity_setup(void) +{ + u32 cable_sense; + bool polarity = !external_common_state->hpd_state; + bool trigger = false; + + if (polarity) + HDMI_OUTP(0x0254, BIT(2) | BIT(1)); + else + HDMI_OUTP(0x0254, BIT(2)); + + cable_sense = (HDMI_INP(0x0250) & BIT(1)) >> 1; + + if (cable_sense == polarity) + trigger = true; + + DEV_DBG("%s: listen=%s, sense=%s, trigger=%s\n", __func__, + polarity ? "connect" : "disconnect", + cable_sense ? "connect" : "disconnect", + trigger ? "Yes" : "No"); + + if (trigger) { + u32 reg_val = HDMI_INP(0x0258); + + /* Toggle HPD circuit to trigger HPD sense */ + HDMI_OUTP(0x0258, reg_val & ~BIT(28)); + HDMI_OUTP(0x0258, reg_val | BIT(28)); + } +} + static void hdmi_msm_hpd_off(void) { int rc = 0; @@ -4220,9 +4219,12 @@ static void hdmi_msm_hpd_off(void) } DEV_DBG("%s: (timer, 5V, IRQ off)\n", __func__); - del_timer(&hdmi_msm_state->hpd_state_timer); disable_irq(hdmi_msm_state->irq); + /* Disable HPD interrupt */ + HDMI_OUTP(0x0254, 0); + DEV_DBG("%s: Disabling HPD_CTRLd\n", __func__); + hdmi_msm_set_mode(FALSE); hdmi_msm_state->pd->enable_5v(0); hdmi_msm_clk(0); @@ -4241,7 +4243,7 @@ static void hdmi_msm_dump_regs(const char *prefix) #endif } -static int hdmi_msm_hpd_on(bool trigger_handler) +static int hdmi_msm_hpd_on(void) { static int phy_reset_done; uint32 hpd_ctrl; @@ -4282,35 +4284,28 @@ static int hdmi_msm_hpd_on(bool trigger_handler) /* HDMI_USEC_REFTIMER[0x0208] */ HDMI_OUTP(0x0208, 0x0001001B); - /* set timeout to 4.1ms (max) for hardware debounce */ - hpd_ctrl = HDMI_INP(0x0258) | 0x1FFF; + /* Set up HPD state variables */ + mutex_lock(&external_common_state_hpd_mutex); + external_common_state->hpd_state = 0; + mutex_unlock(&external_common_state_hpd_mutex); + mutex_lock(&hdmi_msm_state_mutex); + mutex_unlock(&hdmi_msm_state_mutex); - /* Toggle HPD circuit to trigger HPD sense */ - HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl); - HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl); + enable_irq(hdmi_msm_state->irq); hdmi_msm_state->hpd_initialized = TRUE; - /* Check HPD State */ - enable_irq(hdmi_msm_state->irq); - } + /* set timeout to 4.1ms (max) for hardware debounce */ + hpd_ctrl = HDMI_INP(0x0258) | 0x1FFF; - if (trigger_handler) { - /* Set HPD state machine: ensure at least 2 readouts */ - mutex_lock(&external_common_state_hpd_mutex); - mutex_lock(&hdmi_msm_state_mutex); - hdmi_msm_state->hpd_stable = 0; - hdmi_msm_state->hpd_prev_state = TRUE; - external_common_state->hpd_state = FALSE; - hdmi_msm_state->hpd_cable_chg_detected = TRUE; - mutex_unlock(&hdmi_msm_state_mutex); - mutex_unlock(&external_common_state_hpd_mutex); - mod_timer(&hdmi_msm_state->hpd_state_timer, - jiffies + HZ/2); + /* Turn on HPD HW circuit */ + HDMI_OUTP(0x0258, hpd_ctrl | BIT(28)); + + /* Set HPD cable sense polarity */ + hdmi_msm_hpd_polarity_setup(); } - DEV_DBG("%s: (IRQ, 5V on) \n", __func__, - trigger_handler ? "true" : "false"); + DEV_DBG("%s: (IRQ, 5V on)\n", __func__); return 0; error3: @@ -4323,7 +4318,8 @@ static int hdmi_msm_hpd_on(bool trigger_handler) static int hdmi_msm_power_ctrl(boolean enable) { - int rc = 0; + int rc = 0; + int time = 0; if (enable) { /* @@ -4333,7 +4329,22 @@ static int hdmi_msm_power_ctrl(boolean enable) if (hdmi_prim_display || external_common_state->hpd_feature_on) { DEV_DBG("%s: Turning HPD ciruitry on\n", __func__); - rc = hdmi_msm_hpd_on(true); + + rc = hdmi_msm_hpd_on(); + if (rc) { + DEV_ERR("%s: HPD ON FAILED\n", __func__); + return rc; + } + + /* Wait for HPD initialization to complete */ + INIT_COMPLETION(hdmi_msm_state->hpd_event_processed); + time = wait_for_completion_interruptible_timeout( + &hdmi_msm_state->hpd_event_processed, HZ); + if (!time && !external_common_state->hpd_state) { + DEV_DBG("%s: cable not detected\n", __func__); + queue_work(hdmi_work_queue, + &hdmi_msm_state->hpd_state_work); + } } } else { DEV_DBG("%s: Turning HPD ciruitry off\n", __func__); @@ -4346,39 +4357,62 @@ static int hdmi_msm_power_ctrl(boolean enable) static int hdmi_msm_power_on(struct platform_device *pdev) { struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + int ret = 0; bool changed; - if (!hdmi_msm_state || !hdmi_msm_state->hdmi_app_clk || !MSM_HDMI_BASE) - return -ENODEV; + if (!hdmi_ready()) { + DEV_ERR("%s: HDMI/HPD not initialized\n", __func__); + return ret; + } - DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres, - mfd->var_pixclock); + if (!external_common_state->hpd_state) { + DEV_DBG("%s:HDMI cable not connected\n", __func__); + goto error; + } + /* Only start transmission with supported resolution */ changed = hdmi_common_get_video_format_from_drv_data(mfd); - hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE); + if (changed || external_common_state->default_res_supported) { + mutex_lock(&external_common_state_hpd_mutex); + if (external_common_state->hpd_state && + hdmi_msm_is_power_on()) { + mutex_unlock(&external_common_state_hpd_mutex); - mutex_lock(&external_common_state_hpd_mutex); - hdmi_msm_state->panel_power_on = TRUE; - if (external_common_state->hpd_state && hdmi_msm_is_power_on()) { - DEV_DBG("%s: Turning HDMI on\n", __func__); - mutex_unlock(&external_common_state_hpd_mutex); - hdmi_msm_turn_on(); + DEV_INFO("HDMI cable connected %s(%dx%d, %d)\n", + __func__, mfd->var_xres, mfd->var_yres, + mfd->var_pixclock); - /* Kick off HDCP Authentication */ - mutex_lock(&hdcp_auth_state_mutex); - hdmi_msm_state->reauth = FALSE; - hdmi_msm_state->full_auth_done = FALSE; - mutex_unlock(&hdcp_auth_state_mutex); - mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2); - } else - mutex_unlock(&external_common_state_hpd_mutex); + hdmi_msm_turn_on(); + hdmi_msm_state->panel_power_on = TRUE; + + if (hdmi_msm_state->hdcp_enable) { + /* Kick off HDCP Authentication */ + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_state->reauth = FALSE; + hdmi_msm_state->full_auth_done = FALSE; + mutex_unlock(&hdcp_auth_state_mutex); + mod_timer(&hdmi_msm_state->hdcp_timer, + jiffies + HZ/2); + } + } else { + mutex_unlock(&external_common_state_hpd_mutex); + } - hdmi_msm_dump_regs("HDMI-ON: "); + hdmi_msm_dump_regs("HDMI-ON: "); + DEV_INFO("power=%s DVI= %s\n", + hdmi_msm_is_power_on() ? "ON" : "OFF" , + hdmi_msm_is_dvi_mode() ? "ON" : "OFF"); + } else { + DEV_ERR("%s: Video fmt %d not supp. Returning\n", + __func__, + external_common_state->video_resolution); + } - DEV_INFO("power=%s DVI= %s\n", - hdmi_msm_is_power_on() ? "ON" : "OFF" , - hdmi_msm_is_dvi_mode() ? "ON" : "OFF"); - return 0; +error: + /* Set HPD cable sense polarity */ + hdmi_msm_hpd_polarity_setup(); + + return ret; } void mhl_connect_api(boolean on) @@ -4386,23 +4420,16 @@ void mhl_connect_api(boolean on) char *envp[2]; /* Simulating a HPD event based on MHL event */ - hdmi_msm_state->hpd_cable_chg_detected = FALSE; - /* QDSP OFF preceding the HPD event notification */ - switch_set_state(&external_common_state->sdev, 0); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); if (on) { hdmi_msm_read_edid(); - if (hdmi_msm_has_hdcp()) - hdmi_msm_state->reauth = FALSE ; + hdmi_msm_state->reauth = FALSE ; /* Build EDID table */ hdmi_msm_turn_on(); DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n"); kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE); - hdmi_msm_hdcp_enable(); envp[0] = 0; - if (!hdmi_msm_has_hdcp()) { + if (!hdmi_msm_state->hdcp_enable) { /* Send Audio for HDMI Compliance Cases*/ envp[0] = "HDCP_STATE=PASS"; envp[1] = NULL; @@ -4410,16 +4437,18 @@ void mhl_connect_api(boolean on) kobject_uevent_env(external_common_state->uevent_kobj, KOBJ_CHANGE, envp); switch_set_state(&external_common_state->sdev, 1); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); + DEV_INFO("%s: hdmi state switched to %d\n", + __func__, external_common_state->sdev.state); + } else { + hdmi_msm_hdcp_enable(); } } else { DEV_INFO("HDMI HPD: DISCONNECTED: send OFFLINE\n"); kobject_uevent(external_common_state->uevent_kobj, KOBJ_OFFLINE); switch_set_state(&external_common_state->sdev, 0); - DEV_INFO("Hdmi state switched to %d: %s\n", - external_common_state->sdev.state, __func__); + DEV_INFO("%s: hdmi state switched to %d\n", __func__, + external_common_state->sdev.state); } } EXPORT_SYMBOL(mhl_connect_api); @@ -4432,35 +4461,108 @@ EXPORT_SYMBOL(mhl_connect_api); */ static int hdmi_msm_power_off(struct platform_device *pdev) { - if (!hdmi_msm_state->hdmi_app_clk) - return -ENODEV; + int ret = 0; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - mutex_lock(&hdmi_msm_state_mutex); - if (hdmi_msm_state->hdcp_activating) { - hdmi_msm_state->panel_power_on = FALSE; - mutex_unlock(&hdmi_msm_state_mutex); - DEV_INFO("HDCP: activating, returning\n"); - return 0; + if (!hdmi_ready()) { + DEV_ERR("%s: HDMI/HPD not initialized\n", __func__); + return ret; } - mutex_unlock(&hdmi_msm_state_mutex); -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ - DEV_INFO("power: OFF (audio off, Reset Core)\n"); - hdmi_msm_audio_off(); -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - hdcp_deauthenticate(); -#endif + if (!hdmi_msm_state->panel_power_on) { + DEV_DBG("%s: panel not ON\n", __func__); + goto error; + } + + if (hdmi_msm_state->hdcp_enable) { + if (hdmi_msm_state->hdcp_activating) { + /* + * Let the HDCP work know that we got an HPD + * disconnect so that it can stop the + * reauthentication loop. + */ + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_state->hpd_during_auth = TRUE; + mutex_unlock(&hdcp_auth_state_mutex); + } + + /* + * Cancel any pending reauth attempts. + * If one is ongoing, wait for it to finish + */ + cancel_work_sync(&hdmi_msm_state->hdcp_reauth_work); + cancel_work_sync(&hdmi_msm_state->hdcp_work); + del_timer_sync(&hdmi_msm_state->hdcp_timer); + hdmi_msm_state->reauth = FALSE; + + hdcp_deauthenticate(); + } + + SWITCH_SET_HDMI_AUDIO(0, 0); + + if (!hdmi_msm_is_dvi_mode()) + hdmi_msm_audio_off(); + hdmi_msm_powerdown_phy(); hdmi_msm_state->panel_power_on = FALSE; - return 0; + DEV_INFO("power: OFF (audio off)\n"); + + if (!completion_done(&hdmi_msm_state->hpd_event_processed)) + complete(&hdmi_msm_state->hpd_event_processed); +error: + /* Set HPD cable sense polarity */ + hdmi_msm_hpd_polarity_setup(); + + return ret; +} + +bool mhl_is_enabled(void) +{ + return hdmi_msm_state->is_mhl_enabled; +} + +void hdmi_msm_config_hdcp_feature(void) +{ + if (hdcp_feature_on && hdmi_msm_has_hdcp()) { + init_timer(&hdmi_msm_state->hdcp_timer); + hdmi_msm_state->hdcp_timer.function = hdmi_msm_hdcp_timer; + hdmi_msm_state->hdcp_timer.data = (uint32)NULL; + hdmi_msm_state->hdcp_timer.expires = 0xffffffffL; + + init_completion(&hdmi_msm_state->hdcp_success_done); + INIT_WORK(&hdmi_msm_state->hdcp_reauth_work, + hdmi_msm_hdcp_reauth_work); + INIT_WORK(&hdmi_msm_state->hdcp_work, hdmi_msm_hdcp_work); + hdmi_msm_state->hdcp_enable = TRUE; + } else { + del_timer(&hdmi_msm_state->hdcp_timer); + hdmi_msm_state->hdcp_enable = FALSE; + } + external_common_state->present_hdcp = hdmi_msm_state->hdcp_enable; + DEV_INFO("%s: HDCP Feature: %s\n", __func__, + hdmi_msm_state->hdcp_enable ? "Enabled" : "Disabled"); +} + +static void hdmi_msm_update_panel_info(struct msm_fb_data_type *mfd) +{ + if (!mfd) + return; + + if (hdmi_common_get_video_format_from_drv_data(mfd)) + hdmi_common_init_panel_info(&mfd->panel_info); +} + +static bool hdmi_msm_cable_connected(void) +{ + return hdmi_msm_state->hpd_initialized && + external_common_state->hpd_state; } static int __devinit hdmi_msm_probe(struct platform_device *pdev) { int rc; struct platform_device *fb_dev; + struct msm_fb_data_type *mfd = NULL; if (!hdmi_msm_state) { pr_err("%s: hdmi_msm_state is NULL\n", __func__); @@ -4562,22 +4664,6 @@ static int __devinit hdmi_msm_probe(struct platform_device *pdev) } disable_irq(hdmi_msm_state->irq); - init_timer(&hdmi_msm_state->hpd_state_timer); - hdmi_msm_state->hpd_state_timer.function = - hdmi_msm_hpd_state_timer; - hdmi_msm_state->hpd_state_timer.data = (uint32)NULL; - - hdmi_msm_state->hpd_state_timer.expires = 0xffffffffL; - -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - init_timer(&hdmi_msm_state->hdcp_timer); - hdmi_msm_state->hdcp_timer.function = - hdmi_msm_hdcp_timer; - hdmi_msm_state->hdcp_timer.data = (uint32)NULL; - - hdmi_msm_state->hdcp_timer.expires = 0xffffffffL; -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ - #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT init_timer(&hdmi_msm_state->cec_read_timer); hdmi_msm_state->cec_read_timer.function = @@ -4598,37 +4684,43 @@ static int __devinit hdmi_msm_probe(struct platform_device *pdev) } else DEV_ERR("Init FAILED: failed to add fb device\n"); + mfd = platform_get_drvdata(fb_dev); + mfd->update_panel_info = hdmi_msm_update_panel_info; + mfd->is_panel_ready = hdmi_msm_cable_connected; + if (hdmi_prim_display) { - rc = hdmi_msm_hpd_on(true); + rc = hdmi_msm_hpd_on(); if (rc) goto error; } - if (hdmi_msm_has_hdcp()) { - /* Don't Set Encryption in case of non HDCP builds */ - external_common_state->present_hdcp = FALSE; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - external_common_state->present_hdcp = TRUE; -#endif - } else { - external_common_state->present_hdcp = FALSE; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - /* - * If the device is not hdcp capable do - * not start hdcp timer. - */ - del_timer(&hdmi_msm_state->hdcp_timer); -#endif - } + hdmi_msm_config_hdcp_feature(); /* Initialize hdmi node and register with switch driver */ if (hdmi_prim_display) external_common_state->sdev.name = "hdmi_as_primary"; else external_common_state->sdev.name = "hdmi"; - if (switch_dev_register(&external_common_state->sdev) < 0) + if (switch_dev_register(&external_common_state->sdev) < 0) { DEV_ERR("Hdmi switch registration failed\n"); + rc = -ENODEV; + goto error; + } + + external_common_state->audio_sdev.name = "hdmi_audio"; + if (switch_dev_register(&external_common_state->audio_sdev) < 0) { + DEV_ERR("Hdmi audio switch registration failed\n"); + switch_dev_unregister(&external_common_state->sdev); + rc = -ENODEV; + goto error; + } + /* Set the default video resolution for MHL-enabled display */ + if (hdmi_msm_state->is_mhl_enabled) { + DEV_DBG("MHL Enabled. Restricting default video resolution\n"); + external_common_state->video_resolution = + HDMI_VFRMT_1920x1080p30_16_9; + } return 0; error: @@ -4664,6 +4756,7 @@ static int __devexit hdmi_msm_remove(struct platform_device *pdev) /* Unregister hdmi node from switch driver */ switch_dev_unregister(&external_common_state->sdev); + switch_dev_unregister(&external_common_state->audio_sdev); hdmi_msm_hpd_off(); free_irq(hdmi_msm_state->irq, NULL); @@ -4701,11 +4794,26 @@ static int hdmi_msm_hpd_feature(int on) DEV_INFO("%s: %d\n", __func__, on); if (on) { - rc = hdmi_msm_hpd_on(true); + rc = hdmi_msm_hpd_on(); } else { + if (external_common_state->hpd_state) { + external_common_state->hpd_state = 0; + + /* Send offline event to switch OFF HDMI and HAL FD */ + hdmi_msm_send_event(HPD_EVENT_OFFLINE); + + /* Wait for HDMI and FD to close */ + INIT_COMPLETION(hdmi_msm_state->hpd_event_processed); + wait_for_completion_interruptible_timeout( + &hdmi_msm_state->hpd_event_processed, HZ); + } + hdmi_msm_hpd_off(); + /* Set HDMI switch node to 0 on HPD feature disable */ switch_set_state(&external_common_state->sdev, 0); + DEV_INFO("%s: hdmi state switched to %d\n", __func__, + external_common_state->sdev.state); } return rc; @@ -4796,12 +4904,8 @@ static int __init hdmi_msm_init(void) hdmi_common_init_panel_info(&hdmi_msm_panel_data.panel_info); init_completion(&hdmi_msm_state->ddc_sw_done); + init_completion(&hdmi_msm_state->hpd_event_processed); INIT_WORK(&hdmi_msm_state->hpd_state_work, hdmi_msm_hpd_state_work); -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - init_completion(&hdmi_msm_state->hdcp_success_done); - INIT_WORK(&hdmi_msm_state->hdcp_reauth_work, hdmi_msm_hdcp_reauth_work); - INIT_WORK(&hdmi_msm_state->hdcp_work, hdmi_msm_hdcp_work); -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT INIT_WORK(&hdmi_msm_state->cec_latch_detect_work, @@ -4825,9 +4929,6 @@ static int __init hdmi_msm_init(void) " RELEASE" #endif " AUDIO EDID HPD HDCP" -#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT - ":0" -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ " DVI" #ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT ":0" @@ -4849,6 +4950,36 @@ static void __exit hdmi_msm_exit(void) platform_driver_unregister(&this_driver); } +static int set_hdcp_feature_on(const char *val, const struct kernel_param *kp) +{ + int rv = param_set_bool(val, kp); + + if (rv) + return rv; + + pr_debug("%s: HDCP feature = %d\n", __func__, hdcp_feature_on); + if (hdmi_msm_state) { + if ((HDMI_INP(0x0250) & 0x2)) { + pr_err("%s: Unable to set HDCP feature", __func__); + pr_err("%s: HDMI panel is currently turned on", + __func__); + } else if (hdcp_feature_on != hdmi_msm_state->hdcp_enable) { + hdmi_msm_config_hdcp_feature(); + } + } + + return 0; +} + +static struct kernel_param_ops hdcp_feature_on_param_ops = { + .set = set_hdcp_feature_on, + .get = param_get_bool, +}; + +module_param_cb(hdcp, &hdcp_feature_on_param_ops, &hdcp_feature_on, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(hdcp, "Enable or Disable HDCP"); + module_init(hdmi_msm_init); module_exit(hdmi_msm_exit); diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h index 76ffce50..f8fcdc06 100644 --- a/drivers/video/msm/hdmi_msm.h +++ b/drivers/video/msm/hdmi_msm.h @@ -56,22 +56,17 @@ struct hdmi_msm_state_type { #ifdef CONFIG_SUSPEND boolean pm_suspended; #endif - int hpd_stable; - boolean hpd_prev_state; - boolean hpd_cable_chg_detected; boolean full_auth_done; boolean hpd_during_auth; struct work_struct hpd_state_work; - struct timer_list hpd_state_timer; struct completion ddc_sw_done; -#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + bool hdcp_enable; boolean hdcp_activating; boolean reauth ; struct work_struct hdcp_reauth_work, hdcp_work; struct completion hdcp_success_done; struct timer_list hdcp_timer; -#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT boolean cec_enabled; @@ -111,6 +106,7 @@ struct hdmi_msm_state_type { struct external_common_state_type common; boolean is_mhl_enabled; + struct completion hpd_event_processed; }; extern struct hdmi_msm_state_type *hdmi_msm_state; diff --git a/drivers/video/msm/lcdc.c b/drivers/video/msm/lcdc.c index ef13c0e6..24c4ec94 100644 --- a/drivers/video/msm/lcdc.c +++ b/drivers/video/msm/lcdc.c @@ -84,8 +84,6 @@ static int lcdc_off(struct platform_device *pdev) } clk_disable_unprepare(mfd->ebi1_clk); } -#else - mdp_bus_scale_update_request(0); #endif return ret; @@ -108,9 +106,7 @@ static int lcdc_on(struct platform_device *pdev) if (!panel_pixclock_freq) panel_pixclock_freq = mfd->fbi->var.pixclock; -#ifdef CONFIG_MSM_BUS_SCALING - mdp_bus_scale_update_request(2); -#else +#ifndef CONFIG_MSM_BUS_SCALING if (panel_pixclock_freq > 65000000) /* pm_qos_rate should be in Khz */ pm_qos_rate = panel_pixclock_freq / 1000 ; diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c index da9dbd1e..4e31d6a2 100644 --- a/drivers/video/msm/lvds.c +++ b/drivers/video/msm/lvds.c @@ -92,11 +92,11 @@ static void lvds_init(struct msm_fb_data_type *mfd) MDP_OUTP(MDP_BASE + 0xc3064, 0x05); MDP_OUTP(MDP_BASE + 0xc3050, 0x20); } else { - MDP_OUTP(MDP_BASE + 0xc3004, 0x62); + MDP_OUTP(MDP_BASE + 0xc3004, 0x8f); MDP_OUTP(MDP_BASE + 0xc3008, 0x30); - MDP_OUTP(MDP_BASE + 0xc300c, 0xc4); + MDP_OUTP(MDP_BASE + 0xc300c, 0xc6); MDP_OUTP(MDP_BASE + 0xc3014, 0x10); - MDP_OUTP(MDP_BASE + 0xc3018, 0x05); + MDP_OUTP(MDP_BASE + 0xc3018, 0x07); MDP_OUTP(MDP_BASE + 0xc301c, 0x62); MDP_OUTP(MDP_BASE + 0xc3020, 0x41); MDP_OUTP(MDP_BASE + 0xc3024, 0x0d); @@ -173,7 +173,7 @@ static void lvds_init(struct msm_fb_data_type *mfd) /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */ MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b); /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */ - MDP_OUTP(MDP_BASE + 0xc2024, 0x151a191a); + MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a); /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */ MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314); /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */ @@ -254,10 +254,6 @@ static int lvds_off(struct platform_device *pdev) if (lvds_pdata && lvds_pdata->lcdc_gpio_config) ret = lvds_pdata->lcdc_gpio_config(0); -#ifdef CONFIG_MSM_BUS_SCALING - mdp_bus_scale_update_request(0); -#endif - return ret; } @@ -273,9 +269,6 @@ static int lvds_on(struct platform_device *pdev) if (!panel_pixclock_freq) panel_pixclock_freq = mfd->fbi->var.pixclock; -#ifdef CONFIG_MSM_BUS_SCALING - mdp_bus_scale_update_request(2); -#endif mfd = platform_get_drvdata(pdev); if (lvds_clk) { diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 66c6ae86..88a476ca 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "mdp.h" #include "msm_fb.h" @@ -53,9 +54,10 @@ static struct clk *mdp_lut_clk; int mdp_rev; int mdp_iommu_split_domain; u32 mdp_max_clk = 200000000; +u64 mdp_max_bw = 2000000000; static struct platform_device *mdp_init_pdev; -static struct regulator *footswitch; +static struct regulator *footswitch, *dsi_pll_vdda, *dsi_pll_vddio; static unsigned int mdp_footswitch_on; struct completion mdp_ppp_comp; @@ -185,7 +187,7 @@ uint32_t mdp_block2base(uint32_t block) base = 0x18000; break; case MDP_BLOCK_OVERLAY_2: - base = (mdp_rev >= MDP_REV_44) ? 0x88000 : 0; + base = (mdp_rev >= MDP_REV_43) ? 0x88000 : 0; break; default: break; @@ -483,6 +485,7 @@ int mdp_hist_lut_config(struct mdp_hist_lut_data *data) DEFINE_MUTEX(mdp_lut_push_sem); static int mdp_lut_i; + static int mdp_lut_hw_update(struct fb_cmap *cmap) { int i; @@ -520,7 +523,9 @@ static int mdp_lut_update_nonlcdc(struct fb_info *info, struct fb_cmap *cmap) int ret; mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); ret = mdp_lut_hw_update(cmap); + mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); if (ret) @@ -542,16 +547,19 @@ static int mdp_lut_update_lcdc(struct fb_info *info, struct fb_cmap *cmap) uint32_t out; mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); ret = mdp_lut_hw_update(cmap); if (ret) { + mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); return ret; } /*mask off non LUT select bits*/ - out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7); + out = inpdw(MDP_BASE + 0x90070); MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out); + mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_lut_i = (mdp_lut_i + 1)%2; @@ -819,14 +827,32 @@ static int mdp_histogram_enable(struct mdp_hist_mgmt *mgmt) } mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + base = (uint32_t) (MDP_BASE + mgmt->base); + /*First make sure that device is not collecting histogram*/ + mgmt->mdp_is_hist_data = FALSE; + mgmt->mdp_is_hist_valid = FALSE; + mgmt->mdp_is_hist_init = FALSE; + spin_lock_irqsave(&mdp_spin_lock, flag); + outp32(MDP_INTR_CLEAR, mgmt->intr); + mdp_intr_mask &= ~mgmt->intr; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + MDP_OUTP(base + 0x001C, 0); + MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE); + MDP_OUTP(base + 0x0024, 0); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + mutex_unlock(&mgmt->mdp_hist_mutex); + cancel_work_sync(&mgmt->mdp_histogram_worker); + mutex_lock(&mgmt->mdp_hist_mutex); + + /*Then initialize histogram*/ INIT_COMPLETION(mgmt->mdp_hist_comp); - base = (uint32_t) (MDP_BASE + mgmt->base); + spin_lock_irqsave(&mdp_spin_lock, flag); MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE); MDP_OUTP(base + 0x0010, 1); MDP_OUTP(base + 0x001C, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE); - spin_lock_irqsave(&mdp_spin_lock, flag); outp32(MDP_INTR_CLEAR, mgmt->intr); mdp_intr_mask |= mgmt->intr; outp32(MDP_INTR_ENABLE, mdp_intr_mask); @@ -890,10 +916,12 @@ int _mdp_histogram_ctrl(boolean en, struct mdp_hist_mgmt *mgmt) int ret = 0; mutex_lock(&mgmt->mdp_hist_mutex); - if (mgmt->mdp_is_hist_start && !mgmt->mdp_is_hist_data && en) - ret = mdp_histogram_enable(mgmt); - else if (mgmt->mdp_is_hist_data && !en) - ret = mdp_histogram_disable(mgmt); + if (mgmt->mdp_is_hist_start == TRUE) { + if (en) + ret = mdp_histogram_enable(mgmt); + else + ret = mdp_histogram_disable(mgmt); + } mutex_unlock(&mgmt->mdp_hist_mutex); if (en == false) @@ -991,6 +1019,7 @@ int mdp_histogram_stop(struct fb_info *info, uint32_t block) mgmt->mdp_is_hist_start = FALSE; if (!mfd->panel_power_on) { + mgmt->mdp_is_hist_data = FALSE; if (mgmt->hist != NULL) { mgmt->hist = NULL; complete(&mgmt->mdp_hist_comp); @@ -1047,6 +1076,7 @@ static int _mdp_histogram_read_dma_data(struct mdp_hist_mgmt *mgmt) } mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); for (i = 0; i < mgmt->num_bins; i++) { mgmt->c0[i] = inpdw(mdp_hist_base + r_data_offset + (4*i)); mgmt->c1[i] = inpdw(mdp_hist_base + g_data_offset + (4*i)); @@ -1062,6 +1092,7 @@ static int _mdp_histogram_read_dma_data(struct mdp_hist_mgmt *mgmt) } else ret = -ENOMEM; } + mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); if (!ret) @@ -1097,6 +1128,7 @@ static int _mdp_histogram_read_vg_data(struct mdp_hist_mgmt *mgmt) } mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); for (i = 0; i < mgmt->num_bins; i++) mgmt->c0[i] = inpdw(mdp_hist_base + MDP_HIST_DATA_LUMA_OFF + (4*i)); @@ -1108,6 +1140,7 @@ static int _mdp_histogram_read_vg_data(struct mdp_hist_mgmt *mgmt) } else ret = -ENOMEM; } + mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); if (!ret) @@ -1304,7 +1337,7 @@ static void vsync_isr_handler(void) } #endif -static ssize_t vsync_show_event(struct device *dev, +ssize_t mdp_dma_show_event(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t ret = 0; @@ -1317,7 +1350,7 @@ static ssize_t vsync_show_event(struct device *dev, wait_for_completion(&vsync_cntrl.vsync_wait); ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", - ktime_to_ns(vsync_cntrl.vsync_time)); + ktime_to_ns(vsync_cntrl.vsync_time)); buf[strlen(buf) + 1] = '\0'; return ret; } @@ -1338,15 +1371,125 @@ int mdp_ppp_pipe_wait(void) if (wait == TRUE) { ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp, 5 * HZ); - if (!ret) printk(KERN_ERR "%s: Timed out waiting for the MDP.\n", - __func__); + __func__); } return ret; } +#define MAX_VSYNC_GAP 4 +#define DEFAULT_FRAME_RATE 60 + +u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd) +{ + u32 frame_rate = 0, pixel_rate = 0, total_pixel; + struct msm_panel_info *panel_info = &mfd->panel_info; + + if ((panel_info->type == MIPI_VIDEO_PANEL || + panel_info->type == MIPI_CMD_PANEL) && + panel_info->mipi.frame_rate) + frame_rate = panel_info->mipi.frame_rate; + + if (mfd->dest == DISPLAY_LCD) { + if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1) + frame_rate = panel_info->lcd.refx100 / (100 * 2); + else if (panel_info->type != MIPI_CMD_PANEL) + frame_rate = panel_info->lcd.refx100 / 100; + } + pr_debug("%s type=%d frame_rate=%d\n", __func__, + panel_info->type, frame_rate); + + if (frame_rate) + return frame_rate; + + pixel_rate = + (panel_info->type == MIPI_CMD_PANEL || + panel_info->type == MIPI_VIDEO_PANEL) ? + panel_info->mipi.dsi_pclk_rate : + panel_info->clk_rate; + + if (!pixel_rate) + pr_warn("%s pixel rate is zero\n", __func__); + + total_pixel = + (panel_info->lcdc.h_back_porch + + panel_info->lcdc.h_front_porch + + panel_info->lcdc.h_pulse_width + + panel_info->xres) * + (panel_info->lcdc.v_back_porch + + panel_info->lcdc.v_front_porch + + panel_info->lcdc.v_pulse_width + + panel_info->yres); + + if (total_pixel) + frame_rate = pixel_rate / total_pixel; + else + pr_warn("%s total pixels are zero\n", __func__); + + if (frame_rate == 0) { + frame_rate = DEFAULT_FRAME_RATE; + pr_warn("%s frame rate=%d is default\n", __func__, frame_rate); + } + pr_debug("%s frame rate=%d total_pixel=%d, pixel_rate=%d\n", __func__, + frame_rate, total_pixel, pixel_rate); + + return frame_rate; +} + +static int mdp_diff_to_next_vsync(ktime_t cur_time, + ktime_t last_vsync, u32 vsync_period) +{ + int diff_from_last, diff_to_next; + /* + * Get interval beween last vsync and current time + * Current time = CPU programming MDP for next Vsync + */ + diff_from_last = + (ktime_to_us(ktime_sub(cur_time, last_vsync))); + diff_from_last /= USEC_PER_MSEC; + /* + * If the last Vsync occurred too long ago, skip programming + * the timer + */ + if (diff_from_last < (vsync_period * MAX_VSYNC_GAP)) { + if (diff_from_last > vsync_period) + diff_to_next = + (diff_from_last - vsync_period) % vsync_period; + else + diff_to_next = vsync_period - diff_from_last; + } else { + /* mark it out of range */ + diff_to_next = vsync_period + 1; + } + return diff_to_next; +} + +void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync) +{ + u32 vsync_period; + int diff_to_next; + ktime_t cur_time, wakeup_time; + + if (!mfd->cpu_pm_hdl) + return; + vsync_period = mfd->panel_info.frame_interval; + cur_time = ktime_get(); + diff_to_next = mdp_diff_to_next_vsync(cur_time, + pre_vsync, + vsync_period); + if (diff_to_next > vsync_period) + return; + pr_debug("%s cur_time %d, pre_vsync %d, to_next %d\n", + __func__, + (int)ktime_to_ms(cur_time), + (int)ktime_to_ms(pre_vsync), + diff_to_next); + wakeup_time = ktime_add_ns(cur_time, diff_to_next * NSEC_PER_MSEC); + activate_event_timer(mfd->cpu_pm_hdl, wakeup_time); +} + static DEFINE_SPINLOCK(mdp_lock); static int mdp_irq_mask; static int mdp_irq_enabled; @@ -1479,15 +1622,12 @@ void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd) outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */ } else if (term == MDP_OVERLAY0_TERM) { mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - mdp_lut_enable(); outpdw(MDP_BASE + 0x0004, 0); } else if (term == MDP_OVERLAY1_TERM) { mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - mdp_lut_enable(); outpdw(MDP_BASE + 0x0008, 0); } else if (term == MDP_OVERLAY2_TERM) { mdp_pipe_ctrl(MDP_OVERLAY2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - mdp_lut_enable(); outpdw(MDP_BASE + 0x00D0, 0); } #else @@ -1565,7 +1705,9 @@ void mdp_clk_ctrl(int on) mdp_clk_cnt--; if (mdp_clk_cnt == 0) mdp_clk_disable_unprepare(); - } + } else + pr_err("%s: %d: mdp clk off is invalid\n", + __func__, __LINE__); } pr_debug("%s: on=%d cnt=%d\n", __func__, on, mdp_clk_cnt); mutex_unlock(&mdp_suspend_mutex); @@ -1758,10 +1900,8 @@ void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt) isr &= mask; if (isr & INTR_HIST_RESET_SEQ_DONE) __mdp_histogram_kickoff(mgmt); - - if (isr & INTR_HIST_DONE) { + else if (isr & INTR_HIST_DONE) queue_work(mdp_hist_wq, &mgmt->mdp_histogram_worker); - } } #ifndef CONFIG_FB_MSM_MDP40 @@ -1857,14 +1997,13 @@ irqreturn_t mdp_isr(int irq, void *ptr) dma = &dma2_data; spin_lock_irqsave(&mdp_spin_lock, flag); vsync_isr = vsync_cntrl.vsync_irq_enabled; - disabled_clocks = vsync_cntrl.disabled_clocks; /* let's disable LCDC interrupt */ if (dma->waiting) { dma->waiting = FALSE; complete(&dma->comp); } - if (!vsync_isr && !vsync_cntrl.disabled_clocks) { + if (!vsync_isr) { mdp_intr_mask &= ~LCDC_FRAME_START; outp32(MDP_INTR_ENABLE, mdp_intr_mask); mdp_disable_irq_nosync(MDP_VSYNC_TERM); @@ -1874,7 +2013,7 @@ irqreturn_t mdp_isr(int irq, void *ptr) } spin_unlock_irqrestore(&mdp_spin_lock, flag); - if (!vsync_isr && !disabled_clocks) + if (!vsync_isr) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); @@ -2110,12 +2249,16 @@ static int mdp_off(struct platform_device *pdev) mfd->panel.type == LCDC_PANEL || mfd->panel.type == LVDS_PANEL) mdp4_lcdc_off(pdev); + else if (mfd->panel.type == MDDI_PANEL) + mdp4_mddi_off(pdev); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); ret = panel_next_off(pdev); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_clk_ctrl(0); - +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(0, 0); +#endif if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL) mdp_dsi_cmd_overlay_suspend(mfd); pr_debug("%s:-\n", __func__); @@ -2133,15 +2276,6 @@ void mdp4_hw_init(void) } #endif -static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); -static struct attribute *vsync_fs_attrs[] = { - &dev_attr_vsync_event.attr, - NULL, -}; -static struct attribute_group vsync_fs_attr_group = { - .attrs = vsync_fs_attrs, -}; - static int mdp_on(struct platform_device *pdev) { int ret = 0; @@ -2164,6 +2298,9 @@ static int mdp_on(struct platform_device *pdev) mfd->panel.type == LCDC_PANEL || mfd->panel.type == LVDS_PANEL) { mdp4_lcdc_on(pdev); + } else if (mfd->panel.type == MDDI_PANEL) { + mdp_vsync_cfg_regs(mfd, FALSE); + mdp4_mddi_on(pdev); } mdp_clk_ctrl(0); @@ -2173,21 +2310,8 @@ static int mdp_on(struct platform_device *pdev) if (mdp_rev == MDP_REV_303 && mfd->panel.type == MIPI_CMD_PANEL) { vsync_cntrl.dev = mfd->fbi->dev; - - if (!vsync_cntrl.sysfs_created) { - ret = sysfs_create_group(&vsync_cntrl.dev->kobj, - &vsync_fs_attr_group); - if (ret) { - pr_err("%s: sysfs creation failed, ret=%d\n", - __func__, ret); - return ret; - } - - kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD); - pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); - vsync_cntrl.sysfs_created = 1; - } atomic_set(&vsync_cntrl.suspend, 0); + atomic_set(&vsync_cntrl.vsync_resume, 1); } mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); @@ -2196,6 +2320,10 @@ static int mdp_on(struct platform_device *pdev) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mdp_histogram_ctrl_all(TRUE); + + if (ret == 0) + ret = panel_next_late_init(pdev); + pr_debug("%s:-\n", __func__); return ret; @@ -2243,20 +2371,77 @@ void mdp_hw_version(void) } #ifdef CONFIG_MSM_BUS_SCALING + +#ifndef MDP_BUS_VECTOR_ENTRY +#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \ + { \ + .src = MSM_BUS_MASTER_MDP_PORT0, \ + .dst = MSM_BUS_SLAVE_EBI_CH0, \ + .ab = (ab_val), \ + .ib = (ib_val), \ + } +#endif +/* + * Entry 0 hold 0 request + * Entry 1 and 2 do ping pong request + */ +static struct msm_bus_vectors mdp_bus_vectors[] = { + MDP_BUS_VECTOR_ENTRY(0, 0), + MDP_BUS_VECTOR_ENTRY( 128000000, 160000000), + MDP_BUS_VECTOR_ENTRY( 128000000, 160000000), +}; + +static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)]; +static struct msm_bus_scale_pdata mdp_bus_scale_table = { + .usecase = mdp_bus_usecases, + .num_usecases = ARRAY_SIZE(mdp_bus_usecases), + .name = "mdp", +}; static uint32_t mdp_bus_scale_handle; -int mdp_bus_scale_update_request(uint32_t index) +static int mdp_bus_scale_register(void) { - if (!mdp_pdata && (!mdp_pdata->mdp_bus_scale_table - || index > (mdp_pdata->mdp_bus_scale_table->num_usecases - 1))) { - printk(KERN_ERR "%s invalid table or index\n", __func__); - return -EINVAL; + struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table; + int i; + for (i = 0; i < bus_pdata->num_usecases; i++) { + mdp_bus_usecases[i].num_paths = 1; + mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i]; + } + mdp_bus_scale_handle = msm_bus_scale_register_client(bus_pdata); + if (!mdp_bus_scale_handle) { + pr_err("%s: not able to get bus scale!\n", __func__); + return -ENOMEM; } + return 0; +} + +int mdp_bus_scale_update_request(u64 ab, u64 ib) +{ + static int bus_index = 1; + if (mdp_bus_scale_handle < 1) { - pr_debug("%s invalid bus handle\n", __func__); + pr_err("%s invalid bus handle\n", __func__); return -EINVAL; } - return msm_bus_scale_client_update_request(mdp_bus_scale_handle, - index); + + if (!ab) + return msm_bus_scale_client_update_request + (mdp_bus_scale_handle, 0); + + /* ping pong bus_index between table entry 1 and 2 */ + bus_index++; + bus_index = (bus_index > 2) ? 1 : bus_index; + + mdp_bus_usecases[bus_index].vectors->ab = min(ab, mdp_max_bw); + ib = max(ib, ab); + mdp_bus_usecases[bus_index].vectors->ib = min(ib, mdp_max_bw); + + pr_debug("%s: handle=%d index=%d ab=%llu ib=%llu\n", __func__, + (u32)mdp_bus_scale_handle, bus_index, + mdp_bus_usecases[bus_index].vectors->ab, + mdp_bus_usecases[bus_index].vectors->ib); + + return msm_bus_scale_client_update_request + (mdp_bus_scale_handle, bus_index); } #endif DEFINE_MUTEX(mdp_clk_lock); @@ -2306,18 +2491,40 @@ static int mdp_irq_clk_setup(struct platform_device *pdev, } disable_irq(mdp_irq); + dsi_pll_vdda = regulator_get(&pdev->dev, "dsi_pll_vdda"); + if (IS_ERR(dsi_pll_vdda)) { + dsi_pll_vdda = NULL; + } else { + if (mdp_rev == MDP_REV_42 || mdp_rev == MDP_REV_44) { + ret = regulator_set_voltage(dsi_pll_vdda, 1200000, + 1200000); + if (ret) { + pr_err("set_voltage failed for dsi_pll_vdda, ret=%d\n", + ret); + } + } + } + + dsi_pll_vddio = regulator_get(&pdev->dev, "dsi_pll_vddio"); + if (IS_ERR(dsi_pll_vddio)) { + dsi_pll_vddio = NULL; + } else { + if (mdp_rev == MDP_REV_42) { + ret = regulator_set_voltage(dsi_pll_vddio, 1800000, + 1800000); + if (ret) { + pr_err("set_voltage failed for dsi_pll_vddio, ret=%d\n", + ret); + } + } + } + footswitch = regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(footswitch)) + if (IS_ERR(footswitch)) { footswitch = NULL; - else { + } else { regulator_enable(footswitch); mdp_footswitch_on = 1; - - if (mdp_rev == MDP_REV_42 && !cont_splashScreen) { - regulator_disable(footswitch); - msleep(20); - regulator_enable(footswitch); - } } mdp_clk = clk_get(&pdev->dev, "core_clk"); @@ -2368,6 +2575,17 @@ static int mdp_irq_clk_setup(struct platform_device *pdev, MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk)); #endif + + if (mdp_rev == MDP_REV_42 && !cont_splashScreen) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* DSI Video Timing generator disable */ + outpdw(MDP_BASE + 0xE0000, 0x0); + /* Clear MDP Interrupt Enable register */ + outpdw(MDP_BASE + 0x50, 0x0); + /* Set Overlay Proc 0 to reset state */ + outpdw(MDP_BASE + 0x10004, 0x3); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } return 0; } @@ -2379,17 +2597,15 @@ static int mdp_probe(struct platform_device *pdev) int rc; resource_size_t size ; unsigned long flag; + u32 frame_rate; #ifdef CONFIG_FB_MSM_MDP40 int intf, if_no; #endif #if defined(CONFIG_FB_MSM_MIPI_DSI) && defined(CONFIG_FB_MSM_MDP40) struct mipi_panel_info *mipi; #endif - static int contSplash_update_done; - void *splash_virt_addr; - int cur_page; - unsigned long cur_addr; - struct splash_pages page_data; + static int contSplash_update_done; + if ((pdev->id == 0) && (pdev->num_resources > 0)) { mdp_init_pdev = pdev; @@ -2411,6 +2627,7 @@ static int mdp_probe(struct platform_device *pdev) } mdp_rev = mdp_pdata->mdp_rev; + mdp_iommu_split_domain = mdp_pdata->mdp_iommu_split_domain; rc = mdp_irq_clk_setup(pdev, mdp_pdata->cont_splash_enabled); @@ -2427,13 +2644,17 @@ static int mdp_probe(struct platform_device *pdev) if (!(mdp_pdata->cont_splash_enabled)) mdp4_hw_init(); #else - mdp_hw_init(mdp_pdata->cont_splash_enabled); + + mdp_hw_init(); + #endif #ifdef CONFIG_FB_MSM_OVERLAY mdp_hw_cursor_init(); #endif - mdp_clk_ctrl(0); + + if (!(mdp_pdata->cont_splash_enabled)) + mdp_clk_ctrl(0); mdp_resource_initialized = 1; return 0; @@ -2462,71 +2683,8 @@ static int mdp_probe(struct platform_device *pdev) mfd->mdp_rev = mdp_rev; mfd->vsync_init = NULL; - if (mdp_pdata) { + if (mdp_pdata) { if (mdp_pdata->cont_splash_enabled) { - uint32 bpp = 3; - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - /*read panel wxh and calculate splash screen - size*/ - mdp_pdata->splash_screen_size = - inpdw(MDP_BASE + 0x90004); - mdp_pdata->splash_screen_size = - (((mdp_pdata->splash_screen_size >> 16) & - 0x00000FFF) * ( - mdp_pdata->splash_screen_size & - 0x00000FFF)) * bpp; - - mdp_pdata->splash_screen_addr = - inpdw(MDP_BASE + 0x90008); - - mfd->copy_splash_buf = dma_alloc_coherent(NULL, - mdp_pdata->splash_screen_size, - (dma_addr_t *) &(mfd->copy_splash_phys), - GFP_KERNEL); - - if (!mfd->copy_splash_buf) { - pr_err("DMA ALLOC FAILED for SPLASH\n"); - return -ENOMEM; - } - - page_data.size = PFN_ALIGN(mdp_pdata->splash_screen_size); - page_data.nrpages = (page_data.size) >> PAGE_SHIFT; - page_data.pages = kzalloc(sizeof(struct page *)*page_data.nrpages, - GFP_KERNEL); - if (!page_data.pages) { - pr_err("KZALLOC FAILED for PAGES\n"); - return -ENOMEM; - } - - /* Following code for obtaining the virtual address for splash - screen address relies on the fact that, splash screen buffer is - part of the kernel's memory map and this code need to be changed - if the memory comes from outside the kernel. */ - cur_addr = mdp_pdata->splash_screen_addr; - for(cur_page = 0; cur_page < page_data.nrpages; cur_page++) { - page_data.pages[cur_page] = phys_to_page(cur_addr); - if (!page_data.pages[cur_page]) { - pr_err("PHYS_TO_PAGE FAILED for SPLASH\n"); - kfree(page_data.pages); - return -ENOMEM; - } - cur_addr += (1 << PAGE_SHIFT); - } - splash_virt_addr = vmap(page_data.pages, page_data.nrpages, - VM_IOREMAP, pgprot_kernel); - if (!splash_virt_addr) { - pr_err("VMAP FAILED for SPLASH\n"); - kfree(page_data.pages); - return -ENOMEM; - } - memcpy(mfd->copy_splash_buf, splash_virt_addr, - mdp_pdata->splash_screen_size); - vunmap(splash_virt_addr); - kfree(page_data.pages); - - MDP_OUTP(MDP_BASE + 0x90008, - mfd->copy_splash_phys); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); mfd->cont_splash_done = 0; if (!contSplash_update_done) { @@ -2567,10 +2725,12 @@ static int mdp_probe(struct platform_device *pdev) rc = -ENOMEM; goto mdp_probe_err; } + /* data chain */ pdata = msm_fb_dev->dev.platform_data; pdata->on = mdp_on; pdata->off = mdp_off; + pdata->late_init = NULL; pdata->next = pdev; mdp_clk_ctrl(1); @@ -2586,6 +2746,9 @@ static int mdp_probe(struct platform_device *pdev) mdp_vsync_resync_workqueue_handler); mfd->hw_refresh = FALSE; + if (mfd->panel.type == MDDI_PANEL) + mdp4_mddi_rdptr_init(0); + if (mfd->panel.type == EXT_MDDI_PANEL) { /* 15 fps -> 66 msec */ mfd->refresh_timer_duration = (66 * HZ / 1000); @@ -2672,10 +2835,13 @@ static int mdp_probe(struct platform_device *pdev) pdata->off = mdp_dsi_video_off; mfd->hw_refresh = TRUE; mfd->dma_fnc = mdp_dsi_video_update; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; mfd->stop_histogram = mdp_histogram_stop; mfd->vsync_ctrl = mdp_dma_video_vsync_ctrl; + mfd->vsync_show = mdp_dma_video_show_event; if (mfd->panel_info.pdest == DISPLAY_1) mfd->dma = &dma2_data; else { @@ -2710,7 +2876,6 @@ static int mdp_probe(struct platform_device *pdev) mfd->start_histogram = mdp_histogram_start; mfd->stop_histogram = mdp_histogram_stop; mdp4_display_intf_sel(if_no, DSI_CMD_INTF); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); spin_lock_irqsave(&mdp_spin_lock, flag); mdp_intr_mask |= INTR_OVERLAY0_DONE; @@ -2718,12 +2883,12 @@ static int mdp_probe(struct platform_device *pdev) spin_unlock_irqrestore(&mdp_spin_lock, flag); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); #else - mfd->dma_fnc = mdp_dma2_update; mfd->do_histogram = mdp_do_histogram; mfd->start_histogram = mdp_histogram_start; mfd->stop_histogram = mdp_histogram_stop; mfd->vsync_ctrl = mdp_dma_vsync_ctrl; + mfd->vsync_show = mdp_dma_show_event; if (mfd->panel_info.pdest == DISPLAY_1) mfd->dma = &dma2_data; else { @@ -2746,9 +2911,12 @@ static int mdp_probe(struct platform_device *pdev) pdata->on = mdp4_dtv_on; pdata->off = mdp4_dtv_off; mfd->hw_refresh = TRUE; - mfd->cursor_update = mdp_hw_cursor_update; + mfd->cursor_update = mdp_hw_cursor_sync_update; mfd->dma_fnc = mdp4_dtv_overlay; mfd->dma = &dma_e_data; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; + mfd->stop_histogram = mdp_histogram_stop; mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF); break; #endif @@ -2790,6 +2958,7 @@ static int mdp_probe(struct platform_device *pdev) #else mfd->dma = &dma2_data; mfd->vsync_ctrl = mdp_dma_lcdc_vsync_ctrl; + mfd->vsync_show = mdp_dma_lcdc_show_event; spin_lock_irqsave(&mdp_spin_lock, flag); mdp_intr_mask &= ~MDP_DMA_P_DONE; outp32(MDP_INTR_ENABLE, mdp_intr_mask); @@ -2829,6 +2998,7 @@ static int mdp_probe(struct platform_device *pdev) mdp_clk_ctrl(0); return -ENODEV; } + mdp4_wfd_init(0); pdata->on = mdp4_overlay_writeback_on; pdata->off = mdp4_overlay_writeback_off; mfd->dma_fnc = mdp4_writeback_overlay; @@ -2850,25 +3020,21 @@ static int mdp_probe(struct platform_device *pdev) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } + frame_rate = mdp_get_panel_framerate(mfd); + if (frame_rate) { + mfd->panel_info.frame_interval = 1000 / frame_rate; + mfd->cpu_pm_hdl = add_event_timer(NULL, (void *)mfd); + } mdp_clk_ctrl(0); #ifdef CONFIG_MSM_BUS_SCALING - if (!mdp_bus_scale_handle && mdp_pdata && - mdp_pdata->mdp_bus_scale_table) { - mdp_bus_scale_handle = - msm_bus_scale_register_client( - mdp_pdata->mdp_bus_scale_table); - if (!mdp_bus_scale_handle) { - printk(KERN_ERR "%s not able to get bus scale\n", - __func__); - return -ENOMEM; - } - } + if (mdp_bus_scale_register()) + return -ENOMEM; /* req bus bandwidth immediately */ if (!(mfd->cont_splash_done)) - mdp_bus_scale_update_request(5); - + mdp_bus_scale_update_request + (MDP_BUS_SCALE_INIT, MDP_BUS_SCALE_INIT); #endif /* set driver data */ @@ -2884,9 +3050,13 @@ static int mdp_probe(struct platform_device *pdev) pdev_list[pdev_list_cnt++] = pdev; mdp4_extn_disp = 0; - - if (mfd->vsync_init != NULL) { - mfd->vsync_init(0); + /* + * vsync_init call not required for mdp3. + * vsync_init call required for mdp4 targets. + */ + if ((mfd->vsync_init != NULL) || (mdp_rev < MDP_REV_40)) { + if (mdp_rev >= MDP_REV_40) + mfd->vsync_init(0); if (!mfd->vsync_sysfs_created) { mfd->dev_attr.attr.name = "vsync_event"; @@ -2912,8 +3082,7 @@ static int mdp_probe(struct platform_device *pdev) mdp_probe_err: platform_device_put(msm_fb_dev); #ifdef CONFIG_MSM_BUS_SCALING - if (mdp_pdata && mdp_pdata->mdp_bus_scale_table && - mdp_bus_scale_handle > 0) + if (mdp_bus_scale_handle > 0) msm_bus_scale_unregister_client(mdp_bus_scale_handle); #endif return rc; @@ -2928,6 +3097,17 @@ void mdp_footswitch_ctrl(boolean on) return; } + if (dsi_pll_vddio) + regulator_enable(dsi_pll_vddio); + + if (dsi_pll_vdda) + regulator_enable(dsi_pll_vdda); + + mipi_dsi_prepare_clocks(); + mipi_dsi_ahb_ctrl(1); + mipi_dsi_phy_ctrl(1); + mipi_dsi_clk_enable(); + if (on && !mdp_footswitch_on) { pr_debug("Enable MDP FS\n"); regulator_enable(footswitch); @@ -2938,20 +3118,21 @@ void mdp_footswitch_ctrl(boolean on) mdp_footswitch_on = 0; } - mutex_unlock(&mdp_suspend_mutex); -} + mipi_dsi_clk_disable(); + mipi_dsi_phy_ctrl(0); + mipi_dsi_ahb_ctrl(0); + mipi_dsi_unprepare_clocks(); -void mdp_free_splash_buffer(struct msm_fb_data_type *mfd) -{ - if (mfd->copy_splash_buf) { - dma_free_coherent(NULL, mdp_pdata->splash_screen_size, - mfd->copy_splash_buf, - (dma_addr_t) mfd->copy_splash_phys); + if (dsi_pll_vdda) + regulator_disable(dsi_pll_vdda); - mfd->copy_splash_buf = NULL; - } + if (dsi_pll_vddio) + regulator_disable(dsi_pll_vddio); + + mutex_unlock(&mdp_suspend_mutex); } + #ifdef CONFIG_PM static void mdp_suspend_sub(void) { @@ -2994,6 +3175,7 @@ static void mdp_early_suspend(struct early_suspend *h) { mdp_suspend_sub(); #ifdef CONFIG_FB_MSM_DTV + mdp4_solidfill_commit(MDP4_MIXER1); mdp4_dtv_set_black_screen(); #endif mdp_footswitch_ctrl(FALSE); @@ -3021,8 +3203,7 @@ static int mdp_remove(struct platform_device *pdev) iounmap(msm_mdp_base); pm_runtime_disable(&pdev->dev); #ifdef CONFIG_MSM_BUS_SCALING - if (mdp_pdata && mdp_pdata->mdp_bus_scale_table && - mdp_bus_scale_handle > 0) + if (mdp_bus_scale_handle > 0) msm_bus_scale_unregister_client(mdp_bus_scale_handle); #endif return 0; diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h index 09d7bc82..ba8b5024 100644 --- a/drivers/video/msm/mdp.h +++ b/drivers/video/msm/mdp.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #ifdef CONFIG_MSM_BUS_SCALING #include @@ -44,6 +44,7 @@ extern spinlock_t mdp_spin_lock; extern int mdp_rev; extern int mdp_iommu_split_domain; extern struct mdp_csc_cfg mdp_csc_convert[4]; +extern struct mdp_csc_cfg_data csc_cfg_matrix[]; extern struct workqueue_struct *mdp_hist_wq; extern uint32 mdp_intr_mask; @@ -739,7 +740,9 @@ extern struct mdp_hist_mgmt *mdp_hist_mgmt_array[]; #define MDP_DMA_P_LUT_C2_EN BIT(2) #define MDP_DMA_P_LUT_POST BIT(4) -void mdp_hw_init(int cont_splash); + +void mdp_hw_init(void); + int mdp_ppp_pipe_wait(void); void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd); void mdp_clk_ctrl(int on); @@ -785,8 +788,6 @@ int mdp_lcdc_on(struct platform_device *pdev); int mdp_lcdc_off(struct platform_device *pdev); void mdp_lcdc_update(struct msm_fb_data_type *mfd); -void mdp_free_splash_buffer(struct msm_fb_data_type *mfd); - #ifdef CONFIG_FB_MSM_MDP303 int mdp_dsi_video_on(struct platform_device *pdev); int mdp_dsi_video_off(struct platform_device *pdev); @@ -804,6 +805,10 @@ static inline int mdp4_lcdc_off(struct platform_device *pdev) { return 0; } +static inline int mdp4_mddi_off(struct platform_device *pdev) +{ + return 0; +} static inline int mdp4_dsi_cmd_on(struct platform_device *pdev) { return 0; @@ -816,6 +821,19 @@ static inline int mdp4_lcdc_on(struct platform_device *pdev) { return 0; } +static inline int mdp4_mddi_on(struct platform_device *pdev) +{ + return 0; +} +#endif + + +#ifndef CONFIG_FB_MSM_MDDI +static inline void mdp4_mddi_rdptr_init(int cndx) +{ + /* empty */ +} + #endif void set_cont_splashScreen_status(int); @@ -840,12 +858,12 @@ int mdp_set_core_clk(u32 rate); int mdp_clk_round_rate(u32 rate); unsigned long mdp_get_core_clk(void); -unsigned long mdp_perf_level2clk_rate(uint32 perf_level); #ifdef CONFIG_MSM_BUS_SCALING -int mdp_bus_scale_update_request(uint32_t index); +int mdp_bus_scale_update_request(u64 ab, u64 ib); #else -static inline int mdp_bus_scale_update_request(uint32_t index) +static inline int mdp_bus_scale_update_request(u64 ab, + u64 ib) { return 0; } @@ -853,6 +871,12 @@ static inline int mdp_bus_scale_update_request(uint32_t index) void mdp_dma_vsync_ctrl(int enable); void mdp_dma_video_vsync_ctrl(int enable); void mdp_dma_lcdc_vsync_ctrl(int enable); +ssize_t mdp_dma_show_event(struct device *dev, + struct device_attribute *attr, char *buf); +ssize_t mdp_dma_video_show_event(struct device *dev, + struct device_attribute *attr, char *buf); +ssize_t mdp_dma_lcdc_show_event(struct device *dev, + struct device_attribute *attr, char *buf); #ifdef MDP_HW_VSYNC void vsync_clk_prepare_enable(void); @@ -912,9 +936,12 @@ static inline int msmfb_overlay_vsync_ctrl(struct fb_info *info, int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req); int mdp_ppp_v4l2_overlay_clear(void); -int mdp_ppp_v4l2_overlay_play(struct fb_info *info, +int mdp_ppp_v4l2_overlay_play(struct fb_info *info, bool bUserPtr, unsigned long srcp0_addr, unsigned long srcp0_size, unsigned long srcp1_addr, unsigned long srcp1_size); +void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync); + +u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd); #ifdef CONFIG_FB_MSM_DTV void mdp_vid_quant_set(void); diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h index 7a18e62a..9d93b26a 100644 --- a/drivers/video/msm/mdp4.h +++ b/drivers/video/msm/mdp4.h @@ -28,6 +28,14 @@ extern uint32 mdp4_extn_disp; extern char *mmss_cc_base; /* mutimedia sub system clock control */ extern spinlock_t dsi_clk_lock; extern u32 mdp_max_clk; +extern u32 dbg_force_ov0_blt; +extern u32 dbg_force_ov1_blt; + +extern u64 mdp_max_bw; +#define MDP4_BW_AB_FACTOR (115) /* 1.15 */ +#define MDP4_BW_IB_FACTOR (125) /* 1.25 */ +#define MDP_BUS_SCALE_AB_STEP (0x4000000) +#define MDP_BUS_SCALE_INIT (0x10000000) #define MDP4_OVERLAYPROC0_BASE 0x10000 #define MDP4_OVERLAYPROC1_BASE 0x18000 @@ -35,6 +43,7 @@ extern u32 mdp_max_clk; #define MDP4_VIDEO_BASE 0x20000 #define MDP4_VIDEO_OFF 0x10000 +#define MDP4_VIDEO_CSC_OFF 0x4000 #define MDP4_RGB_BASE 0x40000 #define MDP4_RGB_OFF 0x10000 @@ -43,13 +52,6 @@ extern u32 mdp_max_clk; #define CS_CONTROLLER_0 0x0707ffff #define CS_CONTROLLER_1 0x03073f3f -enum { - OVERLAY_PERF_LEVEL1 = 1, - OVERLAY_PERF_LEVEL2, - OVERLAY_PERF_LEVEL3, - OVERLAY_PERF_LEVEL4 -}; - typedef int (*cmd_fxn_t)(struct platform_device *pdev); enum { /* display */ @@ -92,11 +94,6 @@ enum { #define MDP4_PANEL_DSI_CMD BIT(5) #define MDP4_PANEL_WRITEBACK BIT(6) -enum { - OVERLAY_MODE_NONE, - OVERLAY_MODE_BLT -}; - enum { OVERLAY_REFRESH_ON_DEMAND, OVERLAY_REFRESH_VSYNC, @@ -182,6 +179,8 @@ enum { MDP4_CHROMA_420 }; +#define CSC_MAX_BLOCKS 6 + #define MDP4_BLEND_BG_TRANSP_EN BIT(9) #define MDP4_BLEND_FG_TRANSP_EN BIT(8) #define MDP4_BLEND_BG_MOD_ALPHA BIT(7) @@ -210,6 +209,7 @@ enum { #define MDP4_OP_FLIP_UD BIT(14) #define MDP4_OP_FLIP_LR BIT(13) #define MDP4_OP_CSC_EN BIT(11) +#define MDP4_OP_DST_DATA_YCBCR BIT(10) #define MDP4_OP_SRC_DATA_YCBCR BIT(9) #define MDP4_OP_SCALEY_FIR (0 << 4) #define MDP4_OP_SCALEY_MN_PHASE (1 << 4) @@ -233,6 +233,12 @@ enum { #define MDP4_MAX_PLANE 4 #define VSYNC_PERIOD 16 +#ifdef BLT_RGB565 +#define BLT_BPP 2 +#else +#define BLT_BPP 3 +#endif + struct mdp4_hsic_regs { int32_t params[NUM_HSIC_PARAM]; int32_t conv_matrix[3][3]; @@ -270,6 +276,7 @@ struct blend_cfg { struct mdp4_overlay_pipe *solidfill_pipe; }; + struct mdp4_overlay_pipe { uint32 pipe_used; uint32 pipe_type; /* rgb, video/graphic */ @@ -302,10 +309,16 @@ struct mdp4_overlay_pipe { uint32 is_fg; /* control alpha & color key */ uint32 srcp0_addr; /* interleave, luma */ uint32 srcp0_ystride; + struct file *srcp0_file; + int put0_need; uint32 srcp1_addr; /* pseudoplanar, chroma plane */ uint32 srcp1_ystride; + struct file *srcp1_file; + int put1_need; uint32 srcp2_addr; /* planar color 2*/ uint32 srcp2_ystride; + struct file *srcp2_file; + int put2_need; uint32 srcp3_addr; /* alpha/color 3 */ uint32 srcp3_ystride; uint32 fetch_plane; @@ -345,15 +358,16 @@ struct mdp4_overlay_pipe { uint32 ov_cnt; uint32 dmap_cnt; uint32 dmae_cnt; - uint32 blt_end; + uint32 blt_end; /* used by mddi only */ uint32 blt_ov_koff; uint32 blt_ov_done; uint32 blt_dmap_koff; uint32 blt_dmap_done; uint32 req_clk; - uint32 req_bw; + uint64 bw_ab_quota; + uint64 bw_ib_quota; uint32 luma_align_size; - struct mdp4_hsic_regs hsic_regs; + struct mdp_overlay_pp_params pp_cfg; struct mdp_overlay req_data; struct completion comp; struct completion dmas_comp; @@ -383,6 +397,7 @@ struct mdp4_statistic { ulong intr_dsi_err; ulong kickoff_ov0; ulong kickoff_ov1; + ulong kickoff_ov2; ulong kickoff_dmap; ulong kickoff_dmae; ulong kickoff_dmas; @@ -438,15 +453,11 @@ void mdp4_lcdc_update(struct msm_fb_data_type *mfd); void mdp4_intr_clear_set(ulong clear, ulong set); void mdp4_dma_p_cfg(void); unsigned is_mdp4_hw_reset(void); -void mdp4_overlay_cfg_init(void); void mdp4_hw_init(void); void mdp4_isr_read(int); void mdp4_clear_lcdc(void); void mdp4_mixer_blend_init(int mixer_num); void mdp4_vg_qseed_init(int vg_num); -void mdp4_vg_csc_setup(int vp_num); -void mdp4_mixer_csc_setup(uint32 mixer); -void mdp4_dmap_csc_setup(void); void mdp4_vg_csc_update(struct mdp_csc *p); irqreturn_t mdp4_isr(int irq, void *ptr); void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe); @@ -542,12 +553,9 @@ void mdp4_overlay0_done_dsi_video(int cndx); void mdp4_overlay0_done_dsi_cmd(int cndx); void mdp4_primary_rdptr(void); void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd); -int mdp4_overlay_commit(struct fb_info *info, int mixer); -int mdp4_dsi_video_pipe_commit(void); -int mdp4_dsi_cmd_pipe_commit(void); +int mdp4_lcdc_pipe_commit(int cndx, int wait); +int mdp4_dtv_pipe_commit(int cndx, int wait); int mdp4_dsi_cmd_update_cnt(int cndx); -int mdp4_lcdc_pipe_commit(void); -int mdp4_dtv_pipe_commit(void); void mdp4_dsi_rdptr_init(int cndx); void mdp4_dsi_vsync_init(int cndx); void mdp4_lcdc_vsync_init(int cndx); @@ -584,9 +592,11 @@ int mdp4_overlay_unset_mixer(int mixer); int mdp4_overlay_play_wait(struct fb_info *info, struct msmfb_overlay_data *req); int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req); +int mdp4_overlay_commit(struct fb_info *info); struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer); void mdp4_overlay_dma_commit(int mixer); void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe); +void mdp4_solidfill_commit(int mixer); void mdp4_mixer_stage_commit(int mixer); void mdp4_dsi_cmd_do_update(int cndx, struct mdp4_overlay_pipe *pipe); void mdp4_lcdc_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe); @@ -596,12 +606,13 @@ void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc); void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe); void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv); void mdp4_overlay_dmae_xy(struct mdp4_overlay_pipe *pipe); -int mdp4_overlay_pipe_staged(int mixer); +int mdp4_overlay_pipe_staged(struct mdp4_overlay_pipe *pipe); void mdp4_lcdc_primary_vsyn(void); void mdp4_overlay0_done_lcdc(int cndx); -void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma); +void mdp4_overlay0_done_mddi(int cndx); void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma); void mdp4_dmap_done_dsi_cmd(int cndx); +void mdp4_dmap_done_mddi(int cndx); void mdp4_dmap_done_dsi_video(int cndx); void mdp4_dmap_done_lcdc(int cndx); void mdp4_overlay1_done_dtv(void); @@ -612,6 +623,7 @@ void mdp4_lcdc_wait4vsync(int cndx, long long *vtime); void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd, struct mdp4_overlay_pipe *pipe); void mdp4_mddi_overlay_dmas_restore(void); +void mdp4_dtv_set_avparams(struct mdp4_overlay_pipe *pipe, int id); #ifndef CONFIG_FB_MSM_MIPI_DSI void mdp4_mddi_dma_busy_wait(struct msm_fb_data_type *mfd); @@ -675,6 +687,12 @@ void mdp4_dsi_cmd_overlay_blt(struct msm_fb_data_type *mfd, void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req); void mdp4_dsi_video_base_swap(int cndx, struct mdp4_overlay_pipe *pipe); +static inline void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd) +{ +} +static inline void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd) +{ +} #ifdef CONFIG_FB_MSM_MDP40 static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd) @@ -683,6 +701,8 @@ static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd) } #endif #else /* CONFIG_FB_MSM_MIPI_DSI */ +void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd); +void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd); int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req); void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd, @@ -690,6 +710,7 @@ void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd, int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd); int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd); void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd); +void mdp4_mddi_rdptr_init(int cndx); static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd) { return -ENODEV; @@ -728,11 +749,9 @@ static inline void mdp4_dsi_video_base_swap(int cndx, } static inline void mdp4_dsi_cmd_blt_start(struct msm_fb_data_type *mfd) { - /* empty */ } static inline void mdp4_dsi_cmd_blt_stop(struct msm_fb_data_type *mfd) { - /* empty */ } #endif /* CONFIG_FB_MSM_MIPI_DSI */ @@ -772,6 +791,8 @@ void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime); void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime); void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe); void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe); +int mdp4_dsi_video_pipe_commit(int cndx, int wait); +int mdp4_dsi_cmd_pipe_commit(int cndx, int wait); void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable); void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable); #ifdef CONFIG_FB_MSM_MDP303 @@ -779,11 +800,37 @@ static inline void mdp4_dsi_cmd_del_timer(void) { /* empty */ } -#else /* CONFIG_FB_MSM_MIPI_DSI */ +#else /* CONFIG_FB_MSM_MDP303 */ void mdp4_dsi_cmd_del_timer(void); +static inline int mdp4_mddi_on(struct platform_device *pdev) +{ + return 0; +} +static inline int mdp4_mddi_off(struct platform_device *pdev) +{ + return 0; +} +static inline void mdp4_mddi_wait4vsync(int cndx, long long *vtime) +{ +} +static inline void mdp4_mddi_vsync_ctrl(struct fb_info *info, + int enable) +{ +} +static inline void mdp4_mddi_pipe_queue(int cndx, + struct mdp4_overlay_pipe *pipe) +{ +} #endif #else /* CONFIG_FB_MSM_MIPI_DSI */ +int mdp4_mddi_off(struct platform_device *pdev); +int mdp4_mddi_on(struct platform_device *pdev); +void mdp4_mddi_wait4vsync(int cndx, long long *vtime); +void mdp4_mddi_vsync_ctrl(struct fb_info *info, int enable); +void mdp4_mddi_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe); +void mdp4_overlay_update_mddi(struct msm_fb_data_type *mfd); + static inline int mdp4_dsi_cmd_on(struct platform_device *pdev) { return 0; @@ -821,8 +868,16 @@ static inline void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe) { } +static inline int mdp4_dsi_video_pipe_commit(int cndx, int wait) +{ + return 0; +} +static inline int mdp4_dsi_cmd_pipe_commit(int cndx, int wait) +{ + return 0; +} static inline void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, - int enable) + int enable) { } static inline void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, @@ -879,10 +934,7 @@ int mdp4_overlay_borderfill_supported(void); int mdp4_overlay_writeback_on(struct platform_device *pdev); int mdp4_overlay_writeback_off(struct platform_device *pdev); void mdp4_writeback_overlay(struct msm_fb_data_type *mfd); -void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe); -void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd); -void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma); +void mdp4_overlay2_done_wfd(struct mdp_dma_data *dma); int mdp4_writeback_start(struct fb_info *info); int mdp4_writeback_stop(struct fb_info *info); @@ -893,11 +945,11 @@ int mdp4_writeback_queue_buffer(struct fb_info *info, void mdp4_writeback_dma_stop(struct msm_fb_data_type *mfd); int mdp4_writeback_init(struct fb_info *info); int mdp4_writeback_terminate(struct fb_info *info); +int mdp4_writeback_set_mirroring_hint(struct fb_info *info, int hint); uint32_t mdp_block2base(uint32_t block); int mdp_hist_lut_config(struct mdp_hist_lut_data *data); -void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl); void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe); int mdp4_csc_config(struct mdp_csc_cfg_data *config); void mdp4_csc_write(struct mdp_csc_cfg *data, uint32_t base); @@ -905,6 +957,8 @@ int mdp4_csc_enable(struct mdp_csc_cfg_data *config); int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr); int mdp4_argc_cfg(struct mdp_pgc_lut_data *pgc_ptr); int mdp4_qseed_cfg(struct mdp_qseed_cfg_data *cfg); +int mdp4_calib_config(struct mdp_calib_config_data *cfg); +int mdp4_qseed_access_cfg(struct mdp_qseed_cfg *cfg, uint32_t base); u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); @@ -922,13 +976,37 @@ void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe); int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe, unsigned long srcp0_addr, unsigned long srcp1_addr, unsigned long srcp2_addr); - int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe, struct msm_fb_data_type *mfd); +int mdp4_calc_blt_mdp_bw(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *plist); + struct mdp4_overlay_pipe *plist); void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag); int mdp4_update_base_blend(struct msm_fb_data_type *mfd, struct mdp_blend_cfg *mdp_blend_cfg); +int mdp4_update_writeback_format(struct msm_fb_data_type *mfd, + struct mdp_mixer_cfg *mdp_mixer_cfg); u32 mdp4_get_mixer_num(u32 panel_type); + +#ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL +static inline void mdp4_wfd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe) +{ + /* empty */ +} +static inline void mdp4_wfd_init(int cndx) +{ + /* empty */ +} +static inline int mdp4_wfd_pipe_commit(struct msm_fb_data_type *mfd, + int cndx, int wait) +{ + return 0; +} +#else +void mdp4_wfd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe); +void mdp4_wfd_init(int cndx); +int mdp4_wfd_pipe_commit(struct msm_fb_data_type *mfd, int cndx, int wait); +#endif + #endif /* MDP_H */ diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c index 6c9d81e0..ba810a9d 100644 --- a/drivers/video/msm/mdp4_dtv.c +++ b/drivers/video/msm/mdp4_dtv.c @@ -38,6 +38,7 @@ static int dtv_remove(struct platform_device *pdev); static int dtv_off(struct platform_device *pdev); static int dtv_on(struct platform_device *pdev); +static int dtv_off_sub(void); static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; static int pdev_list_cnt; @@ -45,6 +46,9 @@ static int pdev_list_cnt; static struct clk *tv_src_clk; static struct clk *hdmi_clk; static struct clk *mdp_tv_clk; +static struct platform_device *dtv_pdev; +static struct workqueue_struct *dtv_work_queue; +static struct work_struct dtv_off_work; static int mdp4_dtv_runtime_suspend(struct device *dev) @@ -86,8 +90,48 @@ static struct clk *ebi1_clk; static int dtv_off(struct platform_device *pdev) { int ret = 0; + struct msm_fb_data_type *mfd = NULL; - ret = panel_next_off(pdev); + if (!pdev) { + pr_err("%s: FAILED: invalid arg\n", __func__); + return -EINVAL; + } + + mfd = platform_get_drvdata(pdev); + if (!mfd) { + pr_err("%s: FAILED: invalid mfd\n", __func__); + return -EINVAL; + } + + dtv_pdev = pdev; + /* + * If it's a suspend operation then handle the device + * power down synchronously. + * Otherwise, queue work item to handle power down sequence. + * This is needed since we need to wait for the audio engine + * to shutdown first before we turn off the DTV device. + */ + if (!mfd->suspend.op_suspend) { + pr_debug("%s: Queuing work to turn off HDMI core\n", __func__); + queue_work(dtv_work_queue, &dtv_off_work); + } else { + pr_debug("%s: turning off HDMI core\n", __func__); + ret = dtv_off_sub(); + } + + return ret; +} + +static int dtv_off_sub(void) +{ + int ret = 0; + + if (!dtv_pdev) { + pr_err("%s: FAILED: invalid arg\n", __func__); + return -EINVAL; + } + + ret = panel_next_off(dtv_pdev); pr_info("%s\n", __func__); @@ -112,12 +156,20 @@ static int dtv_off(struct platform_device *pdev) return ret; } +static void dtv_off_work_func(struct work_struct *work) +{ + dtv_off_sub(); +} + static int dtv_on(struct platform_device *pdev) { int ret = 0; struct msm_fb_data_type *mfd; unsigned long panel_pixclock_freq , pm_qos_rate; + /* If a power down is already underway, wait for it to finish */ + flush_work_sync(&dtv_off_work); + mfd = platform_get_drvdata(pdev); panel_pixclock_freq = mfd->fbi->var.pixclock; @@ -215,6 +267,8 @@ static int dtv_probe(struct platform_device *pdev) return 0; } + dtv_work_queue = create_singlethread_workqueue("dtv_work"); + INIT_WORK(&dtv_off_work, dtv_off_work_func); mfd = platform_get_drvdata(pdev); if (!mfd) @@ -302,6 +356,8 @@ static int dtv_probe(struct platform_device *pdev) static int dtv_remove(struct platform_device *pdev) { + if (dtv_work_queue) + destroy_workqueue(dtv_work_queue); #ifdef CONFIG_MSM_BUS_SCALING if (dtv_pdata && dtv_pdata->bus_scale_table && dtv_bus_scale_handle > 0) diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c index e1209d2c..9e174306 100644 --- a/drivers/video/msm/mdp4_overlay.c +++ b/drivers/video/msm/mdp4_overlay.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -48,11 +47,12 @@ struct mdp4_overlay_ctrl { struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX]; struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX]; struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX]; + struct mdp4_overlay_pipe sf_plist[MDP4_MIXER_MAX][OVERLAY_PIPE_MAX]; + struct mdp_mixer_cfg mdp_mixer_cfg[MDP4_MIXER_MAX]; uint32 mixer_cfg[MDP4_MIXER_MAX]; uint32 flush[MDP4_MIXER_MAX]; struct iommu_free_list iommu_free[MDP4_MIXER_MAX]; uint32 cs_controller; - uint32 hw_version; uint32 panel_3d; uint32 panel_mode; uint32 mixer0_played; @@ -107,20 +107,19 @@ static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db; struct mdp4_overlay_perf { u32 mdp_clk_rate; - u32 use_ov0_blt; - u32 use_ov1_blt; - u32 mdp_bw; + u32 use_ov_blt[MDP4_MIXER_MAX]; + u64 mdp_ov_ab_bw[MDP4_MIXER_MAX]; + u64 mdp_ov_ib_bw[MDP4_MIXER_MAX]; + u32 mdp_ab_bw; + u32 mdp_ib_bw; }; -struct mdp4_overlay_perf perf_request = { - .mdp_bw = OVERLAY_PERF_LEVEL4, -}; -struct mdp4_overlay_perf perf_current = { - .mdp_bw = OVERLAY_PERF_LEVEL4, -}; +struct mdp4_overlay_perf perf_request; +struct mdp4_overlay_perf perf_current; static struct ion_client *display_iclient; +static void mdp4_overlay_bg_solidfill(struct blend_cfg *blend); /* * mdp4_overlay_iommu_unmap_freelist() @@ -191,6 +190,26 @@ void mdp4_overlay_iommu_pipe_free(int ndx, int all) if (pipe == NULL) return; + if (pipe->flags & MDP_MEMORY_ID_TYPE_FB) { + pipe->flags &= ~MDP_MEMORY_ID_TYPE_FB; + if (pipe->put0_need) { + fput_light(pipe->srcp0_file, pipe->put0_need); + pipe->put0_need = 0; + } + if (pipe->put1_need) { + fput_light(pipe->srcp1_file, pipe->put1_need); + pipe->put1_need = 0; + } + if (pipe->put2_need) { + fput_light(pipe->srcp2_file, pipe->put2_need); + pipe->put2_need = 0; + } + + pr_debug("%s: ndx=%d flags=%x put=%d\n", __func__, + pipe->pipe_ndx, pipe->flags, pipe->put0_need); + return; + } + mutex_lock(&iommu_mutex); mixer = pipe->mixer_num; iom = &pipe->iommu; @@ -226,12 +245,12 @@ int mdp4_overlay_iommu_map_buf(int mem_id, return PTR_ERR(*srcp_ihdl); } pr_debug("%s(): ion_hdl %p, ion_buf %d\n", __func__, *srcp_ihdl, - ion_share_dma_buf(display_iclient, *srcp_ihdl)); + mem_id); pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num, pipe->pipe_ndx, plane); if (ion_map_iommu(display_iclient, *srcp_ihdl, DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start, - len, 0, ION_IOMMU_UNMAP_DELAYED)) { + len, 0, 0)) { ion_free(display_iclient, *srcp_ihdl); pr_err("ion_map_iommu() failed\n"); return -EINVAL; @@ -332,23 +351,9 @@ uint32 mdp4_overlay_panel_list(void) return ctrl->panel_mode; } -void mdp4_overlay_cfg_init(void) -{ - if (ctrl->hw_version == 0) { - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); - } - - if (ctrl->hw_version >= 0x0402030b) { - /* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */ - outpdw(MDP_BASE + 0x100fc, 0x01); - } -} - int mdp4_overlay_borderfill_supported(void) { - return (ctrl->hw_version >= 0x0402030b); + return (mdp_rev >= MDP_REV_42); } void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv) @@ -396,53 +401,34 @@ void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } -#ifdef CONFIG_FB_MSM_HDMI_3D -void unfill_black_screen(void) { return; } -#else -void unfill_black_screen(void) +void fill_black_screen(bool on, uint8 pipe_num, uint8 mixer_num) { - uint32 temp_src_format; - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - /* - * VG2 Constant Color - */ - temp_src_format = inpdw(MDP_BASE + 0x30050); - MDP_OUTP(MDP_BASE + 0x30050, temp_src_format&(~BIT(22))); - /* - * MDP_OVERLAY_REG_FLUSH - */ - MDP_OUTP(MDP_BASE + 0x18000, BIT(3)); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); - return; -} -#endif + uint32 reg_base = 0x010000; + uint32 const_color_reg = reg_base * (pipe_num + 2) + 0x1008; + uint32 src_fmt_reg = reg_base * (pipe_num + 2) + 0x50; + uint32 color = 0x00000000; + uint32 temp_src_format = 0x00000000; + uint8 bit = pipe_num + 2; -#ifdef CONFIG_FB_MSM_HDMI_3D -void fill_black_screen(void) { return; } -#else -void fill_black_screen(void) -{ - /*Black color*/ - uint32 color = 0x00000000; - uint32 temp_src_format; mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - /* - * VG2 Constant Color - */ - MDP_OUTP(MDP_BASE + 0x31008, color); - /* - * MDP_VG2_SRC_FORMAT - */ - temp_src_format = inpdw(MDP_BASE + 0x30050); - MDP_OUTP(MDP_BASE + 0x30050, temp_src_format | BIT(22)); - /* - * MDP_OVERLAY_REG_FLUSH - */ - MDP_OUTP(MDP_BASE + 0x18000, BIT(3)); + + /* Fill constant color */ + MDP_OUTP(MDP_BASE + const_color_reg, color); + + /* Update source format for pipe */ + temp_src_format = inpdw(MDP_BASE + src_fmt_reg); + + if (on) + MDP_OUTP(MDP_BASE + src_fmt_reg, temp_src_format | BIT(22)); + else + MDP_OUTP(MDP_BASE + src_fmt_reg, temp_src_format | (~BIT(22))); + + /* MDP_OVERLAY_REG_FLUSH for pipe*/ + MDP_OUTP(MDP_BASE + 0x18000, BIT(bit) | BIT(mixer_num)); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return; } -#endif void mdp4_overlay_dmae_xy(struct mdp4_overlay_pipe *pipe) { @@ -492,14 +478,18 @@ void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc) dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; - if (mfd->panel_info.bpp == 18) { + if ((mfd->panel_info.type == MIPI_CMD_PANEL) || + (mfd->panel_info.type == MIPI_VIDEO_PANEL)) { + dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 24BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } else if (mfd->panel_info.bpp == 18) { dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; } else if (mfd->panel_info.bpp == 16) { dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; } else { - dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ + dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 24BPP */ DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; } @@ -713,8 +703,14 @@ void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe) op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN); op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN); outpdw(rgb_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */ - } else + } else { + if (pipe->op_mode & MDP4_OP_FLIP_LR && mdp_rev >= MDP_REV_42) { + /* Enable x-scaling bit to enable LR flip */ + /* for MDP > 4.2 targets */ + pipe->op_mode |= 0x01; + } outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + } outpdw(rgb_base + 0x005c, pipe->phasex_step); outpdw(rgb_base + 0x0060, pipe->phasey_step); @@ -731,41 +727,62 @@ static void mdp4_overlay_vg_get_src_offset(struct mdp4_overlay_pipe *pipe, *luma_off = 0; *chroma_off = 0; - if (pipe->src_x && (pipe->frame_format == + if ((pipe->src_x || pipe->src_y) && (pipe->frame_format == MDP4_FRAME_FORMAT_LINEAR)) { - src_xy = (pipe->src_y << 16) | pipe->src_x; - src_xy &= 0xffff0000; + src_xy = 0; outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ switch (pipe->src_format) { case MDP_Y_CR_CB_H2V2: case MDP_Y_CR_CB_GH2V2: case MDP_Y_CB_CR_H2V2: - *luma_off = pipe->src_x; - *chroma_off = pipe->src_x/2; + *luma_off = pipe->src_x + + (pipe->src_y * pipe->srcp0_ystride); + *chroma_off = pipe->src_x / 2 + + ((pipe->src_y / 2) * pipe->srcp1_ystride); break; case MDP_Y_CBCR_H2V2_TILE: case MDP_Y_CRCB_H2V2_TILE: case MDP_Y_CBCR_H2V2: case MDP_Y_CRCB_H2V2: + *luma_off = pipe->src_x + + (pipe->src_y * pipe->srcp0_ystride); + *chroma_off = pipe->src_x + + ((pipe->src_y / 2) * pipe->srcp1_ystride); + break; + case MDP_Y_CRCB_H1V1: case MDP_Y_CBCR_H1V1: + *luma_off = pipe->src_x + + (pipe->src_y * pipe->srcp0_ystride); + *chroma_off = pipe->src_x + + ((pipe->src_y * 2) * pipe->srcp1_ystride); + break; + case MDP_Y_CRCB_H2V1: case MDP_Y_CBCR_H2V1: - *luma_off = pipe->src_x; - *chroma_off = pipe->src_x; + case MDP_Y_CRCB_H1V2: + case MDP_Y_CBCR_H1V2: + *luma_off = pipe->src_x + + (pipe->src_y * pipe->srcp0_ystride); + *chroma_off = pipe->src_x + + (pipe->src_y * pipe->srcp1_ystride); break; + case MDP_YCBYCR_H2V1: case MDP_YCRYCB_H2V1: + case MDP_CBYCRY_H2V1: if (pipe->src_x & 0x1) pipe->src_x += 1; - *luma_off += pipe->src_x * 2; + *luma_off += pipe->src_x * 2 + + ((pipe->src_y * 2) * pipe->srcp0_ystride); break; case MDP_ARGB_8888: case MDP_RGBA_8888: case MDP_BGRA_8888: + case MDP_BGRX_8888: case MDP_RGBX_8888: case MDP_RGB_565: case MDP_BGR_565: @@ -773,7 +790,8 @@ static void mdp4_overlay_vg_get_src_offset(struct mdp4_overlay_pipe *pipe, case MDP_RGB_888: case MDP_YCBCR_H1V1: case MDP_YCRCB_H1V1: - *luma_off = pipe->src_x * pipe->bpp; + *luma_off = (pipe->src_x * pipe->bpp) + + (pipe->src_y * pipe->srcp0_ystride); break; default: @@ -789,8 +807,9 @@ void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) char *vg_base; uint32 frame_size, src_size, src_xy, dst_size, dst_xy; uint32 format, pattern, luma_offset, chroma_offset; - uint32 mask, curr, addr; - int pnum, ptype; + uint32 mask; + int pnum, ptype, i; + uint32_t block; pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */ vg_base = MDP_BASE + MDP4_VIDEO_BASE; @@ -806,10 +825,43 @@ void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) format = mdp4_overlay_format(pipe); pattern = mdp4_overlay_unpack_pattern(pipe); + /* CSC Post Processing enabled? */ + if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) { + if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG) { + if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_ENABLE) + pipe->op_mode |= MDP4_OP_CSC_EN; + if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_IN) + pipe->op_mode |= MDP4_OP_SRC_DATA_YCBCR; + if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_OUT) + pipe->op_mode |= MDP4_OP_DST_DATA_YCBCR; + + mdp4_csc_write(&pipe->pp_cfg.csc_cfg, + (uint32_t) (vg_base + MDP4_VIDEO_CSC_OFF)); + + if (pipe->pipe_num == OVERLAY_PIPE_VG1) + block = MDP_BLOCK_VG_1; + else + block = MDP_BLOCK_VG_2; + + for (i = 0; i < CSC_MAX_BLOCKS; i++) { + if (block == csc_cfg_matrix[i].block) { + memcpy(&csc_cfg_matrix[i].csc_data, + &(pipe->pp_cfg.csc_cfg), + sizeof(struct mdp_csc_cfg)); + break; + } + } + } + if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_QSEED_CFG) { + mdp4_qseed_access_cfg(&pipe->pp_cfg.qseed_cfg[0], + (uint32_t) vg_base); + mdp4_qseed_access_cfg(&pipe->pp_cfg.qseed_cfg[1], + (uint32_t) vg_base); + } + } /* not RGB use VG pipe, pure VG pipe */ - pipe->op_mode |= MDP4_OP_CSC_EN; if (ptype != OVERLAY_TYPE_RGB) - pipe->op_mode |= MDP4_OP_SRC_DATA_YCBCR; + pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR); #ifdef MDP4_IGC_LUT_ENABLE pipe->op_mode |= MDP4_OP_IGC_LUT_EN; @@ -853,24 +905,6 @@ void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) &chroma_offset); } - /* Ensure proper covert matrix loaded when color space swaps */ - curr = inpdw(vg_base + 0x0058); - mask = 0x600; - - if ((curr & mask) != (pipe->op_mode & mask)) { - addr = ((uint32_t)vg_base) + 0x4000; - if (ptype != OVERLAY_TYPE_RGB) - mdp4_csc_write(&(mdp_csc_convert[1]), addr); - else - mdp4_csc_write(&(mdp_csc_convert[0]), addr); - - mask = 0xFFFCFFFF; - } else { - /* Don't touch bits you don't want to configure*/ - mask = 0xFFFCF1FF; - } - pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask); - /* luma component plane */ outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset); @@ -903,15 +937,6 @@ void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit); } - if (pipe->flags & MDP_SHARPENING) { - outpdw(vg_base + 0x8200, - mdp4_ss_table_value(pipe->req_data.dpp.sharp_strength, - 0)); - outpdw(vg_base + 0x8204, - mdp4_ss_table_value(pipe->req_data.dpp.sharp_strength, - 1)); - } - if (mdp_rev > MDP_REV_41) { /* mdp chip select controller */ mask = 0; @@ -945,11 +970,16 @@ int mdp4_overlay_format2type(uint32 format) case MDP_ARGB_8888: case MDP_RGBA_8888: case MDP_BGRA_8888: + case MDP_BGRX_8888: case MDP_RGBX_8888: return OVERLAY_TYPE_RGB; + case MDP_YCBYCR_H2V1: case MDP_YCRYCB_H2V1: + case MDP_CBYCRY_H2V1: case MDP_Y_CRCB_H2V1: case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H1V2: + case MDP_Y_CBCR_H1V2: case MDP_Y_CRCB_H2V2: case MDP_Y_CBCR_H2V2: case MDP_Y_CBCR_H2V2_TILE: @@ -1113,6 +1143,24 @@ int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) pipe->element0 = C1_B_Cb; /* B */ pipe->bpp = 4; /* 4 bpp */ break; + case MDP_BGRX_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_YCBYCR_H2V1: case MDP_YCRYCB_H2V1: pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; @@ -1124,15 +1172,42 @@ int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) pipe->unpack_tight = 1; pipe->unpack_align_msb = 0; pipe->unpack_count = 3; - pipe->element3 = C0_G_Y; /* G */ - pipe->element2 = C2_R_Cr; /* R */ - pipe->element1 = C0_G_Y; /* G */ - pipe->element0 = C1_B_Cb; /* B */ + pipe->element3 = C1_B_Cb; /* B */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C0_G_Y; /* G */ + pipe->bpp = 2; /* 2 bpp */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + break; + case MDP_CBYCRY_H2V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + if (pipe->src_format == MDP_YCRYCB_H2V1) { + pipe->element3 = C0_G_Y; /* G */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + } else if (pipe->src_format == MDP_YCBYCR_H2V1) { + pipe->element3 = C0_G_Y; /* G */ + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + } pipe->bpp = 2; /* 2 bpp */ pipe->chroma_sample = MDP4_CHROMA_H2V1; break; case MDP_Y_CRCB_H2V1: case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H1V2: + case MDP_Y_CBCR_H1V2: case MDP_Y_CRCB_H2V2: case MDP_Y_CBCR_H2V2: case MDP_Y_CRCB_H1V1: @@ -1169,6 +1244,14 @@ int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) pipe->chroma_sample = MDP4_CHROMA_H1V2; else pipe->chroma_sample = MDP4_CHROMA_RGB; + } else if (pipe->src_format == MDP_Y_CRCB_H1V2) { + pipe->element1 = C1_B_Cb; + pipe->element0 = C2_R_Cr; + pipe->chroma_sample = MDP4_CHROMA_H1V2; + } else if (pipe->src_format == MDP_Y_CBCR_H1V2) { + pipe->element1 = C2_R_Cr; + pipe->element0 = C1_B_Cb; + pipe->chroma_sample = MDP4_CHROMA_H1V2; } else if (pipe->src_format == MDP_Y_CRCB_H2V2) { pipe->element1 = C1_B_Cb; pipe->element0 = C2_R_Cr; @@ -1290,6 +1373,7 @@ void transp_color_key(int format, uint32 transp, case MDP_XRGB_8888: case MDP_ARGB_8888: case MDP_BGRA_8888: + case MDP_BGRX_8888: b_start = 0; g_start = 8; r_start = 16; @@ -1329,6 +1413,8 @@ void transp_color_key(int format, uint32 transp, case MDP_Y_CR_CB_GH2V2: case MDP_Y_CRCB_H2V2: case MDP_Y_CRCB_H2V1: + case MDP_Y_CRCB_H1V2: + case MDP_Y_CBCR_H1V2: case MDP_Y_CRCB_H1V1: case MDP_Y_CBCR_H1V1: case MDP_YCRCB_H1V1: @@ -1400,6 +1486,87 @@ uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe) (pipe->element1 << 8) | pipe->element0; } +static uint32 mdp4_overlayproc_cfg_wb_panel(struct mdp4_overlay_pipe *pipe, + char *overlay_base, uint32 curr) +{ + int off, bpp; + uint32 flag; + bool is_rgb = false; + struct mdp_mixer_cfg *mixer_cfg; + + off = 0; + mixer_cfg = &ctrl->mdp_mixer_cfg[MDP4_MIXER2]; + + switch (mixer_cfg->writeback_format) { + case WB_FORMAT_RGB_888: + bpp = 3; /* RGB888 */ + flag = 0x0; + is_rgb = true; + break; + case WB_FORMAT_RGB_565: + bpp = 2; /* RGB565 */ + flag = 0x1; + is_rgb = true; + break; + case WB_FORMAT_xRGB_8888: + bpp = 4; /* xRGB8888 */ + flag = 0x3; + is_rgb = true; + break; + case WB_FORMAT_ARGB_8888: + bpp = 4; /* ARGB8888 */ + flag = 0x80000003; + is_rgb = true; + break; + case WB_FORMAT_ARGB_8888_INPUT_ALPHA: + pr_warn("currently not supported ARGB_8888_INPUT_ALPHA\n"); + default: + bpp = 1; /* NV12 */ + is_rgb = false; + break; + } + + if (is_rgb == true) { + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + + outpdw(overlay_base + 0x000c, pipe->ov_blt_addr + off); + /* overlay ouput is RGB888 */ + outpdw(overlay_base + 0x0010, pipe->src_width * bpp); + outpdw(overlay_base + 0x001c, pipe->ov_blt_addr + off); + /* MDDI - BLT + on demand */ + outpdw(overlay_base + 0x0004, 0x08); + + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; + + outpdw(overlay_base + 0x0014, curr | flag); + } else { + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + + outpdw(overlay_base + 0x000c, pipe->ov_blt_addr + off); + /* overlay ouput is RGB888 */ + outpdw(overlay_base + 0x0010, ((pipe->src_width << 16) | + pipe->src_width)); + outpdw(overlay_base + 0x001c, pipe->ov_blt_addr + off); + off = pipe->src_height * pipe->src_width; + /* align chroma to 2k address */ + off = (off + 2047) & ~2047; + /* UV plane adress */ + outpdw(overlay_base + 0x0020, pipe->ov_blt_addr + off); + /* MDDI - BLT + on demand */ + outpdw(overlay_base + 0x0004, 0x08); + /* pseudo planar + writeback */ + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; + outpdw(overlay_base + 0x0014, curr | 0x012); + /* rgb->yuv */ + outpdw(overlay_base + 0x0200, 0x05); + } + return curr; +} + /* * mdp4_overlayproc_cfg: only be called from base layer */ @@ -1459,34 +1626,8 @@ void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) #endif } else if (pipe->mixer_num == MDP4_MIXER2) { if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) { - off = 0; - bpp = 1; - if (pipe->ov_cnt & 0x01) - off = pipe->src_height * - pipe->src_width * bpp; - - outpdw(overlay_base + 0x000c, - pipe->ov_blt_addr + off); - /* overlay ouput is RGB888 */ - outpdw(overlay_base + 0x0010, - ((pipe->src_width << 16) | - pipe->src_width)); - outpdw(overlay_base + 0x001c, - pipe->ov_blt_addr + off); - off = pipe->src_height * pipe->src_width; - /* align chroma to 2k address */ - off = (off + 2047) & ~2047; - /* UV plane adress */ - outpdw(overlay_base + 0x0020, - pipe->ov_blt_addr + off); - /* MDDI - BLT + on demand */ - outpdw(overlay_base + 0x0004, 0x08); - /* pseudo planar + writeback */ - curr = inpdw(overlay_base + 0x0014); - curr &= 0x4; - outpdw(overlay_base + 0x0014, curr | 0x012); - /* rgb->yuv */ - outpdw(overlay_base + 0x0200, 0x05); + curr = mdp4_overlayproc_cfg_wb_panel(pipe, + overlay_base, curr); } } } else { @@ -1519,36 +1660,19 @@ void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } -int mdp4_overlay_pipe_staged(int mixer) +int mdp4_overlay_pipe_staged(struct mdp4_overlay_pipe *pipe) { - uint32 data, mask, i, off; - int p1, p2; + uint32 data, mask; + int mixer; - if (mixer == MDP4_MIXER2) - off = 0x100F0; - else - off = 0x10100; + mixer = pipe->mixer_num; + data = ctrl->mixer_cfg[mixer]; - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - data = inpdw(MDP_BASE + off); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); - p1 = 0; - p2 = 0; - for (i = 0; i < 8; i++) { - mask = data & 0x0f; - if (mask) { - if (mask <= 4) - p1++; - else - p2++; - } - data >>= 4; - } + mask = 0x0f; + mask <<= (4 * pipe->pipe_num); + data &= mask; - if (mixer) - return p2; - else - return p1; + return data; } int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info) @@ -1578,6 +1702,35 @@ int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info) return cnt; } +void mdp4_solidfill_commit(int mixer) +{ + struct blend_cfg bcfg; + struct mdp4_overlay_pipe *pp = NULL; + int i = 0; + + for (i = 0; i < OVERLAY_PIPE_MAX; i++) { + pp = &ctrl->sf_plist[mixer][i]; + if (pp->pipe_ndx && pp->solid_fill) { + bcfg.solidfill = 1; + bcfg.solidfill_pipe = pp; + mdp4_overlay_bg_solidfill(&bcfg); + mdp4_overlay_reg_flush(pp, 1); + mdp4_mixer_stage_up(pp, 0); + } + } + mdp4_mixer_stage_commit(MDP4_MIXER1); + + for (i = 0; i < OVERLAY_PIPE_MAX; i++) { + pp = &ctrl->sf_plist[mixer][i]; + if (pp->pipe_ndx && pp->solid_fill) { + mdp4_overlay_reg_flush(pp, 1); + mdp4_mixer_stage_down(pp, 0); + pp->solid_fill = 0; + } + } + mdp4_mixer_stage_commit(MDP4_MIXER1); +} + void mdp4_mixer_stage_commit(int mixer) { struct mdp4_overlay_pipe *pipe; @@ -1600,8 +1753,14 @@ void mdp4_mixer_stage_commit(int mixer) data |= stage; } + /* + * stage_commit may be called from overlay_unset + * for command panel, mdp clocks may be off at this time. + * so mdp clock enabled is necessary + */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_clk_ctrl(1); + mdp4_mixer_blend_setup(mixer); off = 0; @@ -1669,7 +1828,8 @@ void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe, int commit) ctrl->stage[mixer][i] = NULL; /* clear it */ } - if (commit || (mixer > 0 && !hdmi_prim_display)) + if (commit || ((mixer == 1) && !hdmi_prim_display) || + (mixer == 2)) mdp4_mixer_stage_commit(mixer); } /* @@ -1739,6 +1899,7 @@ void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe) struct mdp4_overlay_pipe *bspipe; int ptype, pnum, pndx, mixer; int format, alpha_enable, alpha; + struct mdp4_iommu_pipe_info iom; if (pipe->pipe_type != OVERLAY_TYPE_BF) return; @@ -1753,6 +1914,7 @@ void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe) return; } + iom = bspipe->iommu; ptype = bspipe->pipe_type; pnum = bspipe->pipe_num; pndx = bspipe->pipe_ndx; @@ -1766,6 +1928,7 @@ void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe) bspipe->src_format = format; bspipe->alpha_enable = alpha_enable; bspipe->alpha = alpha; + bspipe->iommu = iom; bspipe->pipe_used++; /* mark base layer pipe used */ @@ -1910,7 +2073,7 @@ void mdp4_mixer_blend_setup(int mixer) struct mdp4_overlay_pipe *d_pipe; struct mdp4_overlay_pipe *s_pipe; struct blend_cfg *blend; - int i, off, ptype, alpha_drop = 0; + int i, off, alpha_drop; int d_alpha, s_alpha; unsigned char *overlay_base; uint32 c0, c1, c2, base_premulti; @@ -1936,11 +2099,14 @@ void mdp4_mixer_blend_setup(int mixer) d_alpha = 0; continue; } + alpha_drop = 0; /* per stage */ /* alpha channel is lost on VG pipe when using QSEED or M/N */ if (s_pipe->pipe_type == OVERLAY_TYPE_VIDEO && + s_pipe->alpha_enable && ((s_pipe->op_mode & MDP4_OP_SCALEY_EN) || (s_pipe->op_mode & MDP4_OP_SCALEX_EN)) && - !(s_pipe->op_mode & MDP4_OP_SCALEY_PIXEL_RPT)) + !(s_pipe->op_mode & (MDP4_OP_SCALEX_PIXEL_RPT | + MDP4_OP_SCALEY_PIXEL_RPT))) alpha_drop = 1; d_pipe = mdp4_background_layer(mixer, s_pipe); @@ -1956,7 +2122,8 @@ void mdp4_mixer_blend_setup(int mixer) blend->bg_alpha = 0x0ff - s_pipe->alpha; blend->fg_alpha = s_pipe->alpha; blend->co3_sel = 1; /* use fg alpha */ - + pr_debug("%s: bg alpha %d, fg alpha %d\n", + __func__, blend->bg_alpha, blend->fg_alpha); if (s_pipe->is_fg) { if (s_pipe->alpha == 0xff) { blend->solidfill = 1; @@ -1972,30 +2139,21 @@ void mdp4_mixer_blend_setup(int mixer) MDP4_BLEND_FG_ALPHA_FG_PIXEL; else blend->fg_alpha = 0xff; + blend->op |= MDP4_BLEND_BG_INV_ALPHA; } else blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST; - - blend->op |= MDP4_BLEND_BG_INV_ALPHA; } else if (d_alpha) { - ptype = mdp4_overlay_format2type(s_pipe->src_format); - if (ptype == OVERLAY_TYPE_VIDEO) { - blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL | - MDP4_BLEND_FG_INV_ALPHA); - if ((!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) && - ((i != MDP4_MIXER_STAGE0) || - (!base_premulti))) - blend->op |= - MDP4_BLEND_BG_ALPHA_BG_PIXEL; - else - blend->fg_alpha = 0xff; + blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL | + MDP4_BLEND_FG_INV_ALPHA); + if ((!(d_pipe->flags & MDP_BLEND_FG_PREMULT)) && + ((i != MDP4_MIXER_STAGE0) || + (!base_premulti))) + blend->op |= + MDP4_BLEND_BG_ALPHA_BG_PIXEL; + else + blend->fg_alpha = 0xff; - blend->co3_sel = 0; /* use bg alpha */ - } else { - /* s_pipe is rgb without alpha */ - blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST | - MDP4_BLEND_BG_ALPHA_BG_CONST); - blend->bg_alpha = 0; - } + blend->co3_sel = 0; /* use bg alpha */ } if (s_pipe->transp != MDP_TRANSP_NOP) { @@ -2057,7 +2215,9 @@ void mdp4_mixer_blend_setup(int mixer) outpdw(overlay_base + off + 0x108, blend->fg_alpha); outpdw(overlay_base + off + 0x10c, blend->bg_alpha); - if (mdp_rev >= MDP_REV_42) + if (mdp_rev >= MDP_REV_42 || + ctrl->panel_mode & MDP4_PANEL_MDDI || + ctrl->panel_mode & MDP4_PANEL_DSI_CMD) outpdw(overlay_base + off + 0x104, blend->op); outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel); @@ -2392,6 +2552,11 @@ static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer, * zorder 2 == stage 2 == 4 */ if (req->id == MSMFB_NEW_REQUEST) { /* new request */ + if (mdp4_overlay_pipe_staged(pipe)) { + pr_err("%s: ndx=%d still staged\n", __func__, + pipe->pipe_ndx); + return -EPERM; + } pipe->pipe_used++; pipe->mixer_num = mixer; pr_debug("%s: zorder=%d pipe ndx=%d num=%d\n", __func__, @@ -2453,26 +2618,13 @@ static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd, if (!pipe) { pr_err("%s: pipe is null!\n", __func__); - pipe->req_bw = OVERLAY_PERF_LEVEL4; return ret; } if (!mfd) { pr_err("%s: mfd is null!\n", __func__); - pipe->req_bw = OVERLAY_PERF_LEVEL4; return ret; } - /* - * Serveral special cases require the max mdp clk but cannot - * be explained by mdp clk equation. - */ - if (pipe->flags & MDP_DEINTERLACE) { - pr_info("%s deinterlace requires max mdp clk.\n", - __func__); - pipe->req_clk = mdp_max_clk; - return 0; - } - pr_debug("%s: pipe sets: panel res(x,y)=(%d,%d)\n", __func__, mfd->panel_info.xres, mfd->panel_info.yres); pr_debug("%s: src(w,h)(%d,%d),src(x,y)(%d,%d)\n", @@ -2484,6 +2636,11 @@ static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd, mfd->panel_info.type == MIPI_CMD_PANEL) ? mfd->panel_info.mipi.dsi_pclk_rate : mfd->panel_info.clk_rate; + + if (mfd->panel_info.type == LVDS_PANEL && + mfd->panel_info.lvds.channel_mode == LVDS_DUAL_CHANNEL_MODE) + pclk = pclk << 1; + if (!pclk) { pipe->req_clk = mdp_max_clk; pr_err("%s panel pixel clk is zero!\n", __func__); @@ -2590,7 +2747,8 @@ static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd, * required(FIR). */ if ((mfd->panel_info.lcdc.v_back_porch <= 4) && - (pipe->src_h != pipe->dst_h)) { + (pipe->src_h != pipe->dst_h) && + (mfd->panel_info.lcdc.v_back_porch)) { u32 clk = 0; clk = 4 * (pclk >> shift) / mfd->panel_info.lcdc.v_back_porch; clk <<= shift; @@ -2611,6 +2769,16 @@ static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd, __func__); } + /* + * Interlaced videos require the max mdp clk but cannot + * be explained by mdp clk equation. + */ + if (pipe->flags & MDP_DEINTERLACE) { + rst = (rst > mdp_max_clk) ? rst : mdp_max_clk; + pr_info("%s deinterlace requires max mdp clk.\n", + __func__); + } + pipe->req_clk = (u32) rst; pr_debug("%s: required mdp clk %d mixer %d pipe ndx %d\n", @@ -2619,18 +2787,13 @@ static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd, return 0; } -#define OVERLAY_VGA_SIZE 0x04B000 -#define OVERLAY_720P_TILE_SIZE 0x0E6000 -#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */ - -#define OVERLAY_BUS_SCALE_TABLE_BASE 6 - - static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) + struct mdp4_overlay_pipe *pipe) { - u32 res; + u32 fps; int ret = -EINVAL; + u32 quota; + u32 shift = 16; if (!pipe) { pr_err("%s: pipe is null!\n", __func__); @@ -2641,28 +2804,79 @@ static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd, return ret; } - if (pipe->flags & MDP_DEINTERLACE) { - pr_info("%s deinterlace requires max mdp bw.\n", - __func__); - pipe->req_bw = OVERLAY_PERF_LEVEL1; - return 0; + fps = mdp_get_panel_framerate(mfd); + quota = pipe->src_w * pipe->src_h * fps * pipe->bpp; + + quota >>= shift; + /* factor 1.15 for ab */ + pipe->bw_ab_quota = quota * MDP4_BW_AB_FACTOR / 100; + /* factor 1.25 for ib */ + pipe->bw_ib_quota = quota * MDP4_BW_IB_FACTOR / 100; + /* down scaling factor for ib */ + if ((!pipe->dst_h) && (!pipe->src_h) && + (pipe->src_h > pipe->dst_h)) { + u64 ib = quota; + ib *= pipe->src_h; + ib /= pipe->dst_h; + pipe->bw_ib_quota = max(ib, pipe->bw_ib_quota); + pr_debug("%s: src_h=%d dst_h=%d mdp ib %llu, ib_quota=%llu\n", + __func__, pipe->src_h, pipe->dst_h, + ib<bw_ib_quota<pipe_type == OVERLAY_TYPE_BF) { - pipe->req_bw = OVERLAY_PERF_LEVEL4; - return 0; + pipe->bw_ab_quota <<= shift; + pipe->bw_ib_quota <<= shift; + + pr_debug("%s: pipe ndx=%d src(h,w)(%d, %d) fps=%d bpp=%d\n", + __func__, pipe->pipe_ndx, pipe->src_h, pipe->src_w, + fps, pipe->bpp); + pr_debug("%s: ab_quota=%llu ib_quota=%llu\n", __func__, + pipe->bw_ab_quota, pipe->bw_ib_quota); + + return 0; +} + +int mdp4_calc_blt_mdp_bw(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_overlay_perf *perf_req = &perf_request; + u32 fps; + int bpp; + int ret = -EINVAL; + u32 quota; + u32 shift = 16; + if (!pipe) { + pr_err("%s: pipe is null!\n", __func__); + return ret; + } + if (!mfd) { + pr_err("%s: mfd is null!\n", __func__); + return ret; } - res = pipe->src_w * pipe->src_h; + bpp = BLT_BPP; + fps = mdp_get_panel_framerate(mfd); - if (res <= OVERLAY_WSVGA_SIZE) - pipe->req_bw = OVERLAY_PERF_LEVEL4; - else if (res <= OVERLAY_VGA_SIZE) - pipe->req_bw = OVERLAY_PERF_LEVEL3; - else if (res <= OVERLAY_720P_TILE_SIZE) - pipe->req_bw = OVERLAY_PERF_LEVEL2; - else - pipe->req_bw = OVERLAY_PERF_LEVEL1; + /* read and write bw*/ + quota = pipe->dst_w * pipe->dst_h * fps * bpp * 2; + quota >>= shift; + + perf_req->mdp_ov_ab_bw[pipe->mixer_num] = + quota * MDP4_BW_AB_FACTOR / 100; + + perf_req->mdp_ov_ib_bw[pipe->mixer_num] = + quota * MDP4_BW_IB_FACTOR / 100; + + perf_req->mdp_ov_ab_bw[pipe->mixer_num] <<= shift; + perf_req->mdp_ov_ib_bw[pipe->mixer_num] <<= shift; + + pr_debug("%s: pipe ndx=%d dst(h,w)(%d, %d) fps=%d bpp=%d\n", + __func__, pipe->pipe_ndx, pipe->dst_h, pipe->dst_w, + fps, bpp); + pr_debug("%s: overlay=%d ab_bw=%llu ib_bw=%llu\n", __func__, + pipe->mixer_num, + perf_req->mdp_ov_ab_bw[pipe->mixer_num], + perf_req->mdp_ov_ib_bw[pipe->mixer_num]); return 0; } @@ -2671,12 +2885,12 @@ int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd, struct mdp4_overlay_pipe *plist) { u32 worst_mdp_clk = 0; - u32 worst_mdp_bw = OVERLAY_PERF_LEVEL4; int i; struct mdp4_overlay_perf *perf_req = &perf_request; struct mdp4_overlay_pipe *pipe = plist; u32 cnt = 0; int ret = -EINVAL; + u64 ab_quota_total = 0, ib_quota_total = 0; if (!mfd) { pr_err("%s: mfd is null!\n", __func__); @@ -2688,8 +2902,8 @@ int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd, return ret; } - perf_req->use_ov0_blt = 0; - perf_req->use_ov1_blt = 0; + for (i = 0; i < MDP4_MIXER_MAX; i++) + perf_req->use_ov_blt[i] = 0; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { @@ -2701,25 +2915,17 @@ int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd, cnt++; if (worst_mdp_clk < pipe->req_clk) worst_mdp_clk = pipe->req_clk; - if (pipe->req_clk > mdp_max_clk) { - if (pipe->mixer_num == MDP4_MIXER0) - perf_req->use_ov0_blt = 1; - if (pipe->mixer_num == MDP4_MIXER1) - perf_req->use_ov1_blt = 1; - } - if (!pipe->req_bw) { - pr_err("%s mdp pipe bw request should not be zero!\n", - __func__); - pr_debug("%s %d pid %d num %d idx %d mix %d bw %d\n", - __func__, __LINE__, current->pid, - pipe->pipe_num, pipe->pipe_ndx, - pipe->mixer_num, pipe->req_bw); - pipe->req_bw = OVERLAY_PERF_LEVEL4; - } + if (pipe->req_clk > mdp_max_clk) + perf_req->use_ov_blt[pipe->mixer_num] = 1; - if (pipe->req_bw < worst_mdp_bw) - worst_mdp_bw = pipe->req_bw; + if (pipe->mixer_num == MDP4_MIXER2) + perf_req->use_ov_blt[MDP4_MIXER2] = 1; + + if (pipe->pipe_type != OVERLAY_TYPE_BF) { + ab_quota_total += pipe->bw_ab_quota; + ib_quota_total += pipe->bw_ib_quota; + } if (mfd->mdp_rev == MDP_REV_41) { /* @@ -2728,32 +2934,45 @@ int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd, */ if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { if (pipe->dst_x != 0) - perf_req->use_ov0_blt = 1; + perf_req->use_ov_blt[MDP4_MIXER0] = 1; } if ((mfd->panel_info.xres > 1280) && (mfd->panel_info.type != DTV_PANEL)) { - perf_req->use_ov0_blt = 1; + perf_req->use_ov_blt[MDP4_MIXER0] = 1; } } } - perf_req->mdp_clk_rate = worst_mdp_clk; - if (perf_req->mdp_clk_rate > mdp_max_clk) - perf_req->mdp_clk_rate = mdp_max_clk; - + perf_req->mdp_clk_rate = min(worst_mdp_clk, mdp_max_clk); perf_req->mdp_clk_rate = mdp_clk_round_rate(perf_req->mdp_clk_rate); - perf_req->mdp_bw = worst_mdp_bw; + for (i = 0; i < MDP4_MIXER_MAX; i++) { + if (perf_req->use_ov_blt[i]) { + ab_quota_total += perf_req->mdp_ov_ab_bw[i]; + ib_quota_total += perf_req->mdp_ov_ib_bw[i]; + } + } + + perf_req->mdp_ab_bw = roundup(ab_quota_total, MDP_BUS_SCALE_AB_STEP); + perf_req->mdp_ib_bw = roundup(ib_quota_total, MDP_BUS_SCALE_AB_STEP); + + pr_debug("%s %d: ab_quota_total=(%llu, %d) ib_quota_total=(%llu, %d)\n", + __func__, __LINE__, + ab_quota_total, perf_req->mdp_ab_bw, + ib_quota_total, perf_req->mdp_ib_bw); - if (cnt >= 3) - perf_req->mdp_bw = OVERLAY_PERF_LEVEL1; + if (ab_quota_total > mdp_max_bw) + pr_warn("%s: req ab bw=%llu is larger than max bw=%llu", + __func__, ab_quota_total, mdp_max_bw); + if (ib_quota_total > mdp_max_bw) + pr_warn("%s: req ib bw=%llu is larger than max bw=%llu", + __func__, ib_quota_total, mdp_max_bw); - pr_debug("%s %d pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d bw %d\n", + pr_debug("%s %d: pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d\n", __func__, __LINE__, current->pid, cnt, perf_req->mdp_clk_rate, - perf_req->use_ov0_blt, - perf_req->use_ov1_blt, - perf_req->mdp_bw); + perf_req->use_ov_blt[0], + perf_req->use_ov_blt[1]); return 0; } @@ -2789,7 +3008,7 @@ void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, flag); if (!mdp4_extn_disp) - perf_cur->use_ov1_blt = 0; + perf_cur->use_ov_blt[1] = 0; if (flag) { if (perf_req->mdp_clk_rate > perf_cur->mdp_clk_rate) { @@ -2802,19 +3021,27 @@ void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, perf_cur->mdp_clk_rate = perf_req->mdp_clk_rate; } - if (perf_req->mdp_bw < perf_cur->mdp_bw) { + if ((perf_req->mdp_ab_bw > perf_cur->mdp_ab_bw) || + (perf_req->mdp_ib_bw > perf_cur->mdp_ib_bw)) { mdp_bus_scale_update_request - (OVERLAY_BUS_SCALE_TABLE_BASE - - perf_req->mdp_bw); - pr_info("%s mdp bw is changed [%d] from %d to %d\n", + (perf_req->mdp_ab_bw, perf_req->mdp_ib_bw); + pr_debug("%s mdp ab_bw is changed [%d] from %d to %d\n", + __func__, + flag, + perf_cur->mdp_ab_bw, + perf_req->mdp_ab_bw); + pr_debug("%s mdp ib_bw is changed [%d] from %d to %d\n", __func__, flag, - perf_cur->mdp_bw, - perf_req->mdp_bw); - perf_cur->mdp_bw = perf_req->mdp_bw; + perf_cur->mdp_ib_bw, + perf_req->mdp_ib_bw); + perf_cur->mdp_ab_bw = perf_req->mdp_ab_bw; + perf_cur->mdp_ib_bw = perf_req->mdp_ib_bw; } - if (mfd->panel_info.pdest == DISPLAY_1 && - perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) { + + if ((mfd->panel_info.pdest == DISPLAY_1 && + perf_req->use_ov_blt[0] && !perf_cur->use_ov_blt[0]) || + dbg_force_ov0_blt) { if (mfd->panel_info.type == LCDC_PANEL || mfd->panel_info.type == LVDS_PANEL) mdp4_lcdc_overlay_blt_start(mfd); @@ -2822,22 +3049,25 @@ void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, mdp4_dsi_video_blt_start(mfd); else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) mdp4_dsi_cmd_blt_start(mfd); - pr_info("%s mixer0 start blt [%d] from %d to %d.\n", + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_blt_start(mfd); + pr_debug("%s mixer0 start blt [%d] from %d to %d.\n", __func__, flag, - perf_cur->use_ov0_blt, - perf_req->use_ov0_blt); - perf_cur->use_ov0_blt = perf_req->use_ov0_blt; + perf_cur->use_ov_blt[0], + perf_req->use_ov_blt[0]); + perf_cur->use_ov_blt[0] = perf_req->use_ov_blt[0]; } - if (mfd->panel_info.pdest == DISPLAY_2 && - perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) { + if ((mfd->panel_info.pdest == DISPLAY_2 && + perf_req->use_ov_blt[1] && !perf_cur->use_ov_blt[1]) || + dbg_force_ov1_blt) { mdp4_dtv_overlay_blt_start(mfd); - pr_info("%s mixer1 start blt [%d] from %d to %d.\n", + pr_debug("%s mixer1 start blt [%d] from %d to %d.\n", __func__, flag, - perf_cur->use_ov1_blt, - perf_req->use_ov1_blt); - perf_cur->use_ov1_blt = perf_req->use_ov1_blt; + perf_cur->use_ov_blt[1], + perf_req->use_ov_blt[1]); + perf_cur->use_ov_blt[1] = perf_req->use_ov_blt[1]; } } else { if (perf_req->mdp_clk_rate < perf_cur->mdp_clk_rate) { @@ -2850,19 +3080,26 @@ void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, perf_cur->mdp_clk_rate = perf_req->mdp_clk_rate; } - if (perf_req->mdp_bw > perf_cur->mdp_bw) { - pr_info("%s mdp bw is changed [%d] from %d to %d\n", + if (perf_req->mdp_ab_bw < perf_cur->mdp_ab_bw || + perf_req->mdp_ib_bw < perf_cur->mdp_ib_bw) { + mdp_bus_scale_update_request + (perf_req->mdp_ab_bw, perf_req->mdp_ib_bw); + pr_debug("%s mdp ab bw is changed [%d] from %d to %d\n", __func__, flag, - perf_cur->mdp_bw, - perf_req->mdp_bw); - mdp_bus_scale_update_request - (OVERLAY_BUS_SCALE_TABLE_BASE - - perf_req->mdp_bw); - perf_cur->mdp_bw = perf_req->mdp_bw; + perf_cur->mdp_ab_bw, + perf_req->mdp_ab_bw); + pr_debug("%s mdp ib bw is changed [%d] from %d to %d\n", + __func__, + flag, + perf_cur->mdp_ib_bw, + perf_req->mdp_ib_bw); + perf_cur->mdp_ab_bw = perf_req->mdp_ab_bw; + perf_cur->mdp_ib_bw = perf_req->mdp_ib_bw; } - if (mfd->panel_info.pdest == DISPLAY_1 && - !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) { + if ((mfd->panel_info.pdest == DISPLAY_1 && + !perf_req->use_ov_blt[0] && perf_cur->use_ov_blt[0]) || + dbg_force_ov0_blt) { if (mfd->panel_info.type == LCDC_PANEL || mfd->panel_info.type == LVDS_PANEL) mdp4_lcdc_overlay_blt_stop(mfd); @@ -2870,22 +3107,25 @@ void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, mdp4_dsi_video_blt_stop(mfd); else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) mdp4_dsi_cmd_blt_stop(mfd); - pr_info("%s mixer0 stop blt [%d] from %d to %d.\n", + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_blt_stop(mfd); + pr_debug("%s mixer0 stop blt [%d] from %d to %d.\n", __func__, flag, - perf_cur->use_ov0_blt, - perf_req->use_ov0_blt); - perf_cur->use_ov0_blt = perf_req->use_ov0_blt; + perf_cur->use_ov_blt[0], + perf_req->use_ov_blt[0]); + perf_cur->use_ov_blt[0] = perf_req->use_ov_blt[0]; } - if (mfd->panel_info.pdest == DISPLAY_2 && - !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) { + if ((mfd->panel_info.pdest == DISPLAY_2 && + !perf_req->use_ov_blt[1] && perf_cur->use_ov_blt[1]) || + dbg_force_ov1_blt) { mdp4_dtv_overlay_blt_stop(mfd); - pr_info("%s mixer1 stop blt [%d] from %d to %d.\n", + pr_debug("%s mixer1 stop blt [%d] from %d to %d.\n", __func__, flag, - perf_cur->use_ov1_blt, - perf_req->use_ov1_blt); - perf_cur->use_ov1_blt = perf_req->use_ov1_blt; + perf_cur->use_ov_blt[1], + perf_req->use_ov_blt[1]); + perf_cur->use_ov_blt[1] = perf_req->use_ov_blt[1]; } } return; @@ -2898,9 +3138,6 @@ static int get_img(struct msmfb_data *img, struct fb_info *info, { struct file *file; int put_needed, ret = 0, fb_num; -#ifdef CONFIG_ANDROID_PMEM - unsigned long vstart; -#endif *p_need = 0; if (img->flags & MDP_BLIT_SRC_GEM) { @@ -2914,14 +3151,13 @@ static int get_img(struct msmfb_data *img, struct fb_info *info, if (file == NULL) return -EINVAL; + pipe->flags |= MDP_MEMORY_ID_TYPE_FB; if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { fb_num = MINOR(file->f_dentry->d_inode->i_rdev); if (get_fb_phys_info(start, len, fb_num, DISPLAY_SUBSYSTEM_ID)) { ret = -1; } else { - pr_warn("%s: mdp4_overlay play with FB memory\n", - __func__); *srcp_file = file; *p_need = put_needed; } @@ -2936,13 +3172,6 @@ static int get_img(struct msmfb_data *img, struct fb_info *info, return mdp4_overlay_iommu_map_buf(img->memory_id, pipe, plane, start, len, srcp_ihdl); #endif -#ifdef CONFIG_ANDROID_PMEM - if (!get_pmem_file(img->memory_id, start, &vstart, - len, srcp_file)) - return 0; - else - return -EINVAL; -#endif } #ifdef CONFIG_FB_MSM_MIPI_DSI @@ -3054,22 +3283,22 @@ int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) pr_debug("pipe->flags 0x%x\n", pipe->flags); if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) { mfd->mem_hid &= ~BIT(ION_IOMMU_HEAP_ID); - mfd->mem_hid |= ION_SECURE; + mfd->mem_hid |= ION_FLAG_SECURE; } else { mfd->mem_hid |= BIT(ION_IOMMU_HEAP_ID); - mfd->mem_hid &= ~ION_SECURE; + mfd->mem_hid &= ~ION_FLAG_SECURE; } } - if (pipe->flags & MDP_SHARPENING) { - bool test = ((pipe->req_data.dpp.sharp_strength > 0) && - ((req->src_rect.w > req->dst_rect.w) && - (req->src_rect.h > req->dst_rect.h))); - if (test) { - pr_debug("%s: No sharpening while downscaling.\n", + mdp4_stat.overlay_set[pipe->mixer_num]++; + + if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) { + if (pipe->pipe_num <= OVERLAY_PIPE_VG2) + memcpy(&pipe->pp_cfg, &req->overlay_pp_cfg, + sizeof(struct mdp_overlay_pp_params)); + else + pr_debug("%s: RGB Pipes don't support CSC/QSEED\n", __func__); - pipe->flags &= ~MDP_SHARPENING; - } } mdp4_overlay_mdp_pipe_req(pipe, mfd); @@ -3108,8 +3337,6 @@ int mdp4_overlay_unset(struct fb_info *info, int ndx) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; struct mdp4_overlay_pipe *pipe; - struct dpp_ctrl dpp; - int i; if (mfd == NULL) return -ENODEV; @@ -3137,33 +3364,25 @@ int mdp4_overlay_unset(struct fb_info *info, int ndx) else { /* mixer 0 */ ctrl->mixer0_played = 0; - if (ctrl->panel_mode & MDP4_PANEL_MDDI) { - if (mfd->panel_power_on) - mdp4_mddi_blt_dmap_busy_wait(mfd); - } + } mdp4_overlay_reg_flush(pipe, 1); mdp4_mixer_stage_down(pipe, 0); if (pipe->mixer_num == MDP4_MIXER0) { - if (ctrl->panel_mode & MDP4_PANEL_MDDI) { - if (mfd->panel_power_on) - mdp4_mddi_overlay_restore(); - } } else { /* mixer1, DTV, ATV */ - if (ctrl->panel_mode & MDP4_PANEL_DTV) + if (ctrl->panel_mode & MDP4_PANEL_DTV) { + if (hdmi_prim_display) { + struct mdp4_overlay_pipe *pp; + pp = &ctrl->sf_plist[pipe->mixer_num] + [pipe->pipe_ndx - 1]; + *pp = *pipe; /* clone it */ + pp->solid_fill = 1; + } mdp4_overlay_dtv_unset(mfd, pipe); - } - - /* Reset any HSIC settings to default */ - if (pipe->flags & MDP_DPP_HSIC) { - for (i = 0; i < NUM_HSIC_PARAM; i++) - dpp.hsic_params[i] = 0; - - mdp4_hsic_set(pipe, &dpp); - mdp4_hsic_update(pipe); + } } mdp4_stat.overlay_unset[pipe->mixer_num]++; @@ -3184,6 +3403,8 @@ int mdp4_overlay_wait4vsync(struct fb_info *info, long long *vtime) mdp4_dsi_cmd_wait4vsync(0, vtime); else if (ctrl->panel_mode & MDP4_PANEL_LCDC) mdp4_lcdc_wait4vsync(0, vtime); + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_wait4vsync(0, vtime); } else if (hdmi_prim_display || info->node == 1) { mdp4_dtv_wait4vsync(0, vtime); } @@ -3207,6 +3428,8 @@ int mdp4_overlay_vsync_ctrl(struct fb_info *info, int enable) mdp4_dsi_cmd_vsync_ctrl(info, cmd); else if (ctrl->panel_mode & MDP4_PANEL_LCDC) mdp4_lcdc_vsync_ctrl(info, cmd); + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_vsync_ctrl(info, cmd); } else if (hdmi_prim_display || info->node == 1) mdp4_dtv_vsync_ctrl(info, cmd); @@ -3291,11 +3514,8 @@ int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) struct mdp4_overlay_pipe *pipe; ulong start, addr; ulong len = 0; - struct file *srcp0_file = NULL; - struct file *srcp1_file = NULL, *srcp2_file = NULL; struct ion_handle *srcp0_ihdl = NULL; struct ion_handle *srcp1_ihdl = NULL, *srcp2_ihdl = NULL; - int ps0_need, p_need; uint32_t overlay_version = 0; int ret = 0; @@ -3320,8 +3540,8 @@ int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) mutex_lock(&mfd->dma->ov_mutex); img = &req->data; - get_img(img, info, pipe, 0, &start, &len, &srcp0_file, - &ps0_need, &srcp0_ihdl); + get_img(img, info, pipe, 0, &start, &len, &pipe->srcp0_file, + &pipe->put0_need, &srcp0_ihdl); if (len == 0) { pr_err("%s: pmem Error\n", __func__); ret = -1; @@ -3343,8 +3563,9 @@ int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { if (overlay_version > 0) { img = &req->plane1_data; - get_img(img, info, pipe, 1, &start, &len, &srcp1_file, - &p_need, &srcp1_ihdl); + get_img(img, info, pipe, 1, &start, &len, + &pipe->srcp1_file, &pipe->put1_need, + &srcp1_ihdl); if (len == 0) { pr_err("%s: Error to get plane1\n", __func__); ret = -EINVAL; @@ -3363,7 +3584,9 @@ int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) } pipe->srcp0_ystride = pipe->src_width; if ((pipe->src_format == MDP_Y_CRCB_H1V1) || - (pipe->src_format == MDP_Y_CBCR_H1V1)) { + (pipe->src_format == MDP_Y_CBCR_H1V1) || + (pipe->src_format == MDP_Y_CRCB_H1V2) || + (pipe->src_format == MDP_Y_CBCR_H1V2)) { if (pipe->src_width > YUV_444_MAX_WIDTH) pipe->srcp1_ystride = pipe->src_width << 2; else @@ -3374,8 +3597,9 @@ int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) } else if (pipe->fetch_plane == OVERLAY_PLANE_PLANAR) { if (overlay_version > 0) { img = &req->plane1_data; - get_img(img, info, pipe, 1, &start, &len, &srcp1_file, - &p_need, &srcp1_ihdl); + get_img(img, info, pipe, 1, &start, &len, + &pipe->srcp1_file, &pipe->put1_need, + &srcp1_ihdl); if (len == 0) { pr_err("%s: Error to get plane1\n", __func__); ret = -EINVAL; @@ -3384,8 +3608,9 @@ int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) pipe->srcp1_addr = start + img->offset; img = &req->plane2_data; - get_img(img, info, pipe, 2, &start, &len, &srcp2_file, - &p_need, &srcp2_ihdl); + get_img(img, info, pipe, 2, &start, &len, + &pipe->srcp2_file, &pipe->put2_need, + &srcp2_ihdl); if (len == 0) { pr_err("%s: Error to get plane2\n", __func__); ret = -EINVAL; @@ -3426,78 +3651,85 @@ int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) mdp4_overlay_mdp_perf_req(mfd, ctrl->plist); - if (pipe->mixer_num == MDP4_MIXER2 || ctrl->panel_mode & MDP4_PANEL_MDDI) - goto mddi; - if (pipe->mixer_num == MDP4_MIXER0) { if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { /* cndx = 0 */ mdp4_dsi_cmd_pipe_queue(0, pipe); - } - if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { /* cndx = 0 */ mdp4_dsi_video_pipe_queue(0, pipe); } else if (ctrl->panel_mode & MDP4_PANEL_LCDC) { /* cndx = 0 */ mdp4_lcdc_pipe_queue(0, pipe); } + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + /* cndx = 0 */ + mdp4_mddi_pipe_queue(0, pipe); + } } else if (pipe->mixer_num == MDP4_MIXER1) { - if (ctrl->panel_mode & MDP4_PANEL_DTV) + if (ctrl->panel_mode & MDP4_PANEL_DTV) { mdp4_dtv_pipe_queue(0, pipe);/* cndx = 0 */ + mdp4_dtv_set_avparams(pipe, img->memory_id); + } + } else if (pipe->mixer_num == MDP4_MIXER2) { + ctrl->mixer2_played++; + if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) + mdp4_wfd_pipe_queue(0, pipe);/* cndx = 0 */ } mutex_unlock(&mfd->dma->ov_mutex); return ret; -mddi: - if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) { - mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ - } else { - mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ - } +end: + mutex_unlock(&mfd->dma->ov_mutex); - mdp4_mixer_stage_up(pipe, 0); + return ret; +} - if (pipe->mixer_num == MDP4_MIXER2) { - ctrl->mixer2_played++; -#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL - if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) { - mdp4_writeback_dma_busy_wait(mfd); - mdp4_writeback_kickoff_video(mfd, pipe); - } -#endif - } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) { - if (pipe->flags & MDP_OV_PLAY_NOWAIT) { - mdp4_stat.overlay_play[pipe->mixer_num]++; - mutex_unlock(&mfd->dma->ov_mutex); - goto end; - } - mdp4_mixer_stage_commit(pipe->mixer_num); - mdp4_mddi_dma_busy_wait(mfd); - mdp4_mddi_kickoff_video(mfd, pipe); +int mdp4_overlay_commit(struct fb_info *info) +{ + int ret = 0; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mfd == NULL) + return -ENODEV; + + if (!mfd->panel_power_on) /* suspended */ + return -EINVAL; + + mutex_lock(&mfd->dma->ov_mutex); + + mdp4_overlay_mdp_perf_upd(mfd, 1); + + msm_fb_wait_for_fence(mfd); + + switch (mfd->panel.type) { + case MIPI_CMD_PANEL: + mdp4_dsi_cmd_pipe_commit(0, 1); + break; + case MIPI_VIDEO_PANEL: + mdp4_dsi_video_pipe_commit(0, 1); + break; + case LCDC_PANEL: + mdp4_lcdc_pipe_commit(0, 1); + break; + case DTV_PANEL: + mdp4_dtv_pipe_commit(0, 1); + break; + case WRITEBACK_PANEL: + mdp4_wfd_pipe_commit(mfd, 0, 1); + break; + default: + pr_err("Panel Not Supported for Commit"); + ret = -EINVAL; + break; } + msm_fb_signal_timeline(mfd); - /* write out DPP HSIC registers */ - if (pipe->flags & MDP_DPP_HSIC) - mdp4_hsic_update(pipe); - if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) - mdp4_iommu_unmap(pipe); - mdp4_stat.overlay_play[pipe->mixer_num]++; + mdp4_overlay_mdp_perf_upd(mfd, 0); -end: mutex_unlock(&mfd->dma->ov_mutex); -#ifdef CONFIG_ANDROID_PMEM - if (srcp0_file) - put_pmem_file(srcp0_file); - if (srcp1_file) - put_pmem_file(srcp1_file); - if (srcp2_file) - put_pmem_file(srcp2_file); -#endif - /* only source may use frame buffer */ - if (img->flags & MDP_MEMORY_ID_TYPE_FB) - fput_light(srcp0_file, ps0_need); return ret; } @@ -3730,3 +3962,58 @@ int mdp4_update_base_blend(struct msm_fb_data_type *mfd, } return ret; } + +int mdp4_update_writeback_format(struct msm_fb_data_type *mfd, + struct mdp_mixer_cfg *mdp_mixer_cfg) +{ + int ret = 0; + u32 mixer_num; + struct mdp_mixer_cfg *mixer; + + mixer_num = mdp4_get_mixer_num(mfd->panel_info.type); + if (!ctrl) { + pr_warn("mdp4_overlay_ctrl is NULL\n"); + return -EPERM; + } + mixer = &ctrl->mdp_mixer_cfg[mixer_num]; + + switch (mdp_mixer_cfg->writeback_format) { + case WB_FORMAT_RGB_888: + case WB_FORMAT_RGB_565: + case WB_FORMAT_NV12: + case WB_FORMAT_xRGB_8888: + case WB_FORMAT_ARGB_8888: + mixer->writeback_format = mdp_mixer_cfg->writeback_format; + break; + case WB_FORMAT_ARGB_8888_INPUT_ALPHA: + mixer->writeback_format = mdp_mixer_cfg->writeback_format; + mixer->alpha = mdp_mixer_cfg->alpha; + break; + default: + mixer->writeback_format = WB_FORMAT_NV12; + pr_warn("Unsupported format request, setting to NV12\n"); + ret = -EINVAL; + break; + } + return ret; +} + +int mdp4_update_base_blend(struct msm_fb_data_type *mfd, + struct mdp_blend_cfg *mdp_blend_cfg) +{ + int ret = 0; + u32 mixer_num; + struct blend_cfg *blend; + mixer_num = mdp4_get_mixer_num(mfd->panel_info.type); + if (!ctrl) + return -EPERM; + blend = &ctrl->blend[mixer_num][MDP4_MIXER_STAGE_BASE]; + if (mdp_blend_cfg->is_premultiplied) { + blend->bg_alpha = 0xFF; + blend->op = MDP4_BLEND_FG_ALPHA_BG_CONST; + } else { + blend->op = MDP4_BLEND_FG_ALPHA_FG_PIXEL; + blend->bg_alpha = 0; + } + return ret; +} diff --git a/drivers/video/msm/mdp4_overlay.c.save b/drivers/video/msm/mdp4_overlay.c.save new file mode 100644 index 00000000..0c755b3c --- /dev/null +++ b/drivers/video/msm/mdp4_overlay.c.save @@ -0,0 +1,3709 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#define VERSION_KEY_MASK 0xFFFFFF00 + +struct mdp4_overlay_ctrl { + struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX]; + struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX]; + struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX]; + struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX]; + uint32 mixer_cfg[MDP4_MIXER_MAX]; + uint32 flush[MDP4_MIXER_MAX]; + struct iommu_free_list iommu_free[MDP4_MIXER_MAX]; + uint32 cs_controller; + uint32 hw_version; + uint32 panel_3d; + uint32 panel_mode; + uint32 mixer0_played; + uint32 mixer1_played; + uint32 mixer2_played; +} mdp4_overlay_db = { + .cs_controller = CS_CONTROLLER_0, + .plist = { + { + .pipe_type = OVERLAY_TYPE_RGB, + .pipe_num = OVERLAY_PIPE_RGB1, + .pipe_ndx = 1, + }, + { + .pipe_type = OVERLAY_TYPE_RGB, + .pipe_num = OVERLAY_PIPE_RGB2, + .pipe_ndx = 2, + }, + { + .pipe_type = OVERLAY_TYPE_VIDEO, + .pipe_num = OVERLAY_PIPE_VG1, + .pipe_ndx = 3, + }, + { + .pipe_type = OVERLAY_TYPE_VIDEO, + .pipe_num = OVERLAY_PIPE_VG2, + .pipe_ndx = 4, + }, + { + .pipe_type = OVERLAY_TYPE_BF, + .pipe_num = OVERLAY_PIPE_RGB3, + .pipe_ndx = 5, + .mixer_num = MDP4_MIXER0, + }, + { + .pipe_type = OVERLAY_TYPE_BF, + .pipe_num = OVERLAY_PIPE_VG3, + .pipe_ndx = 6, + .mixer_num = MDP4_MIXER1, + }, + { + .pipe_type = OVERLAY_TYPE_BF, + .pipe_num = OVERLAY_PIPE_VG4, + .pipe_ndx = 7, + .mixer_num = MDP4_MIXER2, + }, + }, +}; + +static DEFINE_MUTEX(iommu_mutex); +static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db; + +struct mdp4_overlay_perf { + u32 mdp_clk_rate; + u32 use_ov0_blt; + u32 use_ov1_blt; + u32 mdp_bw; +}; + +struct mdp4_overlay_perf perf_request = { + .mdp_bw = OVERLAY_PERF_LEVEL4, +}; +struct mdp4_overlay_perf perf_current = { + .mdp_bw = OVERLAY_PERF_LEVEL4, +}; + +static struct ion_client *display_iclient; + + +/* + * mdp4_overlay_iommu_unmap_freelist() + * mdp4_overlay_iommu_2freelist() + * mdp4_overlay_iommu_pipe_free() + * above three functiosns need to be called from same thread and + * in order so that no mutex are needed. + */ +void mdp4_overlay_iommu_unmap_freelist(int mixer) +{ + int i; + struct ion_handle *ihdl; + struct iommu_free_list *flist; + + mutex_lock(&iommu_mutex); + flist = &ctrl->iommu_free[mixer]; + if (flist->total == 0) { + mutex_unlock(&iommu_mutex); + return; + } + for (i = 0; i < IOMMU_FREE_LIST_MAX; i++) { + ihdl = flist->ihdl[i]; + if (ihdl == NULL) + continue; + pr_debug("%s: mixer=%d i=%d ihdl=0x%p\n", __func__, + mixer, i, ihdl); + ion_unmap_iommu(display_iclient, ihdl, DISPLAY_READ_DOMAIN, + GEN_POOL); + mdp4_stat.iommu_unmap++; + pr_debug("%s: map=%d unmap=%d drop=%d\n", __func__, + (int)mdp4_stat.iommu_map, (int)mdp4_stat.iommu_unmap, + (int)mdp4_stat.iommu_drop); + ion_free(display_iclient, ihdl); + flist->ihdl[i] = NULL; + } + + flist->fndx = 0; + flist->total = 0; + mutex_unlock(&iommu_mutex); +} + +void mdp4_overlay_iommu_2freelist(int mixer, struct ion_handle *ihdl) +{ + struct iommu_free_list *flist; + + flist = &ctrl->iommu_free[mixer]; + if (flist->fndx >= IOMMU_FREE_LIST_MAX) { + pr_err("%s: Error, mixer=%d iommu fndx=%d\n", + __func__, mixer, flist->fndx); + mdp4_stat.iommu_drop++; + return; + } + + pr_debug("%s: add mixer=%d fndx=%d ihdl=0x%p\n", __func__, + mixer, flist->fndx, ihdl); + + flist->total++; + flist->ihdl[flist->fndx++] = ihdl; +} + +void mdp4_overlay_iommu_pipe_free(int ndx, int all) +{ + struct mdp4_overlay_pipe *pipe; + struct mdp4_iommu_pipe_info *iom; + int plane, mixer; + + pipe = mdp4_overlay_ndx2pipe(ndx); + if (pipe == NULL) + return; + + mutex_lock(&iommu_mutex); + mixer = pipe->mixer_num; + iom = &pipe->iommu; + pr_debug("%s: mixer=%d ndx=%d all=%d\n", __func__, + mixer, pipe->pipe_ndx, all); + for (plane = 0; plane < MDP4_MAX_PLANE; plane++) { + if (iom->prev_ihdl[plane]) { + mdp4_overlay_iommu_2freelist(mixer, + iom->prev_ihdl[plane]); + iom->prev_ihdl[plane] = NULL; + } + if (all && iom->ihdl[plane]) { + mdp4_overlay_iommu_2freelist(mixer, iom->ihdl[plane]); + iom->ihdl[plane] = NULL; + } + } + mutex_unlock(&iommu_mutex); +} + +int mdp4_overlay_iommu_map_buf(int mem_id, + struct mdp4_overlay_pipe *pipe, unsigned int plane, + unsigned long *start, unsigned long *len, + struct ion_handle **srcp_ihdl) +{ + struct mdp4_iommu_pipe_info *iom; + + if (!display_iclient) + return -EINVAL; + + *srcp_ihdl = ion_import_dma_buf(display_iclient, mem_id); + if (IS_ERR_OR_NULL(*srcp_ihdl)) { + pr_err("ion_import_dma_buf() failed\n"); + return PTR_ERR(*srcp_ihdl); + } + pr_debug("%s(): ion_hdl %p, ion_buf %d\n", __func__, *srcp_ihdl, + ion_share_dma_buf(display_iclient, *srcp_ihdl)); + pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num, + pipe->pipe_ndx, plane); + if (ion_map_iommu(display_iclient, *srcp_ihdl, + DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start, + len, 0, ION_IOMMU_UNMAP_DELAYED)) { + ion_free(display_iclient, *srcp_ihdl); + pr_err("ion_map_iommu() failed\n"); + return -EINVAL; + } + + mutex_lock(&iommu_mutex); + iom = &pipe->iommu; + if (iom->prev_ihdl[plane]) { + mdp4_overlay_iommu_2freelist(pipe->mixer_num, + iom->prev_ihdl[plane]); + mdp4_stat.iommu_drop++; + pr_err("%s: dropped, ndx=%d plane=%d\n", __func__, + pipe->pipe_ndx, plane); + } + iom->prev_ihdl[plane] = iom->ihdl[plane]; + iom->ihdl[plane] = *srcp_ihdl; + mdp4_stat.iommu_map++; + + pr_debug("%s: ndx=%d plane=%d prev=0x%p cur=0x%p start=0x%lx len=%lx\n", + __func__, pipe->pipe_ndx, plane, iom->prev_ihdl[plane], + iom->ihdl[plane], *start, *len); + mutex_unlock(&iommu_mutex); + return 0; +} + +static struct mdp4_iommu_pipe_info mdp_iommu[MDP4_MIXER_MAX][OVERLAY_PIPE_MAX]; + +void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_iommu_pipe_info *iom_pipe_info; + unsigned char i, j; + + if (!display_iclient) + return; + + for (j = 0; j < OVERLAY_PIPE_MAX; j++) { + iom_pipe_info = &mdp_iommu[pipe->mixer_num][j]; + for (i = 0; i < MDP4_MAX_PLANE; i++) { + if (iom_pipe_info->prev_ihdl[i]) { + pr_debug("%s(): mixer %u, pipe %u, plane %u, " + "prev_ihdl %p\n", __func__, + pipe->mixer_num, j + 1, i, + iom_pipe_info->prev_ihdl[i]); + ion_unmap_iommu(display_iclient, + iom_pipe_info->prev_ihdl[i], + DISPLAY_READ_DOMAIN, GEN_POOL); + ion_free(display_iclient, + iom_pipe_info->prev_ihdl[i]); + iom_pipe_info->prev_ihdl[i] = NULL; + } + + if (iom_pipe_info->mark_unmap) { + if (iom_pipe_info->ihdl[i]) { + pr_debug("%s(): MARK, mixer %u, pipe %u, plane %u, " + "ihdl %p\n", __func__, + pipe->mixer_num, j + 1, i, + iom_pipe_info->ihdl[i]); + ion_unmap_iommu(display_iclient, + iom_pipe_info->ihdl[i], + DISPLAY_READ_DOMAIN, GEN_POOL); + ion_free(display_iclient, + iom_pipe_info->ihdl[i]); + iom_pipe_info->ihdl[i] = NULL; + } + } + } + iom_pipe_info->mark_unmap = 0; + } +} + +int mdp4_overlay_mixer_play(int mixer_num) +{ + if (mixer_num == MDP4_MIXER2) + return ctrl->mixer2_played; + else if (mixer_num == MDP4_MIXER1) + return ctrl->mixer1_played; + else + return ctrl->mixer0_played; +} + +void mdp4_overlay_panel_3d(int mixer_num, uint32 panel_3d) +{ + ctrl->panel_3d = panel_3d; +} + +void mdp4_overlay_panel_mode(int mixer_num, uint32 mode) +{ + ctrl->panel_mode |= mode; +} + +void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode) +{ + ctrl->panel_mode &= ~mode; +} + +uint32 mdp4_overlay_panel_list(void) +{ + return ctrl->panel_mode; +} + +void mdp4_overlay_cfg_init(void) +{ + if (ctrl->hw_version == 0) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } + + if (ctrl->hw_version >= 0x0402030b) { + /* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */ + outpdw(MDP_BASE + 0x100fc, 0x01); + } +} + +int mdp4_overlay_borderfill_supported(void) +{ + return (ctrl->hw_version >= 0x0402030b); +} + +void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv) +{ + uint32 dmae_cfg_reg; + + if (atv) + dmae_cfg_reg = DMA_DEFLKR_EN; + else + dmae_cfg_reg = 0; + + if (mfd->fb_imgType == MDP_BGR_565) + dmae_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dmae_cfg_reg |= DMA_PACK_PATTERN_RGB; + + + if (mfd->panel_info.bpp == 18) { + dmae_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else if (mfd->panel_info.bpp == 16) { + dmae_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } else { + dmae_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* dma2 config register */ + MDP_OUTP(MDP_BASE + 0xb0000, dmae_cfg_reg); + if (atv) { + MDP_OUTP(MDP_BASE + 0xb0070, 0xeb0010); + MDP_OUTP(MDP_BASE + 0xb0074, 0xf00010); + MDP_OUTP(MDP_BASE + 0xb0078, 0xf00010); + MDP_OUTP(MDP_BASE + 0xb3000, 0x80); + MDP_OUTP(MDP_BASE + 0xb3010, 0x1800040); + MDP_OUTP(MDP_BASE + 0xb3014, 0x1000080); + MDP_OUTP(MDP_BASE + 0xb4004, 0x67686970); + } else { + mdp_vid_quant_set(); + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +#ifdef CONFIG_FB_MSM_HDMI_3D +void unfill_black_screen(void) { return; } +#else +void unfill_black_screen(void) +{ + uint32 temp_src_format; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* + * VG2 Constant Color + */ + temp_src_format = inpdw(MDP_BASE + 0x30050); + MDP_OUTP(MDP_BASE + 0x30050, temp_src_format&(~BIT(22))); + /* + * MDP_OVERLAY_REG_FLUSH + */ + MDP_OUTP(MDP_BASE + 0x18000, BIT(3)); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return; +} +#endif + +#ifdef CONFIG_FB_MSM_HDMI_3D +void fill_black_screen(void) { return; } +#else +void fill_black_screen(void) +{ + /*Black color*/ + uint32 color = 0x00000000; + uint32 temp_src_format; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* + * VG2 Constant Color + */ + MDP_OUTP(MDP_BASE + 0x31008, color); + /* + * MDP_VG2_SRC_FORMAT + */ + temp_src_format = inpdw(MDP_BASE + 0x30050); + MDP_OUTP(MDP_BASE + 0x30050, temp_src_format | BIT(22)); + /* + * MDP_OVERLAY_REG_FLUSH + */ + MDP_OUTP(MDP_BASE + 0x18000, BIT(3)); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return; +} +#endif + +void mdp4_overlay_dmae_xy(struct mdp4_overlay_pipe *pipe) +{ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + MDP_OUTP(MDP_BASE + 0xb0004, + (pipe->src_height << 16 | pipe->src_width)); + if (pipe->dma_blt_addr) { + uint32 off, bpp; +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + MDP_OUTP(MDP_BASE + 0xb0008, pipe->dma_blt_addr + off); + /* RGB888, output of overlay blending */ + MDP_OUTP(MDP_BASE + 0xb000c, pipe->src_width * bpp); + } else { + /* dma_e source */ + MDP_OUTP(MDP_BASE + 0xb0008, pipe->srcp0_addr); + MDP_OUTP(MDP_BASE + 0xb000c, pipe->srcp0_ystride); + } + /* dma_e dest */ + MDP_OUTP(MDP_BASE + 0xb0010, (pipe->dst_y << 16 | pipe->dst_x)); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc) +{ + uint32 dma2_cfg_reg; + uint32 mask, curr; + + dma2_cfg_reg = DMA_DITHER_EN; +#ifdef BLT_RGB565 + /* RGB888 is 0 */ + dma2_cfg_reg |= DMA_BUF_FORMAT_RGB565; /* blt only */ +#endif + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + + if (mfd->panel_info.bpp == 18) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else if (mfd->panel_info.bpp == 16) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } else { + dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifndef CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL + if (lcdc) + dma2_cfg_reg |= DMA_PACK_ALIGN_MSB; +#endif + + /* dma2 config register */ + curr = inpdw(MDP_BASE + 0x90000); + mask = 0x0FFFFFFF; + dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask); + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +/* + * mdp4_overlay_dmap_xy: called form baselayer only + */ +void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, bpp; + + if (!in_interrupt()) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (pipe->dma_blt_addr) { +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->dmap_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + MDP_OUTP(MDP_BASE + 0x90008, pipe->dma_blt_addr + off); + /* RGB888, output of overlay blending */ + MDP_OUTP(MDP_BASE + 0x9000c, pipe->src_width * bpp); + } else { + MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr); + MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride); + } + /* dma_p source */ + MDP_OUTP(MDP_BASE + 0x90004, + (pipe->src_height << 16 | pipe->src_width)); + + /* dma_p dest */ + MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x)); + + if (!in_interrupt()) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +#define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 +#define MDP4_VG_PHASE_STEP_SHIFT 29 + +static int mdp4_leading_0(uint32 num) +{ + uint32 bit = 0x80000000; + int i; + + for (i = 0; i < 32; i++) { + if (bit & num) + return i; + bit >>= 1; + } + + return i; +} + +static uint32 mdp4_scale_phase_step(int f_num, uint32 src, uint32 dst) +{ + uint32 val, s; + int n; + + n = mdp4_leading_0(src); + if (n > f_num) + n = f_num; + s = src << n; /* maximum to reduce lose of resolution */ + val = s / dst; + if (n < f_num) { + n = f_num - n; + val <<= n; + val |= ((s % dst) << n) / dst; + } + + return val; +} + +static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe) +{ + pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; + pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; + + if (pipe->dst_h && pipe->src_h != pipe->dst_h) { + u32 upscale_max; + upscale_max = (mdp_rev >= MDP_REV_41) ? + MDP4_REV41_OR_LATER_UP_SCALING_MAX : + MDP4_REV40_UP_SCALING_MAX; + if (pipe->dst_h > pipe->src_h * upscale_max) + return; + + pipe->op_mode |= MDP4_OP_SCALEY_EN; + + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) { + if (pipe->flags & MDP_BACKEND_COMPOSITION && + pipe->alpha_enable && pipe->dst_h > pipe->src_h) + pipe->op_mode |= MDP4_OP_SCALEY_PIXEL_RPT; + else if (pipe->dst_h <= (pipe->src_h / 4)) + pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEY_FIR; + } else { /* RGB pipe */ + pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED | + MDP4_OP_SCALE_RGB_BILINEAR | + MDP4_OP_SCALE_ALPHA_BILINEAR; + } + + pipe->phasey_step = mdp4_scale_phase_step(29, + pipe->src_h, pipe->dst_h); + } + + if (pipe->dst_w && pipe->src_w != pipe->dst_w) { + u32 upscale_max; + upscale_max = (mdp_rev >= MDP_REV_41) ? + MDP4_REV41_OR_LATER_UP_SCALING_MAX : + MDP4_REV40_UP_SCALING_MAX; + + if (pipe->dst_w > pipe->src_w * upscale_max) + return; + pipe->op_mode |= MDP4_OP_SCALEX_EN; + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) { + if (pipe->flags & MDP_BACKEND_COMPOSITION && + pipe->alpha_enable && pipe->dst_w > pipe->src_w) + pipe->op_mode |= MDP4_OP_SCALEX_PIXEL_RPT; + else if (pipe->dst_w <= (pipe->src_w / 4)) + pipe->op_mode |= MDP4_OP_SCALEX_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEX_FIR; + } else { /* RGB pipe */ + pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED | + MDP4_OP_SCALE_RGB_BILINEAR | + MDP4_OP_SCALE_ALPHA_BILINEAR; + } + + pipe->phasex_step = mdp4_scale_phase_step(29, + pipe->src_w, pipe->dst_w); + } +} + +void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe) +{ + char *rgb_base; + uint32 src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern; + uint32 curr, mask; + uint32 offset = 0; + int pnum; + + pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1; /* start from 0 */ + rgb_base = MDP_BASE + MDP4_RGB_BASE; + rgb_base += (MDP4_RGB_OFF * pnum); + + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + if ((pipe->src_x + pipe->src_w) > 0x7FF) { + offset += pipe->src_x * pipe->bpp; + src_xy &= 0xFFFF0000; + } + + if ((pipe->src_y + pipe->src_h) > 0x7FF) { + offset += pipe->src_y * pipe->src_width * pipe->bpp; + src_xy &= 0x0000FFFF; + } + + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + +#ifdef MDP4_IGC_LUT_ENABLE + pipe->op_mode |= MDP4_OP_IGC_LUT_EN; +#endif + + mdp4_scale_setup(pipe); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* Ensure proper covert matrix loaded when color space swaps */ + curr = inpdw(rgb_base + 0x0058); + /* Don't touch bits you don't want to configure*/ + mask = 0xFFFEFFFF; + pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask); + + outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(rgb_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + + outpdw(rgb_base + 0x0010, pipe->srcp0_addr + offset); + outpdw(rgb_base + 0x0040, pipe->srcp0_ystride); + + outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */ + outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */ + if (format & MDP4_FORMAT_SOLID_FILL) { + u32 op_mode = pipe->op_mode; + op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN); + op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN); + outpdw(rgb_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */ + } else + outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(rgb_base + 0x005c, pipe->phasex_step); + outpdw(rgb_base + 0x0060, pipe->phasey_step); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp4_stat.pipe[pipe->pipe_num]++; +} + + +static void mdp4_overlay_vg_get_src_offset(struct mdp4_overlay_pipe *pipe, + char *vg_base, uint32 *luma_off, uint32 *chroma_off) +{ + uint32 src_xy; + *luma_off = 0; + *chroma_off = 0; + + if (pipe->src_x && (pipe->frame_format == + MDP4_FRAME_FORMAT_LINEAR)) { + src_xy = (pipe->src_y << 16) | pipe->src_x; + src_xy &= 0xffff0000; + outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + + switch (pipe->src_format) { + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CB_CR_H2V2: + *luma_off = pipe->src_x; + *chroma_off = pipe->src_x/2; + break; + + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + *luma_off = pipe->src_x; + *chroma_off = pipe->src_x; + break; + + case MDP_YCRYCB_H2V1: + if (pipe->src_x & 0x1) + pipe->src_x += 1; + *luma_off += pipe->src_x * 2; + break; + + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + case MDP_RGB_565: + case MDP_BGR_565: + case MDP_XRGB_8888: + case MDP_RGB_888: + case MDP_YCBCR_H1V1: + case MDP_YCRCB_H1V1: + *luma_off = pipe->src_x * pipe->bpp; + break; + + default: + pr_err("%s: fmt %u not supported for adjustment\n", + __func__, pipe->src_format); + break; + } + } +} + +void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) +{ + char *vg_base; + uint32 frame_size, src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern, luma_offset, chroma_offset; + uint32 mask, curr, addr; + int pnum, ptype; + + pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */ + vg_base = MDP_BASE + MDP4_VIDEO_BASE; + vg_base += (MDP4_VIDEO_OFF * pnum); + + frame_size = ((pipe->src_height << 16) | pipe->src_width); + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + ptype = mdp4_overlay_format2type(pipe->src_format); + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + + /* not RGB use VG pipe, pure VG pipe */ + pipe->op_mode |= MDP4_OP_CSC_EN; + if (ptype != OVERLAY_TYPE_RGB) + pipe->op_mode |= MDP4_OP_SRC_DATA_YCBCR; + +#ifdef MDP4_IGC_LUT_ENABLE + pipe->op_mode |= MDP4_OP_IGC_LUT_EN; +#endif + + mdp4_scale_setup(pipe); + + luma_offset = 0; + chroma_offset = 0; + + if (ptype == OVERLAY_TYPE_RGB) { + if ((pipe->src_y + pipe->src_h) > 0x7FF) { + luma_offset = pipe->src_y * pipe->src_width * pipe->bpp; + src_xy &= 0x0000FFFF; + } + + if ((pipe->src_x + pipe->src_w) > 0x7FF) { + luma_offset += pipe->src_x * pipe->bpp; + src_xy &= 0xFFFF0000; + } + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(vg_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(vg_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + + if (pipe->frame_format != MDP4_FRAME_FORMAT_LINEAR) + outpdw(vg_base + 0x0048, frame_size); /* TILE frame size */ + + /* + * Adjust src X offset to avoid MDP from overfetching pixels + * present before the offset. This is required for video + * frames coming with unused green pixels along the left margin + */ + /* not RGB use VG pipe, pure VG pipe */ + if (ptype != OVERLAY_TYPE_RGB) { + mdp4_overlay_vg_get_src_offset(pipe, vg_base, &luma_offset, + &chroma_offset); + } + + /* Ensure proper covert matrix loaded when color space swaps */ + curr = inpdw(vg_base + 0x0058); + mask = 0x600; + + if ((curr & mask) != (pipe->op_mode & mask)) { + addr = ((uint32_t)vg_base) + 0x4000; + if (ptype != OVERLAY_TYPE_RGB) + mdp4_csc_write(&(mdp_csc_convert[1]), addr); + else + mdp4_csc_write(&(mdp_csc_convert[0]), addr); + + mask = 0xFFFCFFFF; + } else { + /* Don't touch bits you don't want to configure*/ + mask = 0xFFFCF1FF; + } + pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask); + + /* luma component plane */ + outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset); + + /* chroma component plane or planar color 1 */ + outpdw(vg_base + 0x0014, pipe->srcp1_addr + chroma_offset); + + /* planar color 2 */ + outpdw(vg_base + 0x0018, pipe->srcp2_addr + chroma_offset); + + outpdw(vg_base + 0x0040, + pipe->srcp1_ystride << 16 | pipe->srcp0_ystride); + + outpdw(vg_base + 0x0044, + pipe->srcp3_ystride << 16 | pipe->srcp2_ystride); + + outpdw(vg_base + 0x0050, format); /* MDP_RGB_SRC_FORMAT */ + outpdw(vg_base + 0x0054, pattern); /* MDP_RGB_SRC_UNPACK_PATTERN */ + if (format & MDP4_FORMAT_SOLID_FILL) { + u32 op_mode = pipe->op_mode; + op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN); + op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN); + outpdw(vg_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */ + } else + outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(vg_base + 0x005c, pipe->phasex_step); + outpdw(vg_base + 0x0060, pipe->phasey_step); + + if (pipe->op_mode & MDP4_OP_DITHER_EN) { + outpdw(vg_base + 0x0068, + pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit); + } + + if (pipe->flags & MDP_SHARPENING) { + outpdw(vg_base + 0x8200, + mdp4_ss_table_value(pipe->req_data.dpp.sharp_strength, + 0)); + outpdw(vg_base + 0x8204, + mdp4_ss_table_value(pipe->req_data.dpp.sharp_strength, + 1)); + } + + if (mdp_rev > MDP_REV_41) { + /* mdp chip select controller */ + mask = 0; + if (pipe->pipe_num == OVERLAY_PIPE_VG1) + mask = 0x020; /* bit 5 */ + else if (pipe->pipe_num == OVERLAY_PIPE_VG2) + mask = 0x02000; /* bit 13 */ + if (mask) { + if (pipe->op_mode & MDP4_OP_SCALEY_MN_PHASE) + ctrl->cs_controller &= ~mask; + else + ctrl->cs_controller |= mask; + /* NOT double buffered */ + outpdw(MDP_BASE + 0x00c0, ctrl->cs_controller); + } + } + + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp4_stat.pipe[pipe->pipe_num]++; +} + +int mdp4_overlay_format2type(uint32 format) +{ + switch (format) { + case MDP_RGB_565: + case MDP_RGB_888: + case MDP_BGR_565: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + return OVERLAY_TYPE_RGB; + case MDP_YCRYCB_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CB_CR_H2V2: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + case MDP_YCRCB_H1V1: + case MDP_YCBCR_H1V1: + return OVERLAY_TYPE_VIDEO; + case MDP_RGB_BORDERFILL: + return OVERLAY_TYPE_BF; + default: + mdp4_stat.err_format++; + return -ERANGE; + } + +} + +#define C3_ALPHA 3 /* alpha */ +#define C2_R_Cr 2 /* R/Cr */ +#define C1_B_Cb 1 /* B/Cb */ +#define C0_G_Y 0 /* G/luma */ +#define YUV_444_MAX_WIDTH 1280 /* Max width for YUV 444*/ + +int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) +{ + switch (pipe->src_format) { + case MDP_RGB_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_RGB_888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 3; /* 3 bpp */ + break; + case MDP_BGR_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_XRGB_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C1_B_Cb; /* B */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_ARGB_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C1_B_Cb; /* B */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_RGBA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_RGBX_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_BGRA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_YCRYCB_H2V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C0_G_Y; /* G */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + break; + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + if (pipe->src_format == MDP_Y_CRCB_H2V1) { + pipe->element1 = C1_B_Cb; + pipe->element0 = C2_R_Cr; + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CRCB_H1V1) { + pipe->element1 = C1_B_Cb; + pipe->element0 = C2_R_Cr; + if (pipe->src_width > YUV_444_MAX_WIDTH) + pipe->chroma_sample = MDP4_CHROMA_H1V2; + else + pipe->chroma_sample = MDP4_CHROMA_RGB; + } else if (pipe->src_format == MDP_Y_CBCR_H2V1) { + pipe->element1 = C2_R_Cr; + pipe->element0 = C1_B_Cb; + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CBCR_H1V1) { + pipe->element1 = C2_R_Cr; + pipe->element0 = C1_B_Cb; + if (pipe->src_width > YUV_444_MAX_WIDTH) + pipe->chroma_sample = MDP4_CHROMA_H1V2; + else + pipe->chroma_sample = MDP4_CHROMA_RGB; + } else if (pipe->src_format == MDP_Y_CRCB_H2V2) { + pipe->element1 = C1_B_Cb; + pipe->element0 = C2_R_Cr; + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2) { + pipe->element1 = C2_R_Cr; + pipe->element0 = C1_B_Cb; + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + pipe->frame_format = MDP4_FRAME_FORMAT_VIDEO_SUPERTILE; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + if (pipe->src_format == MDP_Y_CRCB_H2V2_TILE) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2_TILE) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CB_CR_H2V2: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->chroma_sample = MDP4_CHROMA_420; + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_YCBCR_H1V1: + case MDP_YCRCB_H1V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element0 = C0_G_Y; /* G */ + if (pipe->src_format == MDP_YCRCB_H1V1) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element2 = C1_B_Cb; /* B */ + } else { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element2 = C2_R_Cr; /* R */ + } + pipe->bpp = 3; /* 3 bpp */ + case MDP_RGB_BORDERFILL: + pipe->alpha_enable = 0; + pipe->alpha = 0; + break; + default: + /* not likely */ + mdp4_stat.err_format++; + return -ERANGE; + } + + return 0; +} + +/* + * color_key_convert: output with 12 bits color key + */ +static uint32 color_key_convert(int start, int num, uint32 color) +{ + uint32 data; + + data = (color >> start) & ((1 << num) - 1); + + /* convert to 8 bits */ + if (num == 5) + data = ((data << 3) | (data >> 2)); + else if (num == 6) + data = ((data << 2) | (data >> 4)); + + /* convert 8 bits to 12 bits */ + data = (data << 4) | (data >> 4); + + return data; +} + +void transp_color_key(int format, uint32 transp, + uint32 *c0, uint32 *c1, uint32 *c2) +{ + int b_start, g_start, r_start; + int b_num, g_num, r_num; + + switch (format) { + case MDP_RGB_565: + b_start = 0; + g_start = 5; + r_start = 11; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_RGB_888: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_BGRA_8888: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_RGBA_8888: + case MDP_RGBX_8888: + b_start = 16; + g_start = 8; + r_start = 0; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_BGR_565: + b_start = 11; + g_start = 5; + r_start = 0; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_Y_CB_CR_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V1: + case MDP_YCBCR_H1V1: + b_start = 8; + g_start = 16; + r_start = 0; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + case MDP_YCRCB_H1V1: + b_start = 0; + g_start = 16; + r_start = 8; + r_num = 8; + g_num = 8; + b_num = 8; + break; + default: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + } + + *c0 = color_key_convert(g_start, g_num, transp); + *c1 = color_key_convert(b_start, b_num, transp); + *c2 = color_key_convert(r_start, r_num, transp); +} + +uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe) +{ + uint32 format; + + format = 0; + + if (pipe->solid_fill) + format |= MDP4_FORMAT_SOLID_FILL; + + if (pipe->unpack_align_msb) + format |= MDP4_FORMAT_UNPACK_ALIGN_MSB; + + if (pipe->unpack_tight) + format |= MDP4_FORMAT_UNPACK_TIGHT; + + if (pipe->alpha_enable) + format |= MDP4_FORMAT_ALPHA_ENABLE; + + if (pipe->flags & MDP_SOURCE_ROTATED_90) + format |= MDP4_FORMAT_90_ROTATED; + format |= (pipe->unpack_count << 13); + format |= ((pipe->bpp - 1) << 9); + format |= (pipe->a_bit << 6); + format |= (pipe->r_bit << 4); + format |= (pipe->b_bit << 2); + format |= pipe->g_bit; + + format |= (pipe->frame_format << 29); + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR || + pipe->fetch_plane == OVERLAY_PLANE_PLANAR) { + /* video/graphic */ + format |= (pipe->fetch_plane << 19); + format |= (pipe->chroma_site << 28); + format |= (pipe->chroma_sample << 26); + } + + return format; +} + +uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe) +{ + return (pipe->element3 << 24) | (pipe->element2 << 16) | + (pipe->element1 << 8) | pipe->element0; +} + +/* + * mdp4_overlayproc_cfg: only be called from base layer + */ +void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) +{ + uint32 data, intf; + char *overlay_base; + uint32 curr; + + intf = 0; + if (pipe->mixer_num == MDP4_MIXER2) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE; + else if (pipe->mixer_num == MDP4_MIXER1) { + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + intf = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */ + intf >>= 4; + intf &= 0x03; + } else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + if (!in_interrupt()) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* + * BLT support both primary and external external + */ + if (pipe->ov_blt_addr) { + int off, bpp; +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + data = pipe->src_height; + data <<= 16; + data |= pipe->src_width; + outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ + if (pipe->mixer_num == MDP4_MIXER0 || + pipe->mixer_num == MDP4_MIXER1) { + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + + outpdw(overlay_base + 0x000c, pipe->ov_blt_addr + off); + /* overlay ouput is RGB888 */ + outpdw(overlay_base + 0x0010, pipe->src_width * bpp); + outpdw(overlay_base + 0x001c, pipe->ov_blt_addr + off); + /* MDDI - BLT + on demand */ + outpdw(overlay_base + 0x0004, 0x08); + + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; +#ifdef BLT_RGB565 + outpdw(overlay_base + 0x0014, curr | 0x1); /* RGB565 */ +#else + outpdw(overlay_base + 0x0014, curr | 0x0); /* RGB888 */ +#endif + } else if (pipe->mixer_num == MDP4_MIXER2) { + if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) { + off = 0; + bpp = 1; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * + pipe->src_width * bpp; + + outpdw(overlay_base + 0x000c, + pipe->ov_blt_addr + off); + /* overlay ouput is RGB888 */ + outpdw(overlay_base + 0x0010, + ((pipe->src_width << 16) | + pipe->src_width)); + outpdw(overlay_base + 0x001c, + pipe->ov_blt_addr + off); + off = pipe->src_height * pipe->src_width; + /* align chroma to 2k address */ + off = (off + 2047) & ~2047; + /* UV plane adress */ + outpdw(overlay_base + 0x0020, + pipe->ov_blt_addr + off); + /* MDDI - BLT + on demand */ + outpdw(overlay_base + 0x0004, 0x08); + /* pseudo planar + writeback */ + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; + outpdw(overlay_base + 0x0014, curr | 0x012); + /* rgb->yuv */ + outpdw(overlay_base + 0x0200, 0x05); + } + } + } else { + data = pipe->src_height; + data <<= 16; + data |= pipe->src_width; + outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ + outpdw(overlay_base + 0x000c, pipe->srcp0_addr); + outpdw(overlay_base + 0x0010, pipe->srcp0_ystride); + outpdw(overlay_base + 0x0004, 0x01); /* directout */ + } + + if (pipe->mixer_num == MDP4_MIXER1) { + if (intf == TV_INTF) { + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; + outpdw(overlay_base + 0x0014, 0x02); /* yuv422 */ + /* overlay1 CSC config */ + outpdw(overlay_base + 0x0200, 0x05); /* rgb->yuv */ + } + } + +#ifdef MDP4_IGC_LUT_ENABLE + curr = inpdw(overlay_base + 0x0014); + curr &= ~0x4; + outpdw(overlay_base + 0x0014, curr | 0x4); /* GC_LUT_EN, 888 */ +#endif + + if (!in_interrupt()) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +int mdp4_overlay_pipe_staged(int mixer) +{ + uint32 data, mask, i, off; + int p1, p2; + + if (mixer == MDP4_MIXER2) + off = 0x100F0; + else + off = 0x10100; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + data = inpdw(MDP_BASE + off); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + p1 = 0; + p2 = 0; + for (i = 0; i < 8; i++) { + mask = data & 0x0f; + if (mask) { + if (mask <= 4) + p1++; + else + p2++; + } + data >>= 4; + } + + if (mixer) + return p2; + else + return p1; +} + +int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info) +{ + + int ndx, cnt; + struct mdp4_overlay_pipe *pipe; + + if (mixer_num > MDP4_MIXER_MAX) + return -ENODEV; + + cnt = 0; + ndx = MDP4_MIXER_STAGE_BASE; + for ( ; ndx < MDP4_MIXER_STAGE_MAX; ndx++) { + pipe = ctrl->stage[mixer_num][ndx]; + if (pipe == NULL) + continue; + info->z_order = pipe->mixer_stage - MDP4_MIXER_STAGE0; + /* z_order == -1, means base layer */ + info->ptype = pipe->pipe_type; + info->pnum = pipe->pipe_num; + info->pndx = pipe->pipe_ndx; + info->mixer_num = pipe->mixer_num; + info++; + cnt++; + } + return cnt; +} + +void mdp4_mixer_stage_commit(int mixer) +{ + struct mdp4_overlay_pipe *pipe; + int i, num; + u32 data, stage; + int off; + unsigned long flags; + + data = 0; + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pipe = ctrl->stage[mixer][i]; + if (pipe == NULL) + continue; + pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__, + mixer, pipe->pipe_ndx, i); + stage = pipe->mixer_stage; + if (mixer >= MDP4_MIXER1) + stage += 8; + stage <<= (4 * pipe->pipe_num); + data |= stage; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); + mdp4_mixer_blend_setup(mixer); + + off = 0; + if (data != ctrl->mixer_cfg[mixer]) { + ctrl->mixer_cfg[mixer] = data; + if (mixer >= MDP4_MIXER2) { + /* MDP_LAYERMIXER2_IN_CFG */ + off = 0x100f0; + } else { + /* mixer 0 or 1 */ + num = mixer + 1; + num &= 0x01; + data |= ctrl->mixer_cfg[num]; + off = 0x10100; + } + pr_debug("%s: mixer=%d data=%x flush=%x pid=%d\n", __func__, + mixer, data, ctrl->flush[mixer], current->pid); + } + + local_irq_save(flags); + if (off) + outpdw(MDP_BASE + off, data); + + if (ctrl->flush[mixer]) { + outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]); + ctrl->flush[mixer] = 0; + } + local_irq_restore(flags); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_clk_ctrl(0); +} + + +void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe, int commit) +{ + struct mdp4_overlay_pipe *pp; + int i, mixer; + + mixer = pipe->mixer_num; + + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pp = ctrl->stage[mixer][i]; + if (pp && pp->pipe_ndx == pipe->pipe_ndx) { + ctrl->stage[mixer][i] = NULL; + break; + } + } + + ctrl->stage[mixer][pipe->mixer_stage] = pipe; /* keep it */ + + if (commit) + mdp4_mixer_stage_commit(mixer); +} + +void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe, int commit) +{ + struct mdp4_overlay_pipe *pp; + int i, mixer; + + mixer = pipe->mixer_num; + + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pp = ctrl->stage[mixer][i]; + if (pp && pp->pipe_ndx == pipe->pipe_ndx) + ctrl->stage[mixer][i] = NULL; /* clear it */ + } + + if (commit || (mixer > 0 && !hdmi_prim_display)) + mdp4_mixer_stage_commit(mixer); +} +/* + * mixer0: rgb3: border color at register 0x15004, 0x15008 + * mixer1: vg3: border color at register 0x1D004, 0x1D008 + * mixer2: xxx: border color at register 0x8D004, 0x8D008 + */ +void mdp4_overlay_borderfill_stage_up(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_overlay_pipe *bspipe; + int ptype, pnum, pndx, mixer; + int format, alpha_enable, alpha; + + if (pipe->pipe_type != OVERLAY_TYPE_BF) + return; + + mixer = pipe->mixer_num; + + if (ctrl->baselayer[mixer]) + return; + + bspipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE]; + + /* + * bspipe is clone here + * get real pipe + */ + bspipe = mdp4_overlay_ndx2pipe(bspipe->pipe_ndx); + + /* save original base layer */ + ctrl->baselayer[mixer] = bspipe; + + pipe->alpha = 0; /* make sure bf pipe has alpha 0 */ + ptype = pipe->pipe_type; + pnum = pipe->pipe_num; + pndx = pipe->pipe_ndx; + format = pipe->src_format; + alpha_enable = pipe->alpha_enable; + alpha = pipe->alpha; + *pipe = *bspipe; /* keep base layer configuration */ + pipe->pipe_type = ptype; + pipe->pipe_num = pnum; + pipe->pipe_ndx = pndx; + pipe->src_format = format; + pipe->alpha_enable = alpha_enable; + pipe->alpha = alpha; + + /* free original base layer pipe to be sued as normal pipe */ + bspipe->pipe_used = 0; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + mdp4_dsi_video_base_swap(0, pipe); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_cmd_base_swap(0, pipe); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_lcdc_base_swap(0, pipe); + else if (ctrl->panel_mode & MDP4_PANEL_DTV) + mdp4_dtv_base_swap(0, pipe); + + mdp4_overlay_reg_flush(bspipe, 1); + /* borderfill pipe as base layer */ + mdp4_mixer_stage_up(pipe, 0); +} + +void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_overlay_pipe *bspipe; + int ptype, pnum, pndx, mixer; + int format, alpha_enable, alpha; + + if (pipe->pipe_type != OVERLAY_TYPE_BF) + return; + + mixer = pipe->mixer_num; + + /* retrieve original base layer */ + bspipe = ctrl->baselayer[mixer]; + if (bspipe == NULL) { + pr_err("%s: no base layer at mixer=%d\n", + __func__, mixer); + return; + } + + ptype = bspipe->pipe_type; + pnum = bspipe->pipe_num; + pndx = bspipe->pipe_ndx; + format = bspipe->src_format; + alpha_enable = bspipe->alpha_enable; + alpha = bspipe->alpha; + *bspipe = *pipe; /* restore base layer configuration */ + bspipe->pipe_type = ptype; + bspipe->pipe_num = pnum; + bspipe->pipe_ndx = pndx; + bspipe->src_format = format; + bspipe->alpha_enable = alpha_enable; + bspipe->alpha = alpha; + + bspipe->pipe_used++; /* mark base layer pipe used */ + + ctrl->baselayer[mixer] = NULL; + + /* free borderfill pipe */ + pipe->pipe_used = 0; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + mdp4_dsi_video_base_swap(0, bspipe); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_cmd_base_swap(0, bspipe); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_lcdc_base_swap(0, bspipe); + else if (ctrl->panel_mode & MDP4_PANEL_DTV) + mdp4_dtv_base_swap(0, bspipe); + + /* free borderfill pipe */ + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_down(pipe, 0); /* commit will happen for bspipe up */ + mdp4_overlay_pipe_free(pipe); + + /* stage up base layer */ + mdp4_overlay_reg_flush(bspipe, 1); + /* restore original base layer */ + mdp4_mixer_stage_up(bspipe, 1); +} + + +static struct mdp4_overlay_pipe *mdp4_background_layer(int mixer, + struct mdp4_overlay_pipe *sp) +{ + struct mdp4_overlay_pipe *pp; + struct mdp4_overlay_pipe *kp; + int i; + + kp = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE]; + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pp = ctrl->stage[mixer][i]; + if (pp == NULL) + continue; + if (pp == sp) + break; + + if ((pp->dst_x <= sp->dst_x) && + ((pp->dst_x + pp->dst_w) >= (sp->dst_x + sp->dst_w))) { + if ((pp->dst_y <= sp->dst_y) && + ((pp->dst_y + pp->dst_h) >= + (sp->dst_y + sp->dst_h))) { + kp = pp; + } + } + } + return kp; +} + +static void mdp4_overlay_bg_solidfill(struct blend_cfg *blend) +{ + struct mdp4_overlay_pipe *pipe; + char *base; + u32 op_mode, format; + int pnum, ptype; + + pipe = blend->solidfill_pipe; + if (pipe == NULL) + return; + + if (pipe->pipe_type == OVERLAY_TYPE_BF) + return; + + ptype = mdp4_overlay_format2type(pipe->src_format); + if (ptype == OVERLAY_TYPE_RGB) { + pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1; + base = MDP_BASE + MDP4_RGB_BASE; + base += MDP4_RGB_OFF * pnum; + } else { + pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; + base = MDP_BASE + MDP4_VIDEO_BASE; + base += MDP4_VIDEO_OFF * pnum; + } + + format = inpdw(base + 0x50); + if (blend->solidfill) { + format |= MDP4_FORMAT_SOLID_FILL; + /* + * If solid fill is enabled, flip and scale + * have to be disabled. otherwise, h/w + * underruns. + */ + op_mode = inpdw(base + 0x0058); + op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN); + op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN); + outpdw(base + 0x0058, op_mode); + outpdw(base + 0x1008, 0); /* black */ + /* + * Set src size and dst size same to avoid underruns + */ + outpdw(base + 0x0000, inpdw(base + 0x0008)); + } else { + u32 src_size = ((pipe->src_h << 16) | pipe->src_w); + outpdw(base + 0x0000, src_size); + format &= ~MDP4_FORMAT_SOLID_FILL; + blend->solidfill_pipe = NULL; + } + + outpdw(base + 0x50, format); + + mdp4_overlay_reg_flush(pipe, 0); +} + +void mdp4_mixer_blend_cfg(int mixer) +{ + int i, off; + unsigned char *overlay_base; + struct blend_cfg *blend; + + if (mixer == MDP4_MIXER2) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE; + else if (mixer == MDP4_MIXER1) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE; + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE; + + blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE]; + blend++; /* stage0 */ + + for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) { + off = 20 * i; + off = 0x20 * (i - MDP4_MIXER_STAGE0); + if (i == MDP4_MIXER_STAGE3) + off -= 4; + outpdw(overlay_base + off + 0x104, blend->op); + blend++; + } +} + +/* + * D(i+1) = Ks * S + Kd * D(i) + */ +void mdp4_mixer_blend_setup(int mixer) +{ + struct mdp4_overlay_pipe *d_pipe; + struct mdp4_overlay_pipe *s_pipe; + struct blend_cfg *blend; + int i, off, ptype, alpha_drop = 0; + int d_alpha, s_alpha; + unsigned char *overlay_base; + uint32 c0, c1, c2; + + + d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE]; + if (d_pipe == NULL) { + pr_err("%s: Error: no bg_pipe at mixer=%d\n", __func__, mixer); + return; + } + + blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0]; + for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) { + blend->solidfill = 0; + blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST | + MDP4_BLEND_BG_ALPHA_BG_CONST); + s_pipe = ctrl->stage[mixer][i]; + if (s_pipe == NULL) { + blend++; + d_pipe = NULL; + d_alpha = 0; + continue; + } + /* alpha channel is lost on VG pipe when using QSEED or M/N */ + if (s_pipe->pipe_type == OVERLAY_TYPE_VIDEO && + ((s_pipe->op_mode & MDP4_OP_SCALEY_EN) || + (s_pipe->op_mode & MDP4_OP_SCALEX_EN)) && + !(s_pipe->op_mode & MDP4_OP_SCALEY_PIXEL_RPT)) + alpha_drop = 1; + + d_pipe = mdp4_background_layer(mixer, s_pipe); + d_alpha = d_pipe->alpha_enable; + s_alpha = s_pipe->alpha_enable; + pr_debug("%s: stage=%d: bg: ndx=%d da=%d dalpha=%x " + "fg: ndx=%d sa=%d salpha=%x is_fg=%d alpha_drop=%d\n", + __func__, i-2, d_pipe->pipe_ndx, d_alpha, d_pipe->alpha, + s_pipe->pipe_ndx, s_alpha, s_pipe->alpha, s_pipe->is_fg, + alpha_drop); + + /* base on fg's alpha */ + blend->bg_alpha = 0x0ff - s_pipe->alpha; + blend->fg_alpha = s_pipe->alpha; + blend->co3_sel = 1; /* use fg alpha */ + + if (s_pipe->is_fg) { + if (s_pipe->alpha == 0xff) { + blend->solidfill = 1; + blend->solidfill_pipe = d_pipe; + } + } else if (s_alpha) { + if (!alpha_drop) { + blend->op = MDP4_BLEND_BG_ALPHA_FG_PIXEL; + if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) + blend->op |= + MDP4_BLEND_FG_ALPHA_FG_PIXEL; + } else + blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST; + + blend->op |= MDP4_BLEND_BG_INV_ALPHA; + } else if (d_alpha) { + ptype = mdp4_overlay_format2type(s_pipe->src_format); + if (ptype == OVERLAY_TYPE_VIDEO) { + blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL | + MDP4_BLEND_FG_INV_ALPHA); + if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) + blend->op |= + MDP4_BLEND_BG_ALPHA_BG_PIXEL; + blend->co3_sel = 0; /* use bg alpha */ + } else { + /* s_pipe is rgb without alpha */ + blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST | + MDP4_BLEND_BG_ALPHA_BG_CONST); + blend->bg_alpha = 0; + } + } + + if (s_pipe->transp != MDP_TRANSP_NOP) { + if (s_pipe->is_fg) { + transp_color_key(s_pipe->src_format, + s_pipe->transp, &c0, &c1, &c2); + /* Fg blocked */ + blend->op |= MDP4_BLEND_FG_TRANSP_EN; + /* lower limit */ + blend->transp_low0 = (c1 << 16 | c0); + blend->transp_low1 = c2; + /* upper limit */ + blend->transp_high0 = (c1 << 16 | c0); + blend->transp_high1 = c2; + } else { + transp_color_key(d_pipe->src_format, + s_pipe->transp, &c0, &c1, &c2); + /* Fg blocked */ + blend->op |= MDP4_BLEND_BG_TRANSP_EN; + blend--; /* one stage back */ + /* lower limit */ + blend->transp_low0 = (c1 << 16 | c0); + blend->transp_low1 = c2; + /* upper limit */ + blend->transp_high0 = (c1 << 16 | c0); + blend->transp_high1 = c2; + blend++; /* back to original stage */ + } + } + blend++; + } + + /* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */ + if (mixer == MDP4_MIXER2) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */ + else if (mixer == MDP4_MIXER1) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE]; + /* lower limit */ + outpdw(overlay_base + 0x180, blend->transp_low0); + outpdw(overlay_base + 0x184, blend->transp_low1); + /* upper limit */ + outpdw(overlay_base + 0x188, blend->transp_high0); + outpdw(overlay_base + 0x18c, blend->transp_high1); + blend++; /* stage0 */ + for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) { + off = 20 * i; + off = 0x20 * (i - MDP4_MIXER_STAGE0); + if (i == MDP4_MIXER_STAGE3) + off -= 4; + + if (blend->solidfill_pipe) + mdp4_overlay_bg_solidfill(blend); + + outpdw(overlay_base + off + 0x108, blend->fg_alpha); + outpdw(overlay_base + off + 0x10c, blend->bg_alpha); + + if (mdp_rev >= MDP_REV_42) + outpdw(overlay_base + off + 0x104, blend->op); + + outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel); + outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */ + outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */ + /* upper limit */ + outpdw(overlay_base + off + 0x118, blend->transp_high0); + outpdw(overlay_base + off + 0x11c, blend->transp_high1); + blend++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all) +{ + int mixer; + uint32 *reg; + + mixer = pipe->mixer_num; + reg = &ctrl->flush[mixer]; + *reg |= (1 << (2 + pipe->pipe_num)); + + if (all) { + if (mixer == MDP4_MIXER0) + *reg |= 0x01; + else + *reg |= 0x02; + } +} + +void mdp4_overlay_flush_piggyback(int m0, int m1) +{ + u32 data; + + data = ctrl->flush[m0] | ctrl->flush[m1]; + ctrl->flush[m0] = data; +} + +void mdp4_overlay_reg_flush_reset(struct mdp4_overlay_pipe *pipe) +{ + int mixer; + + mixer = pipe->mixer_num; + ctrl->flush[mixer] = 0; +} + +struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage) +{ + return ctrl->stage[mixer][stage]; +} + +struct mdp4_overlay_pipe *mdp4_overlay_ndx2pipe(int ndx) +{ + struct mdp4_overlay_pipe *pipe; + + if (ndx <= 0 || ndx > OVERLAY_PIPE_MAX) + return NULL; + + pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */ + + if (pipe->pipe_used == 0) + return NULL; + + return pipe; +} + +struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer) +{ + int i; + struct mdp4_overlay_pipe *pipe; + + if (ptype == OVERLAY_TYPE_BF) { + if (!mdp4_overlay_borderfill_supported()) + return NULL; + } + + for (i = 0; i < OVERLAY_PIPE_MAX; i++) { + pipe = &ctrl->plist[i]; + if ((pipe->pipe_used == 0) && ((pipe->pipe_type == ptype) || + (ptype == OVERLAY_TYPE_RGB && + pipe->pipe_type == OVERLAY_TYPE_VIDEO))) { + if (ptype == OVERLAY_TYPE_BF && + mixer != pipe->mixer_num) + continue; + init_completion(&pipe->comp); + init_completion(&pipe->dmas_comp); + pr_debug("%s: pipe=%x ndx=%d num=%d\n", __func__, + (int)pipe, pipe->pipe_ndx, pipe->pipe_num); + return pipe; + } + } + + pr_err("%s: ptype=%d FAILED\n", __func__, ptype); + + return NULL; +} + + +void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe) +{ + uint32 ptype, num, ndx, mixer; + struct mdp4_iommu_pipe_info iom; + + pr_debug("%s: pipe=%x ndx=%d\n", __func__, (int)pipe, pipe->pipe_ndx); + + ptype = pipe->pipe_type; + num = pipe->pipe_num; + ndx = pipe->pipe_ndx; + mixer = pipe->mixer_num; + + mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); + + iom = pipe->iommu; + + memset(pipe, 0, sizeof(*pipe)); + pipe->pipe_type = ptype; + pipe->pipe_num = num; + pipe->pipe_ndx = ndx; + pipe->mixer_num = mixer; + pipe->iommu = iom; + +} + +static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer, + struct mdp4_overlay_pipe **ppipe, + struct msm_fb_data_type *mfd) +{ + struct mdp4_overlay_pipe *pipe; + int ret, ptype; + + u32 upscale_max; + upscale_max = (mdp_rev >= MDP_REV_41) ? + MDP4_REV41_OR_LATER_UP_SCALING_MAX : + MDP4_REV40_UP_SCALING_MAX; + + if (mfd == NULL) { + pr_err("%s: mfd == NULL, -ENODEV\n", __func__); + return -ENODEV; + } + + if (mixer >= MDP4_MIXER_MAX) { + pr_err("%s: mixer out of range!\n", __func__); + mdp4_stat.err_mixer++; + return -ERANGE; + } + + if (req->z_order < 0 || req->z_order > 3) { + pr_err("%s: z_order=%d out of range!\n", __func__, + req->z_order); + mdp4_stat.err_zorder++; + return -ERANGE; + } + + if (req->src_rect.h > 0xFFF) { + pr_err("%s: src_h is out of range: 0X%x!\n", + __func__, req->src_rect.h); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->src_rect.w > 0xFFF) { + pr_err("%s: src_w is out of range: 0X%x!\n", + __func__, req->src_rect.w); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->src_rect.x > 0xFFF) { + pr_err("%s: src_x is out of range: 0X%x!\n", + __func__, req->src_rect.x); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->src_rect.y > 0xFFF) { + pr_err("%s: src_y is out of range: 0X%x!\n", + __func__, req->src_rect.y); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->dst_rect.h > 0xFFF) { + pr_err("%s: dst_h is out of range: 0X%x!\n", + __func__, req->dst_rect.h); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->dst_rect.w > 0xFFF) { + pr_err("%s: dst_w is out of range: 0X%x!\n", + __func__, req->dst_rect.w); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->dst_rect.x > 0xFFF) { + pr_err("%s: dst_x is out of range: 0X%x!\n", + __func__, req->dst_rect.x); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->dst_rect.y > 0xFFF) { + pr_err("%s: dst_y is out of range: 0X%x!\n", + __func__, req->dst_rect.y); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->src_rect.h == 0 || req->src_rect.w == 0) { + pr_err("%s: src img of zero size!\n", __func__); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->dst_rect.h > (req->src_rect.h * upscale_max)) { + mdp4_stat.err_scale++; + pr_err("%s: scale up, too much (h)!\n", __func__); + return -ERANGE; + } + + if (req->src_rect.h > (req->dst_rect.h * 8)) { /* too little */ + mdp4_stat.err_scale++; + pr_err("%s: scale down, too little (h)!\n", __func__); + return -ERANGE; + } + + if (req->dst_rect.w > (req->src_rect.w * upscale_max)) { + mdp4_stat.err_scale++; + pr_err("%s: scale up, too much (w)!\n", __func__); + return -ERANGE; + } + + if (req->src_rect.w > (req->dst_rect.w * 8)) { /* too little */ + mdp4_stat.err_scale++; + pr_err("%s: scale down, too little (w)!\n", __func__); + return -ERANGE; + } + + if (mdp_rev <= MDP_REV_41) { + if ((mdp4_overlay_format2type(req->src.format) == + OVERLAY_TYPE_RGB) && + !(req->flags & MDP_OV_PIPE_SHARE) && + ((req->src_rect.w > req->dst_rect.w) || + (req->src_rect.h > req->dst_rect.h))) { + mdp4_stat.err_size++; + pr_err("%s: downscale on RGB pipe!\n", __func__); + return -EINVAL; + } + } + + if (mdp_hw_revision == MDP4_REVISION_V1) { + /* non integer down saceling ratio smaller than 1/4 + * is not supportted + */ + if (req->src_rect.h > (req->dst_rect.h * 4)) { + if (req->src_rect.h % req->dst_rect.h) { + mdp4_stat.err_scale++; + pr_err("%s: need integer (h)!\n", __func__); + return -ERANGE; + } + } + + if (req->src_rect.w > (req->dst_rect.w * 4)) { + if (req->src_rect.w % req->dst_rect.w) { + mdp4_stat.err_scale++; + pr_err("%s: need integer (w)!\n", __func__); + return -ERANGE; + } + } + } + + if (((req->src_rect.x + req->src_rect.w) > req->src.width) || + ((req->src_rect.y + req->src_rect.h) > req->src.height)) { + mdp4_stat.err_size++; + pr_err("%s invalid src rectangle\n", __func__); + return -ERANGE; + } + + if (ctrl->panel_3d != MDP4_3D_SIDE_BY_SIDE) { + int xres; + int yres; + + xres = mfd->panel_info.xres; + yres = mfd->panel_info.yres; + + if (((req->dst_rect.x + req->dst_rect.w) > xres) || + ((req->dst_rect.y + req->dst_rect.h) > yres)) { + mdp4_stat.err_size++; + pr_err("%s invalid dst rectangle\n", __func__); + return -ERANGE; + } + } + + ptype = mdp4_overlay_format2type(req->src.format); + if (ptype < 0) { + pr_err("%s: mdp4_overlay_format2type!\n", __func__); + return ptype; + } + + if (req->flags & MDP_OV_PIPE_SHARE) + ptype = OVERLAY_TYPE_VIDEO; /* VG pipe supports both RGB+YUV */ + + if (req->id == MSMFB_NEW_REQUEST) /* new request */ + pipe = mdp4_overlay_pipe_alloc(ptype, mixer); + else + pipe = mdp4_overlay_ndx2pipe(req->id); + + if (pipe == NULL) { + pr_err("%s: pipe == NULL!\n", __func__); + return -ENOMEM; + } + + if (!display_iclient && !IS_ERR_OR_NULL(mfd->iclient)) { + display_iclient = mfd->iclient; + pr_debug("%s(): display_iclient %p\n", __func__, + display_iclient); + } + + pipe->src_format = req->src.format; + ret = mdp4_overlay_format2pipe(pipe); + + if (ret < 0) { + pr_err("%s: mdp4_overlay_format2pipe!\n", __func__); + return ret; + } + + /* + * base layer == 1, reserved for frame buffer + * zorder 0 == stage 0 == 2 + * zorder 1 == stage 1 == 3 + * zorder 2 == stage 2 == 4 + */ + if (req->id == MSMFB_NEW_REQUEST) { /* new request */ + pipe->pipe_used++; + pipe->mixer_num = mixer; + pr_debug("%s: zorder=%d pipe ndx=%d num=%d\n", __func__, + req->z_order, pipe->pipe_ndx, pipe->pipe_num); + + } + + pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0; + pipe->src_width = req->src.width & 0x1fff; /* source img width */ + pipe->src_height = req->src.height & 0x1fff; /* source img height */ + pipe->src_h = req->src_rect.h & 0x07ff; + pipe->src_w = req->src_rect.w & 0x07ff; + pipe->src_y = req->src_rect.y & 0x07ff; + pipe->src_x = req->src_rect.x & 0x07ff; + pipe->dst_h = req->dst_rect.h & 0x07ff; + pipe->dst_w = req->dst_rect.w & 0x07ff; + pipe->dst_y = req->dst_rect.y & 0x07ff; + pipe->dst_x = req->dst_rect.x & 0x07ff; + + pipe->op_mode = 0; + + if (req->flags & MDP_FLIP_LR) + pipe->op_mode |= MDP4_OP_FLIP_LR; + + if (req->flags & MDP_FLIP_UD) + pipe->op_mode |= MDP4_OP_FLIP_UD; + + if (req->flags & MDP_DITHER) + pipe->op_mode |= MDP4_OP_DITHER_EN; + + if (req->flags & MDP_DEINTERLACE) + pipe->op_mode |= MDP4_OP_DEINT_EN; + + if (req->flags & MDP_DEINTERLACE_ODD) + pipe->op_mode |= MDP4_OP_DEINT_ODD_REF; + + pipe->is_fg = req->is_fg;/* control alpha and color key */ + + pipe->alpha = req->alpha & 0x0ff; + + pipe->transp = req->transp_mask; + + pipe->flags = req->flags; + + *ppipe = pipe; + + return 0; +} + +static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + u32 pclk; + u32 xscale, yscale; + u32 hsync = 0; + u32 shift = 16; + u64 rst; + int ret = -EINVAL; + + if (!pipe) { + pr_err("%s: pipe is null!\n", __func__); + pipe->req_bw = OVERLAY_PERF_LEVEL4; + return ret; + } + if (!mfd) { + pr_err("%s: mfd is null!\n", __func__); + pipe->req_bw = OVERLAY_PERF_LEVEL4; + return ret; + } + + /* + * Serveral special cases require the max mdp clk but cannot + * be explained by mdp clk equation. + */ + if (pipe->flags & MDP_DEINTERLACE) { + pr_info("%s deinterlace requires max mdp clk.\n", + __func__); + pipe->req_clk = mdp_max_clk; + return 0; + } + + pr_debug("%s: pipe sets: panel res(x,y)=(%d,%d)\n", + __func__, mfd->panel_info.xres, mfd->panel_info.yres); + pr_debug("%s: src(w,h)(%d,%d),src(x,y)(%d,%d)\n", + __func__, pipe->src_w, pipe->src_h, pipe->src_x, pipe->src_y); + pr_debug("%s: dst(w,h)(%d,%d),dst(x,y)(%d,%d)\n", + __func__, pipe->dst_w, pipe->dst_h, pipe->dst_x, pipe->dst_y); + + pclk = (mfd->panel_info.type == MIPI_VIDEO_PANEL || + mfd->panel_info.type == MIPI_CMD_PANEL) ? + mfd->panel_info.mipi.dsi_pclk_rate : + mfd->panel_info.clk_rate; + if (!pclk) { + pipe->req_clk = mdp_max_clk; + pr_err("%s panel pixel clk is zero!\n", __func__); + return ret; + } + pr_debug("%s: mdp panel pixel clk is %d.\n", + __func__, pclk); + + if (!pipe->dst_h) { + pr_err("%s: pipe dst_h is zero!\n", __func__); + pipe->req_clk = mdp_max_clk; + return ret; + } + + if (!pipe->src_h) { + pr_err("%s: pipe src_h is zero!\n", __func__); + pipe->req_clk = mdp_max_clk; + return ret; + } + + if (!pipe->dst_w) { + pr_err("%s: pipe dst_w is zero!\n", __func__); + pipe->req_clk = mdp_max_clk; + return ret; + } + + if (!pipe->dst_h) { + pr_err("%s: pipe dst_h is zero!\n", __func__); + pipe->req_clk = mdp_max_clk; + return ret; + } + + /* + * For the scaling cases, make more margin by removing porch + * values and adding extra 20%. + */ + if ((pipe->src_h != pipe->dst_h) || + (pipe->src_w != pipe->dst_w)) { + hsync = mfd->panel_info.xres; + hsync *= 100; + hsync /= 120; + pr_debug("%s: panel hsync is %d. with scaling\n", + __func__, hsync); + + } else { + hsync = mfd->panel_info.lcdc.h_back_porch + + mfd->panel_info.lcdc.h_front_porch + + mfd->panel_info.lcdc.h_pulse_width + + mfd->panel_info.xres; + pr_debug("%s: panel hsync is %d.\n", + __func__, hsync); + } + + if (!hsync) { + pipe->req_clk = mdp_max_clk; + pr_err("%s: panel hsync is zero!\n", __func__); + return 0; + } + + xscale = mfd->panel_info.xres; + xscale += pipe->src_w; + + if (xscale < pipe->dst_w) { + pipe->req_clk = mdp_max_clk; + pr_err("%s: xres+src_w cannot be less than dst_w!\n", + __func__); + return ret; + } + + xscale -= pipe->dst_w; + xscale <<= shift; + xscale /= hsync; + pr_debug("%s: the right %d shifted xscale is %d.\n", + __func__, shift, xscale); + + if (pipe->src_h > pipe->dst_h) { + yscale = pipe->src_h; + yscale <<= shift; + yscale /= pipe->dst_h; + } else { /* upscale */ + yscale = pipe->dst_h; + yscale <<= shift; + yscale /= pipe->src_h; + } + + yscale *= pipe->src_w; + yscale /= hsync; + + pr_debug("%s: the right %d shifted yscale is %d.\n", + __func__, shift, yscale); + + rst = pclk; + if (yscale > xscale) + rst *= yscale; + else + rst *= xscale; + + rst >>= shift; + + /* + * There is one special case for the panels that have low + * v_back_porch (<=4), mdp clk should be fast enough to buffer + * 4 lines input during back porch time if scaling is + * required(FIR). + */ + if ((mfd->panel_info.lcdc.v_back_porch <= 4) && + (pipe->src_h != pipe->dst_h)) { + u32 clk = 0; + clk = 4 * (pclk >> shift) / mfd->panel_info.lcdc.v_back_porch; + clk <<= shift; + pr_debug("%s: mdp clk rate %d based on low vbp %d\n", + __func__, clk, mfd->panel_info.lcdc.v_back_porch); + rst = (rst > clk) ? rst : clk; + } + + /* + * If the calculated mdp clk is less than panel pixel clk, + * most likely due to upscaling, mdp clk rate will be set to + * greater than pclk. Now the driver uses 1.15 as the + * factor. Ideally this factor is passed from board file. + */ + if (rst < pclk) { + rst = ((pclk >> shift) * 23 / 20) << shift; + pr_debug("%s calculated mdp clk is less than pclk.\n", + __func__); + } + + pipe->req_clk = (u32) rst; + + pr_debug("%s: required mdp clk %d mixer %d pipe ndx %d\n", + __func__, pipe->req_clk, pipe->mixer_num, pipe->pipe_ndx); + + return 0; +} + +#define OVERLAY_VGA_SIZE 0x04B000 +#define OVERLAY_720P_TILE_SIZE 0x0E6000 +#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */ + +#define OVERLAY_BUS_SCALE_TABLE_BASE 6 + + +static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + u32 res; + int ret = -EINVAL; + + if (!pipe) { + pr_err("%s: pipe is null!\n", __func__); + return ret; + } + if (!mfd) { + pr_err("%s: mfd is null!\n", __func__); + return ret; + } + + if (pipe->flags & MDP_DEINTERLACE) { + pr_info("%s deinterlace requires max mdp bw.\n", + __func__); + pipe->req_bw = OVERLAY_PERF_LEVEL1; + return 0; + } + + if (pipe->pipe_type == OVERLAY_TYPE_BF) { + pipe->req_bw = OVERLAY_PERF_LEVEL4; + return 0; + } + + res = pipe->src_w * pipe->src_h; + + if (res <= OVERLAY_WSVGA_SIZE) + pipe->req_bw = OVERLAY_PERF_LEVEL4; + else if (res <= OVERLAY_VGA_SIZE) + pipe->req_bw = OVERLAY_PERF_LEVEL3; + else if (res <= OVERLAY_720P_TILE_SIZE) + pipe->req_bw = OVERLAY_PERF_LEVEL2; + else + pipe->req_bw = OVERLAY_PERF_LEVEL1; + + return 0; +} + +int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *plist) +{ + u32 worst_mdp_clk = 0; + u32 worst_mdp_bw = OVERLAY_PERF_LEVEL4; + int i; + struct mdp4_overlay_perf *perf_req = &perf_request; + struct mdp4_overlay_pipe *pipe = plist; + u32 cnt = 0; + int ret = -EINVAL; + + if (!mfd) { + pr_err("%s: mfd is null!\n", __func__); + return ret; + } + + if (!plist) { + pr_err("%s: plist is null!\n", __func__); + return ret; + } + + perf_req->use_ov0_blt = 0; + perf_req->use_ov1_blt = 0; + + for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { + + if (!pipe) + return ret; + + if (!pipe->pipe_used) + continue; + cnt++; + if (worst_mdp_clk < pipe->req_clk) + worst_mdp_clk = pipe->req_clk; + if (pipe->req_clk > mdp_max_clk) { + if (pipe->mixer_num == MDP4_MIXER0) + perf_req->use_ov0_blt = 1; + if (pipe->mixer_num == MDP4_MIXER1) + perf_req->use_ov1_blt = 1; + } + + if (!pipe->req_bw) { + pr_err("%s mdp pipe bw request should not be zero!\n", + __func__); + pr_debug("%s %d pid %d num %d idx %d mix %d bw %d\n", + __func__, __LINE__, current->pid, + pipe->pipe_num, pipe->pipe_ndx, + pipe->mixer_num, pipe->req_bw); + pipe->req_bw = OVERLAY_PERF_LEVEL4; + } + + if (pipe->req_bw < worst_mdp_bw) + worst_mdp_bw = pipe->req_bw; + + if (mfd->mdp_rev == MDP_REV_41) { + /* + * writeback (blt) mode to provide work around + * for dsi cmd mode interface hardware bug. + */ + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + if (pipe->dst_x != 0) + perf_req->use_ov0_blt = 1; + } + if ((mfd->panel_info.xres > 1280) && + (mfd->panel_info.type != DTV_PANEL)) { + perf_req->use_ov0_blt = 1; + } + } + } + + perf_req->mdp_clk_rate = worst_mdp_clk; + if (perf_req->mdp_clk_rate > mdp_max_clk) + perf_req->mdp_clk_rate = mdp_max_clk; + + perf_req->mdp_clk_rate = mdp_clk_round_rate(perf_req->mdp_clk_rate); + + perf_req->mdp_bw = worst_mdp_bw; + + if (cnt >= 3) + perf_req->mdp_bw = OVERLAY_PERF_LEVEL1; + + pr_debug("%s %d pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d bw %d\n", + __func__, __LINE__, current->pid, cnt, + perf_req->mdp_clk_rate, + perf_req->use_ov0_blt, + perf_req->use_ov1_blt, + perf_req->mdp_bw); + + return 0; +} + +int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe, + struct msm_fb_data_type *mfd) +{ + int ret = 0; + + if (mdp4_calc_pipe_mdp_clk(mfd, pipe)) { + pr_err("%s unable to calc mdp pipe clk rate ret=%d\n", + __func__, ret); + ret = -EINVAL; + } + if (mdp4_calc_pipe_mdp_bw(mfd, pipe)) { + pr_err("%s unable to calc mdp pipe bandwidth ret=%d\n", + __func__, ret); + ret = -EINVAL; + } + return ret; +} + +void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, + int flag) +{ + struct mdp4_overlay_perf *perf_req = &perf_request; + struct mdp4_overlay_perf *perf_cur = &perf_current; + + pr_debug("%s %d: req mdp clk %d, cur mdp clk %d flag %d\n", + __func__, __LINE__, + perf_req->mdp_clk_rate, + perf_cur->mdp_clk_rate, + flag); + + if (!mdp4_extn_disp) + perf_cur->use_ov1_blt = 0; + + if (flag) { + if (perf_req->mdp_clk_rate > perf_cur->mdp_clk_rate) { + mdp_set_core_clk(perf_req->mdp_clk_rate); + pr_info("%s mdp clk is changed [%d] from %d to %d\n", + __func__, + flag, + perf_cur->mdp_clk_rate, + perf_req->mdp_clk_rate); + perf_cur->mdp_clk_rate = + perf_req->mdp_clk_rate; + } + if (perf_req->mdp_bw < perf_cur->mdp_bw) { + mdp_bus_scale_update_request + (OVERLAY_BUS_SCALE_TABLE_BASE - + perf_req->mdp_bw); + pr_info("%s mdp bw is changed [%d] from %d to %d\n", + __func__, + flag, + perf_cur->mdp_bw, + perf_req->mdp_bw); + perf_cur->mdp_bw = perf_req->mdp_bw; + } + if (mfd->panel_info.pdest == DISPLAY_1 && + perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) { + if (mfd->panel_info.type == LCDC_PANEL || + mfd->panel_info.type == LVDS_PANEL) + mdp4_lcdc_overlay_blt_start(mfd); + else if (mfd->panel_info.type == MIPI_VIDEO_PANEL) + mdp4_dsi_video_blt_start(mfd); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_cmd_blt_start(mfd); + pr_info("%s mixer0 start blt [%d] from %d to %d.\n", + __func__, + flag, + perf_cur->use_ov0_blt, + perf_req->use_ov0_blt); + perf_cur->use_ov0_blt = perf_req->use_ov0_blt; + } + if (mfd->panel_info.pdest == DISPLAY_2 && + perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) { + mdp4_dtv_overlay_blt_start(mfd); + pr_info("%s mixer1 start blt [%d] from %d to %d.\n", + __func__, + flag, + perf_cur->use_ov1_blt, + perf_req->use_ov1_blt); + perf_cur->use_ov1_blt = perf_req->use_ov1_blt; + } + } else { + if (perf_req->mdp_clk_rate < perf_cur->mdp_clk_rate) { + pr_info("%s mdp clk is changed [%d] from %d to %d\n", + __func__, + flag, + perf_cur->mdp_clk_rate, + perf_req->mdp_clk_rate); + mdp_set_core_clk(perf_req->mdp_clk_rate); + perf_cur->mdp_clk_rate = + perf_req->mdp_clk_rate; + } + if (perf_req->mdp_bw > perf_cur->mdp_bw) { + pr_info("%s mdp bw is changed [%d] from %d to %d\n", + __func__, + flag, + perf_cur->mdp_bw, + perf_req->mdp_bw); + mdp_bus_scale_update_request + (OVERLAY_BUS_SCALE_TABLE_BASE - + perf_req->mdp_bw); + perf_cur->mdp_bw = perf_req->mdp_bw; + } + if (mfd->panel_info.pdest == DISPLAY_1 && + !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) { + if (mfd->panel_info.type == LCDC_PANEL || + mfd->panel_info.type == LVDS_PANEL) + mdp4_lcdc_overlay_blt_stop(mfd); + else if (mfd->panel_info.type == MIPI_VIDEO_PANEL) + mdp4_dsi_video_blt_stop(mfd); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_cmd_blt_stop(mfd); + pr_info("%s mixer0 stop blt [%d] from %d to %d.\n", + __func__, + flag, + perf_cur->use_ov0_blt, + perf_req->use_ov0_blt); + perf_cur->use_ov0_blt = perf_req->use_ov0_blt; + } + if (mfd->panel_info.pdest == DISPLAY_2 && + !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) { + mdp4_dtv_overlay_blt_stop(mfd); + pr_info("%s mixer1 stop blt [%d] from %d to %d.\n", + __func__, + flag, + perf_cur->use_ov1_blt, + perf_req->use_ov1_blt); + perf_cur->use_ov1_blt = perf_req->use_ov1_blt; + } + } + return; +} + +static int get_img(struct msmfb_data *img, struct fb_info *info, + struct mdp4_overlay_pipe *pipe, unsigned int plane, + unsigned long *start, unsigned long *len, struct file **srcp_file, + int *p_need, struct ion_handle **srcp_ihdl) +{ + struct file *file; + int put_needed, ret = 0, fb_num; +#ifdef CONFIG_ANDROID_PMEM + unsigned long vstart; +#endif + *p_need = 0; + + if (img->flags & MDP_BLIT_SRC_GEM) { + *srcp_file = NULL; + return kgsl_gem_obj_addr(img->memory_id, (int) img->priv, + start, len); + } + + if (img->flags & MDP_MEMORY_ID_TYPE_FB) { + file = fget_light(img->memory_id, &put_needed); + if (file == NULL) + return -EINVAL; + + if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + fb_num = MINOR(file->f_dentry->d_inode->i_rdev); + if (get_fb_phys_info(start, len, fb_num, + DISPLAY_SUBSYSTEM_ID)) { + ret = -1; + } else { + pr_warn("%s: mdp4_overlay play with FB memory\n", + __func__); + *srcp_file = file; + *p_need = put_needed; + } + } else + ret = -1; + if (ret) + fput_light(file, put_needed); + return ret; + } + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + return mdp4_overlay_iommu_map_buf(img->memory_id, pipe, plane, + start, len, srcp_ihdl); +#endif +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file(img->memory_id, start, &vstart, + len, srcp_file)) + return 0; + else + return -EINVAL; +#endif +} + +#ifdef CONFIG_FB_MSM_MIPI_DSI +int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret = -EPERM; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD mdp4_dsi_cmd_3d_sbys(mfd, req); + ret = 0; + } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + mdp4_dsi_video_3d_sbys(mfd, req);) { + mdp4_dsi_cmd_3d_sbys(mfd, req); + ret = 0; + } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO mdp4_dsi_cmd_3d_sbys(mfd, req); + ret = 0; + } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + mdp4_dsi_video_3d_sbys(mfd, req);) { + mdp4_dsi_video_3d_sbys(mfd, req); + ret = 0; + } + mutex_unlock(&mfd->dma->ov_mutex); + + return ret; +} +#else +int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req) +{ + /* do nothing */ + return -EPERM; +} +#endif + +int mdp4_overlay_blt(struct fb_info *info, struct msmfb_overlay_blt *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mfd == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_cmd_overlay_blt(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + mdp4_dsi_video_overlay_blt(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_lcdc_overlay_blt(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_overlay_blt(mfd, req); + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req) +{ + struct mdp4_overlay_pipe *pipe; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) + return -ENODEV; + + *req = pipe->req_data; + + if (mdp4_overlay_borderfill_supported()) + req->flags |= MDP_BORDERFILL_SUPPORTED; + + return 0; +} + +int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret, mixer; + struct mdp4_overlay_pipe *pipe; + + if (mfd == NULL) { + pr_err("%s: mfd == NULL, -ENODEV\n", __func__); + return -ENODEV; + } + + if (info->node != 0 || mfd->cont_splash_done) /* primary */ + if (!mfd->panel_power_on) /* suspended */ + return -EPERM; + + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) { + pr_err("%s: mutex_lock_interruptible, -EINTR\n", __func__); + return -EINTR; + } + + mixer = mfd->panel_info.pdest; /* DISPLAY_1 or DISPLAY_2 */ + + ret = mdp4_overlay_req2pipe(req, mixer, &pipe, mfd); + + if (ret < 0) { + mutex_unlock(&mfd->dma->ov_mutex); + pr_err("%s: mdp4_overlay_req2pipe, ret=%d\n", __func__, ret); + return ret; + } + + /* return id back to user */ + req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */ + pipe->req_data = *req; /* keep original req */ + + if (!IS_ERR_OR_NULL(mfd->iclient)) { + pr_debug("pipe->flags 0x%x\n", pipe->flags); + if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) { + mfd->mem_hid &= ~BIT(ION_IOMMU_HEAP_ID); + mfd->mem_hid |= ION_SECURE; + } else { + mfd->mem_hid |= BIT(ION_IOMMU_HEAP_ID); + mfd->mem_hid &= ~ION_SECURE; + } + } + + if (pipe->flags & MDP_SHARPENING) { + bool test = ((pipe->req_data.dpp.sharp_strength > 0) && + ((req->src_rect.w > req->dst_rect.w) && + (req->src_rect.h > req->dst_rect.h))); + if (test) { + pr_debug("%s: No sharpening while downscaling.\n", + __func__); + pipe->flags &= ~MDP_SHARPENING; + } + } + + mdp4_overlay_mdp_pipe_req(pipe, mfd); + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +int mdp4_overlay_unset_mixer(int mixer) +{ + struct mdp4_overlay_pipe *pipe; + struct mdp4_overlay_pipe *orgpipe; + int i, cnt = 0; + + /* free pipe besides base layer pipe */ + for (i = MDP4_MIXER_STAGE3; i > MDP4_MIXER_STAGE_BASE; i--) { + pipe = ctrl->stage[mixer][i]; + if (pipe == NULL) + continue; + pipe->flags &= ~MDP_OV_PLAY_NOWAIT; + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_down(pipe, 1); + mdp4_overlay_pipe_free(pipe); + /*Clear real pipe attributes as well */ + orgpipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); + if (orgpipe != NULL) + orgpipe->pipe_used = 0; + cnt++; + } + + return cnt; +} + +int mdp4_overlay_unset(struct fb_info *info, int ndx) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdp4_overlay_pipe *pipe; + struct dpp_ctrl dpp; + int i; + + if (mfd == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + pipe = mdp4_overlay_ndx2pipe(ndx); + + if (pipe == NULL) { + mutex_unlock(&mfd->dma->ov_mutex); + return -ENODEV; + } + + if (pipe->pipe_type == OVERLAY_TYPE_BF) { + mdp4_overlay_borderfill_stage_down(pipe); + mutex_unlock(&mfd->dma->ov_mutex); + return 0; + } + + if (pipe->mixer_num == MDP4_MIXER2) + ctrl->mixer2_played = 0; + else if (pipe->mixer_num == MDP4_MIXER1) + ctrl->mixer1_played = 0; + else { + /* mixer 0 */ + ctrl->mixer0_played = 0; + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + if (mfd->panel_power_on) + mdp4_mddi_blt_dmap_busy_wait(mfd); + } + } + + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_down(pipe, 0); + + if (pipe->mixer_num == MDP4_MIXER0) { + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + if (mfd->panel_power_on) + mdp4_mddi_overlay_restore(); + } + + } else { /* mixer1, DTV, ATV */ + if (ctrl->panel_mode & MDP4_PANEL_DTV) + mdp4_overlay_dtv_unset(mfd, pipe); + } + + /* Reset any HSIC settings to default */ + if (pipe->flags & MDP_DPP_HSIC) { + for (i = 0; i < NUM_HSIC_PARAM; i++) + dpp.hsic_params[i] = 0; + + mdp4_hsic_set(pipe, &dpp); + mdp4_hsic_update(pipe); + } + + mdp4_stat.overlay_unset[pipe->mixer_num]++; + + mdp4_overlay_pipe_free(pipe); + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +int mdp4_overlay_wait4vsync(struct fb_info *info, long long *vtime) +{ + if (!hdmi_prim_display && info->node == 0) { + if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + mdp4_dsi_video_wait4vsync(0, vtime); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_cmd_wait4vsync(0, vtime); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_lcdc_wait4vsync(0, vtime); + } else if (hdmi_prim_display || info->node == 1) { + mdp4_dtv_wait4vsync(0, vtime); + } + + return 0; +} + +int mdp4_overlay_vsync_ctrl(struct fb_info *info, int enable) +{ + int cmd; + + if (enable) + cmd = 1; + else + cmd = 0; + + if (!hdmi_prim_display && info->node == 0) { + if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + mdp4_dsi_video_vsync_ctrl(info, cmd); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_cmd_vsync_ctrl(info, cmd); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_lcdc_vsync_ctrl(info, cmd); + } else if (hdmi_prim_display || info->node == 1) + mdp4_dtv_vsync_ctrl(info, cmd); + + return 0; +} + + +struct tile_desc { + uint32 width; /* tile's width */ + uint32 height; /* tile's height */ + uint32 row_tile_w; /* tiles per row's width */ + uint32 row_tile_h; /* tiles per row's height */ +}; + +void tile_samsung(struct tile_desc *tp) +{ + /* + * each row of samsung tile consists of two tiles in height + * and two tiles in width which means width should align to + * 64 x 2 bytes and height should align to 32 x 2 bytes. + * video decoder generate two tiles in width and one tile + * in height which ends up height align to 32 X 1 bytes. + */ + tp->width = 64; /* 64 bytes */ + tp->row_tile_w = 2; /* 2 tiles per row's width */ + tp->height = 32; /* 32 bytes */ + tp->row_tile_h = 1; /* 1 tiles per row's height */ +} + +uint32 tile_mem_size(struct mdp4_overlay_pipe *pipe, struct tile_desc *tp) +{ + uint32 tile_w, tile_h; + uint32 row_num_w, row_num_h; + + + tile_w = tp->width * tp->row_tile_w; + tile_h = tp->height * tp->row_tile_h; + + row_num_w = (pipe->src_width + tile_w - 1) / tile_w; + row_num_h = (pipe->src_height + tile_h - 1) / tile_h; + return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191; +} + +int mdp4_overlay_play_wait(struct fb_info *info, struct msmfb_overlay_data *req) +{ + return 0; +} + +/* + * mdp4_overlay_dma_commit: called from dma_done isr + * No mutex/sleep allowed + */ +void mdp4_overlay_dma_commit(int mixer) +{ + /* + * non double buffer register update here + * perf level, new clock rate should be done here + */ +} + +/* + * mdp4_overlay_vsync_commit: called from tasklet context + * No mutex/sleep allowed + */ +void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe) +{ + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) + mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ + else + mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ + + pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__, + (int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used); + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe, 0); +} + +int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msmfb_data *img; + struct mdp4_overlay_pipe *pipe; + ulong start, addr; + ulong len = 0; + struct file *srcp0_file = NULL; + struct file *srcp1_file = NULL, *srcp2_file = NULL; + struct ion_handle *srcp0_ihdl = NULL; + struct ion_handle *srcp1_ihdl = NULL, *srcp2_ihdl = NULL; + int ps0_need, p_need; + uint32_t overlay_version = 0; + int ret = 0; + + if (mfd == NULL) + return -ENODEV; + + if (!mfd->panel_power_on) /* suspended */ + return -EPERM; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) { + mdp4_stat.err_play++; + return -ENODEV; + } + + if (pipe->pipe_type == OVERLAY_TYPE_BF) { + mdp4_overlay_borderfill_stage_up(pipe); + mdp4_mixer_stage_commit(pipe->mixer_num); + return 0; + } + + mutex_lock(&mfd->dma->ov_mutex); + + img = &req->data; + get_img(img, info, pipe, 0, &start, &len, &srcp0_file, + &ps0_need, &srcp0_ihdl); + if (len == 0) { + pr_err("%s: pmem Error\n", __func__); + ret = -1; + goto end; + } + + addr = start + img->offset; + pipe->srcp0_addr = addr; + pipe->srcp0_ystride = pipe->src_width * pipe->bpp; + + + pr_debug("%s: mixer=%d ndx=%x addr=%x flags=%x pid=%d\n", __func__, + pipe->mixer_num, pipe->pipe_ndx, (int)addr, pipe->flags, + current->pid); + + if ((req->version_key & VERSION_KEY_MASK) == 0xF9E8D700) + overlay_version = (req->version_key & ~VERSION_KEY_MASK); + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { + if (overlay_version > 0) { + img = &req->plane1_data; + get_img(img, info, pipe, 1, &start, &len, &srcp1_file, + &p_need, &srcp1_ihdl); + if (len == 0) { + pr_err("%s: Error to get plane1\n", __func__); + ret = -EINVAL; + goto end; + } + pipe->srcp1_addr = start + img->offset; + } else if (pipe->frame_format == + MDP4_FRAME_FORMAT_VIDEO_SUPERTILE) { + struct tile_desc tile; + + tile_samsung(&tile); + pipe->srcp1_addr = addr + tile_mem_size(pipe, &tile); + } else { + pipe->srcp1_addr = addr + (pipe->src_width * + pipe->src_height); + } + pipe->srcp0_ystride = pipe->src_width; + if ((pipe->src_format == MDP_Y_CRCB_H1V1) || + (pipe->src_format == MDP_Y_CBCR_H1V1)) { + if (pipe->src_width > YUV_444_MAX_WIDTH) + pipe->srcp1_ystride = pipe->src_width << 2; + else + pipe->srcp1_ystride = pipe->src_width << 1; + } else + pipe->srcp1_ystride = pipe->src_width; + + } else if (pipe->fetch_plane == OVERLAY_PLANE_PLANAR) { + if (overlay_version > 0) { + img = &req->plane1_data; + get_img(img, info, pipe, 1, &start, &len, &srcp1_file, + &p_need, &srcp1_ihdl); + if (len == 0) { + pr_err("%s: Error to get plane1\n", __func__); + ret = -EINVAL; + goto end; + } + pipe->srcp1_addr = start + img->offset; + + img = &req->plane2_data; + get_img(img, info, pipe, 2, &start, &len, &srcp2_file, + &p_need, &srcp2_ihdl); + if (len == 0) { + pr_err("%s: Error to get plane2\n", __func__); + ret = -EINVAL; + goto end; + } + pipe->srcp2_addr = start + img->offset; + } else { + if (pipe->src_format == MDP_Y_CR_CB_GH2V2) { + addr += (ALIGN(pipe->src_width, 16) * + pipe->src_height); + pipe->srcp1_addr = addr; + addr += ((ALIGN((pipe->src_width / 2), 16)) * + (pipe->src_height / 2)); + pipe->srcp2_addr = addr; + } else { + addr += (pipe->src_width * pipe->src_height); + pipe->srcp1_addr = addr; + addr += ((pipe->src_width / 2) * + (pipe->src_height / 2)); + pipe->srcp2_addr = addr; + } + } + /* mdp planar format expects Cb in srcp1 and Cr in p2 */ + if ((pipe->src_format == MDP_Y_CR_CB_H2V2) || + (pipe->src_format == MDP_Y_CR_CB_GH2V2)) + swap(pipe->srcp1_addr, pipe->srcp2_addr); + + if (pipe->src_format == MDP_Y_CR_CB_GH2V2) { + pipe->srcp0_ystride = ALIGN(pipe->src_width, 16); + pipe->srcp1_ystride = ALIGN(pipe->src_width / 2, 16); + pipe->srcp2_ystride = ALIGN(pipe->src_width / 2, 16); + } else { + pipe->srcp0_ystride = pipe->src_width; + pipe->srcp1_ystride = pipe->src_width / 2; + pipe->srcp2_ystride = pipe->src_width / 2; + } + } + + mdp4_overlay_mdp_perf_req(mfd, ctrl->plist); + + if (pipe->mixer_num == MDP4_MIXER2 || ctrl->panel_mode & MDP4_PANEL_MDDI) + goto mddi; + + if (pipe->mixer_num == MDP4_MIXER0) { + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + /* cndx = 0 */ + mdp4_dsi_cmd_pipe_queue(0, pipe); + } + if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + /* cndx = 0 */ + mdp4_dsi_video_pipe_queue(0, pipe); + } else if (ctrl->panel_mode & MDP4_PANEL_LCDC) { + /* cndx = 0 */ + mdp4_lcdc_pipe_queue(0, pipe); + } + } else if (pipe->mixer_num == MDP4_MIXER1) { + if (ctrl->panel_mode & MDP4_PANEL_DTV) + mdp4_dtv_pipe_queue(0, pipe);/* cndx = 0 */ + } + + mutex_unlock(&mfd->dma->ov_mutex); + return ret; + +mddi: + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) { + mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ + } else { + mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ + } + + mdp4_mixer_stage_up(pipe, 0); + + if (pipe->mixer_num == MDP4_MIXER2) { + ctrl->mixer2_played++; +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL + if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) { + mdp4_writeback_dma_busy_wait(mfd); + mdp4_writeback_kickoff_video(mfd, pipe); + } +#endif + } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + if (pipe->flags & MDP_OV_PLAY_NOWAIT) { + mdp4_stat.overlay_play[pipe->mixer_num]++; + mutex_unlock(&mfd->dma->ov_mutex); + goto end; + } + mdp4_mixer_stage_commit(pipe->mixer_num); + mdp4_mddi_dma_busy_wait(mfd); + mdp4_mddi_kickoff_video(mfd, pipe); + } + + /* write out DPP HSIC registers */ + if (pipe->flags & MDP_DPP_HSIC) + mdp4_hsic_update(pipe); + if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) + mdp4_iommu_unmap(pipe); + mdp4_stat.overlay_play[pipe->mixer_num]++; + +end: + mutex_unlock(&mfd->dma->ov_mutex); + +#ifdef CONFIG_ANDROID_PMEM + if (srcp0_file) + put_pmem_file(srcp0_file); + if (srcp1_file) + put_pmem_file(srcp1_file); + if (srcp2_file) + put_pmem_file(srcp2_file); +#endif + /* only source may use frame buffer */ + if (img->flags & MDP_MEMORY_ID_TYPE_FB) + fput_light(srcp0_file, ps0_need); + return ret; +} + +struct msm_iommu_ctx { + char *name; + int domain; +}; + +static struct msm_iommu_ctx msm_iommu_ctx_names[] = { + /* Display read*/ + { + .name = "mdp_port0_cb0", + .domain = DISPLAY_READ_DOMAIN, + }, + /* Display read*/ + { + .name = "mdp_port0_cb1", + .domain = DISPLAY_READ_DOMAIN, + }, + /* Display write */ + { + .name = "mdp_port1_cb0", + .domain = DISPLAY_READ_DOMAIN, + }, + /* Display write */ + { + .name = "mdp_port1_cb1", + .domain = DISPLAY_READ_DOMAIN, + }, +}; + +static struct msm_iommu_ctx msm_iommu_split_ctx_names[] = { + /* Display read*/ + { + .name = "mdp_port0_cb0", + .domain = DISPLAY_READ_DOMAIN, + }, + /* Display read*/ + { + .name = "mdp_port0_cb1", + .domain = DISPLAY_WRITE_DOMAIN, + }, + /* Display write */ + { + .name = "mdp_port1_cb0", + .domain = DISPLAY_READ_DOMAIN, + }, + /* Display write */ + { + .name = "mdp_port1_cb1", + .domain = DISPLAY_WRITE_DOMAIN, + }, +}; + +void mdp4_iommu_attach(void) +{ + static int done; + struct msm_iommu_ctx *ctx_names; + struct iommu_domain *domain; + int i, arr_size; + + if (!done) { + if (mdp_iommu_split_domain) { + ctx_names = msm_iommu_split_ctx_names; + arr_size = ARRAY_SIZE(msm_iommu_split_ctx_names); + } else { + ctx_names = msm_iommu_ctx_names; + arr_size = ARRAY_SIZE(msm_iommu_ctx_names); + } + + for (i = 0; i < arr_size; i++) { + int domain_idx; + struct device *ctx = msm_iommu_get_ctx( + ctx_names[i].name); + + if (!ctx) + continue; + + domain_idx = ctx_names[i].domain; + + domain = msm_get_iommu_domain(domain_idx); + if (!domain) + continue; + + if (iommu_attach_device(domain, ctx)) { + WARN(1, "%s: could not attach domain %d to context %s." + " iommu programming will not occur.\n", + __func__, domain_idx, + ctx_names[i].name); + continue; + } + } + done = 1; + } +} + +int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req, + struct mdp4_overlay_pipe **ppipe) +{ + struct mdp4_overlay_pipe *pipe; + int err; + struct msm_fb_data_type *mfb = info->par; + + req->z_order = 0; + req->id = MSMFB_NEW_REQUEST; + req->is_fg = false; + req->alpha = 0xff; + err = mdp4_overlay_req2pipe(req, MDP4_MIXER0, &pipe, mfb); + if (err < 0) { + pr_err("%s:Could not allocate MDP overlay pipe\n", __func__); + return err; + } + msm_fb_signal_timeline(mfd); + + mdp4_mixer_blend_setup(pipe->mixer_num); + *ppipe = pipe; + + return 0; +} + +void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe) +{ + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_down(pipe, 1); + mdp4_overlay_pipe_free(pipe); +} + +int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe, + unsigned long srcp0_addr, unsigned long srcp1_addr, + unsigned long srcp2_addr) +{ + struct msm_fb_data_type *mfd = info->par; + int err; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + switch (pipe->src_format) { + case MDP_Y_CR_CB_H2V2: + /* YUV420 */ + pipe->srcp0_addr = srcp0_addr; + pipe->srcp0_ystride = pipe->src_width; + /* + * For YUV420, the luma plane is 1 byte per pixel times + * num of pixels in the image Also, the planes are + * switched in MDP, srcp2 is actually first chroma plane + */ + pipe->srcp2_addr = srcp1_addr ? srcp1_addr : + pipe->srcp0_addr + (pipe->src_width * pipe->src_height); + pipe->srcp2_ystride = pipe->src_width/2; + /* + * The chroma planes are half the size of the luma + * planes + */ + pipe->srcp1_addr = srcp2_addr ? srcp2_addr : + pipe->srcp2_addr + + (pipe->src_width * pipe->src_height / 4); + pipe->srcp1_ystride = pipe->src_width/2; + break; + case MDP_Y_CRCB_H2V2: + /* NV12 */ + pipe->srcp0_addr = srcp0_addr; + pipe->srcp0_ystride = pipe->src_width; + pipe->srcp1_addr = srcp1_addr ? srcp1_addr : + pipe->srcp0_addr + + (pipe->src_width * pipe->src_height); + pipe->srcp1_ystride = pipe->src_width; + break; + default: + pr_err("%s: format (%u) is not supported\n", __func__, + pipe->src_format); + err = -EINVAL; + goto done; + } + + pr_debug("%s: pipe ndx=%d stage=%d format=%x\n", __func__, + pipe->pipe_ndx, pipe->mixer_stage, pipe->src_format); + + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) + mdp4_overlay_vg_setup(pipe); + else + mdp4_overlay_rgb_setup(pipe); + + if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_overlay_reg_flush(pipe, 1); + + mdp4_mixer_stage_up(pipe, 0); /* mixer stage commit commits this */ + mdp4_mixer_stage_commit(pipe->mixer_num); + +#ifdef V4L2_VSYNC + /* + * TODO: incorporate v4l2 into vsycn driven mechanism + */ + if (ctrl->panel_mode & MDP4_PANEL_LCDC) { + mdp4_overlay_lcdc_vsync_push(mfd, pipe); + } else { +#ifdef CONFIG_FB_MSM_MIPI_DSI + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + mdp4_dsi_cmd_dma_busy_wait(mfd); + mdp4_dsi_cmd_kickoff_video(mfd, pipe); + } +#else + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + mdp4_mddi_dma_busy_wait(mfd); + mdp4_mddi_kickoff_video(mfd, pipe); + } +#endif + } +#endif + +done: + mutex_unlock(&mfd->dma->ov_mutex); + return err; +} diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c index 5f84662d..4cbac095 100644 --- a/drivers/video/msm/mdp4_overlay_atv.c +++ b/drivers/video/msm/mdp4_overlay_atv.c @@ -184,6 +184,8 @@ void mdp4_atv_overlay(struct msm_fb_data_type *mfd) } else { pipe->srcp0_addr = (uint32)(buf + buf_offset); } + mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time); + mdp4_overlay_mdp_perf_req(pipe, mfd); mdp4_overlay_mdp_perf_upd(mfd, 1); mdp4_overlay_rgb_setup(pipe); diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c index 7a768788..1821cc0f 100644 --- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c +++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c @@ -31,14 +31,14 @@ #include "mipi_dsi.h" #include "mdp4.h" -static int dsi_state; - -#define TOUT_PERIOD HZ /* 1 second */ -#define MS_100 (HZ/10) /* 100 ms */ - static int vsync_start_y_adjust = 4; #define MAX_CONTROLLER 1 + +/* + * VSYNC_EXPIRE_TICK == 0 means clock always on + * VSYNC_EXPIRE_TICK == 4 is recommended + */ #define VSYNC_EXPIRE_TICK 4 static struct vsycn_ctrl { @@ -51,10 +51,10 @@ static struct vsycn_ctrl { u32 ov_done; u32 dmap_koff; u32 dmap_done; + u32 pan_display; uint32 rdptr_intr_tot; uint32 rdptr_sirq_tot; atomic_t suspend; - atomic_t vsync_resume; int wait_vsync_cnt; int blt_change; int blt_free; @@ -70,8 +70,8 @@ static struct vsycn_ctrl { struct vsync_update vlist[2]; int vsync_enabled; int clk_enabled; - int clk_control; int new_update; + int clk_control; ktime_t vsync_time; struct work_struct clk_work; } vsync_ctrl_db[MAX_CONTROLLER]; @@ -155,7 +155,7 @@ static void mdp4_dsi_cmd_do_blt(struct msm_fb_data_type *mfd, int enable) int cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; - int need_wait; + int need_wait = 0; vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; @@ -163,7 +163,7 @@ static void mdp4_dsi_cmd_do_blt(struct msm_fb_data_type *mfd, int enable) mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); if (mfd->ov0_wb_buf->write_addr == 0) { - pr_info("%s: no blt_base assigned\n", __func__); + pr_err("%s: no blt_base assigned\n", __func__); return; } @@ -205,7 +205,7 @@ static void mdp4_dsi_cmd_do_blt(struct msm_fb_data_type *mfd, int enable) vctrl->blt_free = 4; /* 4 commits to free wb buf */ } - pr_info("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__, + pr_debug("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__, vctrl->blt_change, enable, (int)pipe->ov_blt_addr); spin_unlock_irqrestore(&vctrl->spin_lock, flags); @@ -229,8 +229,10 @@ void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe) vctrl = &vsync_ctrl_db[cndx]; - if (atomic_read(&vctrl->suspend) > 0) + if (atomic_read(&vctrl->suspend)) { + pr_err("%s: suspended, no more pipe queue\n", __func__); return; + } mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; @@ -250,7 +252,7 @@ void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe) static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe); -int mdp4_dsi_cmd_pipe_commit(void) +int mdp4_dsi_cmd_pipe_commit(int cndx, int wait) { int i, undx; int mixer = 0; @@ -271,6 +273,8 @@ int mdp4_dsi_cmd_pipe_commit(void) pipe = vctrl->base_pipe; mixer = pipe->mixer_num; + mdp_update_pm(vctrl->mfd, vctrl->vsync_time); + if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return cnt; @@ -363,20 +367,28 @@ int mdp4_dsi_cmd_pipe_commit(void) mdp4_dsi_cmd_blt_ov_update(pipe); pipe->ov_cnt++; vctrl->ov_koff++; + INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); } else { + INIT_COMPLETION(vctrl->dmap_comp); vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); vctrl->dmap_koff++; } - pr_debug("%s: kickoff\n", __func__); + pr_debug("%s: kickoff, pid=%d\n", __func__, current->pid); /* kickoff overlay engine */ mdp4_stat.kickoff_ov0++; outpdw(MDP_BASE + 0x0004, 0); - mb(); + mb(); /* make sure kickoff ececuted */ spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; + if (wait) { + long long tick; + + mdp4_dsi_cmd_wait4vsync(cndx, &tick); + } + return cnt; } @@ -386,15 +398,14 @@ void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable) { struct vsycn_ctrl *vctrl; unsigned long flags; - int clk_set_on = 0; int cndx = 0; + int clk_set_on = 0; vctrl = &vsync_ctrl_db[cndx]; - pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__, - vctrl->clk_enabled, vctrl->vsync_enabled, enable); - mutex_lock(&vctrl->update_lock); + pr_debug("%s: clk_enabled=%d vsync_enabled=%d req=%d\n", __func__, + vctrl->clk_enabled, vctrl->vsync_enabled, enable); if (vctrl->vsync_enabled == enable) { mutex_unlock(&vctrl->update_lock); @@ -404,33 +415,28 @@ void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable) vctrl->vsync_enabled = enable; if (enable) { + spin_lock_irqsave(&vctrl->spin_lock, flags); + vctrl->clk_control = 0; + vctrl->expire_tick = 0; + spin_unlock_irqrestore(&vctrl->spin_lock, flags); if (vctrl->clk_enabled == 0) { pr_debug("%s: SET_CLK_ON\n", __func__); mipi_dsi_clk_cfg(1); mdp_clk_ctrl(1); vctrl->clk_enabled = 1; + vctrl->new_update = 1; clk_set_on = 1; } - spin_lock_irqsave(&vctrl->spin_lock, flags); - vctrl->clk_control = 0; - vctrl->expire_tick = 0; - vctrl->new_update = 1; if (clk_set_on) { vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM); } - spin_unlock_irqrestore(&vctrl->spin_lock, flags); } else { spin_lock_irqsave(&vctrl->spin_lock, flags); - vctrl->clk_control = 1; - if (vctrl->clk_enabled) - vctrl->expire_tick = VSYNC_EXPIRE_TICK; + vctrl->expire_tick = VSYNC_EXPIRE_TICK; spin_unlock_irqrestore(&vctrl->spin_lock, flags); } mutex_unlock(&vctrl->update_lock); - - if (vctrl->vsync_enabled && atomic_read(&vctrl->suspend) == 0) - atomic_set(&vctrl->vsync_resume, 1); } void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime) @@ -508,19 +514,33 @@ static void primary_rdptr_isr(int cndx) struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; - pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id()); + pr_debug("%s: ISR, tick=%d pan=%d cpu=%d\n", __func__, + vctrl->expire_tick, vctrl->pan_display, smp_processor_id()); vctrl->rdptr_intr_tot++; spin_lock(&vctrl->spin_lock); vctrl->vsync_time = ktime_get(); + if (vctrl->new_update) { + vctrl->new_update = 0; + spin_unlock(&vctrl->spin_lock); + return; + } + complete_all(&vctrl->vsync_comp); vctrl->wait_vsync_cnt = 0; if (vctrl->expire_tick) { vctrl->expire_tick--; - if (vctrl->expire_tick == 0) - schedule_work(&vctrl->clk_work); + if (vctrl->expire_tick == 0) { + if (vctrl->pan_display <= 0) { + vctrl->clk_control = 1; + schedule_work(&vctrl->clk_work); + } else { + /* wait one more vsycn */ + vctrl->expire_tick += 1; + } + } } spin_unlock(&vctrl->spin_lock); } @@ -533,16 +553,22 @@ void mdp4_dmap_done_dsi_cmd(int cndx) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; /* blt enabled */ spin_lock(&vctrl->spin_lock); vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM); vctrl->dmap_done++; + + if (vctrl->pan_display) + vctrl->pan_display--; + diff = vctrl->ov_done - vctrl->dmap_done; pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n", __func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id()); - complete_all(&vctrl->dmap_comp); + complete(&vctrl->dmap_comp); if (diff <= 0) { if (vctrl->blt_wait) vctrl->blt_wait = 0; @@ -557,7 +583,7 @@ void mdp4_dmap_done_dsi_cmd(int cndx) vctrl->dmap_koff++; vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */ - mb(); + mb(); /* make sure kickoff executed */ spin_unlock(&vctrl->spin_lock); } @@ -572,11 +598,13 @@ void mdp4_overlay0_done_dsi_cmd(int cndx) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; spin_lock(&vctrl->spin_lock); vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); vctrl->ov_done++; - complete_all(&vctrl->ov_comp); + complete(&vctrl->ov_comp); diff = vctrl->ov_done - vctrl->dmap_done; pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n", @@ -606,26 +634,30 @@ void mdp4_overlay0_done_dsi_cmd(int cndx) vctrl->dmap_koff++; vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */ - mb(); + mb(); /* make sure kickoff executed */ spin_unlock(&vctrl->spin_lock); } static void clk_ctrl_work(struct work_struct *work) { + unsigned long flags; struct vsycn_ctrl *vctrl = container_of(work, typeof(*vctrl), clk_work); - unsigned long flags; mutex_lock(&vctrl->update_lock); + spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->clk_control && vctrl->clk_enabled) { - pr_debug("%s: SET_CLK_OFF\n", __func__); - mdp_clk_ctrl(0); - mipi_dsi_clk_cfg(0); - spin_lock_irqsave(&vctrl->spin_lock, flags); vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM); vctrl->clk_enabled = 0; vctrl->clk_control = 0; spin_unlock_irqrestore(&vctrl->spin_lock, flags); + /* make sure dsi link is idle */ + mipi_dsi_mdp_busy_wait(); + mipi_dsi_clk_cfg(0); + mdp_clk_ctrl(0); + pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid); + } else { + spin_unlock_irqrestore(&vctrl->spin_lock, flags); } mutex_unlock(&vctrl->update_lock); } @@ -642,8 +674,7 @@ ssize_t mdp4_dsi_cmd_show_event(struct device *dev, cndx = 0; vctrl = &vsync_ctrl_db[0]; - if (atomic_read(&vctrl->suspend) > 0 || - atomic_read(&vctrl->vsync_resume) == 0) + if (atomic_read(&vctrl->suspend) > 0) return 0; spin_lock_irqsave(&vctrl->spin_lock, flags); @@ -656,7 +687,10 @@ ssize_t mdp4_dsi_cmd_show_event(struct device *dev, msecs_to_jiffies(VSYNC_PERIOD * 4)); if (ret <= 0) { vctrl->wait_vsync_cnt = 0; - return -EBUSY; + vsync_tick = ktime_to_ns(ktime_get()); + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick); + buf[strlen(buf) + 1] = '\0'; + return ret; } spin_lock_irqsave(&vctrl->spin_lock, flags); @@ -664,6 +698,8 @@ ssize_t mdp4_dsi_cmd_show_event(struct device *dev, spin_unlock_irqrestore(&vctrl->spin_lock, flags); ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick); + pr_debug("%s: UEVENT\n", __func__); + buf[strlen(buf) + 1] = '\0'; return ret; } @@ -688,7 +724,6 @@ void mdp4_dsi_rdptr_init(int cndx) init_completion(&vctrl->dmap_comp); init_completion(&vctrl->vsync_comp); spin_lock_init(&vctrl->spin_lock); - atomic_set(&vctrl->vsync_resume, 1); atomic_set(&vctrl->suspend, 1); INIT_WORK(&vctrl->clk_work, clk_ctrl_work); } @@ -698,20 +733,6 @@ void mdp4_primary_rdptr(void) primary_rdptr_isr(0); } -void mdp4_overlay_dsi_state_set(int state) -{ - unsigned long flag; - - spin_lock_irqsave(&mdp_spin_lock, flag); - dsi_state = state; - spin_unlock_irqrestore(&mdp_spin_lock, flag); -} - -int mdp4_overlay_dsi_state_get(void) -{ - return dsi_state; -} - static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp) { /* @@ -849,6 +870,9 @@ static void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd) pipe = vctrl->base_pipe; } + /* TE enabled */ + mdp4_mipi_vsync_enable(mfd, pipe, 0); + MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */ /* @@ -936,6 +960,7 @@ void mdp4_dsi_cmd_3d_sbys(struct msm_fb_data_type *mfd, pipe->srcp0_addr = (uint32)src; mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); mdp4_overlay_rgb_setup(pipe); @@ -951,6 +976,7 @@ void mdp4_dsi_cmd_3d_sbys(struct msm_fb_data_type *mfd, mdp4_mixer_stage_commit(pipe->mixer_num); /* MDP cmd block disable */ + mdp_clk_ctrl(0); mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } @@ -977,9 +1003,10 @@ int mdp4_dsi_cmd_on(struct platform_device *pdev) struct msm_fb_data_type *mfd; struct vsycn_ctrl *vctrl; - pr_debug("%s+:\n", __func__); + pr_debug("%s+: pid=%d\n", __func__, current->pid); mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + mfd->cont_splash_done = 1; vctrl = &vsync_ctrl_db[cndx]; vctrl->mfd = mfd; @@ -992,8 +1019,8 @@ int mdp4_dsi_cmd_on(struct platform_device *pdev) mdp4_iommu_attach(); atomic_set(&vctrl->suspend, 0); - pr_debug("%s-:\n", __func__); + pr_debug("%s-:\n", __func__); return ret; } @@ -1004,8 +1031,12 @@ int mdp4_dsi_cmd_off(struct platform_device *pdev) struct msm_fb_data_type *mfd; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + struct vsync_update *vp; + int undx; + int need_wait, cnt; + unsigned long flags; - pr_debug("%s+:\n", __func__); + pr_debug("%s+: pid=%d\n", __func__, current->pid); mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); @@ -1016,43 +1047,56 @@ int mdp4_dsi_cmd_off(struct platform_device *pdev) return ret; } + need_wait = 0; + mutex_lock(&vctrl->update_lock); atomic_set(&vctrl->suspend, 1); - atomic_set(&vctrl->vsync_resume, 0); complete_all(&vctrl->vsync_comp); + pr_debug("%s: clk=%d pan=%d\n", __func__, + vctrl->clk_enabled, vctrl->pan_display); + if (vctrl->clk_enabled) + need_wait = 1; + mutex_unlock(&vctrl->update_lock); + + cnt = 0; + if (need_wait) { + while (vctrl->clk_enabled) { + msleep(20); + cnt++; + if (cnt > 10) + break; + } + } + + if (cnt > 10) { + spin_lock_irqsave(&vctrl->spin_lock, flags); + vctrl->clk_control = 0; + vctrl->clk_enabled = 0; + vctrl->expire_tick = 0; + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + mipi_dsi_clk_cfg(0); + mdp_clk_ctrl(0); + pr_err("%s: Error, SET_CLK_OFF by force\n", __func__); + } + /* sanity check, free pipes besides base layer */ mdp4_overlay_unset_mixer(pipe->mixer_num); mdp4_mixer_stage_down(pipe, 1); mdp4_overlay_pipe_free(pipe); vctrl->base_pipe = NULL; - if (vctrl->clk_enabled) { + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; + if (vp->update_cnt) { /* - * in case of suspend, vsycn_ctrl off is not - * received from frame work which left clock on - * then, clock need to be turned off here + * pipe's iommu will be freed at next overlay play + * and iommu_drop statistic will be increased by one */ - mdp_clk_ctrl(0); + vp->update_cnt = 0; /* empty queue */ } - vctrl->clk_enabled = 0; - vctrl->vsync_enabled = 0; - vctrl->clk_control = 0; - vctrl->expire_tick = 0; - - vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM); - - pr_debug("%s-:\n", __func__); - - /* - * footswitch off - * this will casue all mdp register - * to be reset to default - * after footswitch on later - */ - return ret; } @@ -1087,37 +1131,50 @@ void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd) struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; unsigned long flags; + int clk_set_on = 0; + mutex_lock(&mfd->dma->ov_mutex); vctrl = &vsync_ctrl_db[cndx]; - if (!mfd->panel_power_on) + if (!mfd->panel_power_on) { + mutex_unlock(&mfd->dma->ov_mutex); return; + } pipe = vctrl->base_pipe; if (pipe == NULL) { pr_err("%s: NO base pipe\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); return; } mutex_lock(&vctrl->update_lock); - if (!vctrl->clk_enabled) { - pr_err("%s: mdp clocks disabled\n", __func__); + if (atomic_read(&vctrl->suspend)) { mutex_unlock(&vctrl->update_lock); + mutex_unlock(&mfd->dma->ov_mutex); + pr_err("%s: suspended, no more pan display\n", __func__); return; - } - mutex_unlock(&vctrl->update_lock); spin_lock_irqsave(&vctrl->spin_lock, flags); - if (vctrl->expire_tick) { - /* - * in the middle of shutting clocks down - * delay to allow pan display to go through - */ + vctrl->clk_control = 0; + vctrl->pan_display++; + if (!vctrl->clk_enabled) { + clk_set_on = 1; + vctrl->clk_enabled = 1; vctrl->expire_tick = VSYNC_EXPIRE_TICK; } spin_unlock_irqrestore(&vctrl->spin_lock, flags); + if (clk_set_on) { + pr_debug("%s: SET_CLK_ON\n", __func__); + mipi_dsi_clk_cfg(1); + mdp_clk_ctrl(1); + vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM); + } + + mutex_unlock(&vctrl->update_lock); + if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) { mdp4_mipi_vsync_enable(mfd, pipe, 0); mdp4_overlay_setup_pipe_addr(mfd, pipe); @@ -1125,10 +1182,7 @@ void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd) } mdp4_overlay_mdp_perf_upd(mfd, 1); - - mutex_lock(&mfd->dma->ov_mutex); - mdp4_dsi_cmd_pipe_commit(); - mutex_unlock(&mfd->dma->ov_mutex); - + mdp4_dsi_cmd_pipe_commit(cndx, 1); mdp4_overlay_mdp_perf_upd(mfd, 0); + mutex_unlock(&mfd->dma->ov_mutex); } diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c index 5025954c..72a53fcf 100644 --- a/drivers/video/msm/mdp4_overlay_dsi_video.c +++ b/drivers/video/msm/mdp4_overlay_dsi_video.c @@ -56,6 +56,8 @@ static struct vsycn_ctrl { int wait_vsync_cnt; int blt_change; int blt_free; + u32 blt_ctrl; + u32 blt_mode; int sysfs_created; struct mutex update_lock; struct completion ov_comp; @@ -147,7 +149,7 @@ static void mdp4_dsi_video_blt_ov_update(struct mdp4_overlay_pipe *pipe); static void mdp4_dsi_video_wait4dmap(int cndx); static void mdp4_dsi_video_wait4ov(int cndx); -int mdp4_dsi_video_pipe_commit(void) +int mdp4_dsi_video_pipe_commit(int cndx, int wait) { int i, undx; @@ -159,7 +161,7 @@ int mdp4_dsi_video_pipe_commit(void) unsigned long flags; int cnt = 0; - vctrl = &vsync_ctrl_db[0]; + vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; @@ -167,6 +169,8 @@ int mdp4_dsi_video_pipe_commit(void) pipe = vctrl->base_pipe; mixer = pipe->mixer_num; + mdp_update_pm(vctrl->mfd, vctrl->vsync_time); + if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return cnt; @@ -194,20 +198,6 @@ int mdp4_dsi_video_pipe_commit(void) } spin_unlock_irqrestore(&vctrl->spin_lock, flags); - mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1); - - if (vctrl->blt_change) { - pipe = vctrl->base_pipe; - spin_lock_irqsave(&vctrl->spin_lock, flags); - INIT_COMPLETION(vctrl->dmap_comp); - INIT_COMPLETION(vctrl->ov_comp); - vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); - spin_unlock_irqrestore(&vctrl->spin_lock, flags); - mdp4_dsi_video_wait4dmap(0); - if (pipe->ov_blt_addr) - mdp4_dsi_video_wait4ov(0); - } - pipe = vp->plist; for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { @@ -253,6 +243,13 @@ int mdp4_dsi_video_pipe_commit(void) mdp4_stat.overlay_commit[pipe->mixer_num]++; + if (wait) { + if (pipe->ov_blt_addr) + mdp4_dsi_video_wait4ov(cndx); + else + mdp4_dsi_video_wait4dmap(cndx); + } + return cnt; } @@ -348,7 +345,6 @@ static void mdp4_dsi_video_wait4dmap_done(int cndx) vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_dsi_video_wait4dmap(cndx); - vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM); } @@ -385,9 +381,6 @@ ssize_t mdp4_dsi_video_show_event(struct device *dev, atomic_read(&vctrl->vsync_resume) == 0) return 0; - if (!dsi_video_enabled) - return 0; - spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->wait_vsync_cnt == 0) INIT_COMPLETION(vctrl->vsync_comp); @@ -397,7 +390,10 @@ ssize_t mdp4_dsi_video_show_event(struct device *dev, msecs_to_jiffies(VSYNC_PERIOD * 4)); if (ret <= 0) { vctrl->wait_vsync_cnt = 0; - return -EBUSY; + vsync_tick = ktime_to_ns(ktime_get()); + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick); + buf[strlen(buf) + 1] = '\0'; + return ret; } spin_lock_irqsave(&vctrl->spin_lock, flags); @@ -490,6 +486,7 @@ int mdp4_dsi_video_on(struct platform_device *pdev) int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; + struct msm_panel_info *pinfo; vctrl = &vsync_ctrl_db[cndx]; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); @@ -502,6 +499,9 @@ int mdp4_dsi_video_on(struct platform_device *pdev) vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; + pinfo = &mfd->panel_info; + vctrl->blt_ctrl = pinfo->lcd.blt_ctrl; + vctrl->blt_mode = pinfo->lcd.blt_mode; /* mdp clock on */ mdp_clk_ctrl(1); @@ -544,7 +544,11 @@ int mdp4_dsi_video_on(struct platform_device *pdev) mfd->cont_splash_done = 1; mdp4_dsi_video_wait4dmap_done(0); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); + dsi_video_enabled = 0; mipi_dsi_controller_cfg(0); + /* Clks are enabled in probe. + Disabling clocks now */ + mdp_clk_ctrl(0); } pipe->src_height = fbi->var.yres; @@ -567,6 +571,7 @@ int mdp4_dsi_video_on(struct platform_device *pdev) pipe->dst_w = fbi->var.xres; mdp4_overlay_mdp_pipe_req(pipe, mfd); + mdp4_calc_blt_mdp_bw(mfd, pipe); atomic_set(&vctrl->suspend, 0); @@ -668,8 +673,9 @@ int mdp4_dsi_video_off(struct platform_device *pdev) struct msm_fb_data_type *mfd; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + struct vsync_update *vp; unsigned long flags; - int need_wait = 0; + int undx, need_wait = 0; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); vctrl = &vsync_ctrl_db[cndx]; @@ -697,6 +703,21 @@ int mdp4_dsi_video_off(struct platform_device *pdev) dsi_video_enabled = 0; + if (vctrl->vsync_irq_enabled) { + vctrl->vsync_irq_enabled = 0; + vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM); + } + + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; + if (vp->update_cnt) { + /* + * pipe's iommu will be freed at next overlay play + * and iommu_drop statistic will be increased by one + */ + vp->update_cnt = 0; /* empty queue */ + } + if (pipe) { /* sanity check, free pipes besides base layer */ mdp4_overlay_unset_mixer(pipe->mixer_num); @@ -906,26 +927,16 @@ void mdp4_dmap_done_dsi_video(int cndx) } vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; spin_lock(&vctrl->spin_lock); vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM); if (vctrl->blt_change) { mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmap_xy(pipe); - if (pipe->ov_blt_addr) { - mdp4_dsi_video_blt_ov_update(pipe); - pipe->ov_cnt++; - /* Prefill one frame */ - vsync_irq_enable(INTR_OVERLAY0_DONE, - MDP_OVERLAY0_TERM); - /* kickoff overlay0 engine */ - mdp4_stat.kickoff_ov0++; - vctrl->ov_koff++; /* make up for prefill */ - outpdw(MDP_BASE + 0x0004, 0); - } vctrl->blt_change = 0; } - complete_all(&vctrl->dmap_comp); mdp4_overlay_dma_commit(cndx); spin_unlock(&vctrl->spin_lock); @@ -941,6 +952,8 @@ void mdp4_overlay0_done_dsi_video(int cndx) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; spin_lock(&vctrl->spin_lock); vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); @@ -966,19 +979,44 @@ static void mdp4_dsi_video_do_blt(struct msm_fb_data_type *mfd, int enable) int cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + long long vtime; + u32 mode, ctrl; vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; - mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); + mode = (dbg_force_ov0_blt & 0x0f) ? + (dbg_force_ov0_blt & 0x0f) : vctrl->blt_mode; + ctrl = (dbg_force_ov0_blt >> 4) ? + (dbg_force_ov0_blt >> 4) : vctrl->blt_ctrl; - if (mfd->ov0_wb_buf->write_addr == 0) { - pr_info("%s: no blt_base assigned\n", __func__); + pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n", + __func__, mode, enable, (int)pipe->ov_blt_addr); + + if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) && + !pipe->ov_blt_addr) + return; + else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) && + pipe->ov_blt_addr) return; + else if (enable && pipe->ov_blt_addr) + return; + else if (!enable && !pipe->ov_blt_addr) + return; + + if (pipe->ov_blt_addr == 0) { + mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); + if (mfd->ov0_wb_buf->write_addr == 0) { + pr_warning("%s: no blt_base assigned\n", __func__); + return; + } } + pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n", + __func__, mode, enable, (int)pipe->ov_blt_addr); + spin_lock_irqsave(&vctrl->spin_lock, flag); - if (enable && pipe->ov_blt_addr == 0) { + if (pipe->ov_blt_addr == 0) { pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr; pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr; pipe->ov_cnt = 0; @@ -987,23 +1025,57 @@ static void mdp4_dsi_video_do_blt(struct msm_fb_data_type *mfd, int enable) vctrl->ov_done = 0; vctrl->blt_free = 0; mdp4_stat.blt_dsi_video++; - vctrl->blt_change++; - } else if (enable == 0 && pipe->ov_blt_addr) { + } else { pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; vctrl->blt_free = 4; /* 4 commits to free wb buf */ - vctrl->blt_change++; } + spin_unlock_irqrestore(&vctrl->spin_lock, flag); - pr_info("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__, - vctrl->blt_change, enable, (int)pipe->ov_blt_addr); - - if (!vctrl->blt_change) { + if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) { + spin_lock_irqsave(&vctrl->spin_lock, flag); + if (!dsi_video_enabled) { + pr_debug("%s: blt switched not in ISR dsi_video_enabled=%d\n", + __func__, dsi_video_enabled); + mdp4_overlayproc_cfg(pipe); + mdp4_overlay_dmap_xy(pipe); + } else { + pr_debug("%s: blt switched in ISR dsi_video_enabled=%d\n", + __func__, dsi_video_enabled); + vctrl->blt_change++; + } spin_unlock_irqrestore(&vctrl->spin_lock, flag); - return; - } - - spin_unlock_irqrestore(&vctrl->spin_lock, flag); + if (dsi_video_enabled) + mdp4_dsi_video_wait4dmap_done(0); + } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) { + pr_debug("%s: blt switched by turning TG off\n", __func__); + if (dsi_video_enabled) { + mdp4_dsi_video_wait4vsync(0, &vtime); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); + mdp4_dsi_video_wait4dmap_done(0); + } + mdp4_overlayproc_cfg(pipe); + mdp4_overlay_dmap_xy(pipe); + if (dsi_video_enabled) { + /* + * need wait for more than 1 ms to + * make sure dsi lanes' fifo is empty and + * lanes in stop state befroe reset + * controller + */ + usleep(2000); + mipi_dsi_sw_reset(); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1); + } + } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) { + pr_debug("%s: blt switched by polling mdp status\n", __func__); + if (dsi_video_enabled) + while (inpdw(MDP_BASE + 0x0018) & 0x05) + cpu_relax(); + mdp4_overlayproc_cfg(pipe); + mdp4_overlay_dmap_xy(pipe); + } else + pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl); } void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd, @@ -1028,15 +1100,19 @@ void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd) uint8 *buf; unsigned int buf_offset; int bpp; - int cndx = 0; + int cnt, cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + mutex_lock(&mfd->dma->ov_mutex); + vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; - if (!pipe || !mfd->panel_power_on) + if (!pipe || !mfd->panel_power_on) { + mutex_unlock(&mfd->dma->ov_mutex); return; + } pr_debug("%s: cpu=%d pid=%d\n", __func__, smp_processor_id(), current->pid); @@ -1053,17 +1129,16 @@ void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd) mdp4_dsi_video_pipe_queue(0, pipe); } - mutex_lock(&mfd->dma->ov_mutex); mdp4_overlay_mdp_perf_upd(mfd, 1); - mdp4_dsi_video_pipe_commit(); - mutex_unlock(&mfd->dma->ov_mutex); - - if (pipe->ov_blt_addr) - mdp4_dsi_video_wait4ov(0); - else - mdp4_dsi_video_wait4dmap(0); + cnt = mdp4_dsi_video_pipe_commit(cndx, 0); + if (cnt) { + if (pipe->ov_blt_addr) + mdp4_dsi_video_wait4ov(cndx); + else + mdp4_dsi_video_wait4dmap(cndx); + } mdp4_overlay_mdp_perf_upd(mfd, 0); + mutex_unlock(&mfd->dma->ov_mutex); } - diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c index ef661c98..8539c00b 100644 --- a/drivers/video/msm/mdp4_overlay_dtv.c +++ b/drivers/video/msm/mdp4_overlay_dtv.c @@ -33,7 +33,6 @@ #include "mdp4.h" #define DTV_BASE 0xD0000 - static int dtv_enabled; /*#define DEBUG*/ @@ -55,14 +54,6 @@ static void __mdp_outp(uint32 port, uint32 value) static int first_pixel_start_x; static int first_pixel_start_y; -void mdp4_dtv_base_swap(int cndx, struct mdp4_overlay_pipe *pipe) -{ -#ifdef BYPASS4 - if (hdmi_prim_display) - dtv_pipe = pipe; -#endif -} - #define MAX_CONTROLLER 1 static struct vsycn_ctrl { @@ -75,16 +66,24 @@ static struct vsycn_ctrl { int dmae_wait_cnt; int wait_vsync_cnt; int blt_change; + int blt_ctrl; + int blt_mode; + int blt_free; int sysfs_created; struct mutex update_lock; struct completion ov_comp; struct completion dmae_comp; struct completion vsync_comp; spinlock_t spin_lock; + struct msm_fb_data_type *mfd; struct mdp4_overlay_pipe *base_pipe; struct vsync_update vlist[2]; int vsync_irq_enabled; ktime_t vsync_time; + uint32 *avtimer; + int vg1fd; + int vg2fd; + unsigned long long avtimer_tick; } vsync_ctrl_db[MAX_CONTROLLER]; static void vsync_irq_enable(int intr, int term) @@ -163,9 +162,10 @@ void mdp4_dtv_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe) } static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe); +static void mdp4_dtv_wait4ov(int cndx); static void mdp4_dtv_wait4dmae(int cndx); -int mdp4_dtv_pipe_commit(void) +int mdp4_dtv_pipe_commit(int cndx, int wait) { int i, undx; @@ -177,7 +177,7 @@ int mdp4_dtv_pipe_commit(void) unsigned long flags; int cnt = 0; - vctrl = &vsync_ctrl_db[0]; + vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; vp = &vctrl->vlist[undx]; @@ -185,6 +185,8 @@ int mdp4_dtv_pipe_commit(void) mixer = pipe->mixer_num; mdp4_overlay_iommu_unmap_freelist(mixer); + mdp_update_pm(vctrl->mfd, vctrl->vsync_time); + if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; @@ -193,6 +195,13 @@ int mdp4_dtv_pipe_commit(void) vctrl->update_ndx++; vctrl->update_ndx &= 0x01; vp->update_cnt = 0; /* reset */ + + if (vctrl->blt_free) { + vctrl->blt_free--; + if (vctrl->blt_free == 0) + mdp4_free_writeback_buf(vctrl->mfd, mixer); + } + mutex_unlock(&vctrl->update_lock); pipe = vp->plist; @@ -222,6 +231,7 @@ int mdp4_dtv_pipe_commit(void) if (pipe->ov_blt_addr) { mdp4_dtv_blt_ov_update(pipe); pipe->blt_ov_done++; + INIT_COMPLETION(vctrl->ov_comp); vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); mb(); pipe->blt_ov_koff++; @@ -236,6 +246,12 @@ int mdp4_dtv_pipe_commit(void) spin_unlock_irqrestore(&vctrl->spin_lock, flags); mdp4_stat.overlay_commit[pipe->mixer_num]++; + if (wait) { + if (pipe->ov_blt_addr) + mdp4_dtv_wait4ov(cndx); + else + mdp4_dtv_wait4dmae(cndx); + } return cnt; } @@ -295,6 +311,23 @@ void mdp4_dtv_wait4vsync(int cndx, long long *vtime) *vtime = ktime_to_ns(vctrl->vsync_time); } +static void mdp4_dtv_wait4ov(int cndx) +{ + struct vsycn_ctrl *vctrl; + + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } + + vctrl = &vsync_ctrl_db[cndx]; + + if (atomic_read(&vctrl->suspend) > 0) + return; + + wait_for_completion(&vctrl->ov_comp); +} + static void mdp4_dtv_wait4dmae(int cndx) { struct vsycn_ctrl *vctrl; @@ -319,10 +352,14 @@ ssize_t mdp4_dtv_show_event(struct device *dev, struct vsycn_ctrl *vctrl; ssize_t ret = 0; unsigned long flags; - u64 vsync_tick; + char ch = '\0'; + int vg1fd = -1, vg2fd = -1; + unsigned long long avtimer_tick = 0; + u64 vsync_tick = 0; cndx = 0; vctrl = &vsync_ctrl_db[0]; + memset(buf, 0, 64); if (atomic_read(&vctrl->suspend) > 0 || !external_common_state->hpd_state || @@ -339,17 +376,54 @@ ssize_t mdp4_dtv_show_event(struct device *dev, msecs_to_jiffies(VSYNC_PERIOD * 4)); if (ret <= 0) { vctrl->wait_vsync_cnt = 0; - return -EBUSY; + vsync_tick = ktime_to_ns(ktime_get()); + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick); + buf[strlen(buf) + 1] = '\0'; + return ret; } spin_lock_irqsave(&vctrl->spin_lock, flags); + vg1fd = vctrl->vg1fd; + vg2fd = vctrl->vg2fd; + avtimer_tick = vctrl->avtimer_tick; vsync_tick = ktime_to_ns(vctrl->vsync_time); spin_unlock_irqrestore(&vctrl->spin_lock, flags); - ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick); - buf[strlen(buf) + 1] = '\0'; + ret = snprintf(buf, PAGE_SIZE, + "VSYNC=%llu%c" + "AVSYNCTP=%llu%c" + "VG1MEMID=%d%c" + "VG2MEMID=%d", + vsync_tick, + ch, avtimer_tick, + ch, vg1fd, + ch, vg2fd); + return ret; } + +static void mdp4_dtv_wait4dmae_done(int cndx) +{ + unsigned long flags; + struct vsycn_ctrl *vctrl; + + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } + + vctrl = &vsync_ctrl_db[cndx]; + + if (atomic_read(&vctrl->suspend) > 0) + return; + + spin_lock_irqsave(&vctrl->spin_lock, flags); + INIT_COMPLETION(vctrl->dmae_comp); + vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM); + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + mdp4_dtv_wait4dmae(cndx); +} + void mdp4_dtv_vsync_init(int cndx) { struct vsycn_ctrl *vctrl; @@ -376,6 +450,24 @@ void mdp4_dtv_vsync_init(int cndx) spin_lock_init(&vctrl->spin_lock); } +void mdp4_dtv_base_swap(int cndx, struct mdp4_overlay_pipe *pipe) +{ + struct vsycn_ctrl *vctrl; + + if (!hdmi_prim_display) { + pr_err("%s: failed, hdmi is not primary\n", __func__); + return; + } + + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } + + vctrl = &vsync_ctrl_db[cndx]; + vctrl->base_pipe = pipe; +} + static int mdp4_dtv_start(struct msm_fb_data_type *mfd) { int dtv_width; @@ -410,6 +502,9 @@ static int mdp4_dtv_start(struct msm_fb_data_type *mfd) int hsync_end_x; struct fb_info *fbi; struct fb_var_screeninfo *var; + struct vsycn_ctrl *vctrl; + + vctrl = &vsync_ctrl_db[0]; if (!mfd) return -ENODEV; @@ -420,6 +515,8 @@ static int mdp4_dtv_start(struct msm_fb_data_type *mfd) fbi = mfd->fbi; var = &fbi->var; + vctrl->mfd = mfd; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); if (hdmi_prim_display) { if (is_mdp4_hw_reset()) { @@ -514,6 +611,7 @@ static int mdp4_dtv_start(struct msm_fb_data_type *mfd) /* enable DTV block */ MDP_OUTP(MDP_BASE + DTV_BASE, 1); + dtv_enabled = 1; return 0; } @@ -528,6 +626,7 @@ static int mdp4_dtv_stop(struct msm_fb_data_type *mfd) return -EINVAL; MDP_OUTP(MDP_BASE + DTV_BASE, 0); + dtv_enabled = 0; return 0; } @@ -538,6 +637,7 @@ int mdp4_dtv_on(struct platform_device *pdev) int ret = 0; int cndx = 0; struct vsycn_ctrl *vctrl; + struct msm_panel_info *pinfo; vctrl = &vsync_ctrl_db[cndx]; @@ -549,7 +649,12 @@ int mdp4_dtv_on(struct platform_device *pdev) if (mfd->key != MFD_KEY) return -EINVAL; + vctrl->mfd = mfd; vctrl->dev = mfd->fbi->dev; + pinfo = &mfd->panel_info; + + vctrl->blt_ctrl = pinfo->lcd.blt_ctrl; + vctrl->blt_mode = pinfo->lcd.blt_mode; mdp_footswitch_ctrl(TRUE); /* Mdp clock enable */ @@ -571,6 +676,12 @@ int mdp4_dtv_on(struct platform_device *pdev) pr_warn("%s: panel_next_on failed", __func__); atomic_set(&vctrl->suspend, 0); + if (mfd->avtimer_phy && (vctrl->avtimer == NULL)) { + vctrl->avtimer = (uint32 *)ioremap(mfd->avtimer_phy, 8); + if (vctrl->avtimer == NULL) + pr_err(" avtimer ioremap fail\n"); + } + pr_info("%s:\n", __func__); return ret; @@ -581,8 +692,10 @@ int mdp4_dtv_off(struct platform_device *pdev) struct msm_fb_data_type *mfd; int ret = 0; int cndx = 0; + int undx; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + struct vsync_update *vp; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); @@ -591,10 +704,10 @@ int mdp4_dtv_off(struct platform_device *pdev) atomic_set(&vctrl->suspend, 1); atomic_set(&vctrl->vsync_resume, 0); - if (vctrl->vsync_irq_enabled) { - while (vctrl->wait_vsync_cnt) - msleep(20); /* >= 17 ms */ - } + /* wait for one vsycn time to make sure + * previous stage_commit had been kicked in + */ + msleep(20); /* >= 17 ms */ complete_all(&vctrl->vsync_comp); @@ -623,6 +736,26 @@ int mdp4_dtv_off(struct platform_device *pdev) mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV); + if (vctrl->vsync_irq_enabled) { + vctrl->vsync_irq_enabled = 0; + vsync_irq_disable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM); + } + + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; + if (vp->update_cnt) { + /* + * pipe's iommu will be freed at next overlay play + * and iommu_drop statistic will be increased by one + */ + vp->update_cnt = 0; /* empty queue */ + } + + if (vctrl->avtimer != NULL) { + iounmap(vctrl->avtimer); + vctrl->avtimer = NULL; + } + ret = panel_next_off(pdev); mdp_footswitch_ctrl(FALSE); @@ -680,11 +813,6 @@ static void mdp4_dtv_blt_dmae_update(struct mdp4_overlay_pipe *pipe) MDP_OUTP(MDP_BASE + 0xb0008, addr); } -void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd) -{ - -} - static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd, int32 ptype, struct vsycn_ctrl *vctrl) { @@ -744,6 +872,7 @@ static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd, pipe->srcp0_ystride = fbi->fix.line_length; mdp4_overlay_mdp_pipe_req(pipe, mfd); + mdp4_calc_blt_mdp_bw(mfd, pipe); ret = mdp4_overlay_format2pipe(pipe); if (ret < 0) @@ -801,7 +930,7 @@ int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd, struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; - if (vctrl->base_pipe != NULL) + if (vctrl->base_pipe == NULL) return 0; if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE && @@ -809,6 +938,12 @@ int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd, result = mdp4_dtv_stop(mfd); vctrl->base_pipe = NULL; } + + if (pipe->pipe_num == OVERLAY_PIPE_VG1) + vctrl->vg1fd = -1; + else if (pipe->pipe_num == OVERLAY_PIPE_VG2) + vctrl->vg2fd = -1; + return result; } @@ -818,6 +953,7 @@ void mdp4_external_vsync_dtv(void) { int cndx; struct vsycn_ctrl *vctrl; + uint32 *tp, LSW; cndx = 0; vctrl = &vsync_ctrl_db[cndx]; @@ -825,6 +961,15 @@ void mdp4_external_vsync_dtv(void) spin_lock(&vctrl->spin_lock); vctrl->vsync_time = ktime_get(); + vctrl->avtimer_tick = 0; + + if (vctrl->avtimer && ((vctrl->vg1fd > 0) || (vctrl->vg2fd > 0))) { + tp = vctrl->avtimer; + LSW = inpdw(tp); + tp++; + vctrl->avtimer_tick = (unsigned long long) inpdw(tp); + vctrl->avtimer_tick = ((vctrl->avtimer_tick << 32) | LSW); + } if (vctrl->wait_vsync_cnt) { complete_all(&vctrl->vsync_comp); @@ -850,22 +995,14 @@ void mdp4_dmae_done_dtv(void) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; pr_debug("%s: cpu=%d\n", __func__, smp_processor_id()); spin_lock(&vctrl->spin_lock); if (vctrl->blt_change) { - if (pipe->ov_blt_addr) { - mdp4_overlayproc_cfg(pipe); - mdp4_overlay_dmae_xy(pipe); - mdp4_dtv_blt_ov_update(pipe); - pipe->blt_ov_done++; - - /* Prefill one frame */ - vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); - /* kickoff overlay1 engine */ - mdp4_stat.kickoff_ov1++; - outpdw(MDP_BASE + 0x0008, 0); - } + mdp4_overlayproc_cfg(pipe); + mdp4_overlay_dmae_xy(pipe); vctrl->blt_change = 0; } @@ -890,6 +1027,8 @@ void mdp4_overlay1_done_dtv(void) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; spin_lock(&vctrl->spin_lock); if (pipe->ov_blt_addr == 0) { @@ -898,104 +1037,154 @@ void mdp4_overlay1_done_dtv(void) } mdp4_dtv_blt_dmae_update(pipe); + complete_all(&vctrl->ov_comp); pipe->blt_dmap_done++; vsync_irq_disable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM); spin_unlock(&vctrl->spin_lock); } -void mdp4_dtv_set_black_screen(void) +void mdp4_dtv_set_black_screen() { char *rgb_base; /*Black color*/ uint32 color = 0x00000000; uint32 temp_src_format; - int cndx = 0; + int commit = 1, cndx = 0; + int pipe_num = OVERLAY_PIPE_RGB1; struct vsycn_ctrl *vctrl; vctrl = &vsync_ctrl_db[cndx]; - if (vctrl->base_pipe == NULL || !hdmi_prim_display) { - pr_err("dtv_pipe is not configured yet\n"); + if (!hdmi_prim_display) return; - } - rgb_base = MDP_BASE + MDP4_RGB_BASE; - rgb_base += (MDP4_RGB_OFF * vctrl->base_pipe->pipe_num); - /* - * RGB Constant Color - */ + if (vctrl->base_pipe == NULL) + commit = 0; + else + pipe_num = vctrl->base_pipe->pipe_num; + + rgb_base = MDP_BASE; + rgb_base += (MDP4_RGB_OFF * (pipe_num + 2)); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* RGB Constant Color */ MDP_OUTP(rgb_base + 0x1008, color); - /* - * MDP_RGB_SRC_FORMAT - */ + + /* MDP_RGB_SRC_FORMAT */ temp_src_format = inpdw(rgb_base + 0x0050); MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22)); - mdp4_overlay_reg_flush(vctrl->base_pipe, 1); - mdp4_mixer_stage_up(vctrl->base_pipe, 0); - mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + if (commit) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp4_overlay_reg_flush(vctrl->base_pipe, 1); + mdp4_mixer_stage_up(vctrl->base_pipe, 0); + mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num); + } else { + /* MDP_OVERLAY_REG_FLUSH for pipe*/ + MDP_OUTP(MDP_BASE + 0x18000, + BIT(pipe_num + 2) | BIT(MDP4_MIXER1)); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } } static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable) { unsigned long flag; - int data; int cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + u32 mode, ctrl; vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; - mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1); + mode = (dbg_force_ov1_blt & 0x0f) ? + (dbg_force_ov1_blt & 0x0f) : vctrl->blt_mode; + ctrl = (dbg_force_ov1_blt >> 4) ? + (dbg_force_ov1_blt >> 4) : vctrl->blt_ctrl; + + pr_debug("%s: mode=%d, ctrl = %d, enable=%d ov_blt_addr=%x\n", + __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr); - if (!mfd->ov1_wb_buf->write_addr) { - pr_info("%s: ctrl=%d blt_base NOT assigned\n", __func__, cndx); + if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) && + !pipe->ov_blt_addr) + return; + else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) && + pipe->ov_blt_addr) + return; + else if (enable && pipe->ov_blt_addr) + return; + else if (!enable && !pipe->ov_blt_addr) return; + + if (pipe->ov_blt_addr == 0) { + mdp4_allocate_writeback_buf(vctrl->mfd, MDP4_MIXER1); + if (!vctrl->mfd->ov1_wb_buf->write_addr) { + pr_warning("%s: ctrl=%d blt_base NOT assigned\n", + __func__, cndx); + return; + } } + pr_debug("%s: mode=%d, ctrl=%d, enable=%d ov_blt_addr=%x\n", + __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr); + spin_lock_irqsave(&vctrl->spin_lock, flag); if (enable && pipe->ov_blt_addr == 0) { - pipe->ov_blt_addr = mfd->ov1_wb_buf->write_addr; - pipe->dma_blt_addr = mfd->ov1_wb_buf->read_addr; + pipe->ov_blt_addr = vctrl->mfd->ov1_wb_buf->write_addr; + pipe->dma_blt_addr = vctrl->mfd->ov1_wb_buf->read_addr; pipe->blt_cnt = 0; pipe->ov_cnt = 0; pipe->blt_dmap_done = 0; pipe->blt_ov_koff = 0; pipe->blt_ov_done = 0; mdp4_stat.blt_dtv++; - vctrl->blt_change++; + vctrl->blt_free = 0; } else if (enable == 0 && pipe->ov_blt_addr) { pipe->ov_blt_addr = 0; pipe->dma_blt_addr = 0; - vctrl->blt_change++; + vctrl->blt_free = 4; } - - pr_info("%s: enable=%d change=%d blt_addr=%x\n", __func__, - enable, vctrl->blt_change, (int)pipe->ov_blt_addr); - - if (!vctrl->blt_change) { - spin_unlock_irqrestore(&vctrl->spin_lock, flag); - return; - } - - atomic_set(&vctrl->suspend, 1); spin_unlock_irqrestore(&vctrl->spin_lock, flag); - data = inpdw(MDP_BASE + DTV_BASE); - data &= 0x01; - if (data) /* timing generator enabled */ - mdp4_dtv_wait4dmae(0); + if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) { + spin_lock_irqsave(&vctrl->spin_lock, flag); + if (!dtv_enabled) { + pr_debug("%s: blt switched not in isr dtv_enabled=%d\n", + __func__, dtv_enabled); + mdp4_overlayproc_cfg(pipe); + mdp4_overlay_dmae_xy(pipe); + } else { + pr_debug("%s: blt switched in ISR dtv_enabled=%d\n", + __func__, dtv_enabled); + vctrl->blt_change++; - if (pipe->ov_blt_addr == 0) { - MDP_OUTP(MDP_BASE + DTV_BASE, 0); /* stop dtv */ - msleep(20); + } + spin_unlock_irqrestore(&vctrl->spin_lock, flag); + if (dtv_enabled) + mdp4_dtv_wait4dmae_done(0); + } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) { + pr_debug("%s: dtv blt switched by turning TG off\n", + __func__); + if (dtv_enabled) { + mdp4_dtv_wait4dmae_done(0); + MDP_OUTP(MDP_BASE + DTV_BASE, 0); + msleep(20); + } mdp4_overlayproc_cfg(pipe); mdp4_overlay_dmae_xy(pipe); - MDP_OUTP(MDP_BASE + DTV_BASE, 1); /* start dtv */ - } - - atomic_set(&vctrl->suspend, 0); + if (dtv_enabled) + MDP_OUTP(MDP_BASE + DTV_BASE, 1); + } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) { + pr_debug("%s: dtv blt change by polling status\n", + __func__); + while (inpdw(MDP_BASE + 0x0018) & 0x12) + cpu_relax(); + mdp4_overlayproc_cfg(pipe); + mdp4_overlay_dmae_xy(pipe); + } else + pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl); } void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd) @@ -1013,9 +1202,13 @@ void mdp4_dtv_overlay(struct msm_fb_data_type *mfd) int cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + int wait = 0; - if (!mfd->panel_power_on) + mutex_lock(&mfd->dma->ov_mutex); + if (!mfd->panel_power_on) { + mutex_unlock(&mfd->dma->ov_mutex); return; + } vctrl = &vsync_ctrl_db[cndx]; if (vctrl->base_pipe == NULL) @@ -1025,6 +1218,7 @@ void mdp4_dtv_overlay(struct msm_fb_data_type *mfd) if (pipe == NULL) { pr_warn("%s: dtv_pipe == NULL\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); return; } @@ -1040,9 +1234,27 @@ void mdp4_dtv_overlay(struct msm_fb_data_type *mfd) mdp4_dtv_pipe_queue(0, pipe); } - mutex_lock(&mfd->dma->ov_mutex); + if (hdmi_prim_display) + wait = 1; + mdp4_overlay_mdp_perf_upd(mfd, 1); - mdp4_dtv_pipe_commit(); + mdp4_dtv_pipe_commit(cndx, wait); mdp4_overlay_mdp_perf_upd(mfd, 0); mutex_unlock(&mfd->dma->ov_mutex); } + +void mdp4_dtv_set_avparams(struct mdp4_overlay_pipe *pipe, int id) +{ + struct vsycn_ctrl *vctrl; + + if (pipe == NULL) { + pr_warn("%s: dtv_pipe == NULL\n", __func__); + return; + } + vctrl = &vsync_ctrl_db[0]; + if (pipe->pipe_num == OVERLAY_PIPE_VG1) + vctrl->vg1fd = id; + else if (pipe->pipe_num == OVERLAY_PIPE_VG2) + vctrl->vg2fd = id; +} + diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c index 79c9e976..3702b59b 100644 --- a/drivers/video/msm/mdp4_overlay_lcdc.c +++ b/drivers/video/msm/mdp4_overlay_lcdc.c @@ -152,7 +152,7 @@ static void mdp4_lcdc_blt_ov_update(struct mdp4_overlay_pipe *pipe); static void mdp4_lcdc_wait4dmap(int cndx); static void mdp4_lcdc_wait4ov(int cndx); -int mdp4_lcdc_pipe_commit(void) +int mdp4_lcdc_pipe_commit(int cndx, int wait) { int i, undx; @@ -164,7 +164,7 @@ int mdp4_lcdc_pipe_commit(void) unsigned long flags; int cnt = 0; - vctrl = &vsync_ctrl_db[0]; + vctrl = &vsync_ctrl_db[cndx]; mutex_lock(&vctrl->update_lock); undx = vctrl->update_ndx; @@ -172,6 +172,8 @@ int mdp4_lcdc_pipe_commit(void) pipe = vctrl->base_pipe; mixer = pipe->mixer_num; + mdp_update_pm(vctrl->mfd, vctrl->vsync_time); + if (vp->update_cnt == 0) { mutex_unlock(&vctrl->update_lock); return 0; @@ -257,6 +259,13 @@ int mdp4_lcdc_pipe_commit(void) mdp4_stat.overlay_commit[pipe->mixer_num]++; + if (wait) { + if (pipe->ov_blt_addr) + mdp4_lcdc_wait4ov(cndx); + else + mdp4_lcdc_wait4dmap(cndx); + } + return cnt; } @@ -368,9 +377,6 @@ ssize_t mdp4_lcdc_show_event(struct device *dev, atomic_read(&vctrl->vsync_resume) == 0) return 0; - if (!lcdc_enabled) - return 0; - spin_lock_irqsave(&vctrl->spin_lock, flags); if (vctrl->wait_vsync_cnt == 0) INIT_COMPLETION(vctrl->vsync_comp); @@ -380,7 +386,10 @@ ssize_t mdp4_lcdc_show_event(struct device *dev, msecs_to_jiffies(VSYNC_PERIOD * 4)); if (ret <= 0) { vctrl->wait_vsync_cnt = 0; - return -EBUSY; + vsync_tick = ktime_to_ns(ktime_get()); + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_tick); + buf[strlen(buf) + 1] = '\0'; + return ret; } spin_lock_irqsave(&vctrl->spin_lock, flags); @@ -540,6 +549,7 @@ int mdp4_lcdc_on(struct platform_device *pdev) pipe->bpp = bpp; mdp4_overlay_mdp_pipe_req(pipe, mfd); + mdp4_calc_blt_mdp_bw(mfd, pipe); atomic_set(&vctrl->suspend, 0); @@ -655,8 +665,9 @@ int mdp4_lcdc_off(struct platform_device *pdev) struct msm_fb_data_type *mfd; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + struct vsync_update *vp; unsigned long flags; - int need_wait = 0; + int undx, need_wait = 0; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); vctrl = &vsync_ctrl_db[cndx]; @@ -684,6 +695,21 @@ int mdp4_lcdc_off(struct platform_device *pdev) lcdc_enabled = 0; + if (vctrl->vsync_irq_enabled) { + vctrl->vsync_irq_enabled = 0; + vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM); + } + + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; + if (vp->update_cnt) { + /* + * pipe's iommu will be freed at next overlay play + * and iommu_drop statistic will be increased by one + */ + vp->update_cnt = 0; /* empty queue */ + } + if (pipe) { /* sanity check, free pipes besides base layer */ mdp4_overlay_unset_mixer(pipe->mixer_num); @@ -796,6 +822,8 @@ void mdp4_dmap_done_lcdc(int cndx) } vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; spin_lock(&vctrl->spin_lock); vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM); @@ -834,6 +862,8 @@ void mdp4_overlay0_done_lcdc(int cndx) vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; + if (pipe == NULL) + return; spin_lock(&vctrl->spin_lock); vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); @@ -917,16 +947,19 @@ void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd) uint8 *buf; unsigned int buf_offset; int bpp; - int cndx = 0; + int cnt, cndx = 0; struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; + mutex_lock(&mfd->dma->ov_mutex); vctrl = &vsync_ctrl_db[cndx]; pipe = vctrl->base_pipe; - if (!pipe || !mfd->panel_power_on) + if (!pipe || !mfd->panel_power_on) { + mutex_unlock(&mfd->dma->ov_mutex); return; + } pr_debug("%s: cpu=%d pid=%d\n", __func__, smp_processor_id(), current->pid); @@ -943,16 +976,16 @@ void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd) mdp4_lcdc_pipe_queue(0, pipe); } - mutex_lock(&mfd->dma->ov_mutex); mdp4_overlay_mdp_perf_upd(mfd, 1); - mdp4_lcdc_pipe_commit(); - mutex_unlock(&mfd->dma->ov_mutex); - - if (pipe->ov_blt_addr) - mdp4_lcdc_wait4ov(0); - else - mdp4_lcdc_wait4dmap(0); + cnt = mdp4_lcdc_pipe_commit(cndx, 0); + if (cnt) { + if (pipe->ov_blt_addr) + mdp4_lcdc_wait4ov(cndx); + else + mdp4_lcdc_wait4dmap(cndx); + } mdp4_overlay_mdp_perf_upd(mfd, 0); + mutex_unlock(&mfd->dma->ov_mutex); } diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c index 717bba9b..2bdbb1fe 100644 --- a/drivers/video/msm/mdp4_overlay_mddi.c +++ b/drivers/video/msm/mdp4_overlay_mddi.c @@ -17,704 +17,1043 @@ #include #include #include -#include #include -#include #include - -#include -#include #include #include - #include +#include +#include +#include #include "mdp.h" #include "msm_fb.h" #include "mdp4.h" -static struct mdp4_overlay_pipe *mddi_pipe; -static struct msm_fb_data_type *mddi_mfd; -static int busy_wait_cnt; +static int mddi_state; -static int vsync_start_y_adjust = 4; +#define TOUT_PERIOD HZ /* 1 second */ +#define MS_100 (HZ/10) /* 100 ms */ -static int dmap_vsync_enable; +static int vsync_start_y_adjust = 4; -void mdp_dmap_vsync_set(int enable) +#define MAX_CONTROLLER 1 +#define VSYNC_EXPIRE_TICK 8 + +static struct vsycn_ctrl { + struct device *dev; + int inited; + int update_ndx; + int expire_tick; + int blt_wait; + u32 ov_koff; + u32 ov_done; + u32 dmap_koff; + u32 dmap_done; + uint32 rdptr_intr_tot; + uint32 rdptr_sirq_tot; + atomic_t suspend; + int wait_vsync_cnt; + int blt_change; + int blt_free; + int blt_end; + int uevent; + struct mutex update_lock; + struct completion ov_comp; + struct completion dmap_comp; + struct completion vsync_comp; + spinlock_t spin_lock; + struct msm_fb_data_type *mfd; + struct mdp4_overlay_pipe *base_pipe; + struct vsync_update vlist[2]; + int vsync_enabled; + int clk_enabled; + int clk_control; + int new_update; + ktime_t vsync_time; + struct work_struct vsync_work; + struct work_struct clk_work; +} vsync_ctrl_db[MAX_CONTROLLER]; + +static void vsync_irq_enable(int intr, int term) { - dmap_vsync_enable = enable; + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + /* no need to clear other interrupts for comamnd mode */ + mdp_intr_mask |= intr; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(term); + spin_unlock_irqrestore(&mdp_spin_lock, flag); } -int mdp_dmap_vsync_get(void) +static void vsync_irq_disable(int intr, int term) { - return dmap_vsync_enable; + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + /* no need to clrear other interrupts for comamnd mode */ + mdp_intr_mask &= ~intr; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_disable_irq_nosync(term); + spin_unlock_irqrestore(&mdp_spin_lock, flag); } -void mdp4_mddi_vsync_enable(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe, int which) +static void mdp4_mddi_blt_ov_update(struct mdp4_overlay_pipe *pipe) { - uint32 start_y, data, tear_en; + uint32 off, addr; + int bpp; + char *overlay_base; - tear_en = (1 << which); + if (pipe->ov_blt_addr == 0) + return; - if ((mfd->use_mdp_vsync) && (mfd->ibuf.vsync_enable) && - (mfd->panel_info.lcd.vsync_enable)) { + bpp = 3; /* overlay ouput is RGB888 */ + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr = pipe->ov_blt_addr + off; + /* overlay 0 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + outpdw(overlay_base + 0x000c, addr); + outpdw(overlay_base + 0x001c, addr); +} - if (mdp_hw_revision < MDP4_REVISION_V2_1) { - /* need dmas dmap switch */ - if (which == 0 && dmap_vsync_enable == 0 && - mfd->panel_info.lcd.rev < 2) /* dma_p */ - return; - } +static void mdp4_mddi_blt_dmap_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr; + int bpp; - if (vsync_start_y_adjust <= pipe->dst_y) - start_y = pipe->dst_y - vsync_start_y_adjust; - else - start_y = (mfd->total_lcd_lines - 1) - - (vsync_start_y_adjust - pipe->dst_y); - if (which == 0) - MDP_OUTP(MDP_BASE + 0x210, start_y); /* primary */ - else - MDP_OUTP(MDP_BASE + 0x214, start_y); /* secondary */ + if (pipe->ov_blt_addr == 0) + return; - data = inpdw(MDP_BASE + 0x20c); - data |= tear_en; - MDP_OUTP(MDP_BASE + 0x20c, data); - } else { - data = inpdw(MDP_BASE + 0x20c); - data &= ~tear_en; - MDP_OUTP(MDP_BASE + 0x20c, data); - } + bpp = 3; /* overlay ouput is RGB888 */ + off = 0; + if (pipe->dmap_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr = pipe->dma_blt_addr + off; + + /* dmap */ + MDP_OUTP(MDP_BASE + 0x90008, addr); } -#define WHOLESCREEN +static void mdp4_mddi_wait4dmap(int cndx); +static void mdp4_mddi_wait4ov(int cndx); -void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd) +static void mdp4_mddi_do_blt(struct msm_fb_data_type *mfd, int enable) { - MDPIBUF *iBuf = &mfd->ibuf; - uint8 *src; - int ptype; - uint32 mddi_ld_param; - uint16 mddi_vdo_packet_reg; + unsigned long flags; + int cndx = 0; + struct vsycn_ctrl *vctrl; struct mdp4_overlay_pipe *pipe; - int ret; + int need_wait; - if (mfd->key != MFD_KEY) - return; + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; - mddi_mfd = mfd; /* keep it */ + mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); - /* MDP cmd block enable */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + if (mfd->ov0_wb_buf->write_addr == 0) { + pr_err("%s: no blt_base assigned\n", __func__); + return; + } - if (mddi_pipe == NULL) { - ptype = mdp4_overlay_format2type(mfd->fb_imgType); - if (ptype < 0) - printk(KERN_INFO "%s: format2type failed\n", __func__); - pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); - if (pipe == NULL) - printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); - pipe->pipe_used++; - pipe->mixer_num = MDP4_MIXER0; - pipe->src_format = mfd->fb_imgType; - mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_MDDI); - ret = mdp4_overlay_format2pipe(pipe); - if (ret < 0) - printk(KERN_INFO "%s: format2type failed\n", __func__); + spin_lock_irqsave(&vctrl->spin_lock, flags); + if (enable && pipe->ov_blt_addr == 0) { + vctrl->blt_change++; + if (vctrl->dmap_koff != vctrl->dmap_done) { + INIT_COMPLETION(vctrl->dmap_comp); + need_wait = 1; + } + } else if (enable == 0 && pipe->ov_blt_addr) { + vctrl->blt_change++; + if (vctrl->ov_koff != vctrl->dmap_done) { + INIT_COMPLETION(vctrl->dmap_comp); + need_wait = 1; + } + } + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + + if (need_wait) + mdp4_mddi_wait4dmap(0); + + spin_lock_irqsave(&vctrl->spin_lock, flags); + if (enable && pipe->ov_blt_addr == 0) { + pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr; + pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr; + pipe->ov_cnt = 0; + pipe->dmap_cnt = 0; + vctrl->ov_koff = vctrl->dmap_koff; + vctrl->ov_done = vctrl->dmap_done; + vctrl->blt_free = 0; + vctrl->blt_wait = 0; + vctrl->blt_end = 0; + mdp4_stat.blt_mddi++; + } else if (enable == 0 && pipe->ov_blt_addr) { + pipe->ov_blt_addr = 0; + pipe->dma_blt_addr = 0; + vctrl->blt_end = 1; + vctrl->blt_free = 4; /* 4 commits to free wb buf */ + } - mddi_pipe = pipe; /* keep it */ - mddi_ld_param = 0; - mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; + pr_debug("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__, + vctrl->blt_change, enable, (int)pipe->ov_blt_addr); - if (mdp_hw_revision == MDP4_REVISION_V2_1) { - uint32 data; + spin_unlock_irqrestore(&vctrl->spin_lock, flags); +} - data = inpdw(MDP_BASE + 0x0028); - data &= ~0x0300; /* bit 8, 9, MASTER4 */ - if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */ - data |= 0x0200; - else - data |= 0x0100; +/* + * mdp4_mddi_do_update: + * called from thread context + */ +void mdp4_mddi_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe) +{ + struct vsycn_ctrl *vctrl; + struct vsync_update *vp; + struct mdp4_overlay_pipe *pp; + int undx; - MDP_OUTP(MDP_BASE + 0x00028, data); - } + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } - if (mfd->panel_info.type == MDDI_PANEL) { - if (mfd->panel_info.pdest == DISPLAY_1) - mddi_ld_param = 0; - else - mddi_ld_param = 1; - } else { - mddi_ld_param = 2; - } + vctrl = &vsync_ctrl_db[cndx]; - MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); + if (atomic_read(&vctrl->suspend) > 0) + return; - if (mfd->panel_info.bpp == 24) - MDP_OUTP(MDP_BASE + 0x00094, - (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg); - else if (mfd->panel_info.bpp == 16) - MDP_OUTP(MDP_BASE + 0x00094, - (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg); - else - MDP_OUTP(MDP_BASE + 0x00094, - (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); + mutex_lock(&vctrl->update_lock); + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; - MDP_OUTP(MDP_BASE + 0x00098, 0x01); - mdp4_init_writeback_buf(mfd, MDP4_MIXER0); - pipe->ov_blt_addr = 0; - pipe->dma_blt_addr = 0; - } else { - pipe = mddi_pipe; - } + pp = &vp->plist[pipe->pipe_ndx - 1]; /* ndx start form 1 */ - /* 0 for dma_p, client_id = 0 */ - MDP_OUTP(MDP_BASE + 0x00090, 0); + pr_debug("%s: vndx=%d pipe_ndx=%d expire=%x pid=%d\n", __func__, + undx, pipe->pipe_ndx, vctrl->expire_tick, current->pid); + *pp = *pipe; /* clone it */ + vp->update_cnt++; - src = (uint8 *) iBuf->buf; + mutex_unlock(&vctrl->update_lock); + mdp4_stat.overlay_play[pipe->mixer_num]++; +} -#ifdef WHOLESCREEN +static void mdp4_mddi_blt_ov_update(struct mdp4_overlay_pipe *pipe); - { - struct fb_info *fbi; +int mdp4_mddi_pipe_commit(void) +{ + int i, undx; + int mixer = 0; + struct vsycn_ctrl *vctrl; + struct vsync_update *vp; + struct mdp4_overlay_pipe *pipe; + struct mdp4_overlay_pipe *real_pipe; + unsigned long flags; + int need_dmap_wait = 0; + int need_ov_wait = 0; + int cnt = 0; + + vctrl = &vsync_ctrl_db[0]; + + mutex_lock(&vctrl->update_lock); + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; + pipe = vctrl->base_pipe; + mixer = pipe->mixer_num; + + if (vp->update_cnt == 0) { + mutex_unlock(&vctrl->update_lock); + return cnt; + } - fbi = mfd->fbi; - pipe->src_height = fbi->var.yres; - pipe->src_width = fbi->var.xres; - pipe->src_h = fbi->var.yres; - pipe->src_w = fbi->var.xres; - pipe->src_y = 0; - pipe->src_x = 0; - pipe->dst_h = fbi->var.yres; - pipe->dst_w = fbi->var.xres; - pipe->dst_y = 0; - pipe->dst_x = 0; - pipe->srcp0_addr = (uint32)src; - pipe->srcp0_ystride = fbi->fix.line_length; + vctrl->update_ndx++; + vctrl->update_ndx &= 0x01; + vp->update_cnt = 0; /* reset */ + if (vctrl->blt_free) { + vctrl->blt_free--; + if (vctrl->blt_free == 0) + mdp4_free_writeback_buf(vctrl->mfd, mixer); } + mutex_unlock(&vctrl->update_lock); + + /* free previous committed iommu back to pool */ + mdp4_overlay_iommu_unmap_freelist(mixer); + + spin_lock_irqsave(&vctrl->spin_lock, flags); + if (pipe->ov_blt_addr) { + /* Blt */ + if (vctrl->blt_wait) + need_dmap_wait = 1; + if (vctrl->ov_koff != vctrl->ov_done) { + INIT_COMPLETION(vctrl->ov_comp); + need_ov_wait = 1; + } + } else { + /* direct out */ + if (vctrl->dmap_koff != vctrl->dmap_done) { + INIT_COMPLETION(vctrl->dmap_comp); + pr_debug("%s: wait, ok=%d od=%d dk=%d dd=%d cpu=%d\n", + __func__, vctrl->ov_koff, vctrl->ov_done, + vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id()); + need_dmap_wait = 1; + } + } + spin_unlock_irqrestore(&vctrl->spin_lock, flags); -#else - if (mdp4_overlay_active(MDP4_MIXER0)) { - struct fb_info *fbi; + if (need_dmap_wait) { + pr_debug("%s: wait4dmap\n", __func__); + mdp4_mddi_wait4dmap(0); + } - fbi = mfd->fbi; - pipe->src_height = fbi->var.yres; - pipe->src_width = fbi->var.xres; - pipe->src_h = fbi->var.yres; - pipe->src_w = fbi->var.xres; - pipe->src_y = 0; - pipe->src_x = 0; - pipe->dst_h = fbi->var.yres; - pipe->dst_w = fbi->var.xres; - pipe->dst_y = 0; - pipe->dst_x = 0; - pipe->srcp0_addr = (uint32) src; - pipe->srcp0_ystride = fbi->fix.line_length; - } else { - /* starting input address */ - src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) - * iBuf->bpp; - - pipe->src_height = iBuf->dma_h; - pipe->src_width = iBuf->dma_w; - pipe->src_h = iBuf->dma_h; - pipe->src_w = iBuf->dma_w; - pipe->src_y = 0; - pipe->src_x = 0; - pipe->dst_h = iBuf->dma_h; - pipe->dst_w = iBuf->dma_w; - pipe->dst_y = iBuf->dma_y; - pipe->dst_x = iBuf->dma_x; - pipe->srcp0_addr = (uint32) src; - pipe->srcp0_ystride = iBuf->ibuf_width * iBuf->bpp; - } -#endif - - pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + if (need_ov_wait) { + pr_debug("%s: wait4ov\n", __func__); + mdp4_mddi_wait4ov(0); + } - mdp4_overlay_rgb_setup(pipe); + if (pipe->ov_blt_addr) { + if (vctrl->blt_end) { + vctrl->blt_end = 0; + pipe->ov_blt_addr = 0; + pipe->dma_blt_addr = 0; + } + } - mdp4_mixer_stage_up(pipe, 1); + if (vctrl->blt_change) { + mdp4_overlayproc_cfg(pipe); + mdp4_overlay_dmap_xy(pipe); + vctrl->blt_change = 0; + } - mdp4_overlayproc_cfg(pipe); + pipe = vp->plist; + for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { + if (pipe->pipe_used) { + cnt++; + real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); + if (real_pipe && real_pipe->pipe_used) { + /* pipe not unset */ + mdp4_overlay_vsync_commit(pipe); + } + /* free previous iommu to freelist + * which will be freed at next + * pipe_commit + */ + mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); + pipe->pipe_used = 0; /* clear */ + } + } - mdp4_overlay_dmap_xy(pipe); + mdp4_mixer_stage_commit(mixer); - mdp4_overlay_dmap_cfg(mfd, 0); - mdp4_mixer_stage_commit(pipe->mixer_num); - mdp4_mddi_vsync_enable(mfd, pipe, 0); + pipe = vctrl->base_pipe; + spin_lock_irqsave(&vctrl->spin_lock, flags); + if (pipe->ov_blt_addr) { + mdp4_mddi_blt_ov_update(pipe); + pipe->ov_cnt++; + vctrl->ov_koff++; + vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); + } else { + vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); + vctrl->dmap_koff++; + } + pr_debug("%s: kickoff\n", __func__); + /* kickoff overlay engine */ + mdp4_stat.kickoff_ov0++; + outpdw(MDP_BASE + 0x0004, 0); + mb(); /* make sure kickoff ececuted */ + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + + mdp4_stat.overlay_commit[pipe->mixer_num]++; - /* MDP cmd block disable */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return cnt; } -int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd) +void mdp4_mddi_vsync_ctrl(struct fb_info *info, int enable) { - unsigned long flag; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct vsycn_ctrl *vctrl; + unsigned long flags; + int clk_set_on = 0; + int cndx = 0; - pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n", - __func__, mddi_pipe->blt_end, - (int)mddi_pipe->ov_blt_addr, current->pid); + vctrl = &vsync_ctrl_db[cndx]; - mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); + pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__, + vctrl->clk_enabled, vctrl->vsync_enabled, enable); - if (mfd->ov0_wb_buf->write_addr == 0) { - pr_info("%s: no blt_base assigned\n", __func__); - return -EBUSY; - } - - if (mddi_pipe->ov_blt_addr == 0) { - mdp4_mddi_dma_busy_wait(mfd); - spin_lock_irqsave(&mdp_spin_lock, flag); - mddi_pipe->blt_end = 0; - mddi_pipe->blt_cnt = 0; - mddi_pipe->ov_cnt = 0; - mddi_pipe->dmap_cnt = 0; - mddi_pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr; - mddi_pipe->dma_blt_addr = mfd->ov0_wb_buf->write_addr; - mdp4_stat.blt_mddi++; - spin_unlock_irqrestore(&mdp_spin_lock, flag); - return 0; -} + mutex_lock(&vctrl->update_lock); - return -EBUSY; + if (vctrl->vsync_enabled == enable) { + mutex_unlock(&vctrl->update_lock); + return; + } + + vctrl->vsync_enabled = enable; + + if (enable) { + if (vctrl->clk_enabled == 0) { + pr_debug("%s: SET_CLK_ON\n", __func__); + mdp_clk_ctrl(1); + vctrl->clk_enabled = 1; + clk_set_on = 1; + } + spin_lock_irqsave(&vctrl->spin_lock, flags); + vctrl->clk_control = 0; + vctrl->expire_tick = 0; + vctrl->uevent = 1; + vctrl->new_update = 1; + if (clk_set_on) { + vsync_irq_enable(INTR_PRIMARY_RDPTR, + MDP_PRIM_RDPTR_TERM); + } + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + + mdp4_overlay_update_mddi(mfd); + } else { + spin_lock_irqsave(&vctrl->spin_lock, flags); + vctrl->clk_control = 1; + vctrl->uevent = 0; + if (vctrl->clk_enabled) + vctrl->expire_tick = VSYNC_EXPIRE_TICK; + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + } + mutex_unlock(&vctrl->update_lock); } -int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd) +void mdp4_mddi_wait4vsync(int cndx, long long *vtime) { - unsigned long flag; + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + unsigned long flags; - pr_debug("%s: blt_end=%d blt_addr=%x\n", - __func__, mddi_pipe->blt_end, (int)mddi_pipe->ov_blt_addr); + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } - if ((mddi_pipe->blt_end == 0) && mddi_pipe->ov_blt_addr) { - spin_lock_irqsave(&mdp_spin_lock, flag); - mddi_pipe->blt_end = 1; /* mark as end */ - spin_unlock_irqrestore(&mdp_spin_lock, flag); - return 0; + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; + + if (atomic_read(&vctrl->suspend) > 0) { + *vtime = -1; + return; } - return -EBUSY; -} + spin_lock_irqsave(&vctrl->spin_lock, flags); + if (vctrl->wait_vsync_cnt == 0) + INIT_COMPLETION(vctrl->vsync_comp); + vctrl->wait_vsync_cnt++; + spin_unlock_irqrestore(&vctrl->spin_lock, flags); -int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd, - struct msmfb_overlay_blt *req) -{ - req->offset = 0; - req->width = mddi_pipe->src_width; - req->height = mddi_pipe->src_height; - req->bpp = mddi_pipe->bpp; + wait_for_completion(&vctrl->vsync_comp); + mdp4_stat.wait4vsync0++; - return sizeof(*req); + *vtime = ktime_to_ns(vctrl->vsync_time); } -void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd, - struct msmfb_overlay_blt *req) +static void mdp4_mddi_wait4dmap(int cndx) { - if (req->enable) - mdp4_mddi_overlay_blt_start(mfd); - else if (req->enable == 0) - mdp4_mddi_overlay_blt_stop(mfd); + struct vsycn_ctrl *vctrl; -} + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } -void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe) -{ - uint32 off, addr, addr2; - int bpp; - char *overlay_base; + vctrl = &vsync_ctrl_db[cndx]; - if (pipe->ov_blt_addr == 0) + if (atomic_read(&vctrl->suspend) > 0) return; + wait_for_completion(&vctrl->dmap_comp); +} -#ifdef BLT_RGB565 - bpp = 2; /* overlay ouput is RGB565 */ -#else - bpp = 3; /* overlay ouput is RGB888 */ -#endif - off = 0; - if (pipe->dmap_cnt & 0x01) - off = pipe->src_height * pipe->src_width * bpp; +static void mdp4_mddi_wait4ov(int cndx) +{ + struct vsycn_ctrl *vctrl; - addr = pipe->ov_blt_addr + off; + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } - /* dmap */ - MDP_OUTP(MDP_BASE + 0x90008, addr); + vctrl = &vsync_ctrl_db[cndx]; - off = 0; - if (pipe->ov_cnt & 0x01) - off = pipe->src_height * pipe->src_width * bpp; - addr2 = pipe->ov_blt_addr + off; - /* overlay 0 */ - overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ - outpdw(overlay_base + 0x000c, addr2); - outpdw(overlay_base + 0x001c, addr2); -} + if (atomic_read(&vctrl->suspend) > 0) + return; -void mdp4_primary_rdptr(void) -{ + wait_for_completion(&vctrl->ov_comp); } /* - * mdp4_dmap_done_mddi: called from isr + * primary_rdptr_isr: + * called from interrupt context */ -void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma) +static void primary_rdptr_isr(int cndx) { - int diff; + struct vsycn_ctrl *vctrl; - mddi_pipe->dmap_cnt++; - diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt; - pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n", - __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt); + vctrl = &vsync_ctrl_db[cndx]; + pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id()); + vctrl->rdptr_intr_tot++; + vctrl->vsync_time = ktime_get(); - if (diff <= 0) { - spin_lock(&mdp_spin_lock); - dma->dmap_busy = FALSE; - complete(&dma->dmap_comp); - spin_unlock(&mdp_spin_lock); - - if (mddi_pipe->blt_end) { - mddi_pipe->blt_end = 0; - mddi_pipe->ov_blt_addr = 0; - mddi_pipe->dma_blt_addr = 0; - pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__, - mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt); - mdp_intr_mask &= ~INTR_DMA_P_DONE; - outp32(MDP_INTR_ENABLE, mdp_intr_mask); - } + spin_lock(&vctrl->spin_lock); - mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); - mdp_disable_irq_nosync(MDP_DMA2_TERM); /* disable intr */ - return; + if (vctrl->uevent) + schedule_work(&vctrl->vsync_work); + + if (vctrl->wait_vsync_cnt) { + complete(&vctrl->vsync_comp); + vctrl->wait_vsync_cnt = 0; } - spin_lock(&mdp_spin_lock); - dma->busy = FALSE; - spin_unlock(&mdp_spin_lock); - complete(&dma->comp); - if (busy_wait_cnt) - busy_wait_cnt--; + if (vctrl->expire_tick) { + vctrl->expire_tick--; + if (vctrl->expire_tick == 0) + schedule_work(&vctrl->clk_work); + } + spin_unlock(&vctrl->spin_lock); +} - pr_debug("%s: kickoff dmap\n", __func__); +void mdp4_dmap_done_mddi(int cndx) +{ + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + int diff; + + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; + + /* blt enabled */ + spin_lock(&vctrl->spin_lock); + vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM); + vctrl->dmap_done++; + diff = vctrl->ov_done - vctrl->dmap_done; + pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n", + __func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff, + vctrl->dmap_done, smp_processor_id()); + complete_all(&vctrl->dmap_comp); + if (diff <= 0) { + if (vctrl->blt_wait) + vctrl->blt_wait = 0; + spin_unlock(&vctrl->spin_lock); + return; + } - mdp4_blt_xy_update(mddi_pipe); - /* kick off dmap */ - outpdw(MDP_BASE + 0x000c, 0x0); + /* kick dmap */ + mdp4_mddi_blt_dmap_update(pipe); + pipe->dmap_cnt++; mdp4_stat.kickoff_dmap++; - mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + vctrl->dmap_koff++; + vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); + outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */ + mb(); /* make sure kickoff executed */ + spin_unlock(&vctrl->spin_lock); } /* * mdp4_overlay0_done_mddi: called from isr */ -void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma) +void mdp4_overlay0_done_mddi(int cndx) { + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; int diff; - if (mddi_pipe->ov_blt_addr == 0) { - mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); - spin_lock(&mdp_spin_lock); - dma->busy = FALSE; - spin_unlock(&mdp_spin_lock); - complete(&dma->comp); + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; - if (busy_wait_cnt) - busy_wait_cnt--; - mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + spin_lock(&vctrl->spin_lock); + vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM); + vctrl->ov_done++; + complete_all(&vctrl->ov_comp); + diff = vctrl->ov_done - vctrl->dmap_done; - return; - } - - /* blt enabled */ - if (mddi_pipe->blt_end == 0) - mddi_pipe->ov_cnt++; - - pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n", - __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt); + pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n", + __func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff, + vctrl->dmap_done, smp_processor_id()); - if (mddi_pipe->blt_cnt == 0) { - /* first kickoff since blt enabled */ - mdp_intr_mask |= INTR_DMA_P_DONE; - outp32(MDP_INTR_ENABLE, mdp_intr_mask); + if (pipe->ov_blt_addr == 0) { + /* blt disabled */ + spin_unlock(&vctrl->spin_lock); + return; } - mddi_pipe->blt_cnt++; - - diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt; - if (diff >= 2) { - mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + if (diff > 1) { + /* + * two overlay_done and none dmap_done yet + * let dmap_done kickoff dmap + * and put pipe_commit to wait + */ + vctrl->blt_wait = 1; + pr_debug("%s: blt_wait set\n", __func__); + spin_unlock(&vctrl->spin_lock); return; } + mdp4_mddi_blt_dmap_update(pipe); + pipe->dmap_cnt++; + mdp4_stat.kickoff_dmap++; + vctrl->dmap_koff++; + vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM); + outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */ + mb(); /* make sure kickoff executed */ + spin_unlock(&vctrl->spin_lock); +} - spin_lock(&mdp_spin_lock); - dma->busy = FALSE; - dma->dmap_busy = TRUE; - spin_unlock(&mdp_spin_lock); - complete(&dma->comp); - - if (busy_wait_cnt) - busy_wait_cnt--; - - pr_debug("%s: kickoff dmap\n", __func__); +static void clk_ctrl_work(struct work_struct *work) +{ + struct vsycn_ctrl *vctrl = + container_of(work, typeof(*vctrl), clk_work); + unsigned long flags; + + mutex_lock(&vctrl->update_lock); + if (vctrl->clk_control && vctrl->clk_enabled) { + pr_debug("%s: SET_CLK_OFF\n", __func__); + mdp_clk_ctrl(0); + spin_lock_irqsave(&vctrl->spin_lock, flags); + vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM); + vctrl->clk_enabled = 0; + vctrl->clk_control = 0; + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + } + mutex_unlock(&vctrl->update_lock); +} - mdp4_blt_xy_update(mddi_pipe); - mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */ - /* kick off dmap */ - outpdw(MDP_BASE + 0x000c, 0x0); - mdp4_stat.kickoff_dmap++; - mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); +static void send_vsync_work(struct work_struct *work) +{ + struct vsycn_ctrl *vctrl = + container_of(work, typeof(*vctrl), vsync_work); + char buf[64]; + char *envp[2]; + + snprintf(buf, sizeof(buf), "VSYNC=%llu", + ktime_to_ns(vctrl->vsync_time)); + envp[0] = buf; + envp[1] = NULL; + kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp); } -void mdp4_mddi_overlay_restore(void) + +void mdp4_mddi_rdptr_init(int cndx) { - if (mddi_mfd == NULL) - return; + struct vsycn_ctrl *vctrl; - pr_debug("%s: resotre, pid=%d\n", __func__, current->pid); + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } - if (mddi_mfd->panel_power_on == 0) + vctrl = &vsync_ctrl_db[cndx]; + if (vctrl->inited) return; - if (mddi_mfd && mddi_pipe) { - mdp4_mddi_dma_busy_wait(mddi_mfd); - mdp4_overlay_update_lcd(mddi_mfd); - if (mddi_pipe->ov_blt_addr) - mdp4_mddi_blt_dmap_busy_wait(mddi_mfd); - mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe); - mddi_mfd->dma_update_flag = 1; - } - if (mdp_hw_revision < MDP4_REVISION_V2_1) /* need dmas dmap switch */ - mdp4_mddi_overlay_dmas_restore(); + vctrl->inited = 1; + vctrl->update_ndx = 0; + mutex_init(&vctrl->update_lock); + init_completion(&vctrl->ov_comp); + init_completion(&vctrl->dmap_comp); + init_completion(&vctrl->vsync_comp); + spin_lock_init(&vctrl->spin_lock); + INIT_WORK(&vctrl->vsync_work, send_vsync_work); + INIT_WORK(&vctrl->clk_work, clk_ctrl_work); } -void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd) +void mdp4_primary_rdptr(void) { - unsigned long flag; - int need_wait = 0; - - spin_lock_irqsave(&mdp_spin_lock, flag); - if (mfd->dma->dmap_busy == TRUE) { - INIT_COMPLETION(mfd->dma->dmap_comp); - need_wait++; - } - spin_unlock_irqrestore(&mdp_spin_lock, flag); - - if (need_wait) { - /* wait until DMA finishes the current job */ - wait_for_completion(&mfd->dma->dmap_comp); - } + primary_rdptr_isr(0); } -/* - * mdp4_mddi_cmd_dma_busy_wait: check mddi link activity - * mddi link is a shared resource and it can only be used - * while it is in idle state. - * ov_mutex need to be acquired before call this function. - */ -void mdp4_mddi_dma_busy_wait(struct msm_fb_data_type *mfd) +void mdp4_overlay_mddi_state_set(int state) { unsigned long flag; - int need_wait = 0; - pr_debug("%s: START, pid=%d\n", __func__, current->pid); spin_lock_irqsave(&mdp_spin_lock, flag); - if (mfd->dma->busy == TRUE) { - if (busy_wait_cnt == 0) - INIT_COMPLETION(mfd->dma->comp); - busy_wait_cnt++; - need_wait++; - } + mddi_state = state; spin_unlock_irqrestore(&mdp_spin_lock, flag); +} - - if (need_wait) { - /* wait until DMA finishes the current job */ - pr_debug("%s: PENDING, pid=%d\n", __func__, current->pid); - wait_for_completion(&mfd->dma->comp); - } - pr_debug("%s: DONE, pid=%d\n", __func__, current->pid); +int mdp4_overlay_mddi_state_get(void) +{ + return mddi_state; } -void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) +static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp) { /* - * a video kickoff may happen before UI kickoff after - * blt enabled. mdp4_overlay_update_lcd() need - * to be called before kickoff. - * vice versa for blt disabled. + * The adreno GPU hardware requires that the pitch be aligned to + * 32 pixels for color buffers, so for the cases where the GPU + * is writing directly to fb0, the framebuffer pitch + * also needs to be 32 pixel aligned */ - if (mddi_pipe->ov_blt_addr && mddi_pipe->blt_cnt == 0) - mdp4_overlay_update_lcd(mfd); /* first time */ - else if (mddi_pipe->ov_blt_addr == 0 && mddi_pipe->blt_cnt) { - mdp4_overlay_update_lcd(mfd); /* last time */ - mddi_pipe->blt_cnt = 0; - } - pr_debug("%s: blt_addr=%d blt_cnt=%d\n", - __func__, (int)mddi_pipe->ov_blt_addr, mddi_pipe->blt_cnt); - - if (mddi_pipe->ov_blt_addr) - mdp4_mddi_blt_dmap_busy_wait(mddi_mfd); - mdp4_mddi_overlay_kickoff(mfd, pipe); + if (fb_index == 0) + return ALIGN(xres, 32) * bpp; + else + return xres * bpp; } -void mdp4_mddi_kickoff_ui(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) +void mdp4_mddi_vsync_enable(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe, int which) { - pr_debug("%s: pid=%d\n", __func__, current->pid); - mdp4_mddi_overlay_kickoff(mfd, pipe); -} + uint32 start_y, data, tear_en; + tear_en = (1 << which); + + if ((mfd->use_mdp_vsync) && (mfd->ibuf.vsync_enable) && + (mfd->panel_info.lcd.vsync_enable)) { + + if (vsync_start_y_adjust <= pipe->dst_y) + start_y = pipe->dst_y - vsync_start_y_adjust; + else + start_y = (mfd->total_lcd_lines - 1) - + (vsync_start_y_adjust - pipe->dst_y); + if (which == 0) + MDP_OUTP(MDP_BASE + 0x210, start_y); /* primary */ + else + MDP_OUTP(MDP_BASE + 0x214, start_y); /* secondary */ -void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) + data = inpdw(MDP_BASE + 0x20c); + data |= tear_en; + MDP_OUTP(MDP_BASE + 0x20c, data); + } else { + data = inpdw(MDP_BASE + 0x20c); + data &= ~tear_en; + MDP_OUTP(MDP_BASE + 0x20c, data); + } +} + +void mdp4_mddi_base_swap(int cndx, struct mdp4_overlay_pipe *pipe) { - unsigned long flag; + struct vsycn_ctrl *vctrl; - mdp_enable_irq(MDP_OVERLAY0_TERM); - spin_lock_irqsave(&mdp_spin_lock, flag); - mfd->dma->busy = TRUE; - if (mddi_pipe->ov_blt_addr) - mfd->dma->dmap_busy = TRUE; - spin_unlock_irqrestore(&mdp_spin_lock, flag); - /* start OVERLAY pipe */ - mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd); - mdp4_stat.kickoff_ov0++; + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } + + vctrl = &vsync_ctrl_db[cndx]; + vctrl->base_pipe = pipe; } -void mdp4_dma_s_update_lcd(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) +static void mdp4_overlay_setup_pipe_addr(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) { MDPIBUF *iBuf = &mfd->ibuf; - uint32 outBpp = iBuf->bpp; + struct fb_info *fbi; + int bpp; + uint8 *src; + + /* whole screen for base layer */ + src = (uint8 *) iBuf->buf; + fbi = mfd->fbi; + + if (pipe->is_3d) { + bpp = fbi->var.bits_per_pixel / 8; + pipe->src_height = pipe->src_height_3d; + pipe->src_width = pipe->src_width_3d; + pipe->src_h = pipe->src_height_3d; + pipe->src_w = pipe->src_width_3d; + pipe->dst_h = pipe->src_height_3d; + pipe->dst_w = pipe->src_width_3d; + pipe->srcp0_ystride = msm_fb_line_length(0, + pipe->src_width, bpp); + } else { + /* 2D */ + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->srcp0_ystride = fbi->fix.line_length; + } + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_y = 0; + pipe->dst_x = 0; + pipe->srcp0_addr = (uint32)src; +} + +void mdp4_overlay_update_mddi(struct msm_fb_data_type *mfd) +{ + int ptype; + uint32 mddi_ld_param; uint16 mddi_vdo_packet_reg; - uint32 dma_s_cfg_reg; + struct mdp4_overlay_pipe *pipe; + uint32 data; + int ret; + int cndx = 0; + struct vsycn_ctrl *vctrl; - dma_s_cfg_reg = 0; + if (mfd->key != MFD_KEY) + return; - if (mfd->fb_imgType == MDP_RGBA_8888) - dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; /* on purpose */ - else if (mfd->fb_imgType == MDP_BGR_565) - dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; - else - dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB; - - if (outBpp == 4) - dma_s_cfg_reg |= (1 << 26); /* xRGB8888 */ - else if (outBpp == 2) - dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565; - - dma_s_cfg_reg |= DMA_DITHER_EN; - - /* MDP cmd block enable */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - /* PIXELSIZE */ - MDP_OUTP(MDP_BASE + 0xa0004, (pipe->dst_h << 16 | pipe->dst_w)); - MDP_OUTP(MDP_BASE + 0xa0008, pipe->srcp0_addr); /* ibuf address */ - MDP_OUTP(MDP_BASE + 0xa000c, pipe->srcp0_ystride);/* ystride */ - - if (mfd->panel_info.bpp == 24) { - dma_s_cfg_reg |= DMA_DSTC0G_8BITS | /* 666 18BPP */ - DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; - } else if (mfd->panel_info.bpp == 18) { - dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ - DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + vctrl = &vsync_ctrl_db[cndx]; + + if (vctrl->base_pipe == NULL) { + ptype = mdp4_overlay_format2type(mfd->fb_imgType); + + if (ptype < 0) + pr_err("%s: format2type failed\n", __func__); + + pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); + if (pipe == NULL) { + pr_err("%s: pipe_alloc failed\n", __func__); + return; + } + pipe->pipe_used++; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER0; + pipe->src_format = mfd->fb_imgType; + mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_MDDI); + ret = mdp4_overlay_format2pipe(pipe); + if (ret < 0) + pr_err("%s: format2type failed\n", __func__); + + vctrl->base_pipe = pipe; /* keep it */ + mdp4_init_writeback_buf(mfd, MDP4_MIXER0); + pipe->ov_blt_addr = 0; + pipe->dma_blt_addr = 0; } else { - dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ - DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + pipe = vctrl->base_pipe; } - MDP_OUTP(MDP_BASE + 0xa0010, (pipe->dst_y << 16) | pipe->dst_x); - - /* 1 for dma_s, client_id = 0 */ - MDP_OUTP(MDP_BASE + 0x00090, 1); + MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */ + mddi_ld_param = 0; mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; + if (mdp_hw_revision == MDP4_REVISION_V2_1) { + data = inpdw(MDP_BASE + 0x0028); + data &= ~0x0300; /* bit 8, 9, MASTER4 */ + if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */ + data |= 0x0200; + else + data |= 0x0100; + + MDP_OUTP(MDP_BASE + 0x00028, data); + } + + if (mfd->panel_info.type == MDDI_PANEL) { + if (mfd->panel_info.pdest == DISPLAY_1) + mddi_ld_param = 0; + else + mddi_ld_param = 1; + } else { + mddi_ld_param = 2; + } + + MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); + if (mfd->panel_info.bpp == 24) MDP_OUTP(MDP_BASE + 0x00094, - (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg); + (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg); else if (mfd->panel_info.bpp == 16) MDP_OUTP(MDP_BASE + 0x00094, - (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg); + (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg); else MDP_OUTP(MDP_BASE + 0x00094, - (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); + (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); + + MDP_OUTP(MDP_BASE + 0x00098, 0x01); + + + mdp4_overlay_setup_pipe_addr(mfd, pipe); + + mdp4_overlay_rgb_setup(pipe); + + mdp4_overlay_reg_flush(pipe, 1); + + mdp4_mixer_stage_up(pipe, 0); + + mdp4_overlayproc_cfg(pipe); + + mdp4_overlay_dmap_xy(pipe); + + mdp4_overlay_dmap_cfg(mfd, 0); + + mdp4_mixer_stage_commit(pipe->mixer_num); + + wmb(); +} + +void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd) +{ + mdp4_mddi_do_blt(mfd, 1); +} + +void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd) +{ + mdp4_mddi_do_blt(mfd, 0); +} + +void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + mdp4_mddi_do_blt(mfd, req->enable); +} + +int mdp4_mddi_on(struct platform_device *pdev) +{ + int ret = 0; + int cndx = 0; + struct msm_fb_data_type *mfd; + struct vsycn_ctrl *vctrl; + + pr_debug("%s+:\n", __func__); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + vctrl = &vsync_ctrl_db[cndx]; + vctrl->mfd = mfd; + vctrl->dev = mfd->fbi->dev; - MDP_OUTP(MDP_BASE + 0x00098, 0x01); + mdp_clk_ctrl(1); + mdp4_overlay_update_mddi(mfd); + mdp_clk_ctrl(0); - MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg); + mdp4_iommu_attach(); - mdp4_mddi_vsync_enable(mfd, pipe, 1); + atomic_set(&vctrl->suspend, 0); + pr_debug("%s-:\n", __func__); - /* MDP cmd block disable */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return ret; } -void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) +int mdp4_mddi_off(struct platform_device *pdev) { - mdp_enable_irq(MDP_DMA_S_TERM); + int ret = 0; + int cndx = 0; + struct msm_fb_data_type *mfd; + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + + pr_debug("%s+:\n", __func__); - if (mddi_pipe->ov_blt_addr == 0) - mfd->dma->busy = TRUE; + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); - mfd->ibuf_flushed = TRUE; - /* start dma_s pipe */ - mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd); - mdp4_stat.kickoff_dmas++; + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; + if (pipe == NULL) { + pr_err("%s: NO base pipe\n", __func__); + return ret; + } - /* wait until DMA finishes the current job */ - wait_for_completion(&mfd->dma->comp); - mdp_disable_irq(MDP_DMA_S_TERM); + atomic_set(&vctrl->suspend, 1); + + /* sanity check, free pipes besides base layer */ + mdp4_overlay_unset_mixer(pipe->mixer_num); + mdp4_mixer_stage_down(pipe, 1); + mdp4_overlay_pipe_free(pipe); + vctrl->base_pipe = NULL; + + if (vctrl->clk_enabled) { + /* + * in case of suspend, vsycn_ctrl off is not + * received from frame work which left clock on + * then, clock need to be turned off here + */ + mdp_clk_ctrl(0); + } + + vctrl->clk_enabled = 0; + vctrl->vsync_enabled = 0; + vctrl->clk_control = 0; + vctrl->expire_tick = 0; + vctrl->uevent = 0; + + vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM); + + pr_debug("%s-:\n", __func__); + + /* + * footswitch off + * this will casue all mdp register + * to be reset to default + * after footswitch on later + */ + + return ret; } -void mdp4_mddi_overlay_dmas_restore(void) +void mdp_mddi_overlay_suspend(struct msm_fb_data_type *mfd) { - /* mutex held by caller */ - if (mddi_mfd && mddi_pipe) { - mdp4_mddi_dma_busy_wait(mddi_mfd); - mdp4_dma_s_update_lcd(mddi_mfd, mddi_pipe); - mdp4_mddi_dma_s_kickoff(mddi_mfd, mddi_pipe); - mddi_mfd->dma_update_flag = 1; + int cndx = 0; + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; + /* dis-engage rgb0 from mixer0 */ + if (pipe) { + if (mfd->ref_cnt == 0) { + /* adb stop */ + if (pipe->pipe_type == OVERLAY_TYPE_BF) + mdp4_overlay_borderfill_stage_down(pipe); + + /* pipe == rgb1 */ + mdp4_overlay_unset_mixer(pipe->mixer_num); + vctrl->base_pipe = NULL; + } else { + mdp4_mixer_stage_down(pipe, 1); + mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 1); + } } } void mdp4_mddi_overlay(struct msm_fb_data_type *mfd) { - mutex_lock(&mfd->dma->ov_mutex); + int cndx = 0; + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + unsigned long flags; + long long xx; - if (mfd && mfd->panel_power_on) { - mdp4_mddi_dma_busy_wait(mfd); - - if (mddi_pipe && mddi_pipe->ov_blt_addr) - mdp4_mddi_blt_dmap_busy_wait(mfd); - mdp4_overlay_mdp_perf_upd(mfd, 0); - mdp4_overlay_update_lcd(mfd); - - mdp4_overlay_mdp_perf_upd(mfd, 1); - if (mdp_hw_revision < MDP4_REVISION_V2_1) { - /* dmas dmap switch */ - if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num) - == 0) { - mdp4_dma_s_update_lcd(mfd, mddi_pipe); - mdp4_mddi_dma_s_kickoff(mfd, mddi_pipe); - } else - mdp4_mddi_kickoff_ui(mfd, mddi_pipe); - } else /* no dams dmap switch */ - mdp4_mddi_kickoff_ui(mfd, mddi_pipe); - - /* signal if pan function is waiting for the update completion */ - if (mfd->pan_waiting) { - mfd->pan_waiting = FALSE; - complete(&mfd->pan_comp); - } + vctrl = &vsync_ctrl_db[cndx]; + + if (!mfd->panel_power_on) + return; + + pipe = vctrl->base_pipe; + if (pipe == NULL) { + pr_err("%s: NO base pipe\n", __func__); + return; + } + + mutex_lock(&vctrl->update_lock); + if (!vctrl->clk_enabled) { + pr_err("%s: mdp clocks disabled\n", __func__); + mutex_unlock(&vctrl->update_lock); + return; + + } + mutex_unlock(&vctrl->update_lock); + + spin_lock_irqsave(&vctrl->spin_lock, flags); + if (vctrl->expire_tick) { + /* + * in the middle of shutting clocks down + * delay to allow pan display to go through + */ + vctrl->expire_tick = VSYNC_EXPIRE_TICK; } + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + + if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) { + mdp4_mddi_vsync_enable(mfd, pipe, 0); + mdp4_overlay_setup_pipe_addr(mfd, pipe); + mdp4_mddi_pipe_queue(0, pipe); + } + + mdp4_overlay_mdp_perf_upd(mfd, 1); + + mutex_lock(&mfd->dma->ov_mutex); + mdp4_mddi_pipe_commit(); mutex_unlock(&mfd->dma->ov_mutex); + mdp4_mddi_wait4vsync(0, &xx); + + mdp4_overlay_mdp_perf_upd(mfd, 0); } int mdp4_mddi_overlay_cursor(struct fb_info *info, struct fb_cursor *cursor) @@ -722,7 +1061,6 @@ int mdp4_mddi_overlay_cursor(struct fb_info *info, struct fb_cursor *cursor) struct msm_fb_data_type *mfd = info->par; mutex_lock(&mfd->dma->ov_mutex); if (mfd && mfd->panel_power_on) { - mdp4_mddi_dma_busy_wait(mfd); mdp_hw_cursor_update(info, cursor); } mutex_unlock(&mfd->dma->ov_mutex); diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c index 43e8f568..93f0afea 100644 --- a/drivers/video/msm/mdp4_overlay_writeback.c +++ b/drivers/video/msm/mdp4_overlay_writeback.c @@ -45,9 +45,54 @@ enum { WITH_CLIENT }; -static struct mdp4_overlay_pipe *writeback_pipe; -static struct msm_fb_data_type *writeback_mfd; -static int busy_wait_cnt; +#define MAX_CONTROLLER 1 +#define VSYNC_EXPIRE_TICK 0 + +static struct vsycn_ctrl { + struct device *dev; + int inited; + int update_ndx; + u32 ov_koff; + u32 ov_done; + atomic_t suspend; + struct mutex update_lock; + struct completion ov_comp; + spinlock_t spin_lock; + struct msm_fb_data_type *mfd; + struct mdp4_overlay_pipe *base_pipe; + struct vsync_update vlist[2]; + struct work_struct clk_work; +} vsync_ctrl_db[MAX_CONTROLLER]; + +static void vsync_irq_enable(int intr, int term) +{ + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + /* no need to clrear other interrupts for comamnd mode */ + mdp_intr_mask |= intr; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(term); + spin_unlock_irqrestore(&mdp_spin_lock, flag); +} + +static void vsync_irq_disable(int intr, int term) +{ + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + /* no need to clrear other interrupts for comamnd mode */ + mdp_intr_mask &= ~intr; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_disable_irq_nosync(term); + spin_unlock_irqrestore(&mdp_spin_lock, flag); +} + +static int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd); +static void mdp4_wfd_queue_wakeup(struct msm_fb_data_type *mfd, + struct msmfb_writeback_data_list *node); +static void mdp4_wfd_dequeue_update(struct msm_fb_data_type *mfd, + struct msmfb_writeback_data_list **wfdnode); int mdp4_overlay_writeback_on(struct platform_device *pdev) { @@ -58,6 +103,8 @@ int mdp4_overlay_writeback_on(struct platform_device *pdev) int bpp; int ret; uint32 data; + struct vsycn_ctrl *vctrl; + int cndx = 0; mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); @@ -67,7 +114,9 @@ int mdp4_overlay_writeback_on(struct platform_device *pdev) if (mfd->key != MFD_KEY) return -EINVAL; - writeback_mfd = mfd; /* keep it */ + vctrl = &vsync_ctrl_db[cndx]; + vctrl->mfd = mfd; + vctrl->dev = mfd->fbi->dev; fbi = mfd->fbi; @@ -77,12 +126,14 @@ int mdp4_overlay_writeback_on(struct platform_device *pdev) fbi->var.yoffset * fbi->fix.line_length; /* MDP cmd block enable */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); - if (writeback_pipe == NULL) { + if (vctrl->base_pipe == NULL) { pipe = mdp4_overlay_pipe_alloc(OVERLAY_TYPE_BF, MDP4_MIXER2); - if (pipe == NULL) + if (pipe == NULL) { pr_info("%s: pipe_alloc failed\n", __func__); + return -EIO; + } pipe->pipe_used++; pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; pipe->mixer_num = MDP4_MIXER2; @@ -92,11 +143,12 @@ int mdp4_overlay_writeback_on(struct platform_device *pdev) if (ret < 0) pr_info("%s: format2type failed\n", __func__); - writeback_pipe = pipe; /* keep it */ + vctrl->base_pipe = pipe; /* keep it */ } else { - pipe = writeback_pipe; + pipe = vctrl->base_pipe; } + ret = panel_next_on(pdev); /* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */ @@ -113,46 +165,80 @@ int mdp4_overlay_writeback_on(struct platform_device *pdev) MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008, (0x0 & 0xFFF)); /* 12-bit R */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_clk_ctrl(0); return ret; } int mdp4_overlay_writeback_off(struct platform_device *pdev) { - int ret; - struct msm_fb_data_type *mfd = - (struct msm_fb_data_type *)platform_get_drvdata(pdev); - if (mfd && writeback_pipe) { - mdp4_writeback_dma_busy_wait(mfd); - mdp4_overlay_pipe_free(writeback_pipe); - mdp4_overlay_panel_mode_unset(writeback_pipe->mixer_num, - MDP4_PANEL_WRITEBACK); - writeback_pipe = NULL; + int cndx = 0; + struct msm_fb_data_type *mfd; + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + int ret = 0; + int undx; + struct vsync_update *vp; + + pr_debug("%s+:\n", __func__); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; + if (pipe == NULL) { + pr_err("%s: NO base pipe\n", __func__); + return ret; + } + + /* sanity check, free pipes besides base layer */ + mdp4_overlay_unset_mixer(pipe->mixer_num); + mdp4_mixer_stage_down(pipe, 1); + mdp4_overlay_pipe_free(pipe); + vctrl->base_pipe = NULL; + + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; + if (vp->update_cnt) { + /* + * pipe's iommu will be freed at next overlay play + * and iommu_drop statistic will be increased by one + */ + vp->update_cnt = 0; /* empty queue */ } + ret = panel_next_off(pdev); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp_clk_ctrl(1); /* MDP_LAYERMIXER_WB_MUX_SEL to restore to default cfg*/ outpdw(MDP_BASE + 0x100F4, 0x0); - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_clk_ctrl(0); + pr_debug("%s-:\n", __func__); return ret; } -int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd) + +static int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd) { struct fb_info *fbi; uint8 *buf; unsigned int buf_offset; struct mdp4_overlay_pipe *pipe; int bpp; + int cndx = 0; + struct vsycn_ctrl *vctrl; if (mfd->key != MFD_KEY) return -ENODEV; - if (!writeback_pipe) - return -EINVAL; fbi = mfd->fbi; - pipe = writeback_pipe; + vctrl = &vsync_ctrl_db[cndx]; + + pipe = vctrl->base_pipe; + if (!pipe) { + pr_err("%s: no base layer pipe\n", __func__); + return -EINVAL; + } bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; @@ -160,7 +246,7 @@ int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd) fbi->var.yoffset * fbi->fix.line_length; /* MDP cmd block enable */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_clk_ctrl(1); pipe->src_height = fbi->var.yres; pipe->src_width = fbi->var.xres; @@ -175,6 +261,7 @@ int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd) pipe->dst_x = 0; mdp4_overlay_mdp_pipe_req(pipe, mfd); + mdp4_calc_blt_mdp_bw(mfd, pipe); if (mfd->display_iova) pipe->srcp0_addr = mfd->display_iova + buf_offset; @@ -184,208 +271,229 @@ int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd) mdp4_mixer_stage_up(pipe, 0); mdp4_overlayproc_cfg(pipe); - mdp4_mixer_stage_commit(pipe->mixer_num); + + if (hdmi_prim_display) + outpdw(MDP_BASE + 0x100F4, 0x01); + else + outpdw(MDP_BASE + 0x100F4, 0x02); + /* MDP cmd block disable */ - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_clk_ctrl(0); wmb(); return 0; } -void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd) + +/* + * mdp4_wfd_piep_queue: + * called from thread context + */ +void mdp4_wfd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe) { - unsigned long flag; - int need_wait = 0; + struct vsycn_ctrl *vctrl; + struct vsync_update *vp; + struct mdp4_overlay_pipe *pp; + int undx; - spin_lock_irqsave(&mdp_spin_lock, flag); - if (mfd->dma->busy == TRUE) { - if (busy_wait_cnt == 0) - INIT_COMPLETION(mfd->dma->comp); - busy_wait_cnt = 1; - need_wait++; + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; } - spin_unlock_irqrestore(&mdp_spin_lock, flag); - if (need_wait) { - /* wait until DMA finishes the current job */ - pr_debug("%s: pending pid=%d\n", - __func__, current->pid); - wait_for_completion(&mfd->dma->comp); - } -} + vctrl = &vsync_ctrl_db[cndx]; -void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma) -{ - spin_lock(&mdp_spin_lock); - dma->busy = FALSE; - if (busy_wait_cnt) - busy_wait_cnt = 0; - mdp_disable_irq_nosync(MDP_OVERLAY2_TERM); - spin_unlock(&mdp_spin_lock); - complete_all(&dma->comp); - pr_debug("%s ovdone interrupt\n", __func__); + if (atomic_read(&vctrl->suspend) > 0) + return; -} -void mdp4_writeback_overlay_kickoff(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) -{ - unsigned long flag; - spin_lock_irqsave(&mdp_spin_lock, flag); - mdp_enable_irq(MDP_OVERLAY2_TERM); + mutex_lock(&vctrl->update_lock); + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; - mfd->dma->busy = TRUE; - outp32(MDP_INTR_CLEAR, INTR_OVERLAY2_DONE); - mdp_intr_mask |= INTR_OVERLAY2_DONE; - outp32(MDP_INTR_ENABLE, mdp_intr_mask); + pp = &vp->plist[pipe->pipe_ndx - 1]; /* ndx start form 1 */ - wmb(); /* make sure all registers updated */ - spin_unlock_irqrestore(&mdp_spin_lock, flag); - /* start OVERLAY pipe */ - mdp_pipe_kickoff(MDP_OVERLAY2_TERM, mfd); - wmb(); - pr_debug("%s: before ov done interrupt\n", __func__); -} -void mdp4_writeback_dma_stop(struct msm_fb_data_type *mfd) -{ - /* mutex holded by caller */ - if (mfd && writeback_pipe) { - mdp4_writeback_dma_busy_wait(mfd); - mdp4_overlay_writeback_update(mfd); + pr_debug("%s: vndx=%d pipe_ndx=%d pid=%d\n", __func__, + undx, pipe->pipe_ndx, current->pid); - mdp4_writeback_overlay_kickoff(mfd, writeback_pipe); - } + *pp = *pipe; /* clone it */ + vp->update_cnt++; + + mutex_unlock(&vctrl->update_lock); + mdp4_stat.overlay_play[pipe->mixer_num]++; } -void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) +static void mdp4_wfd_wait4ov(int cndx); + +int mdp4_wfd_pipe_commit(struct msm_fb_data_type *mfd, + int cndx, int wait) { + int i, undx; + int mixer = 0; + struct vsycn_ctrl *vctrl; + struct vsync_update *vp; + struct mdp4_overlay_pipe *pipe; + struct mdp4_overlay_pipe *real_pipe; + unsigned long flags; + int cnt = 0; struct msmfb_writeback_data_list *node = NULL; - mutex_lock(&mfd->unregister_mutex); - mutex_lock(&mfd->writeback_mutex); - if (!list_empty(&mfd->writeback_free_queue) - && mfd->writeback_state != WB_STOPING - && mfd->writeback_state != WB_STOP) { - node = list_first_entry(&mfd->writeback_free_queue, - struct msmfb_writeback_data_list, active_entry); + + vctrl = &vsync_ctrl_db[cndx]; + + mutex_lock(&vctrl->update_lock); + undx = vctrl->update_ndx; + vp = &vctrl->vlist[undx]; + pipe = vctrl->base_pipe; + mixer = pipe->mixer_num; + + if (vp->update_cnt == 0) { + mutex_unlock(&vctrl->update_lock); + return cnt; } - if (node) { - list_del(&(node->active_entry)); - node->state = IN_BUSY_QUEUE; - mfd->writeback_active_cnt++; + + vctrl->update_ndx++; + vctrl->update_ndx &= 0x01; + vp->update_cnt = 0; /* reset */ + mutex_unlock(&vctrl->update_lock); + + mdp4_wfd_dequeue_update(mfd, &node); + + /* free previous committed iommu back to pool */ + mdp4_overlay_iommu_unmap_freelist(mixer); + + pipe = vp->plist; + for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) { + if (pipe->pipe_used) { + cnt++; + real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx); + if (real_pipe && real_pipe->pipe_used) { + /* pipe not unset */ + mdp4_overlay_vsync_commit(pipe); + } + /* free previous iommu to freelist + * which will be freed at next + * pipe_commit + */ + mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); + pipe->pipe_used = 0; /* clear */ + } } - mutex_unlock(&mfd->writeback_mutex); - writeback_pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL); + mdp_clk_ctrl(1); - /* free previous iommu at freelist back to pool */ - mdp4_overlay_iommu_unmap_freelist(writeback_pipe->mixer_num); + mdp4_mixer_stage_commit(mixer); - if (!writeback_pipe->ov_blt_addr) { - pr_err("%s: no writeback buffer 0x%x, %p\n", __func__, - (unsigned int)writeback_pipe->ov_blt_addr, node); - mutex_unlock(&mfd->unregister_mutex); + pipe = vctrl->base_pipe; + spin_lock_irqsave(&vctrl->spin_lock, flags); + vctrl->ov_koff++; + INIT_COMPLETION(vctrl->ov_comp); + vsync_irq_enable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM); + pr_debug("%s: kickoff\n", __func__); + /* kickoff overlay engine */ + mdp4_stat.kickoff_ov2++; + outpdw(MDP_BASE + 0x00D0, 0); + mb(); /* make sure kickoff executed */ + spin_unlock_irqrestore(&vctrl->spin_lock, flags); + + mdp4_stat.overlay_commit[pipe->mixer_num]++; + + if (wait) + mdp4_wfd_wait4ov(cndx); + + mdp4_wfd_queue_wakeup(mfd, node); + + return cnt; +} + +static void clk_ctrl_work(struct work_struct *work) +{ + struct vsycn_ctrl *vctrl = + container_of(work, typeof(*vctrl), clk_work); + mdp_clk_ctrl(0); +} + +void mdp4_wfd_init(int cndx) +{ + struct vsycn_ctrl *vctrl; + + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); return; } - if (writeback_pipe->blt_cnt == 0) - mdp4_overlay_writeback_update(mfd); + vctrl = &vsync_ctrl_db[cndx]; + if (vctrl->inited) + return; - pr_debug("%s: pid=%d\n", __func__, current->pid); + vctrl->inited = 1; + vctrl->update_ndx = 0; + mutex_init(&vctrl->update_lock); + init_completion(&vctrl->ov_comp); + spin_lock_init(&vctrl->spin_lock); + INIT_WORK(&vctrl->clk_work, clk_ctrl_work); +} - mdp4_mixer_stage_commit(pipe->mixer_num); +static void mdp4_wfd_wait4ov(int cndx) +{ + struct vsycn_ctrl *vctrl; - mdp4_writeback_overlay_kickoff(mfd, pipe); - mdp4_writeback_dma_busy_wait(mfd); + if (cndx >= MAX_CONTROLLER) { + pr_err("%s: out or range: cndx=%d\n", __func__, cndx); + return; + } - /* move current committed iommu to freelist */ - mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0); + vctrl = &vsync_ctrl_db[cndx]; - mutex_lock(&mfd->writeback_mutex); - list_add_tail(&node->active_entry, &mfd->writeback_busy_queue); - mutex_unlock(&mfd->writeback_mutex); - mfd->writeback_active_cnt--; - mutex_unlock(&mfd->unregister_mutex); - wake_up(&mfd->wait_q); + if (atomic_read(&vctrl->suspend) > 0) + return; + + wait_for_completion(&vctrl->ov_comp); } -void mdp4_writeback_kickoff_ui(struct msm_fb_data_type *mfd, - struct mdp4_overlay_pipe *pipe) + +void mdp4_overlay2_done_wfd(struct mdp_dma_data *dma) { - mdp4_mixer_stage_commit(pipe->mixer_num); + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + int cndx = 0; - pr_debug("%s: pid=%d\n", __func__, current->pid); - mdp4_writeback_overlay_kickoff(mfd, pipe); + vctrl = &vsync_ctrl_db[cndx]; + pipe = vctrl->base_pipe; + + spin_lock(&vctrl->spin_lock); + vsync_irq_disable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM); + vctrl->ov_done++; + complete(&vctrl->ov_comp); + schedule_work(&vctrl->clk_work); + pr_debug("%s ovdone interrupt\n", __func__); + spin_unlock(&vctrl->spin_lock); } void mdp4_writeback_overlay(struct msm_fb_data_type *mfd) { - int ret = 0; - struct msmfb_writeback_data_list *node = NULL; + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; - mutex_lock(&mfd->unregister_mutex); - mutex_lock(&mfd->writeback_mutex); - if (!list_empty(&mfd->writeback_free_queue) - && mfd->writeback_state != WB_STOPING - && mfd->writeback_state != WB_STOP) { - node = list_first_entry(&mfd->writeback_free_queue, - struct msmfb_writeback_data_list, active_entry); - } - if (node) { - list_del(&(node->active_entry)); - node->state = IN_BUSY_QUEUE; - mfd->writeback_active_cnt++; - } - mutex_unlock(&mfd->writeback_mutex); + if (mfd && !mfd->panel_power_on) + return; + + pr_debug("%s:+ mfd=%x\n", __func__, (int)mfd); - writeback_pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL); + vctrl = &vsync_ctrl_db[0]; + pipe = vctrl->base_pipe; mutex_lock(&mfd->dma->ov_mutex); - pr_debug("%s in writeback\n", __func__); - if (writeback_pipe && !writeback_pipe->ov_blt_addr) { - pr_err("%s: no writeback buffer 0x%x\n", __func__, - (unsigned int)writeback_pipe->ov_blt_addr); - ret = mdp4_overlay_writeback_update(mfd); - if (ret) - pr_err("%s: update failed writeback pipe NULL\n", - __func__); - goto fail_no_blt_addr; - } - if (mfd && mfd->panel_power_on) { - pr_debug("%s in before busy wait\n", __func__); - mdp4_writeback_dma_busy_wait(mfd); + if (pipe->pipe_type == OVERLAY_TYPE_RGB) + mdp4_wfd_pipe_queue(0, pipe); - pr_debug("%s in before update\n", __func__); - ret = mdp4_overlay_writeback_update(mfd); - if (ret) { - pr_err("%s: update failed writeback pipe NULL\n", - __func__); - goto fail_no_blt_addr; - } + mdp4_overlay_mdp_perf_upd(mfd, 1); - pr_debug("%s: in writeback pan display 0x%x\n", __func__, - (unsigned int)writeback_pipe->ov_blt_addr); - mdp4_writeback_kickoff_ui(mfd, writeback_pipe); - mdp4_iommu_unmap(writeback_pipe); + mdp4_wfd_pipe_commit(mfd, 0, 1); - /* signal if pan function is waiting for the - * update completion */ - if (mfd->pan_waiting) { - mfd->pan_waiting = FALSE; - complete(&mfd->pan_comp); - } - } + mdp4_overlay_mdp_perf_upd(mfd, 0); - mutex_lock(&mfd->writeback_mutex); - list_add_tail(&node->active_entry, &mfd->writeback_busy_queue); - mfd->writeback_active_cnt--; - mutex_unlock(&mfd->writeback_mutex); - wake_up(&mfd->wait_q); -fail_no_blt_addr: - /*NOTE: This api was removed - mdp4_overlay_resource_release();*/ mutex_unlock(&mfd->dma->ov_mutex); - mutex_unlock(&mfd->unregister_mutex); } + static int mdp4_overlay_writeback_register_buffer( struct msm_fb_data_type *mfd, struct msmfb_writeback_data_list *node) { @@ -634,3 +742,88 @@ int mdp4_writeback_terminate(struct fb_info *info) mutex_unlock(&mfd->unregister_mutex); return rc; } + +static void mdp4_wfd_dequeue_update(struct msm_fb_data_type *mfd, + struct msmfb_writeback_data_list **wfdnode) +{ + struct vsycn_ctrl *vctrl; + struct mdp4_overlay_pipe *pipe; + struct msmfb_writeback_data_list *node = NULL; + + if (mfd && !mfd->panel_power_on) + return; + + pr_debug("%s:+ mfd=%x\n", __func__, (int)mfd); + + vctrl = &vsync_ctrl_db[0]; + pipe = vctrl->base_pipe; + + mutex_lock(&mfd->unregister_mutex); + mutex_lock(&mfd->writeback_mutex); + if (!list_empty(&mfd->writeback_free_queue) + && mfd->writeback_state != WB_STOPING + && mfd->writeback_state != WB_STOP) { + node = list_first_entry(&mfd->writeback_free_queue, + struct msmfb_writeback_data_list, active_entry); + } + if (node) { + list_del(&(node->active_entry)); + node->state = IN_BUSY_QUEUE; + mfd->writeback_active_cnt++; + } + mutex_unlock(&mfd->writeback_mutex); + + pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL); + + if (!pipe->ov_blt_addr) { + pr_err("%s: no writeback buffer 0x%x, %p\n", __func__, + (unsigned int)pipe->ov_blt_addr, node); + mutex_unlock(&mfd->unregister_mutex); + return; + } + + mdp4_overlay_writeback_update(mfd); + + *wfdnode = node; + + mutex_unlock(&mfd->unregister_mutex); +} + +static void mdp4_wfd_queue_wakeup(struct msm_fb_data_type *mfd, + struct msmfb_writeback_data_list *node) +{ + + if (mfd && !mfd->panel_power_on) + return; + + if (node == NULL) + return; + + pr_debug("%s: mfd=%x node: %p", __func__, (int)mfd, node); + + mutex_lock(&mfd->writeback_mutex); + list_add_tail(&node->active_entry, &mfd->writeback_busy_queue); + mfd->writeback_active_cnt--; + mutex_unlock(&mfd->writeback_mutex); + wake_up(&mfd->wait_q); +} + +int mdp4_writeback_set_mirroring_hint(struct fb_info *info, int hint) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mfd->panel.type != WRITEBACK_PANEL) + return -ENOTSUPP; + + switch (hint) { + case MDP_WRITEBACK_MIRROR_ON: + case MDP_WRITEBACK_MIRROR_PAUSE: + case MDP_WRITEBACK_MIRROR_RESUME: + case MDP_WRITEBACK_MIRROR_OFF: + pr_info("wfd state switched to %d\n", hint); + switch_set_state(&mfd->writeback_sdev, hint); + return 0; + default: + return -EINVAL; + } +} diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c index 469e5bcd..a66f5c97 100644 --- a/drivers/video/msm/mdp4_util.c +++ b/drivers/video/msm/mdp4_util.c @@ -35,6 +35,149 @@ struct mdp4_statistic mdp4_stat; +struct mdp_csc_cfg_data csc_cfg_matrix[CSC_MAX_BLOCKS] = { + { + .block = MDP_BLOCK_VG_1, + .csc_data = { + (MDP_CSC_FLAG_YUV_OUT), + { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000, + }, + { + 0xfff0, 0xff80, 0xff80, + }, + { + 0, 0, 0, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + }, + }, + { + .block = MDP_BLOCK_VG_2, + .csc_data = { + (MDP_CSC_FLAG_YUV_OUT), + { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000, + }, + { + 0xfff0, 0xff80, 0xff80, + }, + { + 0, 0, 0, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + }, + }, + { + .block = MDP_BLOCK_DMA_P, + .csc_data = { + (0), + { + 0x0200, 0x0000, 0x0000, + 0x0000, 0x0200, 0x0000, + 0x0000, 0x0000, 0x0200, + }, + { + 0x0, 0x0, 0x0, + }, + { + 0, 0, 0, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + }, + }, + { + .block = MDP_BLOCK_OVERLAY_1, + .csc_data = { + (0), + { + 0x0083, 0x0102, 0x0032, + 0x1fb5, 0x1f6c, 0x00e1, + 0x00e1, 0x1f45, 0x1fdc, + }, + { + 0x0, 0x0, 0x0, + }, + { + 0x0010, 0x0080, 0x0080, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0x0010, 0x00eb, 0x0010, + 0x00f0, 0x0010, 0x00f0, + }, + }, + }, + { + .block = MDP_BLOCK_OVERLAY_2, + .csc_data = { + (0), + { + 0x0083, 0x0102, 0x0032, + 0x1fb5, 0x1f6c, 0x00e1, + 0x00e1, 0x1f45, 0x1fdc, + }, + { + 0x0, 0x0, 0x0, + }, + { + 0x0010, 0x0080, 0x0080, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0x0010, 0x00eb, 0x0010, + 0x00f0, 0x0010, 0x00f0, + }, + }, + }, + { + .block = MDP_BLOCK_DMA_S, + .csc_data = { + (0), + { + 0x0200, 0x0000, 0x0000, + 0x0000, 0x0200, 0x0000, + 0x0000, 0x0000, 0x0200, + }, + { + 0x0, 0x0, 0x0, + }, + { + 0, 0, 0, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + }, + }, +}; + unsigned is_mdp4_hw_reset(void) { unsigned hw_reset = 0; @@ -245,11 +388,12 @@ void mdp4_hw_init(void) { ulong bits; uint32 clk_rate; - + int i; /* MDP cmd block enable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - mdp_bus_scale_update_request(5); + mdp_bus_scale_update_request + (MDP_BUS_SCALE_INIT, MDP_BUS_SCALE_INIT); #ifdef MDP4_ERROR /* @@ -273,11 +417,8 @@ void mdp4_hw_init(void) mdp4_vg_qseed_init(0); mdp4_vg_qseed_init(1); - mdp4_vg_csc_setup(0); - mdp4_vg_csc_setup(1); - mdp4_mixer_csc_setup(1); - mdp4_mixer_csc_setup(2); - mdp4_dmap_csc_setup(); + for (i = 0; i < CSC_MAX_BLOCKS; i++) + mdp4_csc_config(&csc_cfg_matrix[i]); if (mdp_rev <= MDP_REV_41) { mdp4_mixer_gc_lut_setup(0); @@ -314,8 +455,6 @@ void mdp4_hw_init(void) clk_rate = mdp_get_core_clk(); mdp4_fetch_cfg(clk_rate); - mdp4_overlay_cfg_init(); - /* Mark hardware as initialized. Only revisions > v2.1 have a register * for tracking core reset status. */ if (mdp_hw_revision > MDP4_REVISION_V2_1) @@ -417,7 +556,7 @@ irqreturn_t mdp4_isr(int irq, void *ptr) mdp4_dmap_done_dsi_cmd(0); #else else { /* MDDI */ - mdp4_dma_p_done_mddi(dma); + mdp4_dmap_done_mddi(0); mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); complete(&dma->comp); @@ -468,7 +607,7 @@ irqreturn_t mdp4_isr(int irq, void *ptr) mdp4_overlay0_done_dsi_cmd(0); #else if (panel & MDP4_PANEL_MDDI) - mdp4_overlay0_done_mddi(dma); + mdp4_overlay0_done_mddi(0); #endif } mdp_hw_cursor_done(); @@ -490,19 +629,15 @@ irqreturn_t mdp4_isr(int irq, void *ptr) if (panel & MDP4_PANEL_ATV) mdp4_overlay1_done_atv(); #endif + mdp_hw_cursor_done(); } #if defined(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) if (isr & INTR_OVERLAY2_DONE) { mdp4_stat.intr_overlay2++; + mdp_pipe_ctrl(MDP_OVERLAY2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); /* disable DTV interrupt */ - dma = &dma_wb_data; - spin_lock(&mdp_spin_lock); - mdp_intr_mask &= ~INTR_OVERLAY2_DONE; - outp32(MDP_INTR_ENABLE, mdp_intr_mask); - dma->waiting = FALSE; - spin_unlock(&mdp_spin_lock); if (panel & MDP4_PANEL_WRITEBACK) - mdp4_overlay1_done_writeback(dma); + mdp4_overlay2_done_wfd(&dma_wb_data); } #endif #endif /* OVERLAY */ @@ -1252,422 +1387,46 @@ struct mdp_csc_cfg mdp_csc_convert[4] = { }, }; -struct mdp_csc_cfg csc_matrix[3] = { - { - (MDP_CSC_FLAG_YUV_OUT), - { - 0x0254, 0x0000, 0x0331, - 0x0254, 0xff37, 0xfe60, - 0x0254, 0x0409, 0x0000, - }, - { - 0xfff0, 0xff80, 0xff80, - }, - { - 0, 0, 0, - }, - { - 0, 0xff, 0, 0xff, 0, 0xff, - }, - { - 0, 0xff, 0, 0xff, 0, 0xff, - }, - }, - { - (MDP_CSC_FLAG_YUV_OUT), - { - 0x0254, 0x0000, 0x0331, - 0x0254, 0xff37, 0xfe60, - 0x0254, 0x0409, 0x0000, - }, - { - 0xfff0, 0xff80, 0xff80, - }, - { - 0, 0, 0, - }, - { - 0, 0xff, 0, 0xff, 0, 0xff, - }, - { - 0, 0xff, 0, 0xff, 0, 0xff, - }, - }, - { - (0), - { - 0x0200, 0x0000, 0x0000, - 0x0000, 0x0200, 0x0000, - 0x0000, 0x0000, 0x0200, - }, - { - 0x0, 0x0, 0x0, - }, - { - 0, 0, 0, - }, - { - 0, 0xff, 0, 0xff, 0, 0xff, - }, - { - 0, 0xff, 0, 0xff, 0, 0xff, - }, - }, -}; - - -#define MDP4_CSC_MV_OFF 0x4400 -#define MDP4_CSC_PRE_BV_OFF 0x4500 -#define MDP4_CSC_POST_BV_OFF 0x4580 -#define MDP4_CSC_PRE_LV_OFF 0x4600 -#define MDP4_CSC_POST_LV_OFF 0x4680 - -void mdp4_vg_csc_mv_setup(int vp_num) -{ - uint32 *off; - int i, voff; - - voff = MDP4_VIDEO_OFF * vp_num; - off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + - MDP4_CSC_MV_OFF); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 9; i++) { - outpdw(off, csc_matrix[vp_num].csc_mv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_vg_csc_pre_bv_setup(int vp_num) -{ - uint32 *off; - int i, voff; - - voff = MDP4_VIDEO_OFF * vp_num; - off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + - MDP4_CSC_PRE_BV_OFF); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 3; i++) { - outpdw(off, csc_matrix[vp_num].csc_pre_bv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_vg_csc_post_bv_setup(int vp_num) -{ - uint32 *off; - int i, voff; - - voff = MDP4_VIDEO_OFF * vp_num; - off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + - MDP4_CSC_POST_BV_OFF); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 3; i++) { - outpdw(off, csc_matrix[vp_num].csc_post_bv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_vg_csc_pre_lv_setup(int vp_num) -{ - uint32 *off; - int i, voff; - - voff = MDP4_VIDEO_OFF * vp_num; - off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + - MDP4_CSC_PRE_LV_OFF); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 6; i++) { - outpdw(off, csc_matrix[vp_num].csc_pre_lv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_vg_csc_post_lv_setup(int vp_num) -{ - uint32 *off; - int i, voff; - - voff = MDP4_VIDEO_OFF * vp_num; - off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + - MDP4_CSC_POST_LV_OFF); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 6; i++) { - outpdw(off, csc_matrix[vp_num].csc_post_lv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_vg_csc_convert_setup(int vp_num) -{ - struct mdp_csc_cfg_data cfg; - - switch (vp_num) { - case 0: - cfg.block = MDP_BLOCK_VG_1; - break; - case 1: - cfg.block = MDP_BLOCK_VG_2; - break; - default: - pr_err("%s - invalid vp_num = %d", __func__, vp_num); - return; - } - cfg.csc_data = csc_matrix[vp_num]; - mdp4_csc_enable(&cfg); -} - -void mdp4_vg_csc_setup(int vp_num) -{ - /* yuv2rgb */ - mdp4_vg_csc_mv_setup(vp_num); - mdp4_vg_csc_pre_bv_setup(vp_num); - mdp4_vg_csc_post_bv_setup(vp_num); - mdp4_vg_csc_pre_lv_setup(vp_num); - mdp4_vg_csc_post_lv_setup(vp_num); - mdp4_vg_csc_convert_setup(vp_num); -} void mdp4_vg_csc_update(struct mdp_csc *p) { struct mdp4_overlay_pipe *pipe; - int vp_num; + uint32_t block = 0; + int i = 0; pipe = mdp4_overlay_ndx2pipe(p->id); if (pipe == NULL) { pr_err("%s: p->id = %d Error\n", __func__, p->id); return; } - - vp_num = pipe->pipe_num - OVERLAY_PIPE_VG1; - - if (vp_num == 0 || vp_num == 1) { - memcpy(csc_matrix[vp_num].csc_mv, p->csc_mv, sizeof(p->csc_mv)); - memcpy(csc_matrix[vp_num].csc_pre_bv, p->csc_pre_bv, - sizeof(p->csc_pre_bv)); - memcpy(csc_matrix[vp_num].csc_post_bv, p->csc_post_bv, - sizeof(p->csc_post_bv)); - memcpy(csc_matrix[vp_num].csc_pre_lv, p->csc_pre_lv, - sizeof(p->csc_pre_lv)); - memcpy(csc_matrix[vp_num].csc_post_lv, p->csc_post_lv, - sizeof(p->csc_post_lv)); - mdp4_vg_csc_setup(vp_num); - } -} -static uint32 csc_rgb2yuv_matrix_tab[9] = { - 0x0083, 0x0102, 0x0032, - 0x1fb5, 0x1f6c, 0x00e1, - 0x00e1, 0x1f45, 0x1fdc -}; - -static uint32 csc_rgb2yuv_pre_bv_tab[3] = {0, 0, 0}; - -static uint32 csc_rgb2yuv_post_bv_tab[3] = {0x0010, 0x0080, 0x0080}; - -static uint32 csc_rgb2yuv_pre_lv_tab[6] = { - 0x00, 0xff, 0x00, - 0xff, 0x00, 0xff -}; - -static uint32 csc_rgb2yuv_post_lv_tab[6] = { - 0x0010, 0x00eb, 0x0010, - 0x00f0, 0x0010, 0x00f0 -}; - -void mdp4_mixer_csc_mv_setup(uint32 mixer) -{ - uint32 *off; - int i; - - if (mixer == MDP4_MIXER1) - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400); - else - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2400); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 9; i++) { - outpdw(off, csc_rgb2yuv_matrix_tab[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_mixer_csc_pre_bv_setup(uint32 mixer) -{ - uint32 *off; - int i; - - if (mixer == MDP4_MIXER1) - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500); + if (pipe->pipe_num == OVERLAY_PIPE_VG1) + block = MDP_BLOCK_VG_1; + else if (pipe->pipe_num == OVERLAY_PIPE_VG2) + block = MDP_BLOCK_VG_2; else - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2500); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 3; i++) { - outpdw(off, csc_rgb2yuv_pre_bv_tab[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_mixer_csc_post_bv_setup(uint32 mixer) -{ - uint32 *off; - int i; - - if (mixer == MDP4_MIXER1) - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580); - else - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2580); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 3; i++) { - outpdw(off, csc_rgb2yuv_post_bv_tab[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_mixer_csc_pre_lv_setup(uint32 mixer) -{ - uint32 *off; - int i; - - if (mixer == MDP4_MIXER1) - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600); - else - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2600); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 6; i++) { - outpdw(off, csc_rgb2yuv_pre_lv_tab[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_mixer_csc_post_lv_setup(uint32 mixer) -{ - uint32 *off; - int i; - - if (mixer == MDP4_MIXER1) - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680); - else - off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2680); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 6; i++) { - outpdw(off, csc_rgb2yuv_post_lv_tab[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_mixer_csc_setup(uint32 mixer) -{ - if (mixer >= MDP4_MIXER1) { - /* rgb2yuv */ - mdp4_mixer_csc_mv_setup(mixer); - mdp4_mixer_csc_pre_bv_setup(mixer); - mdp4_mixer_csc_post_bv_setup(mixer); - mdp4_mixer_csc_pre_lv_setup(mixer); - mdp4_mixer_csc_post_lv_setup(mixer); - } -} - -#define DMA_P_BASE 0x90000 -void mdp4_dmap_csc_mv_setup(void) -{ - uint32 *off; - int i; - - off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3400); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 9; i++) { - outpdw(off, csc_matrix[2].csc_mv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_dmap_csc_pre_bv_setup(void) -{ - uint32 *off; - int i; - - off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3500); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 3; i++) { - outpdw(off, csc_matrix[2].csc_pre_bv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_dmap_csc_post_bv_setup(void) -{ - uint32 *off; - int i; - - off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3580); - - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 3; i++) { - outpdw(off, csc_matrix[2].csc_post_bv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_dmap_csc_pre_lv_setup(void) -{ - uint32 *off; - int i; - - off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3600); + return; - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 6; i++) { - outpdw(off, csc_matrix[2].csc_pre_lv[i]); - off++; + for (i = 0; i < CSC_MAX_BLOCKS; i++) { + if (csc_cfg_matrix[i].block == block) + break; } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} - -void mdp4_dmap_csc_post_lv_setup(void) -{ - uint32 *off; - int i; + if (i == CSC_MAX_BLOCKS) + return; - off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3680); + memcpy(&csc_cfg_matrix[i].csc_data.csc_mv, p->csc_mv, + sizeof(p->csc_mv)); + memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_bv, p->csc_pre_bv, + sizeof(p->csc_pre_bv)); + memcpy(&csc_cfg_matrix[i].csc_data.csc_post_bv, p->csc_post_bv, + sizeof(p->csc_post_bv)); + memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_lv, p->csc_pre_lv, + sizeof(p->csc_pre_lv)); + memcpy(&csc_cfg_matrix[i].csc_data.csc_post_lv, p->csc_post_lv, + sizeof(p->csc_post_lv)); + csc_cfg_matrix[i].csc_data.flags = MDP_CSC_FLAG_YUV_OUT; - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - for (i = 0; i < 6; i++) { - outpdw(off, csc_matrix[2].csc_post_lv[i]); - off++; - } - mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); -} + mdp4_csc_config(&csc_cfg_matrix[i]); -void mdp4_dmap_csc_setup(void) -{ - mdp4_dmap_csc_mv_setup(); - mdp4_dmap_csc_pre_bv_setup(); - mdp4_dmap_csc_post_bv_setup(); - mdp4_dmap_csc_pre_lv_setup(); - mdp4_dmap_csc_post_lv_setup(); } char gc_lut[] = { @@ -2375,7 +2134,7 @@ static uint32_t mdp4_csc_block2base(uint32_t block) base = 0x1A000; break; case MDP_BLOCK_OVERLAY_2: - base = (mdp_rev >= MDP_REV_44) ? 0x8A000 : 0x0; + base = (mdp_rev >= MDP_REV_43) ? 0x8A000 : 0x0; break; case MDP_BLOCK_VG_1: base = 0x24000; @@ -2546,7 +2305,7 @@ u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num) pr_info("%s:%d ion based allocation mfd->mem_hid 0x%x\n", __func__, __LINE__, mfd->mem_hid); buf->ihdl = ion_alloc(mfd->iclient, buffer_size, SZ_4K, - mfd->mem_hid); + mfd->mem_hid, 0); if (!IS_ERR_OR_NULL(buf->ihdl)) { if (mdp_iommu_split_domain) { if (ion_map_iommu(mfd->iclient, buf->ihdl, @@ -2555,7 +2314,7 @@ u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num) pr_err("ion_map_iommu() read failed\n"); return -ENOMEM; } - if (mfd->mem_hid & ION_SECURE) { + if (mfd->mem_hid & ION_FLAG_SECURE) { if (ion_phys(mfd->iclient, buf->ihdl, &addr, (size_t *)&len)) { pr_err("%s:%d: ion_phys map failed\n", @@ -2618,7 +2377,7 @@ void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num) if (!IS_ERR_OR_NULL(mfd->iclient)) { if (!IS_ERR_OR_NULL(buf->ihdl)) { if (mdp_iommu_split_domain) { - if (!(mfd->mem_hid & ION_SECURE)) + if (!(mfd->mem_hid & ION_FLAG_SECURE)) ion_unmap_iommu(mfd->iclient, buf->ihdl, DISPLAY_WRITE_DOMAIN, GEN_POOL); ion_unmap_iommu(mfd->iclient, buf->ihdl, @@ -2895,7 +2654,7 @@ static uint32_t mdp_pp_block2argc(uint32_t block) break; case MDP_BLOCK_OVERLAY_2: - valid = (mdp_rev >= MDP_REV_44) ? 1 : 0; + valid = (mdp_rev >= MDP_REV_43) ? 1 : 0; break; default: @@ -3232,75 +2991,196 @@ static uint32_t mdp4_pp_block2qseed(uint32_t block) return valid; } -static int mdp4_qseed_write_cfg(struct mdp_qseed_cfg_data *cfg) +int mdp4_qseed_access_cfg(struct mdp_qseed_cfg *config, uint32_t base) { int i, ret = 0; - uint32_t base = (uint32_t) (MDP_BASE + mdp_block2base(cfg->block)); uint32_t *values; - if ((cfg->table_num != 1) && (cfg->table_num != 2)) { + if ((config->table_num != 1) && (config->table_num != 2)) { ret = -ENOTTY; goto error; } - if (((cfg->table_num == 1) && (cfg->len != QSEED_TABLE_1_COUNT)) || - ((cfg->table_num == 2) && (cfg->len != QSEED_TABLE_2_COUNT))) { + if (((config->table_num == 1) && (config->len != QSEED_TABLE_1_COUNT)) + || ((config->table_num == 2) && + (config->len != QSEED_TABLE_2_COUNT))) { ret = -EINVAL; goto error; } - values = kmalloc(cfg->len * sizeof(uint32_t), GFP_KERNEL); + values = kmalloc(config->len * sizeof(uint32_t), GFP_KERNEL); if (!values) { ret = -ENOMEM; goto error; } - ret = copy_from_user(values, cfg->data, sizeof(uint32_t) * cfg->len); + base += (config->table_num == 1) ? MDP4_QSEED_TABLE1_OFF : + MDP4_QSEED_TABLE2_OFF; - base += (cfg->table_num == 1) ? MDP4_QSEED_TABLE1_OFF : - MDP4_QSEED_TABLE2_OFF; - for (i = 0; i < cfg->len; i++) { - MDP_OUTP(base , values[i]); - base += sizeof(uint32_t); + if (config->ops & MDP_PP_OPS_WRITE) { + ret = copy_from_user(values, config->data, + sizeof(uint32_t) * config->len); + if (ret) { + pr_warn("%s: Error copying from user, %d", __func__, + ret); + ret = -EINVAL; + goto err_mem; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < config->len; i++) { + if (!(base & 0x3FF)) + wmb(); + MDP_OUTP(base , values[i]); + base += sizeof(uint32_t); + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } else if (config->ops & MDP_PP_OPS_READ) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < config->len; i++) { + values[i] = inpdw(base); + if (!(base & 0x3FF)) + rmb(); + base += sizeof(uint32_t); + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + ret = copy_to_user(config->data, values, + sizeof(uint32_t) * config->len); + if (ret) { + pr_warn("%s: Error copying to user, %d", __func__, ret); + ret = -EINVAL; + goto err_mem; + } } +err_mem: kfree(values); error: return ret; } -int mdp4_qseed_cfg(struct mdp_qseed_cfg_data *cfg) +int mdp4_qseed_cfg(struct mdp_qseed_cfg_data *config) { int ret = 0; + struct mdp_qseed_cfg *cfg = &config->qseed_data; + uint32_t base; - if (!mdp4_pp_block2qseed(cfg->block)) { + if (!mdp4_pp_block2qseed(config->block)) { ret = -ENOTTY; goto error; } - if (cfg->table_num != 1) { - ret = -ENOTTY; - pr_info("%s: Only QSEED table1 supported.\n", __func__); + if ((cfg->ops & MDP_PP_OPS_READ) && (cfg->ops & MDP_PP_OPS_WRITE)) { + ret = -EPERM; + pr_warn("%s: Cannot read and write on the same request\n", + __func__); goto error; } + base = (uint32_t) (MDP_BASE + mdp_block2base(config->block)); + ret = mdp4_qseed_access_cfg(cfg, base); - switch ((cfg->ops & 0x6) >> 1) { - case 0x1: - pr_info("%s: QSEED read not supported\n", __func__); - ret = -ENOTTY; - break; - case 0x2: - ret = mdp4_qseed_write_cfg(cfg); - if (ret) - goto error; - break; - default: - break; +error: + return ret; +} + +static int is_valid_calib_addr(void *addr) +{ + int ret = 0; + unsigned int ptr; + + ptr = (unsigned int) addr; + + if (mdp_rev >= MDP_REV_30 && mdp_rev < MDP_REV_40) { + /* if request is outside the MDP reg-map or is not aligned 4 */ + if (ptr == 0x0 || ptr > 0xF0600 || ptr % 0x4) + goto end; + + if (ptr >= 0x90000 && ptr < 0x94000) { + if (ptr == 0x90000 || ptr == 0x90070) + ret = 1; + else if (ptr >= 0x93400 && ptr <= 0x93420) + ret = 1; + else if (ptr >= 0x93500 && ptr <= 0x93508) + ret = 1; + else if (ptr >= 0x93580 && ptr <= 0x93588) + ret = 1; + else if (ptr >= 0x93600 && ptr <= 0x93614) + ret = 1; + else if (ptr >= 0x93680 && ptr <= 0x93694) + ret = 1; + else if (ptr >= 0x93800 && ptr <= 0x93BFC) + ret = 1; + } + } else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_44) { + /* if request is outside the MDP reg-map or is not aligned 4 */ + if (ptr > 0xF0600 || ptr % 0x4) + goto end; + + if (ptr < 0x90000) { + if (ptr == 0x0 || ptr == 0x4 || ptr == 0x28200 || + ptr == 0x28204) + ret = 1; + } else if (ptr < 0x95000) { + if (ptr == 0x90000 || ptr == 0x90070) + ret = 1; + else if (ptr >= 0x93400 && ptr <= 0x93420) + ret = 1; + else if (ptr >= 0x93500 && ptr <= 0x93508) + ret = 1; + else if (ptr >= 0x93580 && ptr <= 0x93588) + ret = 1; + else if (ptr >= 0x93600 && ptr <= 0x93614) + ret = 1; + else if (ptr >= 0x93680 && ptr <= 0x93694) + ret = 1; + else if (ptr >= 0x94800 && ptr <= 0x94BFC) + ret = 1; + } else if (ptr < 0x9A000) { + if (ptr >= 0x98800 && ptr <= 0x9883C) + ret = 1; + else if (ptr >= 0x98880 && ptr <= 0x988AC) + ret = 1; + else if (ptr >= 0x98900 && ptr <= 0x9893C) + ret = 1; + else if (ptr >= 0x98980 && ptr <= 0x989BC) + ret = 1; + else if (ptr >= 0x98A00 && ptr <= 0x98A3C) + ret = 1; + else if (ptr >= 0x98A80 && ptr <= 0x98ABC) + ret = 1; + else if (ptr >= 0x99000 && ptr <= 0x993FC) + ret = 1; + else if (ptr >= 0x99800 && ptr <= 0x99BFC) + ret = 1; + } else if (ptr >= 0x9A000 && ptr <= 0x9a08c) { + ret = 1; + } } +end: + return ret; +} -error: +int mdp4_calib_config(struct mdp_calib_config_data *cfg) +{ + int ret = -1; + void *ptr = (void *) cfg->addr; + + if (is_valid_calib_addr(ptr)) + ret = 0; + else + return ret; + + ptr = (void *)(((unsigned int) ptr) + MDP_BASE); + mdp_clk_ctrl(1); + if (cfg->ops & MDP_PP_OPS_READ) { + cfg->data = inpdw(ptr); + ret = 1; + } else if (cfg->ops & MDP_PP_OPS_WRITE) { + outpdw(ptr, cfg->data); + } + mdp_clk_ctrl(0); return ret; } + u32 mdp4_get_mixer_num(u32 panel_type) { u32 mixer_num; diff --git a/drivers/video/msm/mdp4_wfd_writeback.c b/drivers/video/msm/mdp4_wfd_writeback.c index d96fc7d6..7876f9ae 100644 --- a/drivers/video/msm/mdp4_wfd_writeback.c +++ b/drivers/video/msm/mdp4_wfd_writeback.c @@ -75,6 +75,13 @@ static int writeback_probe(struct platform_device *pdev) platform_set_drvdata(mdp_dev, mfd); + mfd->writeback_sdev.name = "wfd"; + rc = switch_dev_register(&mfd->writeback_sdev); + if (rc) { + pr_err("Failed to setup switch dev for writeback panel"); + return rc; + } + rc = platform_device_add(mdp_dev); if (rc) { WRITEBACK_MSG_ERR("failed to add device"); @@ -84,8 +91,16 @@ static int writeback_probe(struct platform_device *pdev) return rc; } +static int writeback_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + switch_dev_unregister(&mfd->writeback_sdev); + return 0; +} + static struct platform_driver writeback_driver = { .probe = writeback_probe, + .remove = writeback_remove, .driver = { .name = "writeback", }, diff --git a/drivers/video/msm/mdp_cursor.c b/drivers/video/msm/mdp_cursor.c index 93ff3882..a3920af5 100644 --- a/drivers/video/msm/mdp_cursor.c +++ b/drivers/video/msm/mdp_cursor.c @@ -52,7 +52,11 @@ void mdp_cursor_ctrl_workqueue_handler(struct work_struct *work) /* disable vsync */ spin_lock_irqsave(&mdp_spin_lock, flag); - mdp_disable_irq(MDP_OVERLAY0_TERM); + if (hdmi_prim_display) + mdp_disable_irq(MDP_OVERLAY1_TERM); + else + mdp_disable_irq(MDP_OVERLAY0_TERM); + spin_unlock_irqrestore(&mdp_spin_lock, flag); } @@ -78,29 +82,37 @@ void mdp_hw_cursor_done(void) * * Moving this code out of the ISR will cause the MDP to underrun! */ + uint32_t base = 0; + + if (hdmi_prim_display) + base = ((uint32_t)(MDP_BASE + 0xB0000)); + else + base = ((uint32_t)(MDP_BASE + 0x90000)); + + spin_lock(&mdp_spin_lock); if (sync_disabled) { spin_unlock(&mdp_spin_lock); return; } - MDP_OUTP(MDP_BASE + 0x90044, (height << 16) | width); - MDP_OUTP(MDP_BASE + 0x90048, cursor_buf_phys); + MDP_OUTP(base + 0x44, (height << 16) | width); + MDP_OUTP(base + 0x48, cursor_buf_phys); - MDP_OUTP(MDP_BASE + 0x90060, + MDP_OUTP(base + 0x60, (transp_en << 3) | (calpha_en << 1) | - (inp32(MDP_BASE + 0x90060) & 0x1)); + (inp32(base + 0x60) & 0x1)); - MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24)); - MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & bg_color)); - MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & bg_color)); + MDP_OUTP(base + 0x64, (alpha << 24)); + MDP_OUTP(base + 0x68, (0xffffff & bg_color)); + MDP_OUTP(base + 0x6C, (0xffffff & bg_color)); /* enable/disable the cursor as per the last request */ - if (cursor_enabled && !(inp32(MDP_BASE + 0x90060) & (0x1))) - MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1); - else if (!cursor_enabled && (inp32(MDP_BASE + 0x90060) & (0x1))) - MDP_OUTP(MDP_BASE + 0x90060, - inp32(MDP_BASE + 0x90060) & (~0x1)); + if (cursor_enabled && !(inp32(base + 0x60) & (0x1))) + MDP_OUTP(base + 0x60, inp32(base + 0x60) | 0x1); + else if (!cursor_enabled && (inp32(base + 0x60) & (0x1))) + MDP_OUTP(base + 0x60, + inp32(base + 0x60) & (~0x1)); /* enqueue the task to disable MDP interrupts */ queue_work(mdp_cursor_ctrl_wq, &mdp_cursor_ctrl_worker); @@ -119,17 +131,26 @@ static void mdp_hw_cursor_enable_vsync(void) if (sync_disabled) { /* cancel pending task to disable MDP interrupts */ - if (work_pending(&mdp_cursor_ctrl_worker)) + if (work_pending(&mdp_cursor_ctrl_worker)) { cancel_work_sync(&mdp_cursor_ctrl_worker); - else + } else { /* enable irq */ - mdp_enable_irq(MDP_OVERLAY0_TERM); + if (hdmi_prim_display) + mdp_enable_irq(MDP_OVERLAY1_TERM); + else + mdp_enable_irq(MDP_OVERLAY0_TERM); + } sync_disabled = 0; /* enable vsync intr */ - outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); - mdp_intr_mask |= INTR_OVERLAY0_DONE; + if (hdmi_prim_display) { + outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE); + mdp_intr_mask |= INTR_OVERLAY1_DONE; + } else { + outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + } outp32(MDP_INTR_ENABLE, mdp_intr_mask); } } @@ -140,14 +161,20 @@ int mdp_hw_cursor_sync_update(struct fb_info *info, struct fb_cursor *cursor) struct fb_image *img = &cursor->image; unsigned long flag; int sync_needed = 0, ret = 0; + uint32_t base = 0; if ((img->width > MDP_CURSOR_WIDTH) || (img->height > MDP_CURSOR_HEIGHT) || (img->depth != 32)) return -EINVAL; + if (hdmi_prim_display) + base = ((uint32_t)(MDP_BASE + 0xB0000)); + else + base = ((uint32_t)(MDP_BASE + 0x90000)); + if (cursor->set & FB_CUR_SETPOS) - MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx); + MDP_OUTP(base + 0x4c, (img->dy << 16) | img->dx); if (cursor->set & FB_CUR_SETIMAGE) { ret = copy_from_user(mfd->cursor_buf, img->data, diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c index 68727f4b..d3e0c8dd 100644 --- a/drivers/video/msm/mdp_debugfs.c +++ b/drivers/video/msm/mdp_debugfs.c @@ -719,84 +719,6 @@ static const struct file_operations pmdh_fops = { .write = pmdh_reg_write, }; - - -#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI) -static int vsync_reg_open(struct inode *inode, struct file *file) -{ - /* non-seekable */ - file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); - return 0; -} - -static int vsync_reg_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static ssize_t vsync_reg_write( - struct file *file, - const char __user *buff, - size_t count, - loff_t *ppos) -{ - uint32 enable; - int cnt; - - if (count >= sizeof(debug_buf)) - return -EFAULT; - - if (copy_from_user(debug_buf, buff, count)) - return -EFAULT; - - debug_buf[count] = 0; /* end of string */ - - cnt = sscanf(debug_buf, "%x", &enable); - - mdp_dmap_vsync_set(enable); - - return count; -} - -static ssize_t vsync_reg_read( - struct file *file, - char __user *buff, - size_t count, - loff_t *ppos) -{ - char *bp; - int len = 0; - int tot = 0; - int dlen; - - if (*ppos) - return 0; /* the end */ - - bp = debug_buf; - dlen = sizeof(debug_buf); - len = snprintf(bp, dlen, "%x\n", mdp_dmap_vsync_get()); - tot += len; - bp += len; - *bp = 0; - tot++; - - if (copy_to_user(buff, debug_buf, tot)) - return -EFAULT; - - *ppos += tot; /* increase offset */ - - return tot; -} - - -static const struct file_operations vsync_fops = { - .open = vsync_reg_open, - .release = vsync_reg_release, - .read = vsync_reg_read, - .write = vsync_reg_write, -}; -#endif - static ssize_t emdh_reg_write( struct file *file, const char __user *buff, @@ -1107,6 +1029,135 @@ static const struct file_operations dbg_reg_fops = { .write = dbg_reg_write, }; +u32 dbg_force_ov0_blt; +u32 dbg_force_ov1_blt; + +static ssize_t dbg_force_ov0_blt_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) { + int len; + + if (*ppos) + return 0; + + len = snprintf(debug_buf, sizeof(debug_buf), + "%d\n", dbg_force_ov0_blt); + + if (len < 0) + return 0; + + if (copy_to_user(buff, debug_buf, len)) + return -EFAULT; + + *ppos += len; + + return len; +} + +static ssize_t dbg_force_ov0_blt_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + u32 cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x", &dbg_force_ov0_blt); + + pr_info("%s: dbg_force_ov0_blt = %x\n", + __func__, dbg_force_ov0_blt); + + if ((dbg_force_ov0_blt & 0x0f) > 2) + pr_err("%s: invalid dbg_force_ov0_blt = %d\n", + __func__, dbg_force_ov0_blt); + + if ((dbg_force_ov0_blt >> 4) > 2) + pr_err("%s: invalid dbg_force_ov0_blt = %d\n", + __func__, dbg_force_ov0_blt); + + return count; +} + +static const struct file_operations dbg_force_ov0_blt_fops = { + .open = dbg_open, + .release = dbg_release, + .read = dbg_force_ov0_blt_read, + .write = dbg_force_ov0_blt_write, +}; + +static ssize_t dbg_force_ov1_blt_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) { + int len; + + if (*ppos) + return 0; + + len = snprintf(debug_buf, sizeof(debug_buf), + "%x\n", dbg_force_ov1_blt); + + if (len < 0) + return 0; + + if (copy_to_user(buff, debug_buf, len)) + return -EFAULT; + + *ppos += len; + + return len; +} + +static ssize_t dbg_force_ov1_blt_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + u32 cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x", &dbg_force_ov1_blt); + + pr_info("%s: dbg_force_ov1_blt = %x\n", + __func__, dbg_force_ov1_blt); + + if ((dbg_force_ov1_blt & 0x0f) > 2) + pr_err("%s: invalid dbg_force_ov1_blt = %x\n", + __func__, dbg_force_ov1_blt); + + if ((dbg_force_ov1_blt >> 4) > 2) + pr_err("%s: invalid dbg_force_ov1_blt = %d\n", + __func__, dbg_force_ov1_blt); + + return count; +} + +static const struct file_operations dbg_force_ov1_blt_fops = { + .open = dbg_open, + .release = dbg_release, + .read = dbg_force_ov1_blt_read, + .write = dbg_force_ov1_blt_write, +}; + #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL static uint32 hdmi_offset; static uint32 hdmi_count; @@ -1327,6 +1378,22 @@ int mdp_debugfs_init(void) } #endif + if (debugfs_create_file("force_ov0_blt", 0644, dent, 0, + &dbg_force_ov0_blt_fops) + == NULL) { + pr_err("%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -EFAULT; + } + + if (debugfs_create_file("force_ov1_blt", 0644, dent, 0, + &dbg_force_ov1_blt_fops) + == NULL) { + pr_err("%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -EFAULT; + } + dent = debugfs_create_dir("mddi", NULL); if (IS_ERR(dent)) { @@ -1342,15 +1409,6 @@ int mdp_debugfs_init(void) return -1; } -#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI) - if (debugfs_create_file("vsync", 0644, dent, 0, &vsync_fops) - == NULL) { - printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", - __FILE__, __LINE__); - return -1; - } -#endif - dent = debugfs_create_dir("emdh", NULL); if (IS_ERR(dent)) { diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c index 12ea0b4b..bf00a8c6 100644 --- a/drivers/video/msm/mdp_dma_dsi_video.c +++ b/drivers/video/msm/mdp_dma_dsi_video.c @@ -34,7 +34,7 @@ static int first_pixel_start_x; static int first_pixel_start_y; -static ssize_t vsync_show_event(struct device *dev, +ssize_t mdp_dma_video_show_event(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t ret = 0; @@ -47,20 +47,11 @@ static ssize_t vsync_show_event(struct device *dev, wait_for_completion(&vsync_cntrl.vsync_wait); ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", - ktime_to_ns(vsync_cntrl.vsync_time)); + ktime_to_ns(vsync_cntrl.vsync_time)); buf[strlen(buf) + 1] = '\0'; return ret; } -static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); -static struct attribute *vsync_fs_attrs[] = { - &dev_attr_vsync_event.attr, - NULL, -}; -static struct attribute_group vsync_fs_attr_group = { - .attrs = vsync_fs_attrs, -}; - int mdp_dsi_video_on(struct platform_device *pdev) { int dsi_width; @@ -254,28 +245,12 @@ int mdp_dsi_video_on(struct platform_device *pdev) /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); - if (!vsync_cntrl.sysfs_created) { - ret = sysfs_create_group(&vsync_cntrl.dev->kobj, - &vsync_fs_attr_group); - if (ret) { - pr_err("%s: sysfs creation failed, ret=%d\n", - __func__, ret); - return ret; - } - - kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD); - pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); - vsync_cntrl.sysfs_created = 1; - } - mdp_histogram_ctrl_all(TRUE); - return ret; } int mdp_dsi_video_off(struct platform_device *pdev) { int ret = 0; - mdp_histogram_ctrl_all(FALSE); /* MDP cmd block enable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); @@ -295,6 +270,7 @@ int mdp_dsi_video_off(struct platform_device *pdev) return ret; } +/* merge qcom patch to solve blue screen when power on */ void mdp_dma_video_vsync_ctrl(int enable) { unsigned long flag; @@ -307,22 +283,20 @@ void mdp_dma_video_vsync_ctrl(int enable) INIT_COMPLETION(vsync_cntrl.vsync_wait); vsync_cntrl.vsync_irq_enabled = enable; + if (!enable) + vsync_cntrl.disabled_clocks = 0; disabled_clocks = vsync_cntrl.disabled_clocks; spin_unlock_irqrestore(&mdp_spin_lock, flag); - if (enable && disabled_clocks) + if (enable && disabled_clocks) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - - spin_lock_irqsave(&mdp_spin_lock, flag); - if (enable && vsync_cntrl.disabled_clocks) { + spin_lock_irqsave(&mdp_spin_lock, flag); outp32(MDP_INTR_CLEAR, LCDC_FRAME_START); mdp_intr_mask |= LCDC_FRAME_START; outp32(MDP_INTR_ENABLE, mdp_intr_mask); mdp_enable_irq(MDP_VSYNC_TERM); - vsync_cntrl.disabled_clocks = 0; + spin_unlock_irqrestore(&mdp_spin_lock, flag); } - spin_unlock_irqrestore(&mdp_spin_lock, flag); - if (vsync_cntrl.vsync_irq_enabled && atomic_read(&vsync_cntrl.suspend) == 0) atomic_set(&vsync_cntrl.vsync_resume, 1); diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c index e213528b..04d8b017 100644 --- a/drivers/video/msm/mdp_dma_lcdc.c +++ b/drivers/video/msm/mdp_dma_lcdc.c @@ -51,7 +51,7 @@ extern uint32 mdp_intr_mask; int first_pixel_start_x; int first_pixel_start_y; -static ssize_t vsync_show_event(struct device *dev, +ssize_t mdp_dma_lcdc_show_event(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t ret = 0; @@ -64,20 +64,11 @@ static ssize_t vsync_show_event(struct device *dev, wait_for_completion(&vsync_cntrl.vsync_wait); ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", - ktime_to_ns(vsync_cntrl.vsync_time)); + ktime_to_ns(vsync_cntrl.vsync_time)); buf[strlen(buf) + 1] = '\0'; return ret; } -static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); -static struct attribute *vsync_fs_attrs[] = { - &dev_attr_vsync_event.attr, - NULL, -}; -static struct attribute_group vsync_fs_attr_group = { - .attrs = vsync_fs_attrs, -}; - int mdp_lcdc_on(struct platform_device *pdev) { int lcdc_width; @@ -320,21 +311,6 @@ int mdp_lcdc_on(struct platform_device *pdev) /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); - if (!vsync_cntrl.sysfs_created) { - ret = sysfs_create_group(&vsync_cntrl.dev->kobj, - &vsync_fs_attr_group); - if (ret) { - pr_err("%s: sysfs creation failed, ret=%d\n", - __func__, ret); - return ret; - } - - kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD); - pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); - vsync_cntrl.sysfs_created = 1; - } - mdp_histogram_ctrl_all(TRUE); - return ret; } @@ -353,7 +329,6 @@ int mdp_lcdc_off(struct platform_device *pdev) timer_base = DTV_BASE; } #endif - mdp_histogram_ctrl_all(FALSE); down(&mfd->dma->mutex); /* MDP cmd block enable */ @@ -387,21 +362,20 @@ void mdp_dma_lcdc_vsync_ctrl(int enable) INIT_COMPLETION(vsync_cntrl.vsync_wait); vsync_cntrl.vsync_irq_enabled = enable; + if (!enable) + vsync_cntrl.disabled_clocks = 0; disabled_clocks = vsync_cntrl.disabled_clocks; spin_unlock_irqrestore(&mdp_spin_lock, flag); - if (enable && disabled_clocks) + if (enable && disabled_clocks) { mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); - - spin_lock_irqsave(&mdp_spin_lock, flag); - if (enable && vsync_cntrl.disabled_clocks) { + spin_lock_irqsave(&mdp_spin_lock, flag); outp32(MDP_INTR_CLEAR, LCDC_FRAME_START); mdp_intr_mask |= LCDC_FRAME_START; outp32(MDP_INTR_ENABLE, mdp_intr_mask); mdp_enable_irq(MDP_VSYNC_TERM); - vsync_cntrl.disabled_clocks = 0; + spin_unlock_irqrestore(&mdp_spin_lock, flag); } - spin_unlock_irqrestore(&mdp_spin_lock, flag); if (vsync_cntrl.vsync_irq_enabled && atomic_read(&vsync_cntrl.suspend) == 0) diff --git a/drivers/video/msm/mdp_hw_init.c b/drivers/video/msm/mdp_hw_init.c index e937dbea..446f76a1 100644 --- a/drivers/video/msm/mdp_hw_init.c +++ b/drivers/video/msm/mdp_hw_init.c @@ -584,7 +584,9 @@ static void mdp_load_lut_param(void) #define IRQ_EN_1__MDP_IRQ___M 0x00000800 -void mdp_hw_init(int cont_splash) + +void mdp_hw_init(void) + { int i; @@ -631,17 +633,7 @@ void mdp_hw_init(int cont_splash) MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0, 0); MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0); -#ifndef CONFIG_FB_MSM_MDP22 - /* Make sure to disable TG if continuous splash screen - * is not enabled on kernel side. This avoids issues - * when multiple panels are supported on same board - * and all the panels do not have splash screen/continuous - * splash support on the boot loader side. - */ - if (!cont_splash) { - MDP_OUTP(MDP_BASE + 0xE0000, 0); - MDP_OUTP(MDP_BASE + 0xF0000, 0); - } +#ifndef CONFIG_FB_MSM_MDP22 MDP_OUTP(MDP_BASE + 0x100, 0xffffffff); MDP_OUTP(MDP_BASE + 0x90070, 0); #endif diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c index b2b66f90..ba18b078 100644 --- a/drivers/video/msm/mdp_ppp.c +++ b/drivers/video/msm/mdp_ppp.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "linux/proc_fs.h" @@ -548,40 +547,8 @@ static void mdp_ppp_setbg(MDPIBUF *iBuf) format == MDP_Y_CRCB_H2V2) ? 2 : (format == MDP_Y_CBCR_H2V1 || \ format == MDP_Y_CRCB_H2V1) ? 1 : 1) -#ifdef CONFIG_ANDROID_PMEM -static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp, - uint32_t *len0, uint32_t *len1) -{ - *len0 = IMG_LEN(rect->h, img->width, rect->w, bpp); - if (IS_PSEUDOPLNR(img->format)) - *len1 = *len0/Y_TO_CRCB_RATIO(img->format); - else - *len1 = 0; -} - -static void flush_imgs(struct mdp_blit_req *req, int src_bpp, int dst_bpp, - struct file *p_src_file, struct file *p_dst_file) -{ - uint32_t src0_len, src1_len; - - if (!(req->flags & MDP_BLIT_NON_CACHED)) { - /* flush src images to memory before dma to mdp */ - get_len(&req->src, &req->src_rect, src_bpp, - &src0_len, &src1_len); - - flush_pmem_file(p_src_file, - req->src.offset, src0_len); - - if (IS_PSEUDOPLNR(req->src.format)) - flush_pmem_file(p_src_file, - req->src.offset + src0_len, src1_len); - } - -} -#else static void flush_imgs(struct mdp_blit_req *req, int src_bpp, int dst_bpp, struct file *p_src_file, struct file *p_dst_file) { } -#endif static void mdp_start_ppp(struct msm_fb_data_type *mfd, MDPIBUF *iBuf, struct mdp_blit_req *req, struct file *p_src_file, struct file *p_dst_file) @@ -1286,9 +1253,6 @@ int get_img(struct mdp_img *img, struct mdp_blit_req *req, #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; #endif -#ifdef CONFIG_ANDROID_PMEM - unsigned long vstart; -#endif if (req->flags & MDP_MEMORY_ID_TYPE_FB) { file = fget_light(img->memory_id, &put_needed); @@ -1321,21 +1285,10 @@ int get_img(struct mdp_img *img, struct mdp_blit_req *req, return -EINVAL; #endif -#ifdef CONFIG_ANDROID_PMEM - if (!get_pmem_file(img->memory_id, start, &vstart, len, srcp_file)) - return ret; - else - return -EINVAL; -#endif } void put_img(struct file *p_src_file, struct ion_handle *p_ihdl) { -#ifdef CONFIG_ANDROID_PMEM - if (p_src_file) - put_pmem_file(p_src_file); -#endif - #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION if (!IS_ERR_OR_NULL(p_ihdl)) ion_free(ppp_display_iclient, p_ihdl); @@ -1401,6 +1354,9 @@ static int mdp_ppp_blit_addr(struct fb_info *info, struct mdp_blit_req *req, iBuf.mdpImg.mdpOp = MDPOP_NOP; + if (req->flags & MDP_IS_FG) + iBuf.mdpImg.mdpOp |= MDPOP_LAYER_IS_FG; + if (req->flags & MDP_IS_FG) iBuf.mdpImg.mdpOp |= MDPOP_LAYER_IS_FG; @@ -1701,12 +1657,19 @@ int mdp_ppp_v4l2_overlay_clear(void) return 0; } -int mdp_ppp_v4l2_overlay_play(struct fb_info *info, +int mdp_ppp_v4l2_overlay_play(struct fb_info *info, bool bUserPtr, unsigned long srcp0_addr, unsigned long srcp0_size, unsigned long srcp1_addr, unsigned long srcp1_size) { int ret; + unsigned long srcp0_start = 0, srcp1_start = 0; + unsigned long srcp0_len = 0, srcp1_len = 0; + struct ion_handle *srcp0_ihdl = NULL; + struct ion_handle *srcp1_ihdl = NULL; + struct msm_fb_data_type *mfd = info->par; + + ppp_display_iclient = mfd->iclient; if (!mdp_overlay_req_set) { pr_err("mdp_ppp:v4l2:No overlay set, ignore play req\n"); return -EINVAL; @@ -1715,6 +1678,31 @@ int mdp_ppp_v4l2_overlay_play(struct fb_info *info, overlay_req.dst.width = info->var.xres; overlay_req.dst.height = info->var.yres; + if (bUserPtr) { + overlay_req.src.memory_id = srcp0_addr; + get_img(&overlay_req.src, &overlay_req, info, &srcp0_start, + &srcp0_len, NULL, &srcp0_ihdl); + if (srcp0_len == 0) { + pr_err("%s: could not retrieve source image0" + , __func__); + return -EINVAL; + } + srcp0_addr = srcp0_start + srcp0_size; + srcp0_size = srcp0_len; + + if (srcp1_addr) { + overlay_req.src.memory_id = srcp1_addr; + get_img(&overlay_req.src, &overlay_req, info, + &srcp1_start, &srcp1_len, NULL, &srcp1_ihdl); + if (srcp1_len == 0) { + pr_err("%s: could not retrieve source image1" + , __func__); + return -EINVAL; + } + srcp1_addr = srcp1_start + srcp1_size; + srcp1_size = srcp1_len; + } + } ret = mdp_ppp_blit_addr(info, &overlay_req, srcp0_addr, srcp0_size, srcp1_addr, srcp1_size, info->fix.smem_start, info->fix.smem_len, NULL, NULL, diff --git a/drivers/video/msm/mipi_byd_otm9608a_wg451v.c b/drivers/video/msm/mipi_byd_otm9608a_wg451v.c old mode 100644 new mode 100755 diff --git "a/drivers/video/msm/mipi_div4_nt35510_cmd_wvga (\320\272\320\276\320\277\320\270.c" "b/drivers/video/msm/mipi_div4_nt35510_cmd_wvga (\320\272\320\276\320\277\320\270.c" new file mode 100755 index 00000000..3b0b49c2 --- /dev/null +++ "b/drivers/video/msm/mipi_div4_nt35510_cmd_wvga (\320\272\320\276\320\277\320\270.c" @@ -0,0 +1,1183 @@ +#include +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mdp4.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum +{ + NT35510_STATUS_LCD_SLEEP, + NT35510_STATUS_LCD_ON, + NT35510_STATUS_LCD_GLANSCREEN_ON, + NT35510_STATUS_LCD_GLANSCREEN_OFF, +}; +#define SN3228B_MAX_BACKLIGHT 14 + +#define GP_CLK_M 1 +#define GP_CLK_N 150 +#define LCM_RESET_GPIO_PIN85 85 +//pjn add for l1ED control +#define LCM_1LED_CTRL_GPIO_PIN121 121 +#define LCD_LOW_POWER_DETECT 1 +#define DSI_BIT_CLK_500M 1 +#define LCM_ID_GPIO_PIN120 120 + +#define MIPI_SEND_DATA_TYPE DTYPE_GEN_LWRITE //DTYPE_DCS_LWRITE // + +DEFINE_SEMAPHORE(nt35510_sem); + +static void nt35510_backlight_set(int level); + +static void mipi_nt35510_gs_set_backlight(int level); + +struct nt35510_state_type +{ + bool disp_initialized;/* disp initialized */ + bool display_on; /* lcd is on */ + uint8 disp_powered_up;/* lcd power and lcd bl power on */ + bool bk_init; + bool gp_clk_flag; + +}; + +typedef struct nt35510_state_type nt35510_state_t; +static nt35510_state_t nt35510_state= { 0 }; +static uint32 mddi_current_bl = 255;//added by zxd to ignore the same level. +static struct msm_panel_info pinfo; +static struct msm_panel_common_pdata *mipi_nt35510_pdata; +static struct dsi_buf nt35510_tx_buf; +static struct dsi_buf nt35510_rx_buf; + +//pjn add for low power glance screen,it specifies lcd state switch +int glancescreen_flag = 0; + +//add for panel module vender detect +extern int ODMM_PANEL_ID; +extern char panel_detect_desc[16]; + +//extern void lcd_lowpower_mode(void); +extern bool glanceview_suspend_statues(void); +extern bool glanceview_resume_statues(void); +extern void mipi_dsi_te_ctrl(struct msm_fb_data_type *mfd, bool flag); +extern void glanceview_oneled_state_ctrl(bool flag); + +static char exit_sleep[1] = {0x11}; +static char display_on[1] = {0x29}; +static char write_ram[1] = {0x2c}; /* write ram */ +static char enter_sleep[2] = {0x10, 0x00}; +static char display_off[2] = {0x28, 0x00}; +//static char STBYB_in[2] = {0x4F, 0x01}; + +#if 0 +static char idle_off[2] = {0x38, 0x00}; +static struct dsi_cmd_desc nt35510_ilde_mode_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(idle_off), idle_off}, +}; +#else +static char idle_on[2] = {0x39, 0x00}; +static struct dsi_cmd_desc nt35510_ilde_mode_on_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(idle_on), idle_on}, +}; +#endif + +#if 0 //use platform tear ctrl code +static char set_tear_on[2] = {0x35, 0x00}; +static struct dsi_cmd_desc dsi_tear_on_cmd = { + DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on}; + + +static char set_tear_off[2] = {0x34, 0x00}; +static struct dsi_cmd_desc dsi_tear_off_cmd = { + DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off}; +#endif + +static struct dsi_cmd_desc nt35510_sleep_in_cmds[] = { + //{DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 20, sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 120, sizeof(enter_sleep), enter_sleep}, +// {DTYPE_DCS_WRITE, 1, 0, 0, 5, sizeof(write_ram), write_ram}, +// {DTYPE_DCS_WRITE1, 1, 0, 0, 5, sizeof(STBYB_in), STBYB_in}, +}; + +#if 0 +//static char nt35510_cmd_00[1] = {0x01}; +static char nt35510_cmd_01[5] = { + 0xFF, 0xAA, 0x55, 0x25, + 0x01}; +static char nt35510_cmd_02[9] = { + 0xF3, 0x00, 0x32, 0x00, + 0x38, 0x31, 0x08, 0x11, + 0x00}; +//page 1 +static char nt35510_cmd_03[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x01}; +static char nt35510_cmd_04[4] = {0xB0, 0x05, 0x05, 0x05}; +static char nt35510_cmd_05[4] = {0xB6, 0x44, 0x44, 0x44}; +static char nt35510_cmd_06[4] = {0xB1, 0x05, 0x05, 0x05}; +static char nt35510_cmd_07[4] = {0xB7, 0x34, 0x34, 0x34}; +static char nt35510_cmd_08[4] = {0xB2, 0x03, 0x03, 0x03}; +static char nt35510_cmd_09[4] = {0xB3, 0x0B, 0x0B, 0x0B}; +static char nt35510_cmd_10[4] = {0xB8, 0x25, 0x25, 0x25}; + +static char nt35510_cmd_11[4] = {0xB9, 0x34, 0x34, 0x34}; +static char nt35510_cmd_12[2] = {0xBF, 0x01}; +static char nt35510_cmd_13[4] = {0xB4, 0x2D, 0x2D, 0x2D}; +static char nt35510_cmd_14[4] = {0xB5, 0x08, 0x08, 0x08}; +static char nt35510_cmd_15[4] = {0xBA, 0x24, 0x24, 0x24}; + +static char nt35510_cmd_16[4] = {0xBC, 0x00, 0xc8, 0x00};//{0xBC, 0x00, 0x68, 0x00}; +static char nt35510_cmd_17[4] = {0xBD, 0x00, 0xc8, 0x00};//{0xBD, 0x00, 0x7C, 0x00}; +static char nt35510_cmd_18[3] = {0xBE, 0x00, 0x78};//{0xBE, 0x00, 0x45}; +//gamma 2.2 +static char nt35510_cmd_19[53] = { + 0xd1, 0x00, 0x37, 0x00, + 0xa3, 0x00, 0xc8, 0x00, + 0xe4, 0x00, 0xf8, 0x01, + 0x0c, 0x01, 0x35, 0x01, + 0x61, 0x01, 0x84, 0x01, + 0xb8, 0x01, 0xe0, 0x02, + 0x22, 0x02, 0x57, 0x02, + 0x59, 0x02, 0x87, 0x02, + 0xBa, 0x02, 0xd9, 0x03, + 0x03, 0x03, 0x20, 0x03, + 0x49, 0x03, 0x62, 0x03, + 0x87, 0x03, 0x9e, 0x03, + 0xbc, 0x03, 0xea, 0x03, + 0xf1}; +static char nt35510_cmd_20[53] = { + 0xd2, 0x00, 0x37, 0x00, + 0xa3, 0x00, 0xc8, 0x00, + 0xe4, 0x00, 0xf8, 0x01, + 0x0c, 0x01, 0x35, 0x01, + 0x61, 0x01, 0x84, 0x01, + 0xb8, 0x01, 0xe0, 0x02, + 0x22, 0x02, 0x57, 0x02, + 0x59, 0x02, 0x87, 0x02, + 0xBa, 0x02, 0xd9, 0x03, + 0x03, 0x03, 0x20, 0x03, + 0x49, 0x03, 0x62, 0x03, + 0x87, 0x03, 0x9e, 0x03, + 0xbc, 0x03, 0xea, 0x03, + 0xf1}; +static char nt35510_cmd_21[53] = { + 0xd3, 0x00, 0x37, 0x00, + 0xa3, 0x00, 0xc8, 0x00, + 0xe4, 0x00, 0xf8, 0x01, + 0x0c, 0x01, 0x35, 0x01, + 0x61, 0x01, 0x84, 0x01, + 0xb8, 0x01, 0xe0, 0x02, + 0x22, 0x02, 0x57, 0x02, + 0x59, 0x02, 0x87, 0x02, + 0xBa, 0x02, 0xd9, 0x03, + 0x03, 0x03, 0x20, 0x03, + 0x49, 0x03, 0x62, 0x03, + 0x87, 0x03, 0x9e, 0x03, + 0xbc, 0x03, 0xea, 0x03, + 0xf1}; +static char nt35510_cmd_22[53] = { + 0xd4, 0x00, 0x37, 0x00, + 0xa3, 0x00, 0xc8, 0x00, + 0xe4, 0x00, 0xf8, 0x01, + 0x0c, 0x01, 0x35, 0x01, + 0x61, 0x01, 0x84, 0x01, + 0xb8, 0x01, 0xe0, 0x02, + 0x22, 0x02, 0x57, 0x02, + 0x59, 0x02, 0x87, 0x02, + 0xBa, 0x02, 0xd9, 0x03, + 0x03, 0x03, 0x20, 0x03, + 0x49, 0x03, 0x62, 0x03, + 0x87, 0x03, 0x9e, 0x03, + 0xbc, 0x03, 0xea, 0x03, + 0xf1}; +static char nt35510_cmd_23[53] = { + 0xd5, 0x00, 0x37, 0x00, + 0xa3, 0x00, 0xc8, 0x00, + 0xe4, 0x00, 0xf8, 0x01, + 0x0c, 0x01, 0x35, 0x01, + 0x61, 0x01, 0x84, 0x01, + 0xb8, 0x01, 0xe0, 0x02, + 0x22, 0x02, 0x57, 0x02, + 0x59, 0x02, 0x87, 0x02, + 0xBa, 0x02, 0xd9, 0x03, + 0x03, 0x03, 0x20, 0x03, + 0x49, 0x03, 0x62, 0x03, + 0x87, 0x03, 0x9e, 0x03, + 0xbc, 0x03, 0xea, 0x03, + 0xf1}; +static char nt35510_cmd_24[53] = { + 0xd6, 0x00, 0x37, 0x00, + 0xa3, 0x00, 0xc8, 0x00, + 0xe4, 0x00, 0xf8, 0x01, + 0x0c, 0x01, 0x35, 0x01, + 0x61, 0x01, 0x84, 0x01, + 0xb8, 0x01, 0xe0, 0x02, + 0x22, 0x02, 0x57, 0x02, + 0x59, 0x02, 0x87, 0x02, + 0xBa, 0x02, 0xd9, 0x03, + 0x03, 0x03, 0x20, 0x03, + 0x49, 0x03, 0x62, 0x03, + 0x87, 0x03, 0x9e, 0x03, + 0xbc, 0x03, 0xea, 0x03, + 0xf1}; +//page 0 +static char nt35510_cmd_25[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00}; +/* + static char nt35510_cmd_26[6] = { + 0xB0, 0x00, 0x05, 0x02, + 0x05, 0x02};*/ +static char nt35510_cmd_27[3] = {0xB1, 0xEC, 0x00};//{0xB1, 0xCC, 0x00}; +static char nt35510_cmd_28[2] = {0xB3, 0x00}; +static char nt35510_cmd_29[2] = {0xB6, 0x03}; +static char nt35510_cmd_30[3] = {0xB7, 0x00, 0x00}; +static char nt35510_cmd_31[5] = { + 0xB8, 0x00, 0x06, 0x06, + 0x06}; +static char nt35510_cmd_32[2] = {0xBa, 0x01}; +static char nt35510_cmd_33[4] = {0xBC, 0x00, 0x00, 0x00}; +static char nt35510_cmd_34[6] = { + 0xBD, 0x01, 0x78, 0x06, + 0x50, 0x00}; +static char nt35510_cmd_35[4] = {0xCC, 0x03, 0x01, 0x06}; + + +static char nt35510_cmd_36[2] = {0x36, 0x00}; +static char nt35510_cmd_37[2] = {0x3a, 0x77}; +//pjn add vivid color +static char nt35510_cmd_38[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00}; +static char nt35510_cmd_39[2] = {0xb4, 0x10}; +static char nt35510_cmd_40[5] = { + 0xFF, 0xAA, 0x55, 0x25, + 0x01}; +//light +/* +static char nt35510_cmd_41[12] = { + 0xF9, 0x14, 0x00, 0x05, + 0x09, 0x0d, 0x11, 0x14, + 0x18, 0x1c, 0x20, 0x24};*/ +//medium + +static char nt35510_cmd_41[12] = { + 0xF9, 0x14, 0x00, 0x0a, + 0x11, 0x17, 0x1d, 0x24, + 0x2a, 0x31, 0x37, 0x3d}; +//high +/* +static char nt35510_cmd_41[12] = { + 0xF9, 0x14, 0x00, 0x0d, + 0x1a, 0x26, 0x33, 0x40, + 0x4d, 0x5a, 0x66, 0x73};*/ + +static struct dsi_cmd_desc nt35510_cmd_on_cmds[] = { +// {MIPI_SEND_DATA_TYPE, 1, 0, 0, 120, sizeof(nt35510_cmd_00), nt35510_cmd_00}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_01), nt35510_cmd_01}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_02), nt35510_cmd_02}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_03), nt35510_cmd_03}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_04), nt35510_cmd_04}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_05), nt35510_cmd_05}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_06), nt35510_cmd_06}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_07), nt35510_cmd_07}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_08), nt35510_cmd_08}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_09), nt35510_cmd_09}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_10), nt35510_cmd_10}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_11), nt35510_cmd_11}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_12), nt35510_cmd_12}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_13), nt35510_cmd_13}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_14), nt35510_cmd_14}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_15), nt35510_cmd_15}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_16), nt35510_cmd_16}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_17), nt35510_cmd_17}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_18), nt35510_cmd_18}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_19), nt35510_cmd_19}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_20), nt35510_cmd_20}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_21), nt35510_cmd_21}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_22), nt35510_cmd_22}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_23), nt35510_cmd_23}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_24), nt35510_cmd_24}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_25), nt35510_cmd_25}, + //{MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_26), nt35510_cmd_26}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_27), nt35510_cmd_27}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_28), nt35510_cmd_28}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_29), nt35510_cmd_29}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_30), nt35510_cmd_30}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_31), nt35510_cmd_31}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_32), nt35510_cmd_32}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_33), nt35510_cmd_33}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_34), nt35510_cmd_34}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_35), nt35510_cmd_35}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_36), nt35510_cmd_36}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_37), nt35510_cmd_37}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_38), nt35510_cmd_38}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_39), nt35510_cmd_39}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_40), nt35510_cmd_40}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_41), nt35510_cmd_41}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 120, sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 1, sizeof(set_tear_on), set_tear_on}, + {DTYPE_DCS_WRITE, 1, 0, 0, 20, sizeof(display_on), display_on}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 5, sizeof(write_ram), write_ram}, +}; +#endif + +//pjn add low power glance screen +#if 1 +//static char nt35510_cmd_00[1] = {0x01}; +static char nt35510_cmd_01[5] = { + 0xFF, 0xAA, 0x55, 0x25, + 0x01}; +static char nt35510_cmd_02[9] = { + 0xF3, 0x00, 0x32, 0x00, + 0x38, 0x31, 0x08, 0x11, + 0x00}; +//page 1 +static char nt35510_cmd_03[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x01}; +#if 0 +static char nt35510_cmd_04[4] = {0xB0, 0x05, 0x0C, 0x05}; +static char nt35510_cmd_05[4] = {0xB6, 0x44, 0x14, 0x44}; +static char nt35510_cmd_06[4] = {0xB1, 0x05, 0x0C, 0x05}; +static char nt35510_cmd_07[4] = {0xB7, 0x34, 0x14, 0x34}; +static char nt35510_cmd_08[4] = {0xB2, 0x03, 0x03, 0x03}; +static char nt35510_cmd_09[4] = {0xB3, 0x0B, 0x08, 0x0B}; +static char nt35510_cmd_10[4] = {0xB8, 0x25, 0x25, 0x25}; + +static char nt35510_cmd_11[4] = {0xB9, 0x34, 0x14, 0x34}; +static char nt35510_cmd_12[2] = {0xBF, 0x01}; +static char nt35510_cmd_13[4] = {0xB4, 0x2D, 0x2D, 0x2D}; +static char nt35510_cmd_14[4] = {0xB5, 0x08, 0x08, 0x08}; +static char nt35510_cmd_15[4] = {0xBA, 0x24, 0x24, 0x24}; + +static char nt35510_cmd_16[4] = {0xBC, 0x00, 0x80, 0x00};//{0xBC, 0x00, 0x68, 0x00}; +static char nt35510_cmd_17[4] = {0xBD, 0x00, 0x80, 0x00};//{0xBD, 0x00, 0x7C, 0x00}; +static char nt35510_cmd_18[3] = {0xBE, 0x00, 0x78};//{0xBE, 0x00, 0x45}; + +static char nt35510_cmd_04[4] = {0xB0, 0x05, 0x05, 0x05}; +static char nt35510_cmd_05[4] = {0xB6, 0x44, 0x44, 0x44}; +static char nt35510_cmd_06[4] = {0xB1, 0x05, 0x05, 0x05}; +static char nt35510_cmd_07[4] = {0xB7, 0x34, 0x34, 0x34}; +static char nt35510_cmd_08[4] = {0xB2, 0x03, 0x03, 0x03}; +static char nt35510_cmd_09[4] = {0xB3, 0x0B, 0x0B, 0x0B}; +static char nt35510_cmd_10[4] = {0xB8, 0x25, 0x25, 0x25}; + +static char nt35510_cmd_11[4] = {0xB9, 0x34, 0x34, 0x34}; +static char nt35510_cmd_12[2] = {0xBF, 0x01}; +static char nt35510_cmd_13[4] = {0xB4, 0x2D, 0x2D, 0x2D}; +static char nt35510_cmd_14[4] = {0xB5, 0x08, 0x08, 0x08}; +static char nt35510_cmd_15[4] = {0xBA, 0x24, 0x24, 0x24}; + +static char nt35510_cmd_16[4] = {0xBC, 0x00, 0xc8, 0x00};//{0xBC, 0x00, 0x68, 0x00}; +static char nt35510_cmd_17[4] = {0xBD, 0x00, 0xc8, 0x00};//{0xBD, 0x00, 0x7C, 0x00}; +static char nt35510_cmd_18[3] = {0xBE, 0x00, 0x78};//{0xBE, 0x00, 0x45}; +#else +static char nt35510_cmd_04[4] = {0xB0, 0x05, 0x0C, 0x05}; +static char nt35510_cmd_05[4] = {0xB6, 0x44, 0x34, 0x44}; +static char nt35510_cmd_06[4] = {0xB1, 0x05, 0x0C, 0x05}; +static char nt35510_cmd_07[4] = {0xB7, 0x34, 0x24, 0x34}; +static char nt35510_cmd_08[4] = {0xB2, 0x03, 0x00, 0x03}; +static char nt35510_cmd_09[4] = {0xB3, 0x0B, 0x08, 0x0B}; +static char nt35510_cmd_10[4] = {0xB8, 0x25, 0x25, 0x25}; + +static char nt35510_cmd_11[4] = {0xB9, 0x34, 0x14, 0x34}; +static char nt35510_cmd_12[2] = {0xBF, 0x01}; +static char nt35510_cmd_13[4] = {0xB4, 0x2D, 0x2D, 0x2D}; +static char nt35510_cmd_14[4] = {0xB5, 0x08, 0x08, 0x08}; +static char nt35510_cmd_15[4] = {0xBA, 0x24, 0x14, 0x24}; + +static char nt35510_cmd_16[4] = {0xBC, 0x00, 0x60, 0x00};//{0xBC, 0x00, 0x68, 0x00}; +static char nt35510_cmd_17[4] = {0xBD, 0x00, 0x60, 0x00};//{0xBD, 0x00, 0x7C, 0x00}; +static char nt35510_cmd_18[3] = {0xBE, 0x00, 0x52};//{0xBE, 0x00, 0x45}; +#endif +//gamma 2.2 +static char nt35510_cmd_19[53] = { + 0xD1, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x33, 0x00, + 0x4b, 0x00, 0x5e, 0x00, + 0x7f, 0x00, 0x9f, 0x00, + 0xCb, 0x00, 0xee, 0x01, + 0x2a, 0x01, 0x5f, 0x01, + 0xAf, 0x01, 0xea, 0x01, + 0xEc, 0x02, 0x27, 0x02, + 0x68, 0x02, 0x92, 0x02, + 0xc8, 0x02, 0xe8, 0x03, + 0x25, 0x03, 0x4a, 0x03, + 0x85, 0x03, 0x95, 0x03, + 0xa3, 0x03, 0xD0, 0x03, + 0xFF}; +static char nt35510_cmd_20[53] = { + 0xD2, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x33, 0x00, + 0x4b, 0x00, 0x5e, 0x00, + 0x7f, 0x00, 0x9f, 0x00, + 0xCb, 0x00, 0xee, 0x01, + 0x2a, 0x01, 0x5f, 0x01, + 0xAf, 0x01, 0xea, 0x01, + 0xEc, 0x02, 0x27, 0x02, + 0x68, 0x02, 0x92, 0x02, + 0xc8, 0x02, 0xe8, 0x03, + 0x25, 0x03, 0x4a, 0x03, + 0x85, 0x03, 0x95, 0x03, + 0xa3, 0x03, 0xD0, 0x03, + 0xFF}; +static char nt35510_cmd_21[53] = { + 0xD3, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x33, 0x00, + 0x4b, 0x00, 0x5e, 0x00, + 0x7f, 0x00, 0x9f, 0x00, + 0xCb, 0x00, 0xee, 0x01, + 0x2a, 0x01, 0x5f, 0x01, + 0xAf, 0x01, 0xea, 0x01, + 0xEc, 0x02, 0x27, 0x02, + 0x68, 0x02, 0x92, 0x02, + 0xc8, 0x02, 0xe8, 0x03, + 0x25, 0x03, 0x4a, 0x03, + 0x85, 0x03, 0x95, 0x03, + 0xa3, 0x03, 0xD0, 0x03, + 0xFF}; +static char nt35510_cmd_22[53] = { + 0xD4, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x33, 0x00, + 0x4b, 0x00, 0x5e, 0x00, + 0x7f, 0x00, 0x9f, 0x00, + 0xCb, 0x00, 0xee, 0x01, + 0x2a, 0x01, 0x5f, 0x01, + 0xAf, 0x01, 0xea, 0x01, + 0xEc, 0x02, 0x27, 0x02, + 0x68, 0x02, 0x92, 0x02, + 0xc8, 0x02, 0xe8, 0x03, + 0x25, 0x03, 0x4a, 0x03, + 0x85, 0x03, 0x95, 0x03, + 0xa3, 0x03, 0xD0, 0x03, + 0xFF}; +static char nt35510_cmd_23[53] = { + 0xD5, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x33, 0x00, + 0x4b, 0x00, 0x5e, 0x00, + 0x7f, 0x00, 0x9f, 0x00, + 0xCb, 0x00, 0xee, 0x01, + 0x2a, 0x01, 0x5f, 0x01, + 0xAf, 0x01, 0xea, 0x01, + 0xEc, 0x02, 0x27, 0x02, + 0x68, 0x02, 0x92, 0x02, + 0xc8, 0x02, 0xe8, 0x03, + 0x25, 0x03, 0x4a, 0x03, + 0x85, 0x03, 0x95, 0x03, + 0xa3, 0x03, 0xD0, 0x03, + 0xFF}; +static char nt35510_cmd_24[53] = { + 0xD6, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x33, 0x00, + 0x4b, 0x00, 0x5e, 0x00, + 0x7f, 0x00, 0x9f, 0x00, + 0xCb, 0x00, 0xee, 0x01, + 0x2a, 0x01, 0x5f, 0x01, + 0xAf, 0x01, 0xea, 0x01, + 0xEc, 0x02, 0x27, 0x02, + 0x68, 0x02, 0x92, 0x02, + 0xc8, 0x02, 0xe8, 0x03, + 0x25, 0x03, 0x4a, 0x03, + 0x85, 0x03, 0x95, 0x03, + 0xa3, 0x03, 0xD0, 0x03, + 0xFF}; +//page 0 +static char nt35510_cmd_25[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00}; +/* + static char nt35510_cmd_26[6] = { + 0xB0, 0x00, 0x05, 0x02, + 0x05, 0x02};*/ +static char nt35510_cmd_27[3] = {0xB1, 0xEC, 0x00};//{0xB1, 0xCC, 0x00}; +static char nt35510_cmd_28[2] = {0xB3, 0x00}; +static char nt35510_cmd_29[2] = {0xB6, 0x03}; +static char nt35510_cmd_30[3] = {0xB7, 0x00, 0x00}; +static char nt35510_cmd_31[5] = { + 0xB8, 0x00, 0x06, 0x06, + 0x06}; +static char nt35510_cmd_32[2] = {0xBa, 0x01}; +static char nt35510_cmd_33[4] = {0xBC, 0x00, 0x00, 0x00}; +static char nt35510_cmd_34[6] = { + 0xBE, 0x01, 0x84, 0x1C, + 0x1C, 0x01}; +static char nt35510_cmd_35[4] = {0xCC, 0x03, 0x01, 0x06}; + + +static char nt35510_cmd_36[2] = {0x36, 0x00}; +static char nt35510_cmd_37[2] = {0x3a, 0x77}; +//pjn add vivid color +static char nt35510_cmd_38[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00}; +static char nt35510_cmd_39[2] = {0xb4, 0x10}; +static char nt35510_cmd_40[5] = { + 0xFF, 0xAA, 0x55, 0x25, + 0x01}; +//light +/* +static char nt35510_cmd_41[12] = { + 0xF9, 0x14, 0x00, 0x05, + 0x09, 0x0d, 0x11, 0x14, + 0x18, 0x1c, 0x20, 0x24};*/ +//medium + +static char nt35510_cmd_41[12] = { + 0xF9, 0x14, 0x00, 0x0a, + 0x11, 0x17, 0x1d, 0x24, + 0x2a, 0x31, 0x37, 0x3d}; +//high +/* +static char nt35510_cmd_41[12] = { + 0xF9, 0x14, 0x00, 0x0d, + 0x1a, 0x26, 0x33, 0x40, + 0x4d, 0x5a, 0x66, 0x73};*/ + +static struct dsi_cmd_desc nt35510_cmd_on_cmds[] = { +// {MIPI_SEND_DATA_TYPE, 1, 0, 0, 120, sizeof(nt35510_cmd_00), nt35510_cmd_00}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_01), nt35510_cmd_01}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_02), nt35510_cmd_02}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_03), nt35510_cmd_03}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_04), nt35510_cmd_04}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_05), nt35510_cmd_05}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_06), nt35510_cmd_06}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_07), nt35510_cmd_07}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_08), nt35510_cmd_08}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_09), nt35510_cmd_09}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_10), nt35510_cmd_10}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_11), nt35510_cmd_11}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_12), nt35510_cmd_12}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_13), nt35510_cmd_13}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_14), nt35510_cmd_14}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_15), nt35510_cmd_15}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_16), nt35510_cmd_16}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_17), nt35510_cmd_17}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_18), nt35510_cmd_18}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_19), nt35510_cmd_19}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_20), nt35510_cmd_20}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_21), nt35510_cmd_21}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_22), nt35510_cmd_22}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_23), nt35510_cmd_23}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_24), nt35510_cmd_24}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_25), nt35510_cmd_25}, + //{MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_26), nt35510_cmd_26}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_27), nt35510_cmd_27}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_28), nt35510_cmd_28}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_29), nt35510_cmd_29}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_30), nt35510_cmd_30}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_31), nt35510_cmd_31}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_32), nt35510_cmd_32}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_33), nt35510_cmd_33}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_34), nt35510_cmd_34}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_35), nt35510_cmd_35}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_36), nt35510_cmd_36}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_37), nt35510_cmd_37}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_38), nt35510_cmd_38}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_39), nt35510_cmd_39}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_40), nt35510_cmd_40}, + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_41), nt35510_cmd_41}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 120, sizeof(exit_sleep), exit_sleep}, +}; + +static struct dsi_cmd_desc nt35510_cmd_on_cmds_1[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 5, sizeof(display_on), display_on}, + //{DTYPE_DCS_WRITE, 1, 0, 0, 1, sizeof(set_tear_on), set_tear_on}, + {DTYPE_DCS_WRITE, 1, 0, 0, 5, sizeof(write_ram), write_ram}, +}; +#endif + +//pjn end +static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = { +#if 0 + /* DSI_BIT_CLK at 350MHz, 2 lane, RGB888 */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + /*{0x69, 0x2B, 0x0D, 0x00, 0x37, 0x3C, 0x12, 0x2E, + 0x10, 0x03, 0x04},*/ + {0x69, 0x2B, 0x0D, 0x00, 0x37, 0x3C, 0x1f, 0x35, + 0x10, 0x07, 0x04}, //pjn modify + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x01, 0x59, 0x31, 0xD2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0F, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +#else + /* DSI_BIT_CLK at 460MHz, 2 lane, RGB888 */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + /*{0x69, 0x2B, 0x0D, 0x00, 0x37, 0x3C, 0x12, 0x2E, + 0x10, 0x03, 0x04},*/ + {0x82, 0x31, 0x12, 0x00, 0x41, 0x4A, 0x16, 0x35, + 0x16, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x01, 0xC6, 0x31, 0xD2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0F, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +#endif +}; + +//pjn add read 0x0a register + +static char nt35510_cmd_page1[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x01}; + +static struct dsi_cmd_desc nt35510_change_page[] = { + {MIPI_SEND_DATA_TYPE, 1, 0, 0, 0, sizeof(nt35510_cmd_page1), nt35510_cmd_page1}, +}; + +static u32 mipi_nt35510_read_reg(struct msm_fb_data_type *mfd, u16 reg, int page) +{ + u32 data; + int len = 4; + + struct dsi_cmd_desc cmd_read_reg = { + DTYPE_GEN_READ2, 1, 0, 1, 0, /* cmd 0x24 */ + sizeof(reg), (char *) ®}; + + mipi_dsi_buf_init(&nt35510_tx_buf); + mipi_dsi_buf_init(&nt35510_rx_buf); + + if(page) + /* mutex had been acquired at mipi_dsi_on */ + mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_change_page, ARRAY_SIZE(nt35510_change_page)); + + len = mipi_dsi_cmds_rx(mfd, &nt35510_tx_buf, &nt35510_rx_buf, + &cmd_read_reg, len); + + data = *(u32 *)nt35510_rx_buf.data; + + printk("[==wxj==]%s: reg=0x%x.data=0x%08x\n", __func__, reg, data); + + return data; +} + +static int msm_lcm_send_init_code(void) +{ + int ret = 0; + my_prepare_enable_clocks(); + msleep(80); + ret = mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_cmd_on_cmds, + ARRAY_SIZE(nt35510_cmd_on_cmds)); + my_unprepare_disable_clocks(); + msleep(16); + + my_prepare_enable_clocks(); + msleep(80); + ret = mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_cmd_on_cmds_1, + ARRAY_SIZE(nt35510_cmd_on_cmds_1)); + msleep(16); + my_unprepare_disable_clocks(); + return ret; +} + +static void msm_lcm_reset(void) +{ + printk(KERN_INFO "[DISPLAY] begain to reset panel\n"); + gpio_direction_output(LCM_RESET_GPIO_PIN85, 1); + msleep(1); + gpio_direction_output(LCM_RESET_GPIO_PIN85, 0); + msleep(3); + gpio_direction_output(LCM_RESET_GPIO_PIN85, 1); + msleep(30); +} + +#define POWER_ON_NOT_BOOTLOGO 1 +static int mipi_nt35510_gpio_init(void) +{ + int ret; + { + printk(KERN_INFO"[DISPLAY] %s called\n",__func__); + + ret = gpio_request(LCM_RESET_GPIO_PIN85, "odmm_gpio_reset_en"); + if(ret < 0) + printk(KERN_ERR" LCM_RESET_GPIO_PIN85 request failed\n"); + + ret=gpio_tlmm_config( + GPIO_CFG( + LCM_RESET_GPIO_PIN85, + 0, + GPIO_CFG_OUTPUT, //LCDC DEN + GPIO_CFG_PULL_UP, + GPIO_CFG_4MA), + GPIO_CFG_ENABLE); + + if(ret) + { + printk(KERN_DEBUG"Failure to set LCM_RESET_GPIO_PIN85 config\n"); + return -1; + } + } + + ret = gpio_request(LCM_1LED_CTRL_GPIO_PIN121,"lcm_gpio_1led_en"); + if (ret < 0){ + printk(KERN_INFO" pjn=== GPIO121 request failed\n"); + return ret; + } + + ret = gpio_tlmm_config( + GPIO_CFG( + 121, + 0, + GPIO_CFG_OUTPUT, //LCDC DEN + GPIO_CFG_PULL_UP,//GPIO_CFG_PULL_UP,//GPIO_CFG_PULL_UP, + GPIO_CFG_4MA), + GPIO_CFG_ENABLE); + if(ret) + { + printk(KERN_DEBUG"Failure to set LCM_1LED_CTRL_GPIO_PIN121 config\n"); + return -1; + } + + gpio_request(LCM_ID_GPIO_PIN120, "odmm_panel_id"); + gpio_tlmm_config(GPIO_CFG(LCM_ID_GPIO_PIN120, 0, + GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, + GPIO_CFG_2MA), + GPIO_CFG_ENABLE); + + gpio_export(LCM_RESET_GPIO_PIN85, 0); + gpio_export(LCM_1LED_CTRL_GPIO_PIN121, 0); + gpio_export(LCM_ID_GPIO_PIN120, 0); + + gpio_direction_output(LCM_1LED_CTRL_GPIO_PIN121, 0); + + return 0; +} + +static int mipi_nt35510_lcd_on(struct platform_device *pdev) +{ + + struct msm_fb_data_type *mfd; + + MSM_DRM_DEBUG("start. \n"); + + mfd = platform_get_drvdata(pdev); + if (!mfd) + { + printk("%s [DISPLAY:mfd] \n", __func__); + return -ENODEV; + } + if (!mfd->cont_splash_done) + { + mfd->cont_splash_done = 1; + printk(" %s [DISPLAY:cont_splash_done] \n", __func__); + return 0; + } + + pr_debug("platform_get_drvdata success \n"); + if (mfd->key != MFD_KEY) + { + printk(" %s [DISPLAY:MFD_KEY] \n", __func__); + return -EINVAL; + } + MSM_DRM_DEBUG("MFD_KEY Okay\n"); + + down(&nt35510_sem); + if (glanceview_resume_statues()) + { + printk("%s(glance 3)=%d skip init\n",__func__,nt35510_state.disp_powered_up); + nt35510_state.disp_powered_up = NT35510_STATUS_LCD_GLANSCREEN_ON; + } + else + { + if(nt35510_state.disp_powered_up == NT35510_STATUS_LCD_SLEEP) + { + printk("%s(0)=%d deep sleep to normal\n",__func__,nt35510_state.disp_powered_up); + + msm_lcm_reset(); + //mipi_set_tx_power_mode(1); +#if 0 + mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_cmd_on_cmds, + ARRAY_SIZE(nt35510_cmd_on_cmds)); + mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_cmd_on_cmds_1, + ARRAY_SIZE(nt35510_cmd_on_cmds_1)); +#endif + msm_lcm_send_init_code(); + //mipi_set_tx_power_mode(0); + } + + else if(nt35510_state.disp_powered_up == NT35510_STATUS_LCD_GLANSCREEN_OFF) + { + printk("%s(3)=%d idle mode to normal\n",__func__,nt35510_state.disp_powered_up); + //nt35510_backlight_set(0); + //gpio_direction_output(LCM_1LED_CTRL_GPIO_PIN121, 0); + glanceview_oneled_state_ctrl(0); + //pjn add lcd reset + msm_lcm_reset(); + + msm_lcm_send_init_code(); + } + else + { + printk("%s(error)=%d\n",__func__,nt35510_state.disp_powered_up); + + //gpio_direction_output(LCM_1LED_CTRL_GPIO_PIN121, 0); + glanceview_oneled_state_ctrl(0); + + msm_lcm_reset(); + //mipi_set_tx_power_mode(1); + msm_lcm_send_init_code(); + + //mipi_set_tx_power_mode(0); + } + nt35510_state.disp_powered_up = NT35510_STATUS_LCD_ON; + + mipi_dsi_te_ctrl(mfd, 1); + } + + up(&nt35510_sem); + + MSM_DRM_DEBUG("end.\n"); + return 0; +} + +//pjn add for glance scrren +int mipi_nt35510_glance_screen(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + int gpio121_val = 2; + mfd = platform_get_drvdata(pdev); + + MSM_DRM_DEBUG("start.\n"); + if (!mfd) + { + printk("%s mfd == NULL\n",__func__); + return -ENODEV; + } + + if (glancescreen_flag) { + gpio121_val = gpio_get_value_cansleep(LCM_1LED_CTRL_GPIO_PIN121); + if((!gpio121_val) && glancescreen_suspend_flag){ + gpio_set_value_cansleep(LCM_1LED_CTRL_GPIO_PIN121, 1); + } + return 0; + } + + down(&nt35510_sem); + nt35510_backlight_set(0); + msm_lcm_reset(); + //mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_lp_cmd_on_cmds, + //ARRAY_SIZE(nt35510_lp_cmd_on_cmds)); + glancescreen_flag = 1; + nt35510_state.disp_powered_up = NT35510_STATUS_LCD_GLANSCREEN_OFF; + up(&nt35510_sem); + + MSM_DRM_DEBUG(" end.\n"); + return 0; +} + +static int mipi_nt35510_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + //int gpio121_val = 2; + + mfd = platform_get_drvdata(pdev); + + MSM_DRM_DEBUG(" start.\n"); + + down(&nt35510_sem); + + mipi_dsi_te_ctrl(mfd, 0); + + if (glanceview_suspend_statues()) + { + if (nt35510_state.disp_powered_up == NT35510_STATUS_LCD_GLANSCREEN_ON) + { + printk("%s(glance 2)=%d \n", __func__,nt35510_state.disp_powered_up); + + if (glancescreen_flag == 1) + { + //move oneled control owner to OS, it will be much more better + //msleep(2); + //gpio_set_value_cansleep(LCM_1LED_CTRL_GPIO_PIN121, 1); + glancescreen_flag = 2; + printk("%s(glance backlight)=%d \n", __func__,nt35510_state.disp_powered_up); + } + } + else + { + printk("%s(glance other)=%d,\n", __func__,nt35510_state.disp_powered_up); + mipi_nt35510_gs_set_backlight(0); + + mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_ilde_mode_on_cmds, + ARRAY_SIZE(nt35510_ilde_mode_on_cmds)); + + glancescreen_flag = 1; + } + nt35510_state.disp_powered_up = NT35510_STATUS_LCD_GLANSCREEN_OFF; + + } + else + { + if(nt35510_state.disp_powered_up == NT35510_STATUS_LCD_ON ) + { + printk("%s(1)=%d\n",__func__,nt35510_state.disp_powered_up); + + //mipi_set_tx_power_mode(1); + + mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_sleep_in_cmds, + ARRAY_SIZE(nt35510_sleep_in_cmds)); + + //mipi_set_tx_power_mode(0); + gpio_direction_output(LCM_RESET_GPIO_PIN85, 0); + } + + else if(nt35510_state.disp_powered_up == NT35510_STATUS_LCD_GLANSCREEN_ON) + { + printk("%s(2)=%d\n",__func__,nt35510_state.disp_powered_up); + //gpio_direction_output(LCM_1LED_CTRL_GPIO_PIN121, 0); + glanceview_oneled_state_ctrl(0); + + //mipi_set_tx_power_mode(1); + + mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_sleep_in_cmds, + ARRAY_SIZE(nt35510_sleep_in_cmds)); + + //mipi_set_tx_power_mode(0); + gpio_direction_output(LCM_RESET_GPIO_PIN85, 0); + } + else + { + printk("%s(error)=%d\n",__func__,nt35510_state.disp_powered_up); + //gpio_direction_output(LCM_1LED_CTRL_GPIO_PIN121, 0); + glanceview_oneled_state_ctrl(0); + + //mipi_set_tx_power_mode(1); + + mipi_dsi_cmds_tx(&nt35510_tx_buf, nt35510_sleep_in_cmds, + ARRAY_SIZE(nt35510_sleep_in_cmds)); + + //mipi_set_tx_power_mode(0); + gpio_direction_output(LCM_RESET_GPIO_PIN85, 0); + + } + nt35510_state.disp_powered_up = NT35510_STATUS_LCD_SLEEP; + } + + up(&nt35510_sem); + MSM_DRM_DEBUG(" end.\n"); + return 0; +} + +#define PERPH_WEB_BLOCK_ADDR (0xA9D00040) +#define PDM0_CTL_OFFSET (0x04) +#define SIZE_8B (0x08) +#define PDM_DUTY_MAXVAL BIT(16) +#define PDM_DUTY_REFVAL BIT(15) +#define LED_FULL 255 + +static void nt35510_backlight_set(int level) +{ + int ret = 0; + if(unlikely(!nt35510_state.bk_init)){ + pmapp_disp_backlight_init(); + nt35510_state.bk_init = TRUE; + } + + if(level > 0) + gpio_direction_output(LCM_1LED_CTRL_GPIO_PIN121, 0); + + ret = pmapp_disp_backlight_set_brightness(level*255/255); + if (ret) + printk(KERN_ERR" can't set backlight level=%d\n",level); +} + +static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd) +{ + + int level; + + level = mfd->bl_level; + + printk(KERN_INFO"[DISPLAY] current_bl=%d; target_bl=%d\n", mddi_current_bl, level); +// if(mddi_current_bl == level) +// return; + + nt35510_backlight_set(level); + mddi_current_bl = level; + + return; +} + +static void mipi_nt35510_gs_set_backlight(int level) +{ + printk("mipi_nt35510_gs_set_backlight()=%d\n",level); + nt35510_backlight_set(level); +} + + +static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev) +{ + printk(KERN_INFO "[DISPLAY] %s is called\n", __func__); + if (pdev->id == 0) + { + mipi_nt35510_pdata = pdev->dev.platform_data; + return 0; + } + + nt35510_state.disp_initialized = TRUE; + nt35510_state.disp_powered_up = NT35510_STATUS_LCD_ON;// first poweron don't reset lcd + + msm_fb_add_device(pdev); + + mipi_nt35510_gpio_init(); + + return 0; +} + + +static void mipi_nt35510_shutdown(struct platform_device *pdev) +{ + printk(KERN_INFO "[DISPLAY] %s is called\n", __func__); + nt35510_backlight_set(0); + gpio_direction_output(LCM_RESET_GPIO_PIN85, 0); + gpio_free(LCM_RESET_GPIO_PIN85); + msleep(120); +} + +static struct platform_driver this_driver = { + .probe = mipi_nt35510_lcd_probe, + .shutdown = mipi_nt35510_shutdown, + .driver = { + .name = "mipi_nt35510", + }, +}; + +static struct msm_fb_panel_data nt35510_panel_data = { + .on = mipi_nt35510_lcd_on, + .off = mipi_nt35510_lcd_off, + .glance_screen = mipi_nt35510_glance_screen, + .set_backlight = mipi_nt35510_set_backlight, +}; + +static struct platform_device this_device = { + .name = "mipi_nt35510", + .id = 2, + .dev = { + .platform_data = &nt35510_panel_data, + } +}; + +static int __init mipi_div4_nt35510_lcd_init(void) +{ + int ret; + + #if 1 + gpio_request(LCM_ID_GPIO_PIN120, "odmm_panel_id"); + gpio_tlmm_config(GPIO_CFG(LCM_ID_GPIO_PIN120, 0, + GPIO_CFG_INPUT, + GPIO_CFG_NO_PULL, + GPIO_CFG_2MA), + GPIO_CFG_ENABLE); + + ODMM_PANEL_ID = gpio_get_value_cansleep(LCM_ID_GPIO_PIN120); + if(ODMM_PANEL_ID == 0){ + strncpy(panel_detect_desc, "N1 DIV4 CMD", 16); + printk(KERN_INFO "[DISPLAY]Detect Device Used DIV4 Panel as ODMM_PANEL_ID = %d\n", ODMM_PANEL_ID); + }else{ + strncpy(panel_detect_desc, "N1 TRUST CMD", 16); + printk(KERN_INFO "[DISPLAY]Detect Device Used TRUST Panel as ODMM_PANEL_ID = %d\n", ODMM_PANEL_ID); + } + gpio_free(LCM_ID_GPIO_PIN120); + #endif + + //if(odmm_nt35510_lcd_id != ODMM_35516_nt35510_ID) + // return 0; + + mipi_dsi_buf_alloc(&nt35510_tx_buf, DSI_BUF_SIZE);//mipi cmd buffer + mipi_dsi_buf_alloc(&nt35510_rx_buf, DSI_BUF_SIZE); + + ret = platform_driver_register(&this_driver); + if (ret) + { + printk(KERN_ERR"[DISPLAY] %s platform_driver_register FAILED\n", __func__); + return ret; + } + + pinfo.xres = 480; + pinfo.yres = 800; + pinfo.type = MIPI_CMD_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + + pinfo.lcdc.h_back_porch = 29; + pinfo.lcdc.h_front_porch = 7; + pinfo.lcdc.h_pulse_width = 3;//8; + pinfo.lcdc.v_back_porch = 12; + pinfo.lcdc.v_front_porch = 16; + pinfo.lcdc.v_pulse_width = 5;////1; + + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 255;//16; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.clk_rate = 350000000; + + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.hw_vsync_mode = TRUE; + pinfo.lcd.refx100 = 6200; //6000; //6200/* adjust refx100 to prevent tearing */ + pinfo.lcd.v_back_porch = 12; + pinfo.lcd.v_front_porch = 16; + pinfo.lcd.v_pulse_width = 5;////1; + + pinfo.mipi.mode = DSI_CMD_MODE; + pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_BGR;//DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2F; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW_TE;//DSI_CMD_TRIGGER_SW_TE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsync gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; + pinfo.mipi.tx_eot_append = 0x01; + pinfo.mipi.rx_eot_ignore = 0x0; + pinfo.mipi.dlane_swap = 0x01; + + nt35510_panel_data.panel_info = pinfo; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + pmapp_disp_backlight_init(); + + return ret; +} +struct dsi_buf * get_lcd_mipi_tx_buf(void) +{ + return &nt35510_tx_buf; +} +module_init(mipi_div4_nt35510_lcd_init); diff --git a/drivers/video/msm/mipi_div4_nt35510_cmd_wvga.c b/drivers/video/msm/mipi_div4_nt35510_cmd_wvga.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c index 7848dbcb..d34fa560 100644 --- a/drivers/video/msm/mipi_dsi.c +++ b/drivers/video/msm/mipi_dsi.c @@ -100,6 +100,8 @@ static int mipi_dsi_off(struct platform_device *pdev) struct msm_fb_data_type *mfd; struct msm_panel_info *pinfo; + pr_debug("%s+:\n", __func__); + mfd = platform_get_drvdata(pdev); pinfo = &mfd->panel_info; @@ -113,7 +115,7 @@ static int mipi_dsi_off(struct platform_device *pdev) /* make sure dsi clk is on so that * dcs commands can be sent */ - mipi_dsi_clk_cfg(1); + mipi_dsi_clk_cfg(1); /* make sure dsi_cmd_mdp is idle */ mipi_dsi_cmd_mdp_busy(); @@ -130,13 +132,11 @@ static int mipi_dsi_off(struct platform_device *pdev) if (MDP_REV_303 != mdp_rev) gpio_free(vsync_gpio); } - //ensure platform TE off modify TE IRQ GPIO to output 0 - //mipi_dsi_set_tear_off(mfd); + mipi_dsi_set_tear_off(mfd); } } ret = panel_next_off(pdev); - #ifdef CONFIG_MSM_BUS_SCALING mdp_bus_scale_update_request(0); #endif @@ -152,7 +152,7 @@ static int mipi_dsi_off(struct platform_device *pdev) mipi_dsi_ahb_ctrl(0); spin_unlock_bh(&dsi_clk_lock); - mipi_dsi_unprepare_clocks(); + mipi_dsi_unprepare_clocks(); if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save) mipi_dsi_pdata->dsi_power_save(0); @@ -180,6 +180,8 @@ static int mipi_dsi_on(struct platform_device *pdev) u32 dummy_xres, dummy_yres; int target_type = 0; + pr_debug("%s+:\n", __func__); + mfd = platform_get_drvdata(pdev); fbi = mfd->fbi; var = &fbi->var; @@ -236,8 +238,7 @@ static int mipi_dsi_on(struct platform_device *pdev) width + dummy_xres + hfp - 1)); } else { /* DSI_LAN_SWAP_CTRL */ - MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, - mipi_dsi_pdata->dlane_swap); + MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, mipi->dlane_swap); MIPI_OUTP(MIPI_DSI_BASE + 0x20, ((hbp + width + dummy_xres) << 16 | (hbp))); @@ -275,7 +276,7 @@ static int mipi_dsi_on(struct platform_device *pdev) MIPI_OUTP(MIPI_DSI_BASE + 0x58, data); } - mipi_dsi_host_init(mipi, mipi_dsi_pdata->dlane_swap); + mipi_dsi_host_init(mipi); if (mipi->force_clk_lane_hs) { u32 tmp; @@ -290,8 +291,9 @@ static int mipi_dsi_on(struct platform_device *pdev) mutex_lock(&mfd->dma->ov_mutex); else down(&mfd->dma->mutex); - - ret = panel_next_on(pdev); + + if (mfd->op_enable) + ret = panel_next_on(pdev); mipi_dsi_op_mode_config(mipi->mode); @@ -325,7 +327,9 @@ static int mipi_dsi_on(struct platform_device *pdev) __func__, vsync_gpio); } tlmm_settings = TRUE; - gpio_direction_input(vsync_gpio); + + gpio_direction_input( + vsync_gpio); } else { if (!tlmm_settings) { pr_err( @@ -336,16 +340,10 @@ static int mipi_dsi_on(struct platform_device *pdev) } } } - //this is the platform base logic, the tear will turn on every wake up - //LCM driver will do this so skip it here - //mipi_dsi_set_tear_on(mfd); + mipi_dsi_set_tear_on(mfd); } } -#ifdef CONFIG_MSM_BUS_SCALING - mdp_bus_scale_update_request(2); -#endif - mdp4_overlay_dsi_state_set(ST_DSI_RESUME); if (mdp_rev >= MDP_REV_41) @@ -359,6 +357,12 @@ static int mipi_dsi_on(struct platform_device *pdev) } +static int mipi_dsi_late_init(struct platform_device *pdev) +{ + return panel_next_late_init(pdev); +} + + static int mipi_dsi_resource_initialized; static int mipi_dsi_probe(struct platform_device *pdev) @@ -505,6 +509,7 @@ static int mipi_dsi_probe(struct platform_device *pdev) pdata = mdp_dev->dev.platform_data; pdata->on = mipi_dsi_on; pdata->off = mipi_dsi_off; + pdata->late_init = mipi_dsi_late_init; pdata->next = pdev; /* diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h index ef6bddff..38e31763 100644 --- a/drivers/video/msm/mipi_dsi.h +++ b/drivers/video/msm/mipi_dsi.h @@ -117,6 +117,7 @@ enum dsi_trigger_type { #define DSI_INTR_CMD_DMA_DONE_MASK BIT(1) #define DSI_INTR_CMD_DMA_DONE BIT(0) +#define DSI_VIDEO_TERM BIT(16) #define DSI_MDP_TERM BIT(8) #define DSI_CMD_TERM BIT(0) @@ -188,7 +189,7 @@ struct dsi_clk_desc { #define DSI_HDR_DATA1(data) ((data) & 0x0ff) #define DSI_HDR_WC(wc) ((wc) & 0x0ffff) -#define DSI_BUF_SIZE 64 +#define DSI_BUF_SIZE 1024 #define MIPI_DSI_MRPS 0x04 /* Maximum Return Packet Size */ #define MIPI_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */ @@ -298,7 +299,7 @@ int mipi_dsi_cmds_rx(struct msm_fb_data_type *mfd, struct dsi_buf *tp, struct dsi_buf *rp, struct dsi_cmd_desc *cmds, int len); int mipi_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen); -void mipi_dsi_host_init(struct mipi_panel_info *pinfo, char dlane_swap); +void mipi_dsi_host_init(struct mipi_panel_info *pinfo); void mipi_dsi_op_mode_config(int mode); void mipi_dsi_cmd_mode_ctrl(int enable); void mdp4_dsi_cmd_trigger(void); @@ -347,6 +348,8 @@ int mipi_dsi_cmdlist_put(struct dcs_cmd_req *cmdreq); struct dcs_cmd_req *mipi_dsi_cmdlist_get(void); void mipi_dsi_cmdlist_commit(int from_mdp); void mipi_dsi_cmd_mdp_busy(void); +void mipi_dsi_configure_fb_divider(u32 fps_level); +void mipi_dsi_wait4video_done(void); #ifdef CONFIG_FB_MSM_MDP303 void update_lane_config(struct msm_panel_info *pinfo); diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c index 94c0df76..3e11c844 100644 --- a/drivers/video/msm/mipi_dsi_host.c +++ b/drivers/video/msm/mipi_dsi_host.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,7 @@ static struct completion dsi_dma_comp; static struct completion dsi_mdp_comp; +static struct completion dsi_video_comp; static struct dsi_buf dsi_tx_buf; static struct dsi_buf dsi_rx_buf; static spinlock_t dsi_irq_lock; @@ -92,6 +94,7 @@ void mipi_dsi_init(void) { init_completion(&dsi_dma_comp); init_completion(&dsi_mdp_comp); + init_completion(&dsi_video_comp); mipi_dsi_buf_alloc(&dsi_tx_buf, DSI_BUF_SIZE); mipi_dsi_buf_alloc(&dsi_rx_buf, DSI_BUF_SIZE); spin_lock_init(&dsi_irq_lock); @@ -183,6 +186,8 @@ void mipi_dsi_clk_cfg(int on) } } } + pr_debug("%s: on=%d clk_cnt=%d pid=%d\n", __func__, ++ on, dsi_clk_cnt, current->pid); spin_unlock_irqrestore(&mdp_spin_lock, flags); } @@ -814,7 +819,7 @@ static int mipi_dsi_long_read_resp(struct dsi_buf *rp) return len; } -void mipi_dsi_host_init(struct mipi_panel_info *pinfo, char dlane_swap) +void mipi_dsi_host_init(struct mipi_panel_info *pinfo) { uint32 dsi_ctrl, intr_ctrl; uint32 data; @@ -905,7 +910,7 @@ void mipi_dsi_host_init(struct mipi_panel_info *pinfo, char dlane_swap) MIPI_OUTP(MIPI_DSI_BASE + 0x0080, data); /* DSI_TRIG_CTRL */ /* DSI_LAN_SWAP_CTRL */ - MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, dlane_swap); + MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, pinfo->dlane_swap); /* clock out ctrl */ data = pinfo->t_clk_post & 0x3f; /* 6 bits */ @@ -964,31 +969,30 @@ void mipi_dsi_controller_cfg(int enable) uint32 dsi_ctrl; uint32 status; - int cnt; - - cnt = 16; - while (cnt--) { - status = MIPI_INP(MIPI_DSI_BASE + 0x0004); - status &= 0x02; /* CMD_MODE_DMA_BUSY */ - if (status == 0) - break; - usleep(1000); - } - if (cnt == 0) + u32 sleep_us = 1000; + u32 timeout_us = 16000; + + /* Check for CMD_MODE_DMA_BUSY */ + if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004), + status, + ((status & 0x02) == 0), + sleep_us, timeout_us)) pr_info("%s: DSI status=%x failed\n", __func__, status); - cnt = 16; - while (cnt--) { - status = MIPI_INP(MIPI_DSI_BASE + 0x0008); - status &= 0x11111000; /* x_HS_FIFO_EMPTY */ - if (status == 0x11111000) /* all empty */ - break; - usleep(1000); - } - - if (cnt == 0) + /* Check for x_HS_FIFO_EMPTY */ + if (readl_poll_timeout((MIPI_DSI_BASE + 0x0008), + status, + ((status & 0x11111000) == 0x11111000), + sleep_us, timeout_us)) pr_info("%s: FIFO status=%x failed\n", __func__, status); + /* Check for VIDEO_MODE_ENGINE_BUSY */ + if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004), + status, + ((status & 0x08) == 0), + sleep_us, timeout_us)) + pr_info("%s: DSI status=%x failed\n", __func__, status); + dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000); if (enable) dsi_ctrl |= 0x01; @@ -1008,7 +1012,8 @@ void mipi_dsi_op_mode_config(int mode) dsi_ctrl &= ~0x07; if (mode == DSI_VIDEO_MODE) { dsi_ctrl |= 0x03; - intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK; + intr_ctrl = (DSI_INTR_CMD_DMA_DONE_MASK | + DSI_INTR_VIDEO_DONE_MASK); } else { /* command mode */ dsi_ctrl |= 0x05; intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK | @@ -1021,6 +1026,18 @@ void mipi_dsi_op_mode_config(int mode) MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); wmb(); } +void mipi_dsi_wait4video_done(void) +{ + unsigned long flag; + + spin_lock_irqsave(&dsi_mdp_lock, flag); + INIT_COMPLETION(dsi_video_comp); + mipi_dsi_enable_irq(DSI_VIDEO_TERM); + spin_unlock_irqrestore(&dsi_mdp_lock, flag); + + wait_for_completion_timeout(&dsi_video_comp, + msecs_to_jiffies(VSYNC_PERIOD * 4)); +} void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd) { @@ -1056,6 +1073,7 @@ void mipi_dsi_cmd_mdp_start(void) spin_lock_irqsave(&dsi_mdp_lock, flag); mipi_dsi_enable_irq(DSI_MDP_TERM); dsi_mdp_busy = TRUE; + INIT_COMPLETION(dsi_mdp_comp); spin_unlock_irqrestore(&dsi_mdp_lock, flag); } @@ -1458,8 +1476,7 @@ int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp) { unsigned long flags; - unsigned long timeout; - + #ifdef DSI_HOST_DEBUG int i; char *bp; @@ -1495,10 +1512,7 @@ int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp) wmb(); spin_unlock_irqrestore(&dsi_mdp_lock, flags); - //wait_for_completion(&dsi_dma_comp); - timeout = wait_for_completion_timeout(&dsi_dma_comp, msecs_to_jiffies(200)); - if(!timeout) - printk(KERN_INFO "%s[MIPI]dsi send data timeout!\n", __func__); + wait_for_completion(&dsi_dma_comp); dma_unmap_single(&dsi_dev, tp->dmap, tp->len, DMA_TO_DEVICE); tp->dmap = 0; @@ -1532,28 +1546,35 @@ int mipi_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen) return rlen; } +static void mipi_dsi_wait4video_eng_busy(void) +{ + mipi_dsi_wait4video_done(); + /* delay 4 ms to skip BLLP */ + usleep(4000); +} + + void mipi_dsi_cmd_mdp_busy(void) { - u32 status; unsigned long flags; int need_wait = 0; + pr_debug("%s: start pid=%d\n", + __func__, current->pid); + spin_lock_irqsave(&dsi_mdp_lock, flags); - status = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */ - if (status & 0x04) { /* MDP BUSY */ - INIT_COMPLETION(dsi_mdp_comp); - need_wait = 1; - pr_debug("%s: status=%x need_wait\n", __func__, (int)status); - mipi_dsi_enable_irq(DSI_MDP_TERM); - } + if (dsi_mdp_busy == TRUE) + need_wait++; spin_unlock_irqrestore(&dsi_mdp_lock, flags); - if (need_wait){ -// wait_for_completion(&dsi_mdp_comp); - if (!wait_for_completion_timeout(&dsi_mdp_comp, msecs_to_jiffies(200))) { - pr_err("%s: dma timeout error\n", __func__); - } + if (need_wait) { + /* wait until DMA finishes the current job */ + pr_debug("%s: pending pid=%d\n", + __func__, current->pid); + wait_for_completion(&dsi_mdp_comp); } + pr_debug("%s: done pid=%d\n", + __func__, current->pid); } /* @@ -1610,16 +1631,32 @@ void mipi_dsi_cmdlist_rx(struct dcs_cmd_req *req) void mipi_dsi_cmdlist_commit(int from_mdp) { struct dcs_cmd_req *req; + u32 dsi_ctrl; mutex_lock(&cmd_mutex); req = mipi_dsi_cmdlist_get(); - if (req == NULL) { - mutex_unlock(&cmd_mutex); - return; - } +/* make sure dsi_cmd_mdp is idle */ + mipi_dsi_cmd_mdp_busy(); + + if (req == NULL) + goto need_lock; pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid); + dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000); + if (dsi_ctrl & 0x02) { + /* video mode, make sure video engine is busy + * so dcs command will be sent at start of BLLP + */ + mipi_dsi_wait4video_eng_busy(); + } else { + /* command mode */ + if (!from_mdp) { /* cmdlist_put */ + /* make sure dsi_cmd_mdp is idle */ + mipi_dsi_cmd_mdp_busy(); + } + } + if (!from_mdp) { /* from put */ /* make sure dsi_cmd_mdp is idle */ mipi_dsi_cmd_mdp_busy(); @@ -1632,6 +1669,11 @@ void mipi_dsi_cmdlist_commit(int from_mdp) mipi_dsi_cmdlist_tx(req); mipi_dsi_clk_cfg(0); + need_lock: + + if (from_mdp) /* from pipe_commit */ + mipi_dsi_cmd_mdp_start(); + mutex_unlock(&cmd_mutex); } @@ -1765,23 +1807,23 @@ irqreturn_t mipi_dsi_isr(int irq, void *ptr) } if (isr & DSI_INTR_VIDEO_DONE) { - /* - * do something here - */ + spin_lock(&dsi_mdp_lock); + mipi_dsi_disable_irq_nosync(DSI_VIDEO_TERM); + complete(&dsi_video_comp); + spin_unlock(&dsi_mdp_lock); } if (isr & DSI_INTR_CMD_DMA_DONE) { - //printk("%s():isr:0x%x,interrupt dma done\n",__func__,isr); mipi_dsi_mdp_stat_inc(STAT_DSI_CMD); spin_lock(&dsi_mdp_lock); complete(&dsi_dma_comp); dsi_ctrl_lock = FALSE; + dsi_mdp_busy = FALSE; mipi_dsi_disable_irq_nosync(DSI_CMD_TERM); spin_unlock(&dsi_mdp_lock); } if (isr & DSI_INTR_CMD_MDP_DONE) { - //printk("%s():isr:0x%x,interrupt mdp done\n",__func__,isr); mipi_dsi_mdp_stat_inc(STAT_DSI_MDP); spin_lock(&dsi_mdp_lock); dsi_ctrl_lock = FALSE; diff --git a/drivers/video/msm/mipi_hx8389b_video_qhd_pt.c b/drivers/video/msm/mipi_hx8389b_video_qhd_pt.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c index 5cd42004..60d09440 100644 --- a/drivers/video/msm/mipi_novatek.c +++ b/drivers/video/msm/mipi_novatek.c @@ -302,19 +302,31 @@ static char manufacture_id[2] = {0x04, 0x00}; /* DTYPE_DCS_READ */ static struct dsi_cmd_desc novatek_manufacture_id_cmd = { DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id), manufacture_id}; +static u32 manu_id; + +static void mipi_novatek_manufacture_cb(u32 data) +{ + manu_id = data; + pr_info("%s: manufacture_id=%x\n", __func__, manu_id); +} + static uint32 mipi_novatek_manufacture_id(struct msm_fb_data_type *mfd) { - struct dsi_buf *rp, *tp; - struct dsi_cmd_desc *cmd; - uint32 *lp; - - tp = &novatek_tx_buf; - rp = &novatek_rx_buf; - cmd = &novatek_manufacture_id_cmd; - mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 3); - lp = (uint32 *)rp->data; - pr_info("%s: manufacture_id=%x\n", __func__, *lp); - return *lp; + struct dcs_cmd_req cmdreq; + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = &novatek_manufacture_id_cmd; + cmdreq.cmds_cnt = 1; + cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT; + cmdreq.rlen = 3; + cmdreq.rbuf = NULL; + cmdreq.cb = mipi_novatek_manufacture_cb; /* call back */ + mipi_dsi_cmdlist_put(&cmdreq); + /* + * blocked here, untill call back called + */ + + return manu_id; } static int fpga_addr; @@ -380,6 +392,7 @@ static int mipi_novatek_lcd_on(struct platform_device *pdev) struct msm_fb_data_type *mfd; struct mipi_panel_info *mipi; struct msm_panel_info *pinfo; + struct dcs_cmd_req cmdreq; mfd = platform_get_drvdata(pdev); if (!mfd) @@ -394,23 +407,31 @@ static int mipi_novatek_lcd_on(struct platform_device *pdev) mipi = &mfd->panel_info.mipi; if (mipi->mode == DSI_VIDEO_MODE) { - mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_video_on_cmds, - ARRAY_SIZE(novatek_video_on_cmds)); + cmdreq.cmds = novatek_video_on_cmds; + cmdreq.cmds_cnt = ARRAY_SIZE(novatek_video_on_cmds); + cmdreq.flags = CMD_REQ_COMMIT; + cmdreq.rlen = 0; + cmdreq.cb = NULL; + mipi_dsi_cmdlist_put(&cmdreq); } else { - mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_cmd_on_cmds, - ARRAY_SIZE(novatek_cmd_on_cmds)); + cmdreq.cmds = novatek_cmd_on_cmds; + cmdreq.cmds_cnt = ARRAY_SIZE(novatek_cmd_on_cmds); + cmdreq.flags = CMD_REQ_COMMIT; + cmdreq.rlen = 0; + cmdreq.cb = NULL; + mipi_dsi_cmdlist_put(&cmdreq); /* clean up ack_err_status */ mipi_dsi_cmd_bta_sw_trigger(); mipi_novatek_manufacture_id(mfd); } - return 0; } static int mipi_novatek_lcd_off(struct platform_device *pdev) { struct msm_fb_data_type *mfd; + struct dcs_cmd_req cmdreq; mfd = platform_get_drvdata(pdev); @@ -419,9 +440,19 @@ static int mipi_novatek_lcd_off(struct platform_device *pdev) if (mfd->key != MFD_KEY) return -EINVAL; - mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_display_off_cmds, - ARRAY_SIZE(novatek_display_off_cmds)); + cmdreq.cmds = novatek_display_off_cmds; + cmdreq.cmds_cnt = ARRAY_SIZE(novatek_display_off_cmds); + cmdreq.flags = CMD_REQ_COMMIT; + cmdreq.rlen = 0; + cmdreq.cb = NULL; + + mipi_dsi_cmdlist_put(&cmdreq); + + return 0; +} +static int mipi_novatek_lcd_late_init(struct platform_device *pdev) +{ return 0; } @@ -431,10 +462,16 @@ static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */ static struct dsi_cmd_desc backlight_cmd = { DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1}; -struct dcs_cmd_req cmdreq; static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd) { + struct dcs_cmd_req cmdreq; + + if (mipi_novatek_pdata && + mipi_novatek_pdata->gpio_set_backlight) { + mipi_novatek_pdata->gpio_set_backlight(mfd->bl_level); + return; + } if ((mipi_novatek_pdata->enable_wled_bl_ctrl) && (wled_trigger_initialized)) { @@ -446,7 +483,7 @@ static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd) cmdreq.cmds = &backlight_cmd; cmdreq.cmds_cnt = 1; - cmdreq.flags = 0; + cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL; cmdreq.rlen = 0; cmdreq.cb = NULL; @@ -462,6 +499,7 @@ static int __devinit mipi_novatek_lcd_probe(struct platform_device *pdev) struct mipi_panel_info *mipi; struct platform_device *current_pdev; static struct mipi_dsi_phy_ctrl *phy_settings; + static char dlane_swap; if (pdev->id == 0) { mipi_novatek_pdata = pdev->dev.platform_data; @@ -471,6 +509,11 @@ static int __devinit mipi_novatek_lcd_probe(struct platform_device *pdev) phy_settings = (mipi_novatek_pdata->phy_ctrl_settings); } + if (mipi_novatek_pdata + && mipi_novatek_pdata->dlane_swap) { + dlane_swap = (mipi_novatek_pdata->dlane_swap); + } + if (mipi_novatek_pdata && mipi_novatek_pdata->fpga_3d_config_addr) mipi_novatek_3d_init(mipi_novatek_pdata @@ -500,6 +543,9 @@ static int __devinit mipi_novatek_lcd_probe(struct platform_device *pdev) if (phy_settings != NULL) mipi->dsi_phy_db = phy_settings; + + if (dlane_swap) + mipi->dlane_swap = dlane_swap; } return 0; } @@ -514,6 +560,7 @@ static struct platform_driver this_driver = { static struct msm_fb_panel_data novatek_panel_data = { .on = mipi_novatek_lcd_on, .off = mipi_novatek_lcd_off, + .late_init = mipi_novatek_lcd_late_init, .set_backlight = mipi_novatek_set_backlight, }; diff --git a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c index 616622ec..d2820a80 100644 --- a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c +++ b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c @@ -64,7 +64,7 @@ static int __init mipi_cmd_novatek_blue_qhd_pt_init(void) pinfo.is_3d_panel = FB_TYPE_3D_PANEL; pinfo.lcd.vsync_enable = TRUE; pinfo.lcd.hw_vsync_mode = TRUE; - pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */ + pinfo.lcd.refx100 = 6200; /* adjust refx100 to prevent tearing */ pinfo.lcd.v_back_porch = 11; pinfo.lcd.v_front_porch = 10; pinfo.lcd.v_pulse_width = 5; diff --git a/drivers/video/msm/mipi_nt35516_e808t.c b/drivers/video/msm/mipi_nt35516_e808t.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/mipi_otm9605a.c b/drivers/video/msm/mipi_otm9605a.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/mipi_yassy_otm9608a_wg451v.c b/drivers/video/msm/mipi_yassy_otm9608a_wg451v.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index e81f0398..89c6e3e0 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -3,7 +3,7 @@ * Core MSM framebuffer driver. * * Copyright (C) 2007 Google Incorporated - * Copyright (c) 2013 The Linux Foundation. All Rights Reserved. + * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -38,10 +38,11 @@ #include #include #include -#include #include #include -#include +#include +#include +#include #define MSM_FB_C #include "msm_fb.h" @@ -63,12 +64,17 @@ static unsigned char *fbram; static unsigned char *fbram_phys; static int fbram_size; static boolean bf_supported; + /* Set backlight on resume after 50 ms after first * pan display on the panel. This is to avoid panel specific * transients during resume. */ unsigned long backlight_duration = (HZ/20); +#ifdef CONFIG_FB_MSM_ALIGN_BUFFER +static bool align_buffer = false; +#endif + static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; static int pdev_list_cnt; @@ -121,12 +127,27 @@ static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma); static int mdp_bl_scale_config(struct msm_fb_data_type *mfd, struct mdp_bl_scale_data *data); static void msm_fb_scale_bl(__u32 *bl_lvl); +static void msm_fb_commit_wq_handler(struct work_struct *work); +static int msm_fb_pan_idle(struct msm_fb_data_type *mfd); +static int hack_lcd = 1; +boolean lcd_have_resume = FALSE; +boolean last_backlight_setting = FALSE; +int last_backlight_level = 0; + + #ifdef MSM_FB_ENABLE_DBGFS #define MSM_FB_MAX_DBGFS 1024 #define MAX_BACKLIGHT_BRIGHTNESS 255 +#define WAIT_FENCE_FIRST_TIMEOUT (3 * MSEC_PER_SEC) +#define WAIT_FENCE_FINAL_TIMEOUT (10 * MSEC_PER_SEC) +/* Display op timeout should be greater than total timeout */ +#define WAIT_DISP_OP_TIMEOUT (WAIT_FENCE_FIRST_TIMEOUT +\ + WAIT_FENCE_FINAL_TIMEOUT) * MDP_MAX_FENCE_FD +#define MAX_TIMELINE_NAME_LEN 16 + int msm_fb_debugfs_file_index; struct dentry *msm_fb_debugfs_root; struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS]; @@ -186,15 +207,25 @@ static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev, /* This maps android backlight level 0 to 255 into driver backlight level 0 to bl_max with rounding */ - bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS) - /(2 * MAX_BACKLIGHT_BRIGHTNESS); + bl_lvl = value; if (!bl_lvl && value) bl_lvl = 1; - - down(&mfd->sem); - msm_fb_set_backlight(mfd, bl_lvl); - up(&mfd->sem); +/* Remove qcom backlight mechanism,user our own */ +/* If LCD don't resume ,don't turn on LCD backlight */ + if (hack_lcd) { + if(FALSE == lcd_have_resume) { + last_backlight_level = bl_lvl; + last_backlight_setting = TRUE; + } else { + msm_fb_set_backlight(mfd, bl_lvl); + last_backlight_setting = FALSE; + } + } else { + down(&mfd->sem); + msm_fb_set_backlight(mfd, bl_lvl); + up(&mfd->sem); + } } static struct led_classdev backlight_led = { @@ -344,8 +375,9 @@ static void msm_fb_remove_sysfs(struct platform_device *pdev) } static void bl_workqueue_handler(struct work_struct *work); + static ssize_t msm_fb_xres(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { ssize_t ret = strnlen(buf, PAGE_SIZE); struct fb_info *fbi = dev_get_drvdata(dev); @@ -386,34 +418,34 @@ static struct attribute_group yres_fs_attr_group = { static int msm_fb_resolution_sysfs(struct platform_device *pdev) { - int rc; - struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + int rc; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); - if (!mfd) { + if (!mfd) { pr_err("%s: mfd not found\n", __func__); return -ENODEV; - } - if (!mfd->fbi) { + } + if (!mfd->fbi) { pr_err("%s: mfd->fbi not found\n", __func__); return -ENODEV; - } - if (!mfd->fbi->dev) { + } + if (!mfd->fbi->dev) { pr_err("%s: mfd->fbi->dev not found\n", __func__); return -ENODEV; - } - rc = sysfs_create_group(&mfd->fbi->dev->kobj, + } + rc = sysfs_create_group(&mfd->fbi->dev->kobj, &xres_fs_attr_group); if (rc) { pr_err("%s: sysfs group creation failed, rc=%d\n", __func__, rc); return rc; - } + } rc = sysfs_create_group(&mfd->fbi->dev->kobj, - &yres_fs_attr_group); + &yres_fs_attr_group); if (rc) { pr_err("%s: sysfs group creation failed, rc=%d\n", - __func__, rc); + __func__, rc); return rc; } return 0; @@ -500,7 +532,21 @@ static int msm_fb_probe(struct platform_device *pdev) pdev_list[pdev_list_cnt++] = pdev; msm_fb_create_sysfs(pdev); - msm_fb_resolution_sysfs(pdev); + msm_fb_resolution_sysfs(pdev); + + if (mfd->timeline == NULL) { + char timeline_name[MAX_TIMELINE_NAME_LEN]; + snprintf(timeline_name, sizeof(timeline_name), + "mdp_fb_%d", mfd->index); + mfd->timeline = sw_sync_timeline_create(timeline_name); + if (mfd->timeline == NULL) { + pr_err("%s: cannot create time line", __func__); + return -ENOMEM; + } else { + mfd->timeline_value = 0; + } + } + return 0; } @@ -512,6 +558,8 @@ static int msm_fb_remove(struct platform_device *pdev) mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + msm_fb_pan_idle(mfd); + msm_fb_remove_sysfs(pdev); pm_runtime_disable(mfd->fbi->dev); @@ -572,15 +620,18 @@ static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state) struct msm_fb_data_type *mfd; int ret = 0; - MSM_FB_DEBUG("Enter\n"); + MSM_FB_DEBUG("msm_fb_suspend\n"); mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); if ((!mfd) || (mfd->key != MFD_KEY)) return 0; + msm_fb_pan_idle(mfd); + console_lock(); fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED); + ret = msm_fb_suspend_sub(mfd); if (ret != 0) { printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret); @@ -674,6 +725,9 @@ static int msm_fb_resume_sub(struct msm_fb_data_type *mfd) mfd->suspend.op_enable,mfd->suspend.panel_power_on); if (mfd->suspend.panel_power_on) { + if (mfd->panel_driver_on == FALSE) + msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->op_enable); ret = msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi, mfd->op_enable); @@ -681,6 +735,8 @@ static int msm_fb_resume_sub(struct msm_fb_data_type *mfd) MSM_FB_INFO("msm_fb_resume: can't turn on display!\n"); } + mfd->suspend.op_suspend = false; + return ret; } #endif @@ -693,13 +749,15 @@ static int msm_fb_resume(struct platform_device *pdev) int ret = 0; struct msm_fb_data_type *mfd; - MSM_FB_DEBUG("Enter\n"); + MSM_FB_DEBUG("msm_fb_resume\n"); mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); if ((!mfd) || (mfd->key != MFD_KEY)) return 0; + msm_fb_pan_idle(mfd); + console_lock(); ret = msm_fb_resume_sub(mfd); pdev->dev.power.power_state = PMSG_ON; @@ -737,14 +795,9 @@ static int msm_fb_ext_suspend(struct device *dev) struct msm_fb_panel_data *pdata = NULL; int ret = 0; - if (hdmi_prim_display) { - MSM_FB_INFO("%s: hdmi primary handles early suspend only\n", - __func__); - return 0; - } - if ((!mfd) || (mfd->key != MFD_KEY)) return 0; + msm_fb_pan_idle(mfd); pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; if (mfd->panel_info.type == HDMI_PANEL || @@ -768,15 +821,9 @@ static int msm_fb_ext_resume(struct device *dev) struct msm_fb_panel_data *pdata = NULL; int ret = 0; - if (hdmi_prim_display) { - MSM_FB_INFO("%s: hdmi primary handles early resume only\n", - __func__); - return 0; - } - if ((!mfd) || (mfd->key != MFD_KEY)) return 0; - + msm_fb_pan_idle(mfd); pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; if (mfd->panel_info.type == HDMI_PANEL || mfd->panel_info.type == DTV_PANEL) { @@ -877,8 +924,7 @@ static struct dev_pm_ops msm_fb_dev_pm_ops = { .runtime_suspend = msm_fb_runtime_suspend, .runtime_resume = msm_fb_runtime_resume, .runtime_idle = msm_fb_runtime_idle, -#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL) && \ - !defined(CONFIG_FB_MSM_HDMI_AS_PRIMARY)) +#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL)) .suspend = msm_fb_ext_suspend, .resume = msm_fb_ext_resume, #endif @@ -903,49 +949,23 @@ static struct platform_driver msm_fb_driver = { static void msmfb_early_suspend(struct early_suspend *h) { struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, - early_suspend); - struct msm_fb_panel_data *pdata = NULL; - MSM_DRM_DEBUG("start\n"); + early_suspend); - - msm_fb_suspend_sub(mfd); + msm_fb_pan_idle(mfd); - pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; - if (hdmi_prim_display && - (mfd->panel_info.type == HDMI_PANEL || - mfd->panel_info.type == DTV_PANEL)) { - /* Turn off the HPD circuitry */ - if (pdata->power_ctrl) { - MSM_FB_INFO("%s: Turning off HPD circuitry\n", - __func__); - pdata->power_ctrl(FALSE); - } - } + msm_fb_suspend_sub(mfd); } static void msmfb_early_resume(struct early_suspend *h) { struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, - early_suspend); - struct msm_fb_panel_data *pdata = NULL; - MSM_DRM_DEBUG("start\n"); - pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; - - if (hdmi_prim_display && - (mfd->panel_info.type == HDMI_PANEL || - mfd->panel_info.type == DTV_PANEL)) { - /* Turn on the HPD circuitry */ - if (pdata->power_ctrl) { - MSM_FB_INFO("%s: Turning on HPD circuitry\n", __func__); - pdata->power_ctrl(TRUE); - } - } - msm_fb_resume_sub(mfd); + early_suspend); + msm_fb_resume_sub(mfd); } #endif static int unset_bl_level, bl_updated; -static int bl_level_old, pan_display_flag; +static int bl_level_old; static int mdp_bl_scale_config(struct msm_fb_data_type *mfd, struct mdp_bl_scale_data *data) { @@ -959,15 +979,16 @@ static int mdp_bl_scale_config(struct msm_fb_data_type *mfd, bl_min_lvl); /* update current backlight to use new scaling*/ - if (mfd->panel_power_on && bl_updated) - msm_fb_set_backlight(mfd, curr_bl); + msm_fb_set_backlight(mfd, curr_bl); up(&mfd->sem); + return ret; } static void msm_fb_scale_bl(__u32 *bl_lvl) { __u32 temp = *bl_lvl; + pr_debug("%s: input = %d, scale = %d", __func__, temp, bl_scale); if (temp >= bl_min_lvl) { /* bl_scale is the numerator of scaling fraction (x/1024)*/ temp = ((*bl_lvl) * bl_scale) / 1024; @@ -976,43 +997,55 @@ static void msm_fb_scale_bl(__u32 *bl_lvl) if (temp < bl_min_lvl) temp = bl_min_lvl; } + pr_debug("%s: output = %d", __func__, temp); (*bl_lvl) = temp; } +/*must call this function from within mfd->sem*/ void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl) { struct msm_fb_panel_data *pdata; __u32 temp = bkl_lvl; - - if(gv_dev.state==1){ - unset_bl_level = 0; - MSM_DRM_DEBUG(":unset_bl_level = %d\n", unset_bl_level); - return; - } + +/* Remove qcom backlight mechanism,user our own */ + if (!hack_lcd) { if (!mfd->panel_power_on || !bl_updated) { unset_bl_level = bkl_lvl; -//Normandy_P010154 remove to fix flash screen in charger mode by wang.xiaojun3@byd.com 131219 - if((unset_bl_level > 10) && !bl_updated && pan_display_flag) - schedule_delayed_work(&mfd->backlight_worker, backlight_duration); - MSM_DRM_DEBUG("bl_updated = %d,power_on=%d,level=%d\n", bl_updated,mfd->panel_power_on, bkl_lvl); return; } else { unset_bl_level = 0; } - - MSM_DRM_DEBUG(" %d\n", unset_bl_level); + } + + msm_fb_scale_bl(&temp); + msm_fb_pan_idle(mfd); pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; - if ((pdata) && (pdata->set_backlight)) { - msm_fb_scale_bl(&temp); + if (!pdata) + return; + if (!pdata->set_backlight) + return; + + if (!hack_lcd) { + if (bl_level_old == temp) { + return; + } mfd->bl_level = temp; pdata->set_backlight(mfd); mfd->bl_level = bkl_lvl; bl_level_old = temp; - } + } else { + if (bl_level_old == bkl_lvl) { + return; + } + down(&mfd->dma->mutex); + mfd->bl_level = bkl_lvl; + pdata->set_backlight(mfd); + up(&mfd->dma->mutex); + bl_level_old = mfd->bl_level; + } } - static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, boolean op_enable) { @@ -1035,24 +1068,22 @@ static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, msleep(16); ret = pdata->on(mfd->pdev); if (ret == 0) { - down(&mfd->sem); mfd->panel_power_on = TRUE; - up(&mfd->sem); - -/* ToDo: possible conflict with android which doesn't expect sw refresher */ -/* - if (!mfd->hw_refresh) - { - if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0) - { - MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret); - } - } -*/ + mfd->panel_driver_on = mfd->op_enable; } +/* LCD resume completed ,then turn on lcd backlight */ + if (ret == 0 && hack_lcd) { + lcd_have_resume = TRUE; + /* Remove qcom backlight mechanism,user our own */ + if(TRUE == last_backlight_setting) + { + msm_fb_set_backlight(mfd,last_backlight_level); + last_backlight_setting = FALSE; + printk("%s:Waiting for LCD resume ,then set backlight level=%d\n",__func__,last_backlight_level); + } } + } break; - case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_NORMAL: @@ -1061,22 +1092,24 @@ static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, if (mfd->panel_power_on) { int curr_pwr_state; + if (hack_lcd) + lcd_have_resume = FALSE; + mfd->op_enable = FALSE; curr_pwr_state = mfd->panel_power_on; - - down(&mfd->sem); - msm_fb_set_backlight(mfd, 0); mfd->panel_power_on = FALSE; - bl_updated = 0; - pan_display_flag = 0; - up(&mfd->sem); - if (delayed_work_pending(&mfd->backlight_worker)) + + if (!hack_lcd) { /* Remove qcom backlight mechanism,user our own */ cancel_delayed_work_sync(&mfd->backlight_worker); + bl_updated = 0; + } + msleep(16); ret = pdata->off(mfd->pdev); if (ret) mfd->panel_power_on = curr_pwr_state; + msm_fb_release_timeline(mfd); mfd->op_enable = TRUE; } break; @@ -1090,6 +1123,13 @@ int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp) struct msm_panel_info *panel_info = &mfd->panel_info; int remainder, yres, offset; +#ifdef CONFIG_FB_MSM_ALIGN_BUFFER + if (!align_buffer) + { + return fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length; + } +#endif + if (panel_info->mode2_yres != 0) { yres = panel_info->mode2_yres; remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1); @@ -1119,7 +1159,7 @@ static void msm_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; - + msm_fb_pan_idle(mfd); cfb_fillrect(info, rect); if (!mfd->hw_refresh && (info->var.yoffset == 0) && !mfd->sw_currently_refreshing) { @@ -1140,6 +1180,7 @@ static void msm_fb_copyarea(struct fb_info *info, { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); cfb_copyarea(info, area); if (!mfd->hw_refresh && (info->var.yoffset == 0) && !mfd->sw_currently_refreshing) { @@ -1159,6 +1200,7 @@ static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); cfb_imageblit(info, image); if (!mfd->hw_refresh && (info->var.yoffset == 0) && !mfd->sw_currently_refreshing) { @@ -1177,6 +1219,13 @@ static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image) static int msm_fb_blank(int blank_mode, struct fb_info *info) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); + if (mfd->op_enable == 0) { + if (blank_mode == FB_BLANK_UNBLANK) + mfd->suspend.panel_power_on = TRUE; + else + mfd->suspend.panel_power_on = FALSE; + } return msm_fb_blank_sub(blank_mode, info, mfd->op_enable); } @@ -1203,6 +1252,7 @@ static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma) u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); unsigned long off = vma->vm_pgoff << PAGE_SHIFT; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); if (off >= len) { /* memory mapped io */ off -= len; @@ -1395,6 +1445,26 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) bpp = 4; break; + case MDP_BGRA_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 24; + var->transp.length = 8; + bpp = 4; + break; + + case MDP_YCRYCB_H2V1: /* ToDo: need to check TV-Out YUV422i framebuffer format */ /* we might need to create new type define */ @@ -1475,27 +1545,6 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) var->yres_virtual = panel_info->yres * mfd->fb_page + ((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page; var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */ - if (mfd->dest == DISPLAY_LCD) { - if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1) - var->reserved[4] = panel_info->lcd.refx100 / (100 * 2); - else - var->reserved[4] = 60;//panel_info->lcd.refx100 / 100; - } else { - if (panel_info->type == MIPI_VIDEO_PANEL) { - var->reserved[4] = panel_info->mipi.frame_rate; - } else { - var->reserved[4] = panel_info->clk_rate / - ((panel_info->lcdc.h_back_porch + - panel_info->lcdc.h_front_porch + - panel_info->lcdc.h_pulse_width + - panel_info->xres) * - (panel_info->lcdc.v_back_porch + - panel_info->lcdc.v_front_porch + - panel_info->lcdc.v_pulse_width + - panel_info->yres)); - } - } - pr_debug("reserved[4] %u\n", var->reserved[4]); /* * id field for fb app @@ -1558,7 +1607,15 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) mfd->msmfb_no_update_notify_timer.data = (unsigned long)mfd; init_completion(&mfd->msmfb_update_notify); init_completion(&mfd->msmfb_no_update_notify); - + init_completion(&mfd->commit_comp); + mutex_init(&mfd->sync_mutex); + INIT_WORK(&mfd->commit_work, msm_fb_commit_wq_handler); + mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type), + GFP_KERNEL); + if (mfd->msm_fb_backup == 0) { + pr_err("error: not enough memory!\n"); + return -ENOMEM; + } fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram; fbram += fbram_offset; fbram_phys += fbram_offset; @@ -1572,6 +1629,16 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) fbi->screen_base = fbram; fbi->fix.smem_start = (unsigned long)fbram_phys; + + memset(fbi->screen_base, 0x0, fix->smem_len); + + msm_iommu_map_contig_buffer(fbi->fix.smem_start, + DISPLAY_WRITE_DOMAIN, + GEN_POOL, + fbi->fix.smem_len, + SZ_4K, + 0, + &(mfd->display_iova)); msm_iommu_map_contig_buffer(fbi->fix.smem_start, DISPLAY_READ_DOMAIN, @@ -1597,10 +1664,22 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) /* cursor memory allocation */ if (mfd->cursor_update) { + unsigned long cursor_buf_iommu = 0; mfd->cursor_buf = dma_alloc_coherent(NULL, MDP_CURSOR_SIZE, (dma_addr_t *) &mfd->cursor_buf_phys, GFP_KERNEL); + + msm_iommu_map_contig_buffer((unsigned long)mfd->cursor_buf_phys, + DISPLAY_READ_DOMAIN, + GEN_POOL, + MDP_CURSOR_SIZE, + SZ_4K, + 0, + &cursor_buf_iommu); + if (cursor_buf_iommu) + mfd->cursor_buf_phys = (void *)cursor_buf_iommu; + if (!mfd->cursor_buf) mfd->cursor_update = 0; } @@ -1642,7 +1721,7 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) ret = 0; #ifdef CONFIG_HAS_EARLYSUSPEND - if (hdmi_prim_display || mfd->panel_info.type != DTV_PANEL) { + if (mfd->panel_info.type != DTV_PANEL) { mfd->early_suspend.suspend = msmfb_early_suspend; mfd->early_suspend.resume = msmfb_early_resume; mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2; @@ -1787,6 +1866,7 @@ glanceview_register(gv_device_id_lcd, &gv_dev, &mfd->pdev->dev); static int msm_fb_open(struct fb_info *info, int user) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + bool unblank = true; int result; result = pm_runtime_get_sync(info->dev); @@ -1808,9 +1888,16 @@ static int msm_fb_open(struct fb_info *info, int user) pr_debug("%s:%d no mdp_set_dma_pan_info %d\n", __func__, __LINE__, info->node); - if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { - printk(KERN_ERR "msm_fb_open: can't turn on display!\n"); - return -1; + if (mfd->is_panel_ready && !mfd->is_panel_ready()) + unblank = false; + + if (unblank) { + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, + info, TRUE)) { + MSM_FB_ERR("%s: can't turn on display!\n", + __func__); + return -EPERM; + } } } @@ -1828,10 +1915,10 @@ static int msm_fb_release(struct fb_info *info, int user) mfd->index); return -EINVAL; } - + msm_fb_pan_idle(mfd); mfd->ref_cnt--; - if (!mfd->ref_cnt) { + if ((!mfd->ref_cnt) && (mfd->op_enable)) { if ((ret = msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable)) != 0) { @@ -1844,74 +1931,199 @@ static int msm_fb_release(struct fb_info *info, int user) return ret; } -DEFINE_SEMAPHORE(msm_fb_pan_sem); +void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd) +{ + int i, ret = 0; + /* buf sync */ + for (i = 0; i < mfd->acq_fen_cnt; i++) { + ret = sync_fence_wait(mfd->acq_fen[i], + WAIT_FENCE_FIRST_TIMEOUT); + if (ret == -ETIME) { + pr_warn("%s: sync_fence_wait timed out!" + "Waiting %ld more seconds\n", + __func__,WAIT_FENCE_FINAL_TIMEOUT/MSEC_PER_SEC); + ret = sync_fence_wait(mfd->acq_fen[i], + WAIT_FENCE_FINAL_TIMEOUT); + } + if (ret < 0) { + pr_err("%s: sync_fence_wait failed! ret = %x\n", + __func__, ret); + break; + } + sync_fence_put(mfd->acq_fen[i]); + } + if (ret < 0) { + while (i < mfd->acq_fen_cnt) { + sync_fence_put(mfd->acq_fen[i]); + i++; + } + } + mfd->acq_fen_cnt = 0; +} +int msm_fb_signal_timeline(struct msm_fb_data_type *mfd) +{ + mutex_lock(&mfd->sync_mutex); + if (mfd->timeline) { + sw_sync_timeline_inc(mfd->timeline, 1); + mfd->timeline_value++; + } + mutex_unlock(&mfd->sync_mutex); + return 0; +} static void bl_workqueue_handler(struct work_struct *work) { struct msm_fb_data_type *mfd = container_of(to_delayed_work(work), struct msm_fb_data_type, backlight_worker); struct msm_fb_panel_data *pdata = mfd->pdev->dev.platform_data; - - down(&mfd->sem); - if ((pdata) && (pdata->set_backlight) && (!bl_updated) - && mfd->panel_power_on) { + + if ((pdata) && (pdata->set_backlight) && (!bl_updated)) { + down(&mfd->sem); mfd->bl_level = unset_bl_level; - printk("%s,backlight=%d\n",__func__,unset_bl_level); pdata->set_backlight(mfd); bl_level_old = unset_bl_level; bl_updated = 1; + up(&mfd->sem); } - up(&mfd->sem); +} + +void msm_fb_release_timeline(struct msm_fb_data_type *mfd) +{ + mutex_lock(&mfd->sync_mutex); + if (mfd->timeline) { + sw_sync_timeline_inc(mfd->timeline, 2); + mfd->timeline_value += 2; + } + mutex_unlock(&mfd->sync_mutex); +} + +DEFINE_SEMAPHORE(msm_fb_pan_sem); +static int msm_fb_pan_idle(struct msm_fb_data_type *mfd) +{ + int ret = 0; + + mutex_lock(&mfd->sync_mutex); + if (mfd->is_committing) { + mutex_unlock(&mfd->sync_mutex); + ret = wait_for_completion_interruptible_timeout( + &mfd->commit_comp, + msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT)); + if (ret <= 0) + ret = -ERESTARTSYS; + else if (!ret) + pr_err("%s wait for commit_comp timeout %d %d", + __func__, ret, mfd->is_committing); + if (ret <= 0) { + mutex_lock(&mfd->sync_mutex); + mfd->is_committing = 0; + complete_all(&mfd->commit_comp); + mutex_unlock(&mfd->sync_mutex); + } + } else { + mutex_unlock(&mfd->sync_mutex); + } + return ret; +} +static int msm_fb_pan_display_ex(struct fb_info *info, + struct mdp_display_commit *disp_commit) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_backup_type *fb_backup; + struct fb_var_screeninfo *var = &disp_commit->var; + u32 wait_for_finish = disp_commit->wait_for_finish; + int ret = 0; + + if (disp_commit->flags & + MDP_DISPLAY_COMMIT_OVERLAY) { + if (!mfd->panel_power_on) /* suspended */ + return -EPERM; + } else { + /* + * If framebuffer is 2, io pan display is not allowed. + */ + if (bf_supported && info->node == 2) { + pr_err("%s: no pan display for fb%d!", + __func__, info->node); + return -EPERM; + } + + if (info->node != 0 || mfd->cont_splash_done) /* primary */ + if ((!mfd->op_enable) || (!mfd->panel_power_on)) + return -EPERM; + + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) + return -EINVAL; + + if (var->yoffset > (info->var.yres_virtual - info->var.yres)) + return -EINVAL; + } + msm_fb_pan_idle(mfd); + + mutex_lock(&mfd->sync_mutex); + + if (!(disp_commit->flags & + MDP_DISPLAY_COMMIT_OVERLAY)) { + if (info->fix.xpanstep) + info->var.xoffset = + (var->xoffset / info->fix.xpanstep) * + info->fix.xpanstep; + + if (info->fix.ypanstep) + info->var.yoffset = + (var->yoffset / info->fix.ypanstep) * + info->fix.ypanstep; + } + fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup; + memcpy(&fb_backup->info, info, sizeof(struct fb_info)); + memcpy(&fb_backup->disp_commit, disp_commit, + sizeof(struct mdp_display_commit)); + mfd->is_committing = 1; + INIT_COMPLETION(mfd->commit_comp); + schedule_work(&mfd->commit_work); + mutex_unlock(&mfd->sync_mutex); + if (wait_for_finish) + msm_fb_pan_idle(mfd); + return ret; } static int msm_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct mdp_display_commit disp_commit; + memset(&disp_commit, 0, sizeof(disp_commit)); + disp_commit.var = *var; + disp_commit.wait_for_finish = TRUE; + memcpy(&disp_commit.var, var, sizeof(struct fb_var_screeninfo)); + return msm_fb_pan_display_ex(info, &disp_commit); +} + +static bool is_first_frame = TRUE; + +static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var, + struct fb_info *info) { struct mdp_dirty_region dirty; struct mdp_dirty_region *dirtyPtr = NULL; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; - static int notify_cnt = 0; - int state = 0; - if (!suspend_set_state()) - { - printk("%s,suspend_status is true\n",__func__); - state= -EPERM; - return state; - - } - + /* * If framebuffer is 2, io pen display is not allowed. */ if (bf_supported && info->node == 2) { pr_err("%s: no pan display for fb%d!", __func__, info->node); - //return -EPERM; - state= -EPERM; - goto MSM_FB_PAN_ERROR; + return -EPERM; } if (info->node != 0 || mfd->cont_splash_done) /* primary */ if ((!mfd->op_enable) || (!mfd->panel_power_on)) - { - //return -EPERM; - state= -EPERM; - goto MSM_FB_PAN_ERROR; - } - + return -EPERM; + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; if (var->yoffset > (info->var.yres_virtual - info->var.yres)) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; if (info->fix.xpanstep) info->var.xoffset = @@ -1928,17 +2140,9 @@ static int msm_fb_pan_display(struct fb_var_screeninfo *var, dirty.yoffset = (var->reserved[1] >> 16) & 0xffff; if ((var->reserved[2] & 0xffff) <= dirty.xoffset) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset; dirty.height = @@ -1946,47 +2150,23 @@ static int msm_fb_pan_display(struct fb_var_screeninfo *var, info->var.yoffset = var->yoffset; if (dirty.xoffset < 0) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; if (dirty.yoffset < 0) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; if ((dirty.xoffset + dirty.width) > info->var.xres) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; if ((dirty.yoffset + dirty.height) > info->var.yres) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; if ((dirty.width <= 0) || (dirty.height <= 0)) - { - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; - } + return -EINVAL; + dirtyPtr = &dirty; } - /* FIXME: reduce fb change notification time to ease mess backlight configuration */ - if (notify_cnt >= 6) { - notify_cnt = 0; - complete(&mfd->msmfb_update_notify); - } else - notify_cnt++; + complete(&mfd->msmfb_update_notify); mutex_lock(&msm_fb_notify_update_sem); if (mfd->msmfb_no_update_notify_timer.function) del_timer(&mfd->msmfb_no_update_notify_timer); @@ -1996,47 +2176,68 @@ static int msm_fb_pan_display(struct fb_var_screeninfo *var, mutex_unlock(&msm_fb_notify_update_sem); down(&msm_fb_pan_sem); - + msm_fb_wait_for_fence(mfd); if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */ mdp_set_dma_pan_info(info, NULL, TRUE); if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { pr_err("%s: can't turn on display!\n", __func__); - up(&msm_fb_pan_sem); - //return -EINVAL; - state= -EINVAL; - goto MSM_FB_PAN_ERROR; + msm_fb_release_timeline(mfd); + return -EINVAL; } - msleep(50); } - //mipi_dsi_set_column_addr(mfd); + mdp_set_dma_pan_info(info, dirtyPtr, - (var->activate == FB_ACTIVATE_VBL)); + (var->activate & FB_ACTIVATE_VBL)); +/* Do not refresh the first frame, because the frame's data is 0x00 */ + if (hack_lcd && is_first_frame) { + is_first_frame = FALSE; + printk("%s:Don't refresh the first frame to LCD\n",__func__); + } else { + /* async call */ mdp_dma_pan_update(info); + } + msm_fb_signal_timeline(mfd); up(&msm_fb_pan_sem); - -//fix BL can't turn on untill next frame come by wang.xiaojun3@byd.com 131219 - pan_display_flag = 1; - if (unset_bl_level && !bl_updated){ - MSM_DRM_DEBUG("call BL set schedule work\n"); + +/* Remove qcom backlight mechanism,user our own */ + if (!hack_lcd && unset_bl_level && !bl_updated) schedule_delayed_work(&mfd->backlight_worker, backlight_duration); - } - if (info->node == 0 && (mfd->cont_splash_done)) /* primary */ - mdp_free_splash_buffer(mfd); ++mfd->panel_info.frame_count; - - -MSM_FB_PAN_ERROR: - suspend_clen_state(); - - return state; + return 0; +} + +static void msm_fb_commit_wq_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd; + struct fb_var_screeninfo *var; + struct fb_info *info; + struct msm_fb_backup_type *fb_backup; + + mfd = container_of(work, struct msm_fb_data_type, commit_work); + fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup; + info = &fb_backup->info; + if (fb_backup->disp_commit.flags & + MDP_DISPLAY_COMMIT_OVERLAY) { + var = &fb_backup->disp_commit.var; + msm_fb_pan_display_sub(var, info); + } else { + var = &fb_backup->disp_commit.var; + msm_fb_pan_display_sub(var, info); + } + mutex_lock(&mfd->sync_mutex); + mfd->is_committing = 0; + complete_all(&mfd->commit_comp); + mutex_unlock(&mfd->sync_mutex); + } static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); if (var->rotate != FB_ROTATE_UR) return -EINVAL; if (var->grayscale != info->var.grayscale) @@ -2125,12 +2326,6 @@ static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if ((var->xres == 0) || (var->yres == 0)) return -EINVAL; - if ((var->xres > MAX(mfd->panel_info.xres, - mfd->panel_info.mode2_xres)) || - (var->yres > MAX(mfd->panel_info.yres, - mfd->panel_info.mode2_yres))) - return -EINVAL; - if (var->xoffset > (var->xres_virtual - var->xres)) return -EINVAL; @@ -2167,7 +2362,7 @@ static int msm_fb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int old_imgType; int blank = 0; - + msm_fb_pan_idle(mfd); old_imgType = mfd->fb_imgType; switch (var->bits_per_pixel) { case 16: @@ -2188,7 +2383,9 @@ static int msm_fb_set_par(struct fb_info *info) break; case 32: - if (var->transp.offset == 24) + if ((var->transp.offset == 24) && (var->blue.offset == 0)) + mfd->fb_imgType = MDP_BGRA_8888; + else if (var->transp.offset == 24) mfd->fb_imgType = MDP_ARGB_8888; else mfd->fb_imgType = MDP_RGBA_8888; @@ -2214,6 +2411,10 @@ static int msm_fb_set_par(struct fb_info *info) if (blank) { msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); + + if (mfd->update_panel_info) + mfd->update_panel_info(mfd); + msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable); } @@ -3163,11 +3364,17 @@ static int msmfb_overlay_play_wait(struct fb_info *info, unsigned long *argp) return ret; } +static int msmfb_overlay_commit(struct fb_info *info) +{ + return mdp4_overlay_commit(info); +} + static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp) { int ret; struct msmfb_overlay_data req; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_panel_data *pdata; if (mfd->overlay_play_enable == 0) /* nothing to do */ return 0; @@ -3198,10 +3405,14 @@ static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp) ret = mdp4_overlay_play(info, &req); - if (unset_bl_level && !bl_updated) +/* Remove qcom backlight mechanism,user our own */ + if (!hack_lcd && unset_bl_level && !bl_updated) schedule_delayed_work(&mfd->backlight_worker, backlight_duration); + if (info->node == 0 && (mfd->cont_splash_done)) /* primary */ + mdp_free_splash_buffer(mfd); + return ret; } @@ -3322,6 +3533,29 @@ static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info) return mdp4_writeback_terminate(info); } +static int msmfb_overlay_ioctl_writeback_set_mirr_hint(struct fb_info * + info, void *argp) +{ + int ret = 0, hint; + + if (!info) { + ret = -EINVAL; + goto error; + } + + ret = copy_from_user(&hint, argp, sizeof(hint)); + if (ret) + goto error; + + ret = mdp4_writeback_set_mirroring_hint(info, hint); + if (ret) + goto error; +error: + if (ret) + pr_err("%s: ioctl failed\n", __func__); + return ret; +} + #else static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info) { @@ -3354,6 +3588,12 @@ static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info) { return -ENOTSUPP; } + +static int msmfb_overlay_ioctl_writeback_set_mirr_hint(struct fb_info * + info, void *argp) +{ + return -ENOTSUPP; +} #endif static int msmfb_overlay_3d_sbys(struct fb_info *info, unsigned long *argp) @@ -3397,6 +3637,7 @@ static int msmfb_mixer_info(struct fb_info *info, unsigned long *argp) #endif DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem); +DEFINE_SEMAPHORE(msm_fb_ioctl_vsync_sem); DEFINE_MUTEX(msm_fb_ioctl_lut_sem); /* Set color conversion matrix from user space */ @@ -3442,13 +3683,12 @@ static void msmfb_set_color_conv(struct mdp_csc *p) } #endif -static int msmfb_notify_update(struct fb_info *info, void __user *argp) +static int msmfb_notify_update(struct fb_info *info, unsigned long *argp) { - int ret; - unsigned int notify; + int ret, notify; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; - ret = copy_from_user(¬ify, argp, sizeof(unsigned int)); + ret = copy_from_user(¬ify, argp, sizeof(int)); if (ret) { pr_err("%s:ioctl failed\n", __func__); return ret; @@ -3466,14 +3706,18 @@ static int msmfb_notify_update(struct fb_info *info, void __user *argp) ret = wait_for_completion_interruptible_timeout( &mfd->msmfb_no_update_notify, 4*HZ); } - return (ret > 0) ? 0 : -1; + if (ret == 0) + ret = -ETIMEDOUT; + return (ret > 0) ? 0 : ret; } static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd, struct msmfb_mdp_pp *pp_ptr) { int ret = -1; - +#ifdef CONFIG_FB_MSM_MDP40 + int i = 0; +#endif if (!pp_ptr) return ret; @@ -3481,6 +3725,15 @@ static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd, #ifdef CONFIG_FB_MSM_MDP40 case mdp_op_csc_cfg: ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data)); + for (i = 0; i < CSC_MAX_BLOCKS; i++) { + if (pp_ptr->data.csc_cfg_data.block == + csc_cfg_matrix[i].block) { + memcpy(&csc_cfg_matrix[i].csc_data, + &(pp_ptr->data.csc_cfg_data.csc_data), + sizeof(struct mdp_csc_cfg)); + break; + } + } break; case mdp_op_pcc_cfg: @@ -3514,6 +3767,10 @@ static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd, ret = mdp4_qseed_cfg((struct mdp_qseed_cfg_data *) &pp_ptr->data.qseed_cfg_data); break; + case mdp_op_calib_cfg: + ret = mdp4_calib_config((struct mdp_calib_config_data *) + &pp_ptr->data.calib_cfg); + break; #endif case mdp_bl_scale_cfg: ret = mdp_bl_scale_config(mfd, (struct mdp_bl_scale_data *) @@ -3538,6 +3795,10 @@ static int msmfb_handle_metadata_ioctl(struct msm_fb_data_type *mfd, ret = mdp4_update_base_blend(mfd, &metadata_ptr->data.blend_cfg); break; + case metadata_op_wb_format: + ret = mdp4_update_writeback_format(mfd, + &metadata_ptr->data.mixer_cfg); + break; #endif default: pr_warn("Unsupported request to MDP META IOCTL.\n"); @@ -3546,10 +3807,151 @@ static int msmfb_handle_metadata_ioctl(struct msm_fb_data_type *mfd, } return ret; } + +static int msmfb_get_metadata(struct msm_fb_data_type *mfd, + struct msmfb_metadata *metadata_ptr) +{ + int ret = 0; + switch (metadata_ptr->op) { + case metadata_op_frame_rate: + metadata_ptr->data.panel_frame_rate = + mdp_get_panel_framerate(mfd); + break; + default: + pr_warn("Unsupported request to MDP META IOCTL.\n"); + ret = -EINVAL; + break; + } + return ret; +} + +static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, + struct mdp_buf_sync *buf_sync) +{ + int i, ret = 0; + u32 threshold; + int acq_fen_fd[MDP_MAX_FENCE_FD]; + struct sync_fence *fence; + struct sync_pt *release_sync_pt; + struct sync_pt *retire_sync_pt; + struct sync_fence *release_fence; + struct sync_fence *retire_fence; + int release_fen_fd; + int retire_fen_fd; + + if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) || + (mfd->timeline == NULL)) + return -EINVAL; + + if ((!mfd->op_enable) || (!mfd->panel_power_on)) + return -EPERM; + + if (buf_sync->acq_fen_fd_cnt) + ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd, + buf_sync->acq_fen_fd_cnt * sizeof(int)); + if (ret) { + pr_err("%s:copy_from_user failed", __func__); + return ret; + } + mutex_lock(&mfd->sync_mutex); + for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) { + fence = sync_fence_fdget(acq_fen_fd[i]); + if (fence == NULL) { + pr_info("%s: null fence! i=%d fd=%d\n", __func__, i, + acq_fen_fd[i]); + ret = -EINVAL; + break; + } + mfd->acq_fen[i] = fence; + } + mfd->acq_fen_cnt = i; + if (ret) + goto buf_sync_err_1; + if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT) { + msm_fb_wait_for_fence(mfd); + } + if ((mfd->panel.type == MIPI_CMD_PANEL) || + (mfd->panel.type == WRITEBACK_PANEL)) + threshold = 1; + else + threshold = 2; + + release_fen_fd = get_unused_fd_flags(0); + if (release_fen_fd < 0) { + pr_err("%s: get_unused_fd_flags failed", __func__); + ret = -EIO; + goto buf_sync_err_1; + } + + retire_fen_fd = get_unused_fd_flags(0); + if (retire_fen_fd < 0) { + pr_err("%s: get_unused_fd_flags failed", __func__); + ret = -EIO; + goto buf_sync_err_2; + } + + release_sync_pt = sw_sync_pt_create(mfd->timeline, + mfd->timeline_value + threshold); + release_fence = sync_fence_create("mdp-fence", + release_sync_pt); + sync_fence_install(release_fence, release_fen_fd); + retire_sync_pt = sw_sync_pt_create(mfd->timeline, + mfd->timeline_value + threshold); + retire_fence = sync_fence_create("mdp-retire-fence", + retire_sync_pt); + sync_fence_install(retire_fence, retire_fen_fd); + + ret = copy_to_user(buf_sync->rel_fen_fd, + &release_fen_fd, sizeof(int)); + if (ret) { + pr_err("%s:copy_to_user failed", __func__); + goto buf_sync_err_3; + } + + ret = copy_to_user(buf_sync->retire_fen_fd, + &retire_fen_fd, sizeof(int)); + if (ret) { + pr_err("%s:copy_to_user failed", __func__); + goto buf_sync_err_3; + } + + mutex_unlock(&mfd->sync_mutex); + return ret; +buf_sync_err_3: + sync_fence_put(release_fence); + sync_fence_put(retire_fence); + put_unused_fd(retire_fen_fd); +buf_sync_err_2: + put_unused_fd(release_fen_fd); +buf_sync_err_1: + for (i = 0; i < mfd->acq_fen_cnt; i++) + sync_fence_put(mfd->acq_fen[i]); + mfd->acq_fen_cnt = 0; + mutex_unlock(&mfd->sync_mutex); + return ret; +} + +static int msmfb_display_commit(struct fb_info *info, + unsigned long *argp) +{ + int ret; + struct mdp_display_commit disp_commit; + ret = copy_from_user(&disp_commit, argp, + sizeof(disp_commit)); + if (ret) { + pr_err("%s:copy_from_user failed", __func__); + return ret; + } + + ret = msm_fb_pan_display_ex(info, &disp_commit); + + return ret; +} + static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct msm_fb_data_type *mfd; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; void __user *argp = (void __user *)arg; struct fb_cursor cursor; struct fb_cmap cmap; @@ -3564,11 +3966,9 @@ static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, struct mdp_page_protection fb_page_protection; struct msmfb_mdp_pp mdp_pp; struct msmfb_metadata mdp_metadata; + struct mdp_buf_sync buf_sync; int ret = 0; - - if (!info || !info->par) - return -EINVAL; - mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); switch (cmd) { #ifdef CONFIG_FB_MSM_OVERLAY @@ -3621,15 +4021,19 @@ static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, case MSMFB_WRITEBACK_TERMINATE: ret = msmfb_overlay_ioctl_writeback_terminate(info); break; + case MSMFB_WRITEBACK_SET_MIRRORING_HINT: + ret = msmfb_overlay_ioctl_writeback_set_mirr_hint( + info, argp); + break; #endif case MSMFB_VSYNC_CTRL: case MSMFB_OVERLAY_VSYNC_CTRL: - down(&msm_fb_ioctl_ppp_sem); + down(&msm_fb_ioctl_vsync_sem); if (mdp_rev >= MDP_REV_40) ret = msmfb_overlay_vsync_ctrl(info, argp); else ret = msmfb_vsync_ctrl(info, argp); - up(&msm_fb_ioctl_ppp_sem); + up(&msm_fb_ioctl_vsync_sem); break; case MSMFB_BLIT: down(&msm_fb_ioctl_ppp_sem); @@ -3847,6 +4251,18 @@ static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, return ret; ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp); + if (ret == 1) + ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp)); + break; + case MSMFB_BUFFER_SYNC: + ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync)); + if (ret) + return ret; + + ret = msmfb_handle_buf_sync_ioctl(mfd, &buf_sync); + + if (!ret) + ret = copy_to_user(argp, &buf_sync, sizeof(buf_sync)); break; case MSMFB_METADATA_SET: @@ -3854,6 +4270,18 @@ static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, if (ret) return ret; ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata); + case MSMFB_DISPLAY_COMMIT: + ret = msmfb_display_commit(info, argp); + break; + + case MSMFB_METADATA_GET: + ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata)); + if (ret) + return ret; + ret = msmfb_get_metadata(mfd, &mdp_metadata); + if (!ret) + ret = copy_to_user(argp, &mdp_metadata, + sizeof(mdp_metadata)); break; default: @@ -4117,7 +4545,7 @@ int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par) EXPORT_SYMBOL(msm_fb_v4l2_enable); /* Called by v4l2 driver to provide a frame for display */ -int msm_fb_v4l2_update(void *par, +int msm_fb_v4l2_update(void *par, bool bUserPtr, unsigned long srcp0_addr, unsigned long srcp0_size, unsigned long srcp1_addr, unsigned long srcp1_size, unsigned long srcp2_addr, unsigned long srcp2_size) @@ -4129,9 +4557,14 @@ int msm_fb_v4l2_update(void *par, srcp2_addr); #else #ifdef CONFIG_FB_MSM_MDP30 - return mdp_ppp_v4l2_overlay_play(fbi_list[0], - srcp0_addr, srcp0_size, - srcp1_addr, srcp1_size); + if (bUserPtr) + return mdp_ppp_v4l2_overlay_play(fbi_list[0], true, + srcp0_addr, srcp0_size, + srcp1_addr, srcp1_size); + else + return mdp_ppp_v4l2_overlay_play(fbi_list[0], false, + srcp0_addr, srcp0_size, + srcp1_addr, srcp1_size); #else return -EINVAL; #endif @@ -4139,4 +4572,8 @@ int msm_fb_v4l2_update(void *par, } EXPORT_SYMBOL(msm_fb_v4l2_update); +#ifdef CONFIG_FB_MSM_ALIGN_BUFFER +module_param(align_buffer, bool, 0644); +#endif + module_init(msm_fb_init); diff --git a/drivers/video/msm/msm_fb.c- b/drivers/video/msm/msm_fb.c- new file mode 100644 index 00000000..eb5a8cee --- /dev/null +++ b/drivers/video/msm/msm_fb.c- @@ -0,0 +1,4643 @@ +/* drivers/video/msm/msm_fb.c + * + * Core MSM framebuffer driver. + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2013 The Linux Foundation. All Rights Reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSM_FB_C +#include "msm_fb.h" +#include "mddihosti.h" +#include "tvenc.h" +#include "mdp.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER +#define MSM_FB_NUM 3 +#endif +#define LCM_1LED_CTRL_GPIO_PIN121 121 +#define LCD_GLANCEVIEW_SCREEN +#ifdef LCD_GLANCEVIEW_SCREEN +#include +#endif + +static unsigned char *fbram; +static unsigned char *fbram_phys; +static int fbram_size; +static boolean bf_supported; + +/* Set backlight on resume after 50 ms after first + * pan display on the panel. This is to avoid panel specific + * transients during resume. + */ +unsigned long backlight_duration = (HZ/20); + +#ifdef CONFIG_FB_MSM_ALIGN_BUFFER +static bool align_buffer = false; +#endif + +/* Set backlight on resume after 50 ms after first + * pan display on the panel. This is to avoid panel specific + * transients during resume. + */ +unsigned long backlight_duration = (HZ/20); + +/* Set backlight on resume after 50 ms after first + * pan display on the panel. This is to avoid panel specific + * transients during resume. + */ +unsigned long backlight_duration = (HZ/20); + +#ifdef CONFIG_FB_MSM_ALIGN_BUFFER +static bool align_buffer = false; +#endif + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +int vsync_mode = 1; + +#define MAX_BLIT_REQ 256 + +#define MAX_FBI_LIST 32 +static struct fb_info *fbi_list[MAX_FBI_LIST]; +static int fbi_list_index; + +static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST]; +static int mfd_list_index; + +static u32 msm_fb_pseudo_palette[16] = { + 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff +}; + +static struct ion_client *iclient; + +u32 msm_fb_debug_enabled; +/* Setting msm_fb_msg_level to 8 prints out ALL messages */ +u32 msm_fb_msg_level = 7; + +/* Setting mddi_msg_level to 8 prints out ALL messages */ +u32 mddi_msg_level = 5; + +extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK]; +extern unsigned long mdp_timer_duration; + +static int msm_fb_register(struct msm_fb_data_type *mfd); +static int msm_fb_open(struct fb_info *info, int user); +static int msm_fb_release(struct fb_info *info, int user); +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd); +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd); +static int msm_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_set_par(struct fb_info *info); +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable); +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd); +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma); +static int mdp_bl_scale_config(struct msm_fb_data_type *mfd, + struct mdp_bl_scale_data *data); +static void msm_fb_scale_bl(__u32 *bl_lvl); +static void msm_fb_commit_wq_handler(struct work_struct *work); +static int msm_fb_pan_idle(struct msm_fb_data_type *mfd); +static int hack_lcd = 1; +boolean lcd_have_resume = FALSE; +boolean last_backlight_setting = FALSE; +int last_backlight_level = 0; + +static void msm_fb_commit_wq_handler(struct work_struct *work); +static int msm_fb_pan_idle(struct msm_fb_data_type *mfd); +static int hack_lcd = 1; +boolean lcd_have_resume = FALSE; +boolean last_backlight_setting = FALSE; +int last_backlight_level = 0; + + + +#ifdef MSM_FB_ENABLE_DBGFS + +#define MSM_FB_MAX_DBGFS 1024 +#define MAX_BACKLIGHT_BRIGHTNESS 255 + +#define WAIT_FENCE_FIRST_TIMEOUT (3 * MSEC_PER_SEC) +#define WAIT_FENCE_FINAL_TIMEOUT (10 * MSEC_PER_SEC) +/* Display op timeout should be greater than total timeout */ +#define WAIT_DISP_OP_TIMEOUT (WAIT_FENCE_FIRST_TIMEOUT +\ + WAIT_FENCE_FINAL_TIMEOUT) * MDP_MAX_FENCE_FD +#define MAX_TIMELINE_NAME_LEN 16 + +#define WAIT_FENCE_FIRST_TIMEOUT (3 * MSEC_PER_SEC) +#define WAIT_FENCE_FINAL_TIMEOUT (10 * MSEC_PER_SEC) +/* Display op timeout should be greater than total timeout */ +#define WAIT_DISP_OP_TIMEOUT (WAIT_FENCE_FIRST_TIMEOUT +\ + WAIT_FENCE_FINAL_TIMEOUT) * MDP_MAX_FENCE_FD +#define MAX_TIMELINE_NAME_LEN 16 + +int msm_fb_debugfs_file_index; +struct dentry *msm_fb_debugfs_root; +struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS]; +static int bl_scale, bl_min_lvl; + +DEFINE_MUTEX(msm_fb_notify_update_sem); +void msmfb_no_update_notify_timer_cb(unsigned long data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + if (!mfd) + pr_err("%s mfd NULL\n", __func__); + complete(&mfd->msmfb_no_update_notify); +} + +struct dentry *msm_fb_get_debugfs_root(void) +{ + if (msm_fb_debugfs_root == NULL) + msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL); + + return msm_fb_debugfs_root; +} + +void msm_fb_debugfs_file_create(struct dentry *root, const char *name, + u32 *var) +{ + if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS) + return; + + msm_fb_debugfs_file[msm_fb_debugfs_file_index++] = + debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var); +} +#endif + +int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->cursor_update) + return -ENODEV; + + return mfd->cursor_update(info, cursor); +} + +static int msm_fb_resource_initialized; + +#ifndef CONFIG_FB_BACKLIGHT +static int lcd_backlight_registered; + +static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent); + int bl_lvl; + + if (value > MAX_BACKLIGHT_BRIGHTNESS) + value = MAX_BACKLIGHT_BRIGHTNESS; + + /* This maps android backlight level 0 to 255 into + driver backlight level 0 to bl_max with rounding */ + bl_lvl = value; + + if (!bl_lvl && value) + bl_lvl = 1; + + down(&mfd->sem); +/* Remove qcom backlight mechanism,user our own */ +/* If LCD don't resume ,don't turn on LCD backlight */ + if (hack_lcd) { + if(FALSE == lcd_have_resume) { + last_backlight_level = bl_lvl; + last_backlight_setting = TRUE; + } else { + msm_fb_set_backlight(mfd, bl_lvl); + last_backlight_setting = FALSE; + } + } else { + down(&mfd->sem); + msm_fb_set_backlight(mfd, bl_lvl); + up(&mfd->sem); + } +} + +static struct led_classdev backlight_led = { + .name = "lcd-backlight", + .brightness = MAX_BACKLIGHT_BRIGHTNESS, + .brightness_set = msm_fb_set_bl_brightness, +}; +#endif + +static struct msm_fb_platform_data *msm_fb_pdata; +unsigned char hdmi_prim_display; +unsigned char hdmi_prim_resolution; + +int msm_fb_detect_client(const char *name) +{ + int ret = 0; + u32 len; +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; +#endif + if (!msm_fb_pdata) + return -EPERM; + + len = strnlen(name, PANEL_NAME_MAX_LEN); + if (strnlen(msm_fb_pdata->prim_panel_name, PANEL_NAME_MAX_LEN)) { + pr_err("\n name = %s, prim_display = %s", + name, msm_fb_pdata->prim_panel_name); + if (!strncmp((char *)msm_fb_pdata->prim_panel_name, + name, len)) { + if (!strncmp((char *)msm_fb_pdata->prim_panel_name, + "hdmi_msm", len)) + hdmi_prim_display = 1; + hdmi_prim_resolution = + msm_fb_pdata->ext_resolution; + return 0; + } else { + ret = -EPERM; + } + } + + if (strnlen(msm_fb_pdata->ext_panel_name, PANEL_NAME_MAX_LEN)) { + pr_err("\n name = %s, ext_display = %s", + name, msm_fb_pdata->ext_panel_name); + if (!strncmp((char *)msm_fb_pdata->ext_panel_name, name, len)) + return 0; + else + ret = -EPERM; + } + + if (ret) + return ret; + + ret = -EPERM; + if (msm_fb_pdata && msm_fb_pdata->detect_client) { + ret = msm_fb_pdata->detect_client(name); + + /* if it's non mddi panel, we need to pre-scan + mddi client to see if we can disable mddi host */ + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (!ret && msm_fb_pdata->mddi_prescan) + id = mddi_get_client_id(); +#endif + } + + return ret; +} + +static ssize_t msm_fb_msm_fb_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct msm_fb_panel_data *pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + switch (pdata->panel_info.type) { + case NO_PANEL: + ret = snprintf(buf, PAGE_SIZE, "no panel\n"); + break; + case MDDI_PANEL: + ret = snprintf(buf, PAGE_SIZE, "mddi panel\n"); + break; + case EBI2_PANEL: + ret = snprintf(buf, PAGE_SIZE, "ebi2 panel\n"); + break; + case LCDC_PANEL: + ret = snprintf(buf, PAGE_SIZE, "lcdc panel\n"); + break; + case EXT_MDDI_PANEL: + ret = snprintf(buf, PAGE_SIZE, "ext mddi panel\n"); + break; + case TV_PANEL: + ret = snprintf(buf, PAGE_SIZE, "tv panel\n"); + break; + case HDMI_PANEL: + ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n"); + break; + case LVDS_PANEL: + ret = snprintf(buf, PAGE_SIZE, "lvds panel\n"); + break; + case DTV_PANEL: + ret = snprintf(buf, PAGE_SIZE, "dtv panel\n"); + break; + case MIPI_VIDEO_PANEL: + ret = snprintf(buf, PAGE_SIZE, "mipi dsi video panel\n"); + break; + case MIPI_CMD_PANEL: + ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n"); + break; + case WRITEBACK_PANEL: + ret = snprintf(buf, PAGE_SIZE, "writeback panel\n"); + break; + default: + ret = snprintf(buf, PAGE_SIZE, "unknown panel\n"); + break; + } + + return ret; +} + +static DEVICE_ATTR(msm_fb_type, S_IRUGO, msm_fb_msm_fb_type, NULL); +static struct attribute *msm_fb_attrs[] = { + &dev_attr_msm_fb_type.attr, + NULL, +}; +static struct attribute_group msm_fb_attr_group = { + .attrs = msm_fb_attrs, +}; + +static int msm_fb_create_sysfs(struct platform_device *pdev) +{ + int rc; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + rc = sysfs_create_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group); + if (rc) + MSM_FB_ERR("%s: sysfs group creation failed, rc=%d\n", __func__, + rc); + return rc; +} +static void msm_fb_remove_sysfs(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + sysfs_remove_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group); +} +static void bl_workqueue_handler(struct work_struct *work); + +static ssize_t msm_fb_xres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", mfd->panel_info.xres); + buf[strnlen(buf, PAGE_SIZE) + 1] = '\0'; + return ret; +} +static DEVICE_ATTR(xres, S_IRUGO, msm_fb_xres, NULL); +static struct attribute *xres_fs_attrs[] = { + &dev_attr_xres.attr, + NULL, +}; +static struct attribute_group xres_fs_attr_group = { + .attrs = xres_fs_attrs, +}; + +static ssize_t msm_fb_yres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", mfd->panel_info.yres); + buf[strnlen(buf, PAGE_SIZE) + 1] = '\0'; + return ret; +} +static DEVICE_ATTR(yres, S_IRUGO, msm_fb_yres, NULL); +static struct attribute *yres_fs_attrs[] = { + &dev_attr_yres.attr, + NULL, +}; +static struct attribute_group yres_fs_attr_group = { + .attrs = yres_fs_attrs, +}; + +static int msm_fb_resolution_sysfs(struct platform_device *pdev) +{ + int rc; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + if (!mfd) { + pr_err("%s: mfd not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi) { + pr_err("%s: mfd->fbi not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi->dev) { + pr_err("%s: mfd->fbi->dev not found\n", __func__); + return -ENODEV; + } + rc = sysfs_create_group(&mfd->fbi->dev->kobj, + &xres_fs_attr_group); + if (rc) { + pr_err("%s: sysfs group creation failed, rc=%d\n", + __func__, rc); + return rc; + } + + rc = sysfs_create_group(&mfd->fbi->dev->kobj, + &yres_fs_attr_group); + if (rc) { + pr_err("%s: sysfs group creation failed, rc=%d\n", + __func__, rc); + return rc; + } + return 0; +} + +static void bl_workqueue_handler(struct work_struct *work); +static ssize_t msm_fb_xres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", mfd->panel_info.xres); + buf[strnlen(buf, PAGE_SIZE) + 1] = '\0'; + return ret; +} +static DEVICE_ATTR(xres, S_IRUGO, msm_fb_xres, NULL); +static struct attribute *xres_fs_attrs[] = { + &dev_attr_xres.attr, + NULL, +}; +static struct attribute_group xres_fs_attr_group = { + .attrs = xres_fs_attrs, +}; + +static ssize_t msm_fb_yres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", mfd->panel_info.yres); + buf[strnlen(buf, PAGE_SIZE) + 1] = '\0'; + return ret; +} +static DEVICE_ATTR(yres, S_IRUGO, msm_fb_yres, NULL); +static struct attribute *yres_fs_attrs[] = { + &dev_attr_yres.attr, + NULL, +}; +static struct attribute_group yres_fs_attr_group = { + .attrs = yres_fs_attrs, +}; + +static int msm_fb_resolution_sysfs(struct platform_device *pdev) +{ + int rc; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + if (!mfd) { + pr_err("%s: mfd not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi) { + pr_err("%s: mfd->fbi not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi->dev) { + pr_err("%s: mfd->fbi->dev not found\n", __func__); + return -ENODEV; + } + rc = sysfs_create_group(&mfd->fbi->dev->kobj, + &xres_fs_attr_group); + if (rc) { + pr_err("%s: sysfs group creation failed, rc=%d\n", + __func__, rc); + return rc; + } + + rc = sysfs_create_group(&mfd->fbi->dev->kobj, + &yres_fs_attr_group); + if (rc) { + pr_err("%s: sysfs group creation failed, rc=%d\n", + __func__, rc); + return rc; + } + return 0; +} + +static void bl_workqueue_handler(struct work_struct *work); + +static ssize_t msm_fb_xres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", mfd->panel_info.xres); + buf[strnlen(buf, PAGE_SIZE) + 1] = '\0'; + return ret; +} +static DEVICE_ATTR(xres, S_IRUGO, msm_fb_xres, NULL); +static struct attribute *xres_fs_attrs[] = { + &dev_attr_xres.attr, + NULL, +}; +static struct attribute_group xres_fs_attr_group = { + .attrs = xres_fs_attrs, +}; + +static ssize_t msm_fb_yres(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", mfd->panel_info.yres); + buf[strnlen(buf, PAGE_SIZE) + 1] = '\0'; + return ret; +} +static DEVICE_ATTR(yres, S_IRUGO, msm_fb_yres, NULL); +static struct attribute *yres_fs_attrs[] = { + &dev_attr_yres.attr, + NULL, +}; +static struct attribute_group yres_fs_attr_group = { + .attrs = yres_fs_attrs, +}; + +static int msm_fb_resolution_sysfs(struct platform_device *pdev) +{ + int rc; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + if (!mfd) { + pr_err("%s: mfd not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi) { + pr_err("%s: mfd->fbi not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi->dev) { + pr_err("%s: mfd->fbi->dev not found\n", __func__); + return -ENODEV; + } + rc = sysfs_create_group(&mfd->fbi->dev->kobj, + &xres_fs_attr_group); + if (rc) { + pr_err("%s: sysfs group creation failed, rc=%d\n", + __func__, rc); + return rc; + } + + rc = sysfs_create_group(&mfd->fbi->dev->kobj, + &yres_fs_attr_group); + if (rc) { + pr_err("%s: sysfs group creation failed, rc=%d\n", + __func__, rc); + return rc; + } + return 0; +} + +static int msm_fb_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + int rc; + int err = 0; + + MSM_FB_DEBUG("msm_fb_probe\n"); + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + msm_fb_pdata = pdev->dev.platform_data; + fbram_size = + pdev->resource[0].end - pdev->resource[0].start + 1; + fbram_phys = (char *)pdev->resource[0].start; + fbram = __va(fbram_phys); + + if (!fbram) { + printk(KERN_ERR "fbram ioremap failed!\n"); + return -ENOMEM; + } + MSM_FB_DEBUG("msm_fb_probe: phy_Addr = 0x%x virt = 0x%x\n", + (int)fbram_phys, (int)fbram); + + iclient = msm_ion_client_create(-1, pdev->name); + if (IS_ERR_OR_NULL(iclient)) { + pr_err("msm_ion_client_create() return" + " error, val %p\n", iclient); + iclient = NULL; + } + + msm_fb_resource_initialized = 1; + return 0; + } + + if (!msm_fb_resource_initialized) + return -EPERM; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + INIT_DELAYED_WORK(&mfd->backlight_worker, bl_workqueue_handler); + + INIT_DELAYED_WORK(&mfd->backlight_worker, bl_workqueue_handler); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + vsync_cntrl.dev = mfd->fbi->dev; + mfd->panel_info.frame_count = 0; + mfd->bl_level = 0; + bl_scale = 1024; + bl_min_lvl = 255; +#ifdef CONFIG_FB_MSM_OVERLAY + mfd->overlay_play_enable = 1; +#endif + + bf_supported = mdp4_overlay_borderfill_supported(); + + rc = msm_fb_register(mfd); + if (rc) + return rc; + err = pm_runtime_set_active(mfd->fbi->dev); + if (err < 0) + printk(KERN_ERR "pm_runtime: fail to set active.\n"); + pm_runtime_enable(mfd->fbi->dev); +#ifdef CONFIG_FB_BACKLIGHT + msm_fb_config_backlight(mfd); +#else + /* android supports only one lcd-backlight/lcd for now */ + if (!lcd_backlight_registered) { + if (led_classdev_register(&pdev->dev, &backlight_led)) + printk(KERN_ERR "led_classdev_register failed\n"); + else + lcd_backlight_registered = 1; + } +#endif + + pdev_list[pdev_list_cnt++] = pdev; + msm_fb_create_sysfs(pdev); + msm_fb_resolution_sysfs(pdev); + + if (mfd->timeline == NULL) { + char timeline_name[MAX_TIMELINE_NAME_LEN]; + snprintf(timeline_name, sizeof(timeline_name), + "mdp_fb_%d", mfd->index); + mfd->timeline = sw_sync_timeline_create(timeline_name); + if (mfd->timeline == NULL) { + pr_err("%s: cannot create time line", __func__); + return -ENOMEM; + } else { + mfd->timeline_value = 0; + } + } + + return 0; +} + +static int msm_fb_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("msm_fb_remove\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + msm_fb_pan_idle(mfd); + + msm_fb_remove_sysfs(pdev); + + pm_runtime_disable(mfd->fbi->dev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (msm_fb_suspend_sub(mfd)) + printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index); + + if (mfd->channel_irq != 0) + free_irq(mfd->channel_irq, (void *)mfd); + + if (mfd->vsync_width_boundary) + vfree(mfd->vsync_width_boundary); + + if (mfd->vsync_resync_timer.function) + del_timer(&mfd->vsync_resync_timer); + + if (mfd->refresh_timer.function) + del_timer(&mfd->refresh_timer); + + if (mfd->dma_hrtimer.function) + hrtimer_cancel(&mfd->dma_hrtimer); + + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + complete(&mfd->msmfb_no_update_notify); + complete(&mfd->msmfb_update_notify); + + /* remove /dev/fb* */ + unregister_framebuffer(mfd->fbi); + +#ifdef CONFIG_FB_BACKLIGHT + /* remove /sys/class/backlight */ + backlight_device_unregister(mfd->fbi->bl_dev); +#else + if (lcd_backlight_registered) { + lcd_backlight_registered = 0; + led_classdev_unregister(&backlight_led); + } +#endif + +#ifdef MSM_FB_ENABLE_DBGFS + if (mfd->sub_dir) + debugfs_remove(mfd->sub_dir); +#endif + + return 0; +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct msm_fb_data_type *mfd; + int ret = 0; + + MSM_FB_DEBUG("Enter\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + msm_fb_pan_idle(mfd); + + console_lock(); + fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED); + ret = msm_fb_suspend_sub(mfd); + if (ret != 0) { + printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret); + fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING); + } else { + pdev->dev.power.power_state = state; + } + + console_unlock(); + return ret; +} +#else +#define msm_fb_suspend NULL +#endif + +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + complete(&mfd->msmfb_no_update_notify); + + /* + * suspend this channel + */ + mfd->suspend.sw_refreshing_enable = mfd->sw_refreshing_enable; + mfd->suspend.op_enable = mfd->op_enable; + mfd->suspend.panel_power_on = mfd->panel_power_on; + mfd->suspend.op_suspend = true; + MSM_DRM_DEBUG(" op_enable:%d,panel_power_on:%d\n", mfd->suspend.op_enable, mfd->suspend.panel_power_on); + + if (mfd->op_enable) { + ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->suspend.op_enable); + if (ret) { + MSM_FB_INFO + ("msm_fb_suspend: can't turn off display!\n"); + return ret; + } + mfd->op_enable = FALSE; + } + /* + * try to power down + */ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + /* + * detach display channel irq if there's any + * or wait until vsync-resync completes + */ + if ((mfd->dest == DISPLAY_LCD)) { + if (mfd->panel_info.lcd.vsync_enable) { + if (mfd->panel_info.lcd.hw_vsync_mode) { + if (mfd->channel_irq != 0) + disable_irq(mfd->channel_irq); + } else { + volatile boolean vh_pending; + do { + vh_pending = mfd->vsync_handler_pending; + } while (vh_pending); + } + } + } + + return 0; +} + +#ifdef CONFIG_PM +static int msm_fb_resume_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + struct msm_fb_panel_data *pdata = NULL; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + /* attach display channel irq if there's any */ + if (mfd->channel_irq != 0) + enable_irq(mfd->channel_irq); + + /* resume state var recover */ + mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable; + mfd->op_enable = mfd->suspend.op_enable; + MSM_DRM_DEBUG("op_enable:%d,panel_power_on:%d\n", + mfd->suspend.op_enable,mfd->suspend.panel_power_on); + + if (mfd->suspend.panel_power_on) { + if (mfd->panel_driver_on == FALSE) + msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->op_enable); + ret = + msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi, + mfd->op_enable); + if (ret) + MSM_FB_INFO("msm_fb_resume: can't turn on display!\n"); + } + + mfd->suspend.op_suspend = false; + + return ret; +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_resume(struct platform_device *pdev) +{ + /* This resume function is called when interrupt is enabled. + */ + int ret = 0; + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("Enter\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + msm_fb_pan_idle(mfd); + + console_lock(); + ret = msm_fb_resume_sub(mfd); + pdev->dev.power.power_state = PMSG_ON; + fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING); + console_unlock(); + + return ret; +} +#else +#define msm_fb_resume NULL +#endif + +static int msm_fb_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int msm_fb_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static int msm_fb_runtime_idle(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: idling...\n"); + return 0; +} + +#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL)) +static int msm_fb_ext_suspend(struct device *dev) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(dev); + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + msm_fb_pan_idle(mfd); + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + if (mfd->panel_info.type == HDMI_PANEL || + mfd->panel_info.type == DTV_PANEL) { + ret = msm_fb_suspend_sub(mfd); + + /* Turn off the HPD circuitry */ + if (pdata->power_ctrl) { + MSM_FB_INFO("%s: Turning off HPD circuitry\n", + __func__); + pdata->power_ctrl(FALSE); + } + } + + return ret; +} + +static int msm_fb_ext_resume(struct device *dev) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(dev); + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + msm_fb_pan_idle(mfd); + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + if (mfd->panel_info.type == HDMI_PANEL || + mfd->panel_info.type == DTV_PANEL) { + /* Turn on the HPD circuitry */ + if (pdata->power_ctrl) { + pdata->power_ctrl(TRUE); + MSM_FB_INFO("%s: Turning on HPD circuitry\n", + __func__); + } + + ret = msm_fb_resume_sub(mfd); + } + + return ret; +} +#endif + +#ifdef LCD_GLANCEVIEW_SCREEN +int glancescreen_suspend_flag = 0; +void lcd_gv_mode_awake(struct device * dev) +{ + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct msm_fb_data_type *mfd; + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + MSM_DRM_DEBUG("start\n"); + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + pdata = (struct msm_fb_panel_data *)dev->platform_data; + if ((!pdata) ||(!pdata->glance_screen)){ + printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n"); + } + + glancescreen_suspend_flag = 0; + + //pjn add to open mipi + msm_fb_resume_sub(mfd); + + ret = pdata->glance_screen(pdev); + if (ret) + printk("%s, lcd glance screen resume fail\n",__func__); + + return; +} + +void lcd_gv_mode_asleep(struct device * dev) +{ + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct msm_fb_data_type *mfd; + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + MSM_DRM_DEBUG("start\n"); + //TODO: + /*Add low power mode under glance view mode here*/ + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + pdata = (struct msm_fb_panel_data *)dev->platform_data; + if ((!pdata) ||(!pdata->glance_screen)){ + printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n"); + } + + glancescreen_suspend_flag = 1; + ret = pdata->glance_screen(pdev); + if (ret) + printk("%s, lcd glance screen sleep fail\n",__func__); + + //pjn add to close mipi + msm_fb_suspend_sub(mfd); +} + +int lcd_gv_mode(struct device * dev,enum glanceview_op op) +{ + if(dev==NULL) + { + return -1; + } + switch(op){ + case gv_enable: + lcd_gv_mode_awake(dev); + break; + case gv_disable: + lcd_gv_mode_asleep(dev); + break; + default: + break; + } + + return 0; +} + +static struct glanceview_ops gv_dev= +{ + .gv_glance_mode=lcd_gv_mode, +}; +#endif +//pjn end +static struct dev_pm_ops msm_fb_dev_pm_ops = { + .runtime_suspend = msm_fb_runtime_suspend, + .runtime_resume = msm_fb_runtime_resume, + .runtime_idle = msm_fb_runtime_idle, +#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL)) + .suspend = msm_fb_ext_suspend, + .resume = msm_fb_ext_resume, +#endif +}; + +static struct platform_driver msm_fb_driver = { + .probe = msm_fb_probe, + .remove = msm_fb_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = msm_fb_suspend, + .resume = msm_fb_resume, +#endif + .shutdown = NULL, + .driver = { + /* Driver name must match the device name added in platform.c. */ + .name = "msm_fb", + .pm = &msm_fb_dev_pm_ops, + }, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void msmfb_early_suspend(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); + + msm_fb_pan_idle(mfd); + + msm_fb_suspend_sub(mfd); +} + +static void msmfb_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); + msm_fb_resume_sub(mfd); +} +#endif + +static int unset_bl_level, bl_updated; +static int bl_level_old, pan_display_flag; +static int mdp_bl_scale_config(struct msm_fb_data_type *mfd, + struct mdp_bl_scale_data *data) +{ + int ret = 0; + int curr_bl; + down(&mfd->sem); + curr_bl = mfd->bl_level; + bl_scale = data->scale; + bl_min_lvl = data->min_lvl; + pr_debug("%s: update scale = %d, min_lvl = %d\n", __func__, bl_scale, + bl_min_lvl); + + /* update current backlight to use new scaling*/ + if (mfd->panel_power_on && bl_updated) + msm_fb_set_backlight(mfd, curr_bl); + up(&mfd->sem); + return ret; +} + +static void msm_fb_scale_bl(__u32 *bl_lvl) +{ + __u32 temp = *bl_lvl; + pr_debug("%s: input = %d, scale = %d", __func__, temp, bl_scale); + if (temp >= bl_min_lvl) { + /* bl_scale is the numerator of scaling fraction (x/1024)*/ + temp = ((*bl_lvl) * bl_scale) / 1024; + + /*if less than minimum level, use min level*/ + if (temp < bl_min_lvl) + temp = bl_min_lvl; + } + pr_debug("%s: output = %d", __func__, temp); + + (*bl_lvl) = temp; +} + +void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl) +{ + struct msm_fb_panel_data *pdata; + __u32 temp = bkl_lvl; + + if(gv_dev.state==1){ + unset_bl_level = 0; + MSM_DRM_DEBUG(":unset_bl_level = %d\n", unset_bl_level); + return; + } + if (!mfd->panel_power_on || !bl_updated) { + unset_bl_level = bkl_lvl; +//Normandy_P010154 remove to fix flash screen in charger mode by wang.xiaojun3@byd.com 131219 + if((unset_bl_level > 10) && !bl_updated && pan_display_flag) + schedule_delayed_work(&mfd->backlight_worker, backlight_duration); + MSM_DRM_DEBUG("bl_updated = %d,power_on=%d,level=%d\n", bl_updated,mfd->panel_power_on, bkl_lvl); + return; + } else { + unset_bl_level = 0; + } + + MSM_DRM_DEBUG(" %d\n", unset_bl_level); + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + if ((pdata) && (pdata->set_backlight)) { + msm_fb_scale_bl(&temp); + mfd->bl_level = temp; + pdata->set_backlight(mfd); + mfd->bl_level = bkl_lvl; + bl_level_old = temp; + } +} + +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + + if (!op_enable) + return -EPERM; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + if ((!pdata) || (!pdata->on) || (!pdata->off)) { + printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n"); + return -ENODEV; + } + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + if (!mfd->panel_power_on) { + msleep(16); + ret = pdata->on(mfd->pdev); + if (ret == 0) { + down(&mfd->sem); + mfd->panel_power_on = TRUE; + up(&mfd->sem); + +/* ToDo: possible conflict with android which doesn't expect sw refresher */ +/* + if (!mfd->hw_refresh) + { + if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0) + { + MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret); + } + } +*/ + } + } + break; + + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + case FB_BLANK_POWERDOWN: + default: + if (mfd->panel_power_on) { + int curr_pwr_state; + + mfd->op_enable = FALSE; + curr_pwr_state = mfd->panel_power_on; + + down(&mfd->sem); + msm_fb_set_backlight(mfd, 0); + mfd->panel_power_on = FALSE; + bl_updated = 0; + pan_display_flag = 0; + up(&mfd->sem); + if (delayed_work_pending(&mfd->backlight_worker)) + cancel_delayed_work_sync(&mfd->backlight_worker); + + ret = pdata->off(mfd->pdev); + if (ret) + mfd->panel_power_on = curr_pwr_state; + + mfd->op_enable = TRUE; + } + break; + } + + return ret; +} + +int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp) +{ + struct msm_panel_info *panel_info = &mfd->panel_info; + int remainder, yres, offset; + +#ifdef CONFIG_FB_MSM_ALIGN_BUFFER + if (!align_buffer) + { + return fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length; + } +#endif + + if (panel_info->mode2_yres != 0) { + yres = panel_info->mode2_yres; + remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1); + } else { + yres = panel_info->yres; + remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1); + } + + if (!remainder) + remainder = PAGE_SIZE; + + if (fbi->var.yoffset < yres) { + offset = (fbi->var.xoffset * bpp); + /* iBuf->buf += fbi->var.xoffset * bpp + 0 * + yres * fbi->fix.line_length; */ + } else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) { + offset = (fbi->var.xoffset * bpp + yres * + fbi->fix.line_length + PAGE_SIZE - remainder); + } else { + offset = (fbi->var.xoffset * bpp + 2 * yres * + fbi->fix.line_length + 2 * (PAGE_SIZE - remainder)); + } + return offset; +} + +static void msm_fb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); + cfb_fillrect(info, rect); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (rect->dy << 16) | (rect->dx); + var.reserved[2] = ((rect->dy + rect->height) << 16) | + (rect->dx + rect->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + msm_fb_pan_idle(mfd); + cfb_copyarea(info, area); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (area->dy << 16) | (area->dx); + var.reserved[2] = ((area->dy + area->height) << 16) | + (area->dx + area->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + msm_fb_pan_idle(mfd); + cfb_imageblit(info, image); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (image->dy << 16) | (image->dx); + var.reserved[2] = ((image->dy + image->height) << 16) | + (image->dx + image->width); + + msm_fb_pan_display(&var, info); + } +} + +static int msm_fb_blank(int blank_mode, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); + if (mfd->op_enable == 0) { + if (blank_mode == FB_BLANK_UNBLANK) + mfd->suspend.panel_power_on = TRUE; + else + mfd->suspend.panel_power_on = FALSE; + } + return msm_fb_blank_sub(blank_mode, info, mfd->op_enable); +} + +static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->lut_update) + return -ENODEV; + + mfd->lut_update(info, cmap); + return 0; +} + +/* + * Custom Framebuffer mmap() function for MSM driver. + * Differs from standard mmap() function by allowing for customized + * page-protection. + */ +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma) +{ + /* Get frame buffer memory range. */ + unsigned long start = info->fix.smem_start; + u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + msm_fb_pan_idle(mfd); + if (off >= len) { + /* memory mapped io */ + off -= len; + if (info->var.accel_flags) { + mutex_unlock(&info->lock); + return -EINVAL; + } + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); + } + + /* Set VM flags. */ + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO | VM_RESERVED; + + /* Set VM page protection */ + if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE) + vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE) + vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE) + vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* Remap the frame buffer I/O range */ + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static struct fb_ops msm_fb_ops = { + .owner = THIS_MODULE, + .fb_open = msm_fb_open, + .fb_release = msm_fb_release, + .fb_read = NULL, + .fb_write = NULL, + .fb_cursor = NULL, + .fb_check_var = msm_fb_check_var, /* vinfo check */ + .fb_set_par = msm_fb_set_par, /* set the video mode according to info->var */ + .fb_setcolreg = NULL, /* set color register */ + .fb_blank = msm_fb_blank, /* blank display */ + .fb_pan_display = msm_fb_pan_display, /* pan display */ + .fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */ + .fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */ + .fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */ + .fb_rotate = NULL, + .fb_sync = NULL, /* wait for blit idle, optional */ + .fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */ + .fb_mmap = msm_fb_mmap, +}; + +static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp) +{ + /* The adreno GPU hardware requires that the pitch be aligned to + 32 pixels for color buffers, so for the cases where the GPU + is writing directly to fb0, the framebuffer pitch + also needs to be 32 pixel aligned */ + + if (fb_index == 0) + return ALIGN(xres, 32) * bpp; + else + return xres * bpp; +} + +static int msm_fb_register(struct msm_fb_data_type *mfd) +{ + int ret = -ENODEV; + int bpp; + struct msm_panel_info *panel_info = &mfd->panel_info; + struct fb_info *fbi = mfd->fbi; + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + int *id; + int fbram_offset; + int remainder, remainder_mode2; + + /* + * fb info initialization + */ + fix = &fbi->fix; + var = &fbi->var; + + fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */ + fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */ + fix->ywrapstep = 0; /* No support */ + fix->mmio_start = 0; /* No MMIO Address */ + fix->mmio_len = 0; /* No MMIO Address */ + fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */ + + var->xoffset = 0, /* Offset from virtual to visible */ + var->yoffset = 0, /* resolution */ + var->grayscale = 0, /* No graylevels */ + var->nonstd = 0, /* standard pixel format */ + var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */ + var->height = -1, /* height of picture in mm */ + var->width = -1, /* width of picture in mm */ + var->accel_flags = 0, /* acceleration flags */ + var->sync = 0, /* see FB_SYNC_* */ + var->rotate = 0, /* angle we rotate counter clockwise */ + mfd->op_enable = FALSE; + + switch (mfd->fb_imgType) { + case MDP_RGB_565: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + case MDP_RGB_888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 3; + break; + + case MDP_ARGB_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 24; + var->transp.length = 8; + bpp = 4; + break; + + case MDP_RGBA_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 8; + var->green.offset = 16; + var->red.offset = 24; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 8; + bpp = 4; + break; + + case MDP_BGRA_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 24; + var->transp.length = 8; + bpp = 4; + break; + + + case MDP_YCRYCB_H2V1: + /* ToDo: need to check TV-Out YUV422i framebuffer format */ + /* we might need to create new type define */ + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->xpanstep = 2; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + /* how about R/G/B offset? */ + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + default: + MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n", + mfd->index); + return ret; + } + + fix->type = panel_info->is_3d_panel; + + fix->line_length = msm_fb_line_length(mfd->index, panel_info->xres, + bpp); + + /* Make sure all buffers can be addressed on a page boundary by an x + * and y offset */ + + remainder = (fix->line_length * panel_info->yres) & (PAGE_SIZE - 1); + /* PAGE_SIZE is a power of 2 */ + if (!remainder) + remainder = PAGE_SIZE; + remainder_mode2 = (fix->line_length * + panel_info->mode2_yres) & (PAGE_SIZE - 1); + if (!remainder_mode2) + remainder_mode2 = PAGE_SIZE; + + /* + * calculate smem_len based on max size of two supplied modes. + * Only fb0 has mem. fb1 and fb2 don't have mem. + */ + if (!bf_supported || mfd->index == 0) + fix->smem_len = MAX((msm_fb_line_length(mfd->index, + panel_info->xres, + bpp) * + panel_info->yres + PAGE_SIZE - + remainder) * mfd->fb_page, + (msm_fb_line_length(mfd->index, + panel_info->mode2_xres, + bpp) * + panel_info->mode2_yres + PAGE_SIZE - + remainder_mode2) * mfd->fb_page); + else if (mfd->index == 1 || mfd->index == 2) { + pr_debug("%s:%d no memory is allocated for fb%d!\n", + __func__, __LINE__, mfd->index); + fix->smem_len = 0; + } + + mfd->var_xres = panel_info->xres; + mfd->var_yres = panel_info->yres; + mfd->var_frame_rate = panel_info->frame_rate; + + var->pixclock = mfd->panel_info.clk_rate; + mfd->var_pixclock = var->pixclock; + + var->xres = panel_info->xres; + var->yres = panel_info->yres; + var->xres_virtual = panel_info->xres; + var->yres_virtual = panel_info->yres * mfd->fb_page + + ((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page; + var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */ + if (mfd->dest == DISPLAY_LCD) { + if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1) + var->reserved[4] = panel_info->lcd.refx100 / (100 * 2); + else + var->reserved[4] = 60;//panel_info->lcd.refx100 / 100; + } else { + if (panel_info->type == MIPI_VIDEO_PANEL) { + var->reserved[4] = panel_info->mipi.frame_rate; + } else { + var->reserved[4] = panel_info->clk_rate / + ((panel_info->lcdc.h_back_porch + + panel_info->lcdc.h_front_porch + + panel_info->lcdc.h_pulse_width + + panel_info->xres) * + (panel_info->lcdc.v_back_porch + + panel_info->lcdc.v_front_porch + + panel_info->lcdc.v_pulse_width + + panel_info->yres)); + } + } + pr_debug("reserved[4] %u\n", var->reserved[4]); + + /* + * id field for fb app + */ + id = (int *)&mfd->panel; + + switch (mdp_rev) { + case MDP_REV_20: + snprintf(fix->id, sizeof(fix->id), "msmfb20_%x", (__u32) *id); + break; + case MDP_REV_22: + snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id); + break; + case MDP_REV_30: + snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id); + break; + case MDP_REV_303: + snprintf(fix->id, sizeof(fix->id), "msmfb303_%x", (__u32) *id); + break; + case MDP_REV_31: + snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id); + break; + case MDP_REV_40: + snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id); + break; + case MDP_REV_41: + snprintf(fix->id, sizeof(fix->id), "msmfb41_%x", (__u32) *id); + break; + case MDP_REV_42: + snprintf(fix->id, sizeof(fix->id), "msmfb42_%x", (__u32) *id); + break; + case MDP_REV_43: + snprintf(fix->id, sizeof(fix->id), "msmfb43_%x", (__u32) *id); + break; + case MDP_REV_44: + snprintf(fix->id, sizeof(fix->id), "msmfb44_%x", (__u32) *id); + break; + default: + snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id); + break; + } + + fbi->fbops = &msm_fb_ops; + fbi->flags = FBINFO_FLAG_DEFAULT; + fbi->pseudo_palette = msm_fb_pseudo_palette; + + mfd->ref_cnt = 0; + mfd->sw_currently_refreshing = FALSE; + mfd->sw_refreshing_enable = TRUE; + mfd->panel_power_on = FALSE; + + mfd->pan_waiting = FALSE; + init_completion(&mfd->pan_comp); + init_completion(&mfd->refresher_comp); + sema_init(&mfd->sem, 1); + + init_timer(&mfd->msmfb_no_update_notify_timer); + mfd->msmfb_no_update_notify_timer.function = + msmfb_no_update_notify_timer_cb; + mfd->msmfb_no_update_notify_timer.data = (unsigned long)mfd; + init_completion(&mfd->msmfb_update_notify); + init_completion(&mfd->msmfb_no_update_notify); + init_completion(&mfd->commit_comp); + mutex_init(&mfd->sync_mutex); + INIT_WORK(&mfd->commit_work, msm_fb_commit_wq_handler); + mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type), + GFP_KERNEL); + if (mfd->msm_fb_backup == 0) { + pr_err("error: not enough memory!\n"); + return -ENOMEM; + } + fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram; + fbram += fbram_offset; + fbram_phys += fbram_offset; + fbram_size -= fbram_offset; + + if (!bf_supported || mfd->index == 0) + if (fbram_size < fix->smem_len) { + pr_err("error: no more framebuffer memory!\n"); + return -ENOMEM; + } + + fbi->screen_base = fbram; + fbi->fix.smem_start = (unsigned long)fbram_phys; + + memset(fbi->screen_base, 0x0, fix->smem_len); + + msm_iommu_map_contig_buffer(fbi->fix.smem_start, + DISPLAY_WRITE_DOMAIN, + GEN_POOL, + fbi->fix.smem_len, + SZ_4K, + 0, + &(mfd->display_iova)); + + msm_iommu_map_contig_buffer(fbi->fix.smem_start, + DISPLAY_READ_DOMAIN, + GEN_POOL, + fbi->fix.smem_len, + SZ_4K, + 0, + &(mfd->display_iova)); + + msm_iommu_map_contig_buffer(fbi->fix.smem_start, + ROTATOR_SRC_DOMAIN, + GEN_POOL, + fbi->fix.smem_len, + SZ_4K, + 0, + &(mfd->rotator_iova)); + + if (!bf_supported || mfd->index == 0) + memset(fbi->screen_base, 0x0, fix->smem_len); + + mfd->op_enable = TRUE; + mfd->panel_power_on = FALSE; + + /* cursor memory allocation */ + if (mfd->cursor_update) { + unsigned long cursor_buf_iommu = 0; + mfd->cursor_buf = dma_alloc_coherent(NULL, + MDP_CURSOR_SIZE, + (dma_addr_t *) &mfd->cursor_buf_phys, + GFP_KERNEL); + + msm_iommu_map_contig_buffer((unsigned long)mfd->cursor_buf_phys, + DISPLAY_READ_DOMAIN, + GEN_POOL, + MDP_CURSOR_SIZE, + SZ_4K, + 0, + &cursor_buf_iommu); + if (cursor_buf_iommu) + mfd->cursor_buf_phys = (void *)cursor_buf_iommu; + + if (!mfd->cursor_buf) + mfd->cursor_update = 0; + } + + if (mfd->lut_update) { + ret = fb_alloc_cmap(&fbi->cmap, 256, 0); + if (ret) + printk(KERN_ERR "%s: fb_alloc_cmap() failed!\n", + __func__); + } + + if (register_framebuffer(fbi) < 0) { + if (mfd->lut_update) + fb_dealloc_cmap(&fbi->cmap); + + if (mfd->cursor_buf) + dma_free_coherent(NULL, + MDP_CURSOR_SIZE, + mfd->cursor_buf, + (dma_addr_t) mfd->cursor_buf_phys); + + mfd->op_enable = FALSE; + return -EPERM; + } + + fbram += fix->smem_len; + fbram_phys += fix->smem_len; + fbram_size -= fix->smem_len; + + MSM_FB_INFO + ("FrameBuffer[%d] %dx%d size=%d bytes is registered successfully!\n", + mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len); + +#ifdef CONFIG_FB_MSM_LOGO + /* Flip buffer */ + if (!load_565rle_image(INIT_IMAGE_FILE, bf_supported)) + ; +#endif + ret = 0; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if (mfd->panel_info.type != DTV_PANEL) { + mfd->early_suspend.suspend = msmfb_early_suspend; + mfd->early_suspend.resume = msmfb_early_resume; + mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2; + register_early_suspend(&mfd->early_suspend); + } +#endif + +//pjn add to register glanceview +#ifdef LCD_GLANCEVIEW_SCREEN +glanceview_register(gv_device_id_lcd, &gv_dev, &mfd->pdev->dev); +#endif +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + struct dentry *sub_dir; + char sub_name[2]; + + root = msm_fb_get_debugfs_root(); + if (root != NULL) { + sub_name[0] = (char)(mfd->index + 0x30); + sub_name[1] = '\0'; + sub_dir = debugfs_create_dir(sub_name, root); + } else { + sub_dir = NULL; + } + + mfd->sub_dir = sub_dir; + + if (sub_dir) { + msm_fb_debugfs_file_create(sub_dir, "op_enable", + (u32 *) &mfd->op_enable); + msm_fb_debugfs_file_create(sub_dir, "panel_power_on", + (u32 *) &mfd-> + panel_power_on); + msm_fb_debugfs_file_create(sub_dir, "ref_cnt", + (u32 *) &mfd->ref_cnt); + msm_fb_debugfs_file_create(sub_dir, "fb_imgType", + (u32 *) &mfd->fb_imgType); + msm_fb_debugfs_file_create(sub_dir, + "sw_currently_refreshing", + (u32 *) &mfd-> + sw_currently_refreshing); + msm_fb_debugfs_file_create(sub_dir, + "sw_refreshing_enable", + (u32 *) &mfd-> + sw_refreshing_enable); + + msm_fb_debugfs_file_create(sub_dir, "xres", + (u32 *) &mfd->panel_info. + xres); + msm_fb_debugfs_file_create(sub_dir, "yres", + (u32 *) &mfd->panel_info. + yres); + msm_fb_debugfs_file_create(sub_dir, "bpp", + (u32 *) &mfd->panel_info. + bpp); + msm_fb_debugfs_file_create(sub_dir, "type", + (u32 *) &mfd->panel_info. + type); + msm_fb_debugfs_file_create(sub_dir, "wait_cycle", + (u32 *) &mfd->panel_info. + wait_cycle); + msm_fb_debugfs_file_create(sub_dir, "pdest", + (u32 *) &mfd->panel_info. + pdest); + msm_fb_debugfs_file_create(sub_dir, "backbuff", + (u32 *) &mfd->panel_info. + fb_num); + msm_fb_debugfs_file_create(sub_dir, "clk_rate", + (u32 *) &mfd->panel_info. + clk_rate); + msm_fb_debugfs_file_create(sub_dir, "frame_count", + (u32 *) &mfd->panel_info. + frame_count); + + + switch (mfd->dest) { + case DISPLAY_LCD: + msm_fb_debugfs_file_create(sub_dir, + "vsync_enable", + (u32 *)&mfd->panel_info.lcd.vsync_enable); + msm_fb_debugfs_file_create(sub_dir, + "refx100", + (u32 *) &mfd->panel_info.lcd. refx100); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcd.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcd.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcd.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "hw_vsync_mode", + (u32 *) &mfd->panel_info.lcd.hw_vsync_mode); + msm_fb_debugfs_file_create(sub_dir, + "vsync_notifier_period", (u32 *) + &mfd->panel_info.lcd.vsync_notifier_period); + break; + + case DISPLAY_LCDC: + msm_fb_debugfs_file_create(sub_dir, + "h_back_porch", + (u32 *) &mfd->panel_info.lcdc.h_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_front_porch", + (u32 *) &mfd->panel_info.lcdc.h_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_pulse_width", + (u32 *) &mfd->panel_info.lcdc.h_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcdc.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcdc.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcdc.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "border_clr", + (u32 *) &mfd->panel_info.lcdc.border_clr); + msm_fb_debugfs_file_create(sub_dir, + "underflow_clr", + (u32 *) &mfd->panel_info.lcdc.underflow_clr); + msm_fb_debugfs_file_create(sub_dir, + "hsync_skew", + (u32 *) &mfd->panel_info.lcdc.hsync_skew); + break; + + default: + break; + } + } + } +#endif /* MSM_FB_ENABLE_DBGFS */ + + return ret; +} + +static int msm_fb_open(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + bool unblank = true; + int result; + + result = pm_runtime_get_sync(info->dev); + + if (result < 0) { + printk(KERN_ERR "pm_runtime: fail to wake up\n"); + } + + if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */ + mfd->ref_cnt++; + return 0; + } + + if (!mfd->ref_cnt) { + if (!bf_supported || + (info->node != 1 && info->node != 2)) + mdp_set_dma_pan_info(info, NULL, TRUE); + else + pr_debug("%s:%d no mdp_set_dma_pan_info %d\n", + __func__, __LINE__, info->node); + + if (mfd->is_panel_ready && !mfd->is_panel_ready()) + unblank = false; + + if (unblank) { + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, + info, TRUE)) { + MSM_FB_ERR("%s: can't turn on display!\n", + __func__); + return -EPERM; + } + } + } + + mfd->ref_cnt++; + return 0; +} + +static int msm_fb_release(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret = 0; + + if (!mfd->ref_cnt) { + MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n", + mfd->index); + return -EINVAL; + } + msm_fb_pan_idle(mfd); + mfd->ref_cnt--; + + if ((!mfd->ref_cnt) && (mfd->op_enable)) { + if ((ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, + mfd->op_enable)) != 0) { + printk(KERN_ERR "msm_fb_release: can't turn off display!\n"); + return ret; + } + } + + pm_runtime_put(info->dev); + return ret; +} + +DEFINE_SEMAPHORE(msm_fb_pan_sem); + +static void bl_workqueue_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd = container_of(to_delayed_work(work), + struct msm_fb_data_type, backlight_worker); + struct msm_fb_panel_data *pdata = mfd->pdev->dev.platform_data; + + down(&mfd->sem); + if ((pdata) && (pdata->set_backlight) && (!bl_updated) + && mfd->panel_power_on) { + mfd->bl_level = unset_bl_level; + printk("%s,backlight=%d\n",__func__,unset_bl_level); + pdata->set_backlight(mfd); + bl_level_old = unset_bl_level; + bl_updated = 1; + } + up(&mfd->sem); +} + +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mdp_dirty_region dirty; + struct mdp_dirty_region *dirtyPtr = NULL; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + static int notify_cnt = 0; + int state = 0; + if (!suspend_set_state()) + { + printk("%s,suspend_status is true\n",__func__); + state= -EPERM; + return state; + + } + + /* + * If framebuffer is 2, io pen display is not allowed. + */ + if (bf_supported && info->node == 2) { + pr_err("%s: no pan display for fb%d!", + __func__, info->node); + //return -EPERM; + state= -EPERM; + goto MSM_FB_PAN_ERROR; + } + + if (info->node != 0 || mfd->cont_splash_done) /* primary */ + if ((!mfd->op_enable) || (!mfd->panel_power_on)) + { + //return -EPERM; + state= -EPERM; + goto MSM_FB_PAN_ERROR; + } + + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + + if (var->yoffset > (info->var.yres_virtual - info->var.yres)) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + + if (info->fix.xpanstep) + info->var.xoffset = + (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep; + + if (info->fix.ypanstep) + info->var.yoffset = + (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep; + + /* "UPDT" */ + if (var->reserved[0] == 0x54445055) { + + dirty.xoffset = var->reserved[1] & 0xffff; + dirty.yoffset = (var->reserved[1] >> 16) & 0xffff; + + if ((var->reserved[2] & 0xffff) <= dirty.xoffset) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + + dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset; + dirty.height = + ((var->reserved[2] >> 16) & 0xffff) - dirty.yoffset; + info->var.yoffset = var->yoffset; + + if (dirty.xoffset < 0) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + + if (dirty.yoffset < 0) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + + if ((dirty.xoffset + dirty.width) > info->var.xres) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + + if ((dirty.yoffset + dirty.height) > info->var.yres) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + + if ((dirty.width <= 0) || (dirty.height <= 0)) + { + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + dirtyPtr = &dirty; + } + /* FIXME: reduce fb change notification time to ease mess backlight configuration */ + if (notify_cnt >= 6) { + notify_cnt = 0; + complete(&mfd->msmfb_update_notify); + } else + notify_cnt++; + mutex_lock(&msm_fb_notify_update_sem); + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + + mfd->msmfb_no_update_notify_timer.expires = jiffies + (2 * HZ); + add_timer(&mfd->msmfb_no_update_notify_timer); + mutex_unlock(&msm_fb_notify_update_sem); + + down(&msm_fb_pan_sem); + + if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */ + mdp_set_dma_pan_info(info, NULL, TRUE); + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { + pr_err("%s: can't turn on display!\n", __func__); + up(&msm_fb_pan_sem); + //return -EINVAL; + state= -EINVAL; + goto MSM_FB_PAN_ERROR; + } + msleep(50); + } + //mipi_dsi_set_column_addr(mfd); + mdp_set_dma_pan_info(info, dirtyPtr, + (var->activate == FB_ACTIVATE_VBL)); + mdp_dma_pan_update(info); + up(&msm_fb_pan_sem); + +//fix BL can't turn on untill next frame come by wang.xiaojun3@byd.com 131219 + pan_display_flag = 1; + if (unset_bl_level && !bl_updated){ + MSM_DRM_DEBUG("call BL set schedule work\n"); + schedule_delayed_work(&mfd->backlight_worker, + backlight_duration); + } + if (info->node == 0 && (mfd->cont_splash_done)) /* primary */ + mdp_free_splash_buffer(mfd); + + ++mfd->panel_info.frame_count; + + +MSM_FB_PAN_ERROR: + suspend_clen_state(); + + return state; +} + +static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (var->rotate != FB_ROTATE_UR) + return -EINVAL; + if (var->grayscale != info->var.grayscale) + return -EINVAL; + + switch (var->bits_per_pixel) { + case 16: + if ((var->green.offset != 5) || + !((var->blue.offset == 11) + || (var->blue.offset == 0)) || + !((var->red.offset == 11) + || (var->red.offset == 0)) || + (var->blue.length != 5) || + (var->green.length != 6) || + (var->red.length != 5) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + (var->transp.offset != 0) || + (var->transp.length != 0)) + return -EINVAL; + break; + + case 24: + if ((var->blue.offset != 0) || + (var->green.offset != 8) || + (var->red.offset != 16) || + (var->blue.length != 8) || + (var->green.length != 8) || + (var->red.length != 8) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + !(((var->transp.offset == 0) && + (var->transp.length == 0)) || + ((var->transp.offset == 24) && + (var->transp.length == 8)))) + return -EINVAL; + break; + + case 32: + /* Figure out if the user meant RGBA or ARGB + and verify the position of the RGB components */ + + if (var->transp.offset == 24) { + if ((var->blue.offset != 0) || + (var->green.offset != 8) || + (var->red.offset != 16)) + return -EINVAL; + } else if (var->transp.offset == 0) { + if ((var->blue.offset != 8) || + (var->green.offset != 16) || + (var->red.offset != 24)) + return -EINVAL; + } else + return -EINVAL; + + /* Check the common values for both RGBA and ARGB */ + + if ((var->blue.length != 8) || + (var->green.length != 8) || + (var->red.length != 8) || + (var->transp.length != 8) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0)) + return -EINVAL; + + break; + + default: + return -EINVAL; + } + + if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0)) + return -EINVAL; + + if (!bf_supported || + (info->node != 1 && info->node != 2)) + if (info->fix.smem_len < + (var->xres_virtual* + var->yres_virtual* + (var->bits_per_pixel/8))) + return -EINVAL; + + if ((var->xres == 0) || (var->yres == 0)) + return -EINVAL; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + return 0; +} + +int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd + , struct fb_info *info) +{ + int panel_height, panel_width, var_frame_rate, fps_mod; + struct fb_var_screeninfo *var = &info->var; + fps_mod = 0; + if ((mfd->panel_info.type == DTV_PANEL) || + (mfd->panel_info.type == HDMI_PANEL)) { + panel_height = var->yres + var->upper_margin + + var->vsync_len + var->lower_margin; + panel_width = var->xres + var->right_margin + + var->hsync_len + var->left_margin; + var_frame_rate = ((var->pixclock)/(panel_height * panel_width)); + if (mfd->var_frame_rate != var_frame_rate) { + fps_mod = 1; + mfd->var_frame_rate = var_frame_rate; + } + } + return fps_mod; +} + +static int msm_fb_set_par(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_var_screeninfo *var = &info->var; + int old_imgType; + int blank = 0; + msm_fb_pan_idle(mfd); + old_imgType = mfd->fb_imgType; + switch (var->bits_per_pixel) { + case 16: + if (var->red.offset == 0) + mfd->fb_imgType = MDP_BGR_565; + else + mfd->fb_imgType = MDP_RGB_565; + break; + + case 24: + if ((var->transp.offset == 0) && (var->transp.length == 0)) + mfd->fb_imgType = MDP_RGB_888; + else if ((var->transp.offset == 24) && + (var->transp.length == 8)) { + mfd->fb_imgType = MDP_ARGB_8888; + info->var.bits_per_pixel = 32; + } + break; + + case 32: + if ((var->transp.offset == 24) && (var->blue.offset == 0)) + mfd->fb_imgType = MDP_BGRA_8888; + else if (var->transp.offset == 24) + mfd->fb_imgType = MDP_ARGB_8888; + else + mfd->fb_imgType = MDP_RGBA_8888; + break; + + default: + return -EINVAL; + } + + if ((mfd->var_pixclock != var->pixclock) || + (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) || + (mfd->var_pixclock != var->pixclock) || + (mfd->var_xres != var->xres) || + (mfd->var_yres != var->yres) || + (msm_fb_check_frame_rate(mfd, info))))) { + mfd->var_xres = var->xres; + mfd->var_yres = var->yres; + mfd->var_pixclock = var->pixclock; + blank = 1; + } + mfd->fbi->fix.line_length = msm_fb_line_length(mfd->index, var->xres, + var->bits_per_pixel/8); + + if (blank) { + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); + + if (mfd->update_panel_info) + mfd->update_panel_info(mfd); + + msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable); + } + + return 0; +} + +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd) +{ + if (mfd->hw_refresh) + return -EPERM; + + if (mfd->sw_currently_refreshing) { + down(&mfd->sem); + mfd->sw_currently_refreshing = FALSE; + up(&mfd->sem); + + /* wait until the refresher finishes the last job */ + wait_for_completion_killable(&mfd->refresher_comp); + } + + return 0; +} + +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd) +{ + boolean do_refresh; + + if (mfd->hw_refresh) + return -EPERM; + + down(&mfd->sem); + if ((!mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) { + do_refresh = TRUE; + mfd->sw_currently_refreshing = TRUE; + } else { + do_refresh = FALSE; + } + up(&mfd->sem); + + if (do_refresh) + mdp_refresh_screen((unsigned long)mfd); + + return 0; +} + +#if defined CONFIG_FB_MSM_MDP31 +static int mdp_blit_split_height(struct fb_info *info, + struct mdp_blit_req *req) +{ + int ret; + struct mdp_blit_req splitreq; + int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; + int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; + + splitreq = *req; + /* break dest roi at height*/ + d_x_0 = d_x_1 = req->dst_rect.x; + d_w_0 = d_w_1 = req->dst_rect.w; + d_y_0 = req->dst_rect.y; + if (req->dst_rect.h % 32 == 3) + d_h_1 = (req->dst_rect.h - 3) / 2 - 1; + else if (req->dst_rect.h % 32 == 2) + d_h_1 = (req->dst_rect.h - 2) / 2 - 6; + else + d_h_1 = (req->dst_rect.h - 1) / 2 - 1; + d_h_0 = req->dst_rect.h - d_h_1; + d_y_1 = d_y_0 + d_h_0; + if (req->dst_rect.h == 3) { + d_h_1 = 2; + d_h_0 = 2; + d_y_1 = d_y_0 + 1; + } + + /* blit first region */ + if (((splitreq.flags & 0x07) == 0x04) || + ((splitreq.flags & 0x07) == 0x0)) { + + if (splitreq.flags & MDP_ROT_90) { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_h_1) / req->dst_rect.h; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_h_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } else { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_h_1) / req->dst_rect.h; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_h_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } + + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + + if (splitreq.flags & MDP_ROT_90) { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_h_0) / req->dst_rect.h; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_h_0 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } else { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_h_0) / req->dst_rect.h; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_h_0 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + ret = mdp_ppp_blit(info, &splitreq); + if (ret) + return ret; + + /* blit second region */ + if (((splitreq.flags & 0x07) == 0x04) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + ret = mdp_ppp_blit(info, &splitreq); + return ret; +} +#endif + +int mdp_blit(struct fb_info *info, struct mdp_blit_req *req) +{ + int ret; +#if defined CONFIG_FB_MSM_MDP31 || defined CONFIG_FB_MSM_MDP30 + unsigned int remainder = 0, is_bpp_4 = 0; + struct mdp_blit_req splitreq; + int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; + int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; + + if (req->flags & MDP_ROT_90) { + if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) || + (req->dst_rect.w != req->src_rect.h))) || + ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) || + (req->dst_rect.h != req->src_rect.w)))) { + printk(KERN_ERR "mpd_ppp: error scaling when size is 1!\n"); + return -EINVAL; + } + } else { + if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) || + (req->dst_rect.h != req->src_rect.h))) || + ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) || + (req->dst_rect.w != req->src_rect.w)))) { + printk(KERN_ERR "mpd_ppp: error scaling when size is 1!\n"); + return -EINVAL; + } + } +#endif + if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) { + printk(KERN_ERR "mpd_ppp: src img of zero size!\n"); + return -EINVAL; + } + if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0)) + return 0; + +#if defined CONFIG_FB_MSM_MDP31 + /* MDP width split workaround */ + remainder = (req->dst_rect.w)%32; + ret = mdp_get_bytes_per_pixel(req->dst.format, + (struct msm_fb_data_type *)info->par); + if (ret <= 0) { + printk(KERN_ERR "mdp_ppp: incorrect bpp!\n"); + return -EINVAL; + } + is_bpp_4 = (ret == 4) ? 1 : 0; + + if ((is_bpp_4 && (remainder == 6 || remainder == 14 || + remainder == 22 || remainder == 30)) || remainder == 3 || + (remainder == 1 && req->dst_rect.w != 1) || + (remainder == 2 && req->dst_rect.w != 2)) { + /* make new request as provide by user */ + splitreq = *req; + + /* break dest roi at width*/ + d_y_0 = d_y_1 = req->dst_rect.y; + d_h_0 = d_h_1 = req->dst_rect.h; + d_x_0 = req->dst_rect.x; + + if (remainder == 14) + d_w_1 = (req->dst_rect.w - 14) / 2 + 4; + else if (remainder == 22) + d_w_1 = (req->dst_rect.w - 22) / 2 + 10; + else if (remainder == 30) + d_w_1 = (req->dst_rect.w - 30) / 2 + 10; + else if (remainder == 6) + d_w_1 = req->dst_rect.w / 2 - 1; + else if (remainder == 3) + d_w_1 = (req->dst_rect.w - 3) / 2 - 1; + else if (remainder == 2) + d_w_1 = (req->dst_rect.w - 2) / 2 - 6; + else + d_w_1 = (req->dst_rect.w - 1) / 2 - 1; + d_w_0 = req->dst_rect.w - d_w_1; + d_x_1 = d_x_0 + d_w_0; + if (req->dst_rect.w == 3) { + d_w_1 = 2; + d_w_0 = 2; + d_x_1 = d_x_0 + 1; + } + + /* blit first region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x0)) { + + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_1) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_1) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_0) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_0 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_0) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_0 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + + if ((splitreq.dst_rect.h % 32 == 3) || + ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) || + ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2)) + ret = mdp_blit_split_height(info, &splitreq); + else + ret = mdp_ppp_blit(info, &splitreq); + if (ret) + return ret; + /* blit second region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + if (((splitreq.dst_rect.h % 32) == 3) || + ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) || + ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2)) + ret = mdp_blit_split_height(info, &splitreq); + else + ret = mdp_ppp_blit(info, &splitreq); + if (ret) + return ret; + } else if ((req->dst_rect.h % 32) == 3 || + ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) || + ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2)) + ret = mdp_blit_split_height(info, req); + else + ret = mdp_ppp_blit(info, req); + return ret; +#elif defined CONFIG_FB_MSM_MDP30 + /* MDP width split workaround */ + remainder = (req->dst_rect.w)%16; + ret = mdp_get_bytes_per_pixel(req->dst.format, + (struct msm_fb_data_type *)info->par); + if (ret <= 0) { + printk(KERN_ERR "mdp_ppp: incorrect bpp!\n"); + return -EINVAL; + } + is_bpp_4 = (ret == 4) ? 1 : 0; + + if ((is_bpp_4 && (remainder == 6 || remainder == 14))) { + + /* make new request as provide by user */ + splitreq = *req; + + /* break dest roi at width*/ + d_y_0 = d_y_1 = req->dst_rect.y; + d_h_0 = d_h_1 = req->dst_rect.h; + d_x_0 = req->dst_rect.x; + + if (remainder == 14 || remainder == 6) + d_w_1 = req->dst_rect.w / 2; + else + d_w_1 = (req->dst_rect.w - 1) / 2 - 1; + + d_w_0 = req->dst_rect.w - d_w_1; + d_x_1 = d_x_0 + d_w_0; + + /* blit first region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x05) || + ((splitreq.flags & 0x07) == 0x02) || + ((splitreq.flags & 0x07) == 0x0)) { + + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_1) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_1) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_0) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_0 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_0) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_0 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + + /* No need to split in height */ + ret = mdp_ppp_blit(info, &splitreq); + + if (ret) + return ret; + + /* blit second region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x05) || + ((splitreq.flags & 0x07) == 0x02) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + + /* No need to split in height ... just width */ + ret = mdp_ppp_blit(info, &splitreq); + + if (ret) + return ret; + + } else + ret = mdp_ppp_blit(info, req); + return ret; +#else + ret = mdp_ppp_blit(info, req); + return ret; +#endif +} + +typedef void (*msm_dma_barrier_function_pointer) (void *, size_t); + +static inline void msm_fb_dma_barrier_for_rect(struct fb_info *info, + struct mdp_img *img, struct mdp_rect *rect, + msm_dma_barrier_function_pointer dma_barrier_fp + ) +{ + /* + * Compute the start and end addresses of the rectangles. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. + */ + unsigned long start; + size_t size; + char * const pmem_start = info->screen_base; + int bytes_per_pixel = mdp_get_bytes_per_pixel(img->format, + (struct msm_fb_data_type *)info->par); + if (bytes_per_pixel <= 0) { + printk(KERN_ERR "%s incorrect bpp!\n", __func__); + return; + } + start = (unsigned long)pmem_start + img->offset + + (img->width * rect->y + rect->x) * bytes_per_pixel; + size = (rect->h * img->width + rect->w) * bytes_per_pixel; + (*dma_barrier_fp) ((void *) start, size); + +} + +static inline void msm_dma_nc_pre(void) +{ + dmb(); +} +static inline void msm_dma_wt_pre(void) +{ + dmb(); +} +static inline void msm_dma_todevice_wb_pre(void *start, size_t size) +{ + dma_cache_pre_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size) +{ + dma_cache_pre_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_nc_post(void) +{ + dmb(); +} + +static inline void msm_dma_fromdevice_wt_post(void *start, size_t size) +{ + dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_todevice_wb_post(void *start, size_t size) +{ + dma_cache_post_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_post(void *start, size_t size) +{ + dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +/* + * Do the write barriers required to guarantee data is committed to RAM + * (from CPU cache or internal buffers) before a DMA operation starts. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_before_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + /* + * Normally, do the requested barriers for each address + * range that corresponds to a rectangle. + * + * But if at least one write barrier is requested for data + * going to or from the device but no address range is + * needed for that barrier, then do the barrier, but do it + * only once, no matter how many requests there are. + */ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_nc_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_wt_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_START)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].src), + &(req_list[i].src_rect), + msm_dma_todevice_wb_pre + ); + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_todevice_wb_pre + ); + } + } + break; + } +#else + dmb(); +#endif +} + + +/* + * Do the write barriers required to guarantee data will be re-read from RAM by + * the CPU after a DMA operation ends. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_after_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_END)) { + msm_dma_nc_post(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wt_post + ); + } + } + break; + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wb_post + ); + } + } + break; + } +#else + dmb(); +#endif +} + +/* + * NOTE: The userspace issues blit operations in a sequence, the sequence + * start with a operation marked START and ends in an operation marked + * END. It is guranteed by the userspace that all the blit operations + * between START and END are only within the regions of areas designated + * by the START and END operations and that the userspace doesnt modify + * those areas. Hence it would be enough to perform barrier/cache operations + * only on the START and END operations. + */ +static int msmfb_blit(struct fb_info *info, void __user *p) +{ + /* + * CAUTION: The names of the struct types intentionally *DON'T* match + * the names of the variables declared -- they appear to be swapped. + * Read the code carefully and you should see that the variable names + * make sense. + */ + const int MAX_LIST_WINDOW = 16; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp_blit_req_list req_list_header; + + int count, i, req_list_count; + if (bf_supported && + (info->node == 1 || info->node == 2)) { + pr_err("%s: no pan display for fb%d.", + __func__, info->node); + return -EPERM; + } + /* Get the count size for the total BLIT request. */ + if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) + return -EFAULT; + p += sizeof(req_list_header); + count = req_list_header.count; + if (count < 0 || count >= MAX_BLIT_REQ) + return -EINVAL; + while (count > 0) { + /* + * Access the requests through a narrow window to decrease copy + * overhead and make larger requests accessible to the + * coherency management code. + * NOTE: The window size is intended to be larger than the + * typical request size, but not require more than 2 + * kbytes of stack storage. + */ + req_list_count = count; + if (req_list_count > MAX_LIST_WINDOW) + req_list_count = MAX_LIST_WINDOW; + if (copy_from_user(&req_list, p, + sizeof(struct mdp_blit_req)*req_list_count)) + return -EFAULT; + + /* + * Ensure that any data CPU may have previously written to + * internal state (but not yet committed to memory) is + * guaranteed to be committed to memory now. + */ + msm_fb_ensure_memory_coherency_before_dma(info, + req_list, req_list_count); + + /* + * Do the blit DMA, if required -- returning early only if + * there is a failure. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & MDP_NO_BLIT)) { + /* Do the actual blit. */ + int ret = mdp_blit(info, &(req_list[i])); + + /* + * Note that early returns don't guarantee + * memory coherency. + */ + if (ret) + return ret; + } + } + + /* + * Ensure that CPU cache and other internal CPU state is + * updated to reflect any change in memory modified by MDP blit + * DMA. + */ + msm_fb_ensure_memory_coherency_after_dma(info, + req_list, + req_list_count); + + /* Go to next window of requests. */ + count -= req_list_count; + p += sizeof(struct mdp_blit_req)*req_list_count; + } + return 0; +} + +static int msmfb_vsync_ctrl(struct fb_info *info, void __user *argp) +{ + int enable, ret; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + ret = copy_from_user(&enable, argp, sizeof(enable)); + if (ret) { + pr_err("%s:msmfb_overlay_vsync ioctl failed", __func__); + return ret; + } + + if (mfd->vsync_ctrl) + mfd->vsync_ctrl(enable); + else { + pr_err("%s: Vsync IOCTL not supported", __func__); + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_FB_MSM_OVERLAY +static int msmfb_overlay_get(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_get(info, &req); + if (ret) { + printk(KERN_ERR "%s: ioctl failed \n", + __func__); + return ret; + } + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_set(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_set(info, &req); + if (ret) { + printk(KERN_ERR "%s: ioctl failed, rc=%d\n", + __func__, ret); + return ret; + } + + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp) +{ + int ret, ndx; + + ret = copy_from_user(&ndx, argp, sizeof(ndx)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n", + __func__); + return ret; + } + + return mdp4_overlay_unset(info, ndx); +} + +static int msmfb_overlay_vsync_ctrl(struct fb_info *info, void __user *argp) +{ + int ret; + int enable; + + ret = copy_from_user(&enable, argp, sizeof(enable)); + if (ret) { + pr_err("%s:msmfb_overlay_vsync ioctl failed", __func__); + return ret; + } + + ret = mdp4_overlay_vsync_ctrl(info, enable); + + return ret; +} + +static int msmfb_overlay_play_wait(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_data req; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mfd->overlay_play_enable == 0) /* nothing to do */ + return 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s:msmfb_overlay_wait ioctl failed", __func__); + return ret; + } + + ret = mdp4_overlay_play_wait(info, &req); + + return ret; +} + +static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_data req; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mfd->overlay_play_enable == 0) /* nothing to do */ + return 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n", + __func__); + return ret; + } + + complete(&mfd->msmfb_update_notify); + mutex_lock(&msm_fb_notify_update_sem); + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + + mfd->msmfb_no_update_notify_timer.expires = jiffies + (2 * HZ); + add_timer(&mfd->msmfb_no_update_notify_timer); + mutex_unlock(&msm_fb_notify_update_sem); + + if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */ + mdp_set_dma_pan_info(info, NULL, TRUE); + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { + pr_err("%s: can't turn on display!\n", __func__); + return -EINVAL; + } + } + + ret = mdp4_overlay_play(info, &req); + + if (unset_bl_level && !bl_updated) + schedule_delayed_work(&mfd->backlight_worker, + backlight_duration); + + return ret; +} + +static int msmfb_overlay_play_enable(struct fb_info *info, unsigned long *argp) +{ + int ret, enable; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + ret = copy_from_user(&enable, argp, sizeof(enable)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_play_enable ioctl failed \n", + __func__); + return ret; + } + + mfd->overlay_play_enable = enable; + + return 0; +} + +static int msmfb_overlay_blt(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_blt req; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s: failed\n", __func__); + return ret; + } + + ret = mdp4_overlay_blt(info, &req); + + return ret; +} + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL +static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info) +{ + return mdp4_writeback_init(info); +} +static int msmfb_overlay_ioctl_writeback_start( + struct fb_info *info) +{ + int ret = 0; + ret = mdp4_writeback_start(info); + if (ret) + goto error; +error: + if (ret) + pr_err("%s:msmfb_writeback_start " + " ioctl failed\n", __func__); + return ret; +} + +static int msmfb_overlay_ioctl_writeback_stop( + struct fb_info *info) +{ + int ret = 0; + ret = mdp4_writeback_stop(info); + if (ret) + goto error; + +error: + if (ret) + pr_err("%s:msmfb_writeback_stop ioctl failed\n", + __func__); + return ret; +} + +static int msmfb_overlay_ioctl_writeback_queue_buffer( + struct fb_info *info, unsigned long *argp) +{ + int ret = 0; + struct msmfb_data data; + + ret = copy_from_user(&data, argp, sizeof(data)); + if (ret) + goto error; + + ret = mdp4_writeback_queue_buffer(info, &data); + if (ret) + goto error; + +error: + if (ret) + pr_err("%s:msmfb_writeback_queue_buffer ioctl failed\n", + __func__); + return ret; +} + +static int msmfb_overlay_ioctl_writeback_dequeue_buffer( + struct fb_info *info, unsigned long *argp) +{ + int ret = 0; + struct msmfb_data data; + + ret = copy_from_user(&data, argp, sizeof(data)); + if (ret) + goto error; + + ret = mdp4_writeback_dequeue_buffer(info, &data); + if (ret) + goto error; + + ret = copy_to_user(argp, &data, sizeof(data)); + if (ret) + goto error; + +error: + if (ret) + pr_err("%s:msmfb_writeback_dequeue_buffer ioctl failed\n", + __func__); + return ret; +} +static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info) +{ + return mdp4_writeback_terminate(info); +} + +static int msmfb_overlay_ioctl_writeback_set_mirr_hint(struct fb_info * + info, void *argp) +{ + int ret = 0, hint; + + if (!info) { + ret = -EINVAL; + goto error; + } + + ret = copy_from_user(&hint, argp, sizeof(hint)); + if (ret) + goto error; + + ret = mdp4_writeback_set_mirroring_hint(info, hint); + if (ret) + goto error; +error: + if (ret) + pr_err("%s: ioctl failed\n", __func__); + return ret; +} + +#else +static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info) +{ + return -ENOTSUPP; +} +static int msmfb_overlay_ioctl_writeback_start( + struct fb_info *info) +{ + return -ENOTSUPP; +} + +static int msmfb_overlay_ioctl_writeback_stop( + struct fb_info *info) +{ + return -ENOTSUPP; +} + +static int msmfb_overlay_ioctl_writeback_queue_buffer( + struct fb_info *info, unsigned long *argp) +{ + return -ENOTSUPP; +} + +static int msmfb_overlay_ioctl_writeback_dequeue_buffer( + struct fb_info *info, unsigned long *argp) +{ + return -ENOTSUPP; +} +static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info) +{ + return -ENOTSUPP; +} + +static int msmfb_overlay_ioctl_writeback_set_mirr_hint(struct fb_info * + info, void *argp) +{ + return -ENOTSUPP; +} +#endif + +static int msmfb_overlay_3d_sbys(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_3d req; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s:msmfb_overlay_3d_ctrl ioctl failed\n", + __func__); + return ret; + } + + ret = mdp4_overlay_3d_sbys(info, &req); + + return ret; +} + +static int msmfb_mixer_info(struct fb_info *info, unsigned long *argp) +{ + int ret, cnt; + struct msmfb_mixer_info_req req; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s: failed\n", __func__); + return ret; + } + + cnt = mdp4_mixer_info(req.mixer_num, req.info); + req.cnt = cnt; + ret = copy_to_user(argp, &req, sizeof(req)); + if (ret) + pr_err("%s:msmfb_overlay_blt_off ioctl failed\n", + __func__); + + return cnt; +} + +#endif + +DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem); +DEFINE_SEMAPHORE(msm_fb_ioctl_vsync_sem); +DEFINE_MUTEX(msm_fb_ioctl_lut_sem); + +/* Set color conversion matrix from user space */ + +#ifndef CONFIG_FB_MSM_MDP40 +static void msmfb_set_color_conv(struct mdp_ccs *p) +{ + int i; + + if (p->direction == MDP_CCS_RGB2YUV) { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* RGB->YUV primary forward matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PFMVn(i)); + + #ifdef CONFIG_FB_MSM_MDP31 + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_POST_BV2n(i)); + #endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } else { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* YUV->RGB primary reverse matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PRMVn(i)); + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_PRE_BV1n(i)); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } +} +#else +static void msmfb_set_color_conv(struct mdp_csc *p) +{ + mdp4_vg_csc_update(p); +} +#endif + +static int msmfb_notify_update(struct fb_info *info, void __user *argp) +{ + int ret; + unsigned int notify; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + ret = copy_from_user(¬ify, argp, sizeof(unsigned int)); + if (ret) { + pr_err("%s:ioctl failed\n", __func__); + return ret; + } + + if (notify > NOTIFY_UPDATE_STOP) + return -EINVAL; + + if (notify == NOTIFY_UPDATE_START) { + INIT_COMPLETION(mfd->msmfb_update_notify); + ret = wait_for_completion_interruptible_timeout( + &mfd->msmfb_update_notify, 4*HZ); + } else { + INIT_COMPLETION(mfd->msmfb_no_update_notify); + ret = wait_for_completion_interruptible_timeout( + &mfd->msmfb_no_update_notify, 4*HZ); + } + if (ret == 0) + ret = -ETIMEDOUT; + return (ret > 0) ? 0 : ret; +} + +static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd, + struct msmfb_mdp_pp *pp_ptr) +{ + int ret = -1; +#ifdef CONFIG_FB_MSM_MDP40 + int i = 0; +#endif + if (!pp_ptr) + return ret; + + switch (pp_ptr->op) { +#ifdef CONFIG_FB_MSM_MDP40 + case mdp_op_csc_cfg: + ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data)); + for (i = 0; i < CSC_MAX_BLOCKS; i++) { + if (pp_ptr->data.csc_cfg_data.block == + csc_cfg_matrix[i].block) { + memcpy(&csc_cfg_matrix[i].csc_data, + &(pp_ptr->data.csc_cfg_data.csc_data), + sizeof(struct mdp_csc_cfg)); + break; + } + } + break; + + case mdp_op_pcc_cfg: + ret = mdp4_pcc_cfg(&(pp_ptr->data.pcc_cfg_data)); + break; + + case mdp_op_lut_cfg: + switch (pp_ptr->data.lut_cfg_data.lut_type) { + case mdp_lut_igc: + ret = mdp4_igc_lut_config( + (struct mdp_igc_lut_data *) + &pp_ptr->data.lut_cfg_data.data); + break; + + case mdp_lut_pgc: + ret = mdp4_argc_cfg( + &pp_ptr->data.lut_cfg_data.data.pgc_lut_data); + break; + + case mdp_lut_hist: + ret = mdp_hist_lut_config( + (struct mdp_hist_lut_data *) + &pp_ptr->data.lut_cfg_data.data); + break; + + default: + break; + } + break; + case mdp_op_qseed_cfg: + ret = mdp4_qseed_cfg((struct mdp_qseed_cfg_data *) + &pp_ptr->data.qseed_cfg_data); + break; + case mdp_op_calib_cfg: + ret = mdp4_calib_config((struct mdp_calib_config_data *) + &pp_ptr->data.calib_cfg); + break; +#endif + case mdp_bl_scale_cfg: + ret = mdp_bl_scale_config(mfd, (struct mdp_bl_scale_data *) + &pp_ptr->data.bl_scale_data); + break; + + default: + pr_warn("Unsupported request to MDP_PP IOCTL.\n"); + ret = -EINVAL; + break; + } + + return ret; +} +static int msmfb_handle_metadata_ioctl(struct msm_fb_data_type *mfd, + struct msmfb_metadata *metadata_ptr) +{ + int ret; + switch (metadata_ptr->op) { +#ifdef CONFIG_FB_MSM_MDP40 + case metadata_op_base_blend: + ret = mdp4_update_base_blend(mfd, + &metadata_ptr->data.blend_cfg); + break; +#endif + default: + pr_warn("Unsupported request to MDP META IOCTL.\n"); + ret = -EINVAL; + break; + } + return ret; +} +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct msm_fb_data_type *mfd; + void __user *argp = (void __user *)arg; + struct fb_cursor cursor; + struct fb_cmap cmap; + struct mdp_histogram_data hist; + struct mdp_histogram_start_req hist_req; + uint32_t block; +#ifndef CONFIG_FB_MSM_MDP40 + struct mdp_ccs ccs_matrix; +#else + struct mdp_csc csc_matrix; +#endif + struct mdp_page_protection fb_page_protection; + struct msmfb_mdp_pp mdp_pp; + struct msmfb_metadata mdp_metadata; + int ret = 0; + + if (!info || !info->par) + return -EINVAL; + mfd = (struct msm_fb_data_type *)info->par; + + switch (cmd) { +#ifdef CONFIG_FB_MSM_OVERLAY + case MSMFB_OVERLAY_GET: + ret = msmfb_overlay_get(info, argp); + break; + case MSMFB_OVERLAY_SET: + ret = msmfb_overlay_set(info, argp); + break; + case MSMFB_OVERLAY_UNSET: + ret = msmfb_overlay_unset(info, argp); + break; + case MSMFB_OVERLAY_PLAY: + ret = msmfb_overlay_play(info, argp); + break; + case MSMFB_OVERLAY_PLAY_ENABLE: + ret = msmfb_overlay_play_enable(info, argp); + break; + case MSMFB_OVERLAY_PLAY_WAIT: + ret = msmfb_overlay_play_wait(info, argp); + break; + case MSMFB_OVERLAY_BLT: + ret = msmfb_overlay_blt(info, argp); + break; + case MSMFB_OVERLAY_3D: + ret = msmfb_overlay_3d_sbys(info, argp); + break; + case MSMFB_MIXER_INFO: + ret = msmfb_mixer_info(info, argp); + break; + case MSMFB_WRITEBACK_INIT: + ret = msmfb_overlay_ioctl_writeback_init(info); + break; + case MSMFB_WRITEBACK_START: + ret = msmfb_overlay_ioctl_writeback_start( + info); + break; + case MSMFB_WRITEBACK_STOP: + ret = msmfb_overlay_ioctl_writeback_stop( + info); + break; + case MSMFB_WRITEBACK_QUEUE_BUFFER: + ret = msmfb_overlay_ioctl_writeback_queue_buffer( + info, argp); + break; + case MSMFB_WRITEBACK_DEQUEUE_BUFFER: + ret = msmfb_overlay_ioctl_writeback_dequeue_buffer( + info, argp); + break; + case MSMFB_WRITEBACK_TERMINATE: + ret = msmfb_overlay_ioctl_writeback_terminate(info); + break; +#endif + case MSMFB_VSYNC_CTRL: + case MSMFB_OVERLAY_VSYNC_CTRL: + down(&msm_fb_ioctl_ppp_sem); + if (mdp_rev >= MDP_REV_40) + ret = msmfb_overlay_vsync_ctrl(info, argp); + else + ret = msmfb_vsync_ctrl(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_BLIT: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_blit(info, argp); + up(&msm_fb_ioctl_ppp_sem); + + break; + + /* Ioctl for setting ccs matrix from user space */ + case MSMFB_SET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)); + if (ret) { + printk(KERN_ERR + "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + mdp_ccs_rgb2yuv = ccs_matrix; + else + mdp_ccs_yuv2rgb = ccs_matrix; + + msmfb_set_color_conv(&ccs_matrix) ; + up(&msm_fb_ioctl_ppp_sem); +#else + ret = copy_from_user(&csc_matrix, argp, sizeof(csc_matrix)); + if (ret) { + pr_err("%s:MSMFB_SET_CSC_MATRIX ioctl failed\n", + __func__); + return ret; + } + down(&msm_fb_ioctl_ppp_sem); + msmfb_set_color_conv(&csc_matrix); + up(&msm_fb_ioctl_ppp_sem); + +#endif + + break; + + /* Ioctl for getting ccs matrix to user space */ + case MSMFB_GET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)) ; + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + ccs_matrix = mdp_ccs_rgb2yuv; + else + ccs_matrix = mdp_ccs_yuv2rgb; + + ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix)); + + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret ; + } + up(&msm_fb_ioctl_ppp_sem); +#else + ret = -EINVAL; +#endif + + break; + + case MSMFB_GRP_DISP: +#ifdef CONFIG_FB_MSM_MDP22 + { + unsigned long grp_id; + + ret = copy_from_user(&grp_id, argp, sizeof(grp_id)); + if (ret) + return ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + writel(grp_id, MDP_FULL_BYPASS_WORD43); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, + FALSE); + break; + } +#else + return -EFAULT; +#endif + case MSMFB_SUSPEND_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = FALSE; + ret = msm_fb_stop_sw_refresher(mfd); + break; + + case MSMFB_RESUME_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = TRUE; + ret = msm_fb_resume_sw_refresher(mfd); + break; + + case MSMFB_CURSOR: + ret = copy_from_user(&cursor, argp, sizeof(cursor)); + if (ret) + return ret; + + ret = msm_fb_cursor(info, &cursor); + break; + + case MSMFB_SET_LUT: + ret = copy_from_user(&cmap, argp, sizeof(cmap)); + if (ret) + return ret; + + mutex_lock(&msm_fb_ioctl_lut_sem); + ret = msm_fb_set_lut(&cmap, info); + mutex_unlock(&msm_fb_ioctl_lut_sem); + break; + + case MSMFB_HISTOGRAM: + if (!mfd->panel_power_on) + return -EPERM; + + if (!mfd->do_histogram) + return -ENODEV; + + ret = copy_from_user(&hist, argp, sizeof(hist)); + if (ret) + return ret; + + ret = mfd->do_histogram(info, &hist); + break; + + case MSMFB_HISTOGRAM_START: + if (!mfd->panel_power_on) + return -EPERM; + + if (!mfd->start_histogram) + return -ENODEV; + + ret = copy_from_user(&hist_req, argp, sizeof(hist_req)); + if (ret) + return ret; + + ret = mfd->start_histogram(&hist_req); + break; + + case MSMFB_HISTOGRAM_STOP: + if (!mfd->stop_histogram) + return -ENODEV; + + ret = copy_from_user(&block, argp, sizeof(int)); + if (ret) + return ret; + + ret = mfd->stop_histogram(info, block); + break; + + + case MSMFB_GET_PAGE_PROTECTION: + fb_page_protection.page_protection + = mfd->mdp_fb_page_protection; + ret = copy_to_user(argp, &fb_page_protection, + sizeof(fb_page_protection)); + if (ret) + return ret; + break; + + case MSMFB_NOTIFY_UPDATE: + ret = msmfb_notify_update(info, argp); + break; + + case MSMFB_SET_PAGE_PROTECTION: +#if defined CONFIG_ARCH_QSD8X50 || defined CONFIG_ARCH_MSM8X60 + ret = copy_from_user(&fb_page_protection, argp, + sizeof(fb_page_protection)); + if (ret) + return ret; + + /* Validate the proposed page protection settings. */ + switch (fb_page_protection.page_protection) { + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* Write-back cache (read allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + /* Write-back cache (write allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + mfd->mdp_fb_page_protection = + fb_page_protection.page_protection; + break; + default: + ret = -EINVAL; + break; + } +#else + /* + * Don't allow caching until 7k DMA cache operations are + * available. + */ + ret = -EINVAL; +#endif + break; + + case MSMFB_MDP_PP: + ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp)); + if (ret) + return ret; + + ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp); + break; + + case MSMFB_METADATA_SET: + ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata)); + if (ret) + return ret; + ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata); + break; + + default: + MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd); + ret = -EINVAL; + break; + } + + return ret; +} +static int msmfb_handle_metadata_ioctl(struct msm_fb_data_type *mfd, + struct msmfb_metadata *metadata_ptr) +{ + int ret; + switch (metadata_ptr->op) { +#ifdef CONFIG_FB_MSM_MDP40 + case metadata_op_base_blend: + ret = mdp4_update_base_blend(mfd, + &metadata_ptr->data.blend_cfg); + break; + case metadata_op_wb_format: + ret = mdp4_update_writeback_format(mfd, + &metadata_ptr->data.mixer_cfg); + break; +#endif + default: + pr_warn("Unsupported request to MDP META IOCTL.\n"); + ret = -EINVAL; + break; + } + return ret; +} + +static int msmfb_get_metadata(struct msm_fb_data_type *mfd, + struct msmfb_metadata *metadata_ptr) +{ + int ret = 0; + switch (metadata_ptr->op) { + case metadata_op_frame_rate: + metadata_ptr->data.panel_frame_rate = + mdp_get_panel_framerate(mfd); + break; + default: + pr_warn("Unsupported request to MDP META IOCTL.\n"); + ret = -EINVAL; + break; + } + return ret; +} + +static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd, + struct mdp_buf_sync *buf_sync) +{ + int i, ret = 0; + u32 threshold; + int acq_fen_fd[MDP_MAX_FENCE_FD]; + struct sync_fence *fence; + struct sync_pt *release_sync_pt; + struct sync_pt *retire_sync_pt; + struct sync_fence *release_fence; + struct sync_fence *retire_fence; + int release_fen_fd; + int retire_fen_fd; + + if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) || + (mfd->timeline == NULL)) + return -EINVAL; + + if ((!mfd->op_enable) || (!mfd->panel_power_on)) + return -EPERM; + + if (buf_sync->acq_fen_fd_cnt) + ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd, + buf_sync->acq_fen_fd_cnt * sizeof(int)); + if (ret) { + pr_err("%s:copy_from_user failed", __func__); + return ret; + } + mutex_lock(&mfd->sync_mutex); + for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) { + fence = sync_fence_fdget(acq_fen_fd[i]); + if (fence == NULL) { + pr_info("%s: null fence! i=%d fd=%d\n", __func__, i, + acq_fen_fd[i]); + ret = -EINVAL; + break; + } + mfd->acq_fen[i] = fence; + } + mfd->acq_fen_cnt = i; + if (ret) + goto buf_sync_err_1; + if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT) { + msm_fb_wait_for_fence(mfd); + } + if ((mfd->panel.type == MIPI_CMD_PANEL) || + (mfd->panel.type == WRITEBACK_PANEL)) + threshold = 1; + else + threshold = 2; + + release_fen_fd = get_unused_fd_flags(0); + if (release_fen_fd < 0) { + pr_err("%s: get_unused_fd_flags failed", __func__); + ret = -EIO; + goto buf_sync_err_1; + } + + retire_fen_fd = get_unused_fd_flags(0); + if (retire_fen_fd < 0) { + pr_err("%s: get_unused_fd_flags failed", __func__); + ret = -EIO; + goto buf_sync_err_2; + } + + release_sync_pt = sw_sync_pt_create(mfd->timeline, + mfd->timeline_value + threshold); + release_fence = sync_fence_create("mdp-fence", + release_sync_pt); + sync_fence_install(release_fence, release_fen_fd); + retire_sync_pt = sw_sync_pt_create(mfd->timeline, + mfd->timeline_value + threshold); + retire_fence = sync_fence_create("mdp-retire-fence", + retire_sync_pt); + sync_fence_install(retire_fence, retire_fen_fd); + + ret = copy_to_user(buf_sync->rel_fen_fd, + &release_fen_fd, sizeof(int)); + if (ret) { + pr_err("%s:copy_to_user failed", __func__); + goto buf_sync_err_3; + } + + ret = copy_to_user(buf_sync->retire_fen_fd, + &retire_fen_fd, sizeof(int)); + if (ret) { + pr_err("%s:copy_to_user failed", __func__); + goto buf_sync_err_3; + } + + mutex_unlock(&mfd->sync_mutex); + return ret; +buf_sync_err_3: + sync_fence_put(release_fence); + sync_fence_put(retire_fence); + put_unused_fd(retire_fen_fd); +buf_sync_err_2: + put_unused_fd(release_fen_fd); +buf_sync_err_1: + for (i = 0; i < mfd->acq_fen_cnt; i++) + sync_fence_put(mfd->acq_fen[i]); + mfd->acq_fen_cnt = 0; + mutex_unlock(&mfd->sync_mutex); + return ret; +} + +static int msmfb_display_commit(struct fb_info *info, + unsigned long *argp) +{ + int ret; + struct mdp_display_commit disp_commit; + ret = copy_from_user(&disp_commit, argp, + sizeof(disp_commit)); + if (ret) { + pr_err("%s:copy_from_user failed", __func__); + return ret; + } + + ret = msm_fb_pan_display_ex(info, &disp_commit); + + return ret; +} + +static int msm_fb_register_driver(void) +{ + return platform_driver_register(&msm_fb_driver); +} + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL +struct fb_info *msm_fb_get_writeback_fb(void) +{ + int c = 0; + for (c = 0; c < fbi_list_index; ++c) { + struct msm_fb_data_type *mfd; + mfd = (struct msm_fb_data_type *)fbi_list[c]->par; + if (mfd->panel.type == WRITEBACK_PANEL) + return fbi_list[c]; + } + + return NULL; +} +EXPORT_SYMBOL(msm_fb_get_writeback_fb); + +int msm_fb_writeback_start(struct fb_info *info) +{ + return mdp4_writeback_start(info); +} +EXPORT_SYMBOL(msm_fb_writeback_start); + +int msm_fb_writeback_queue_buffer(struct fb_info *info, + struct msmfb_data *data) +{ + return mdp4_writeback_queue_buffer(info, data); +} +EXPORT_SYMBOL(msm_fb_writeback_queue_buffer); + +int msm_fb_writeback_dequeue_buffer(struct fb_info *info, + struct msmfb_data *data) +{ + return mdp4_writeback_dequeue_buffer(info, data); +} +EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer); + +int msm_fb_writeback_stop(struct fb_info *info) +{ + return mdp4_writeback_stop(info); +} +EXPORT_SYMBOL(msm_fb_writeback_stop); +int msm_fb_writeback_init(struct fb_info *info) +{ + return mdp4_writeback_init(info); +} +EXPORT_SYMBOL(msm_fb_writeback_init); +int msm_fb_writeback_terminate(struct fb_info *info) +{ + return mdp4_writeback_terminate(info); +} +EXPORT_SYMBOL(msm_fb_writeback_terminate); +#endif + +struct platform_device *msm_fb_add_device(struct platform_device *pdev) +{ + struct msm_fb_panel_data *pdata; + struct platform_device *this_dev = NULL; + struct fb_info *fbi; + struct msm_fb_data_type *mfd = NULL; + u32 type, id, fb_num; + + if (!pdev) + return NULL; + id = pdev->id; + + pdata = pdev->dev.platform_data; + if (!pdata) + return NULL; + type = pdata->panel_info.type; + +#if defined MSM_FB_NUM + /* + * over written fb_num which defined + * at panel_info + * + */ + if (type == HDMI_PANEL || type == DTV_PANEL || + type == TV_PANEL || type == WRITEBACK_PANEL) { + if (hdmi_prim_display) + pdata->panel_info.fb_num = 2; + else + pdata->panel_info.fb_num = 1; + } + else + pdata->panel_info.fb_num = MSM_FB_NUM; + + MSM_FB_INFO("setting pdata->panel_info.fb_num to %d. type: %d\n", + pdata->panel_info.fb_num, type); +#endif + fb_num = pdata->panel_info.fb_num; + + if (fb_num <= 0) + return NULL; + + if (fbi_list_index >= MAX_FBI_LIST) { + printk(KERN_ERR "msm_fb: no more framebuffer info list!\n"); + return NULL; + } + /* + * alloc panel device data + */ + this_dev = msm_fb_device_alloc(pdata, type, id); + + if (!this_dev) { + printk(KERN_ERR + "%s: msm_fb_device_alloc failed!\n", __func__); + return NULL; + } + + /* + * alloc framebuffer info + par data + */ + fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL); + if (fbi == NULL) { + platform_device_put(this_dev); + printk(KERN_ERR "msm_fb: can't alloca framebuffer info data!\n"); + return NULL; + } + + mfd = (struct msm_fb_data_type *)fbi->par; + mfd->key = MFD_KEY; + mfd->fbi = fbi; + mfd->panel.type = type; + mfd->panel.id = id; + mfd->fb_page = fb_num; + mfd->index = fbi_list_index; + mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE; + mfd->iclient = iclient; + /* link to the latest pdev */ + mfd->pdev = this_dev; + + mfd_list[mfd_list_index++] = mfd; + fbi_list[fbi_list_index++] = fbi; + + /* + * set driver data + */ + platform_set_drvdata(this_dev, mfd); + + if (platform_device_add(this_dev)) { + printk(KERN_ERR "msm_fb: platform_device_add failed!\n"); + platform_device_put(this_dev); + framebuffer_release(fbi); + fbi_list_index--; + return NULL; + } + return this_dev; +} +EXPORT_SYMBOL(msm_fb_add_device); + +int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num, + int subsys_id) +{ + struct fb_info *info; + struct msm_fb_data_type *mfd; + + if (fb_num > MAX_FBI_LIST || + (subsys_id != DISPLAY_SUBSYSTEM_ID && + subsys_id != ROTATOR_SUBSYSTEM_ID)) { + pr_err("%s(): Invalid parameters\n", __func__); + return -1; + } + + info = fbi_list[fb_num]; + if (!info) { + pr_err("%s(): info is NULL\n", __func__); + return -1; + } + + mfd = (struct msm_fb_data_type *)info->par; + + if (subsys_id == DISPLAY_SUBSYSTEM_ID) { + if (mfd->display_iova) + *start = mfd->display_iova; + else + *start = info->fix.smem_start; + } else { + if (mfd->rotator_iova) + *start = mfd->rotator_iova; + else + *start = info->fix.smem_start; + } + + *len = info->fix.smem_len; + + return 0; +} +EXPORT_SYMBOL(get_fb_phys_info); + +int __init msm_fb_init(void) +{ + int rc = -ENODEV; + + if (msm_fb_register_driver()) + return rc; + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + + if ((root = msm_fb_get_debugfs_root()) != NULL) { + msm_fb_debugfs_file_create(root, + "msm_fb_msg_printing_level", + (u32 *) &msm_fb_msg_level); + msm_fb_debugfs_file_create(root, + "mddi_msg_printing_level", + (u32 *) &mddi_msg_level); + msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled", + (u32 *) &msm_fb_debug_enabled); + } + } +#endif + + return 0; +} + +/* Called by v4l2 driver to enable/disable overlay pipe */ +int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par) +{ + int err = 0; +#ifdef CONFIG_FB_MSM_MDP40 + struct mdp4_overlay_pipe *pipe; + if (enable) { + + err = mdp4_v4l2_overlay_set(fbi_list[0], req, &pipe); + + *(struct mdp4_overlay_pipe **)par = pipe; + + } else { + pipe = *(struct mdp4_overlay_pipe **)par; + mdp4_v4l2_overlay_clear(pipe); + } +#else +#ifdef CONFIG_FB_MSM_MDP30 + if (enable) + err = mdp_ppp_v4l2_overlay_set(fbi_list[0], req); + else + err = mdp_ppp_v4l2_overlay_clear(); +#else + err = -EINVAL; +#endif +#endif + + return err; +} +EXPORT_SYMBOL(msm_fb_v4l2_enable); + +/* Called by v4l2 driver to provide a frame for display */ +int msm_fb_v4l2_update(void *par, bool bUserPtr, + unsigned long srcp0_addr, unsigned long srcp0_size, + unsigned long srcp1_addr, unsigned long srcp1_size, + unsigned long srcp2_addr, unsigned long srcp2_size) +{ +#ifdef CONFIG_FB_MSM_MDP40 + struct mdp4_overlay_pipe *pipe = (struct mdp4_overlay_pipe *)par; + return mdp4_v4l2_overlay_play(fbi_list[0], pipe, + srcp0_addr, srcp1_addr, + srcp2_addr); +#else +#ifdef CONFIG_FB_MSM_MDP30 + if (bUserPtr) + return mdp_ppp_v4l2_overlay_play(fbi_list[0], true, + srcp0_addr, srcp0_size, + srcp1_addr, srcp1_size); + else + return mdp_ppp_v4l2_overlay_play(fbi_list[0], false, + srcp0_addr, srcp0_size, + srcp1_addr, srcp1_size); +#else + return -EINVAL; +#endif +#endif +} +EXPORT_SYMBOL(msm_fb_v4l2_update); + +#ifdef CONFIG_FB_MSM_ALIGN_BUFFER +module_param(align_buffer, bool, 0644); +#endif + +module_init(msm_fb_init); diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h index 88e99e10..63e1d6da 100644 --- a/drivers/video/msm/msm_fb.h +++ b/drivers/video/msm/msm_fb.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #ifdef CONFIG_HAS_EARLYSUSPEND @@ -54,6 +56,7 @@ struct disp_info_type_suspend { boolean op_enable; boolean sw_refreshing_enable; boolean panel_power_on; + boolean op_suspend; }; struct msmfb_writeback_data_list { @@ -138,6 +141,8 @@ struct msm_fb_data_type { int (*stop_histogram) (struct fb_info *info, uint32_t block); void (*vsync_ctrl) (int enable); void (*vsync_init) (int cndx); + void (*update_panel_info)(struct msm_fb_data_type *mfd); + bool (*is_panel_ready)(void); void *vsync_show; void *cursor_buf; void *cursor_buf_phys; @@ -178,6 +183,7 @@ struct msm_fb_data_type { struct list_head writeback_busy_queue; struct list_head writeback_free_queue; struct list_head writeback_register_queue; + struct switch_dev writeback_sdev; wait_queue_head_t wait_q; struct ion_client *iclient; unsigned long display_iova; @@ -192,7 +198,24 @@ struct msm_fb_data_type { int cont_splash_done; void *copy_splash_buf; unsigned char *copy_splash_phys; + + void *cpu_pm_hdl; + u32 avtimer_phy; int vsync_sysfs_created; + u32 acq_fen_cnt; + struct sync_fence *acq_fen[MDP_MAX_FENCE_FD]; + struct sw_sync_timeline *timeline; + int timeline_value; + struct mutex sync_mutex; + struct completion commit_comp; + u32 is_committing; + struct work_struct commit_work; + void *msm_fb_backup; + boolean panel_driver_on; +}; +struct msm_fb_backup_type { + struct fb_info info; + struct mdp_display_commit disp_commit; }; extern int msm_drm_debug; @@ -207,7 +230,6 @@ extern int msm_drm_debug; "[DISPLAY]%s: " _fmt , \ __func__ , ##_arg); \ } while (0) - struct dentry *msm_fb_get_debugfs_root(void); void msm_fb_debugfs_file_create(struct dentry *root, const char *name, u32 *var); @@ -225,16 +247,14 @@ int msm_fb_writeback_stop(struct fb_info *info); int msm_fb_writeback_terminate(struct fb_info *info); int msm_fb_detect_client(const char *name); int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp); -void mipi_dsi_set_column_addr(struct msm_fb_data_type *mfd); -bool suspend_set_state(void); -void suspend_clen_state(void); - +void msm_fb_wait_for_fence(struct msm_fb_data_type *mfd); +int msm_fb_signal_timeline(struct msm_fb_data_type *mfd); +void msm_fb_release_timeline(struct msm_fb_data_type *mfd); #ifdef CONFIG_FB_BACKLIGHT void msm_fb_config_backlight(struct msm_fb_data_type *mfd); #endif -void fill_black_screen(void); -void unfill_black_screen(void); +void fill_black_screen(bool on, uint8 pipe_num, uint8 mixer_num); int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd, struct fb_info *info); diff --git a/drivers/video/msm/msm_fb_bl.c b/drivers/video/msm/msm_fb_bl.c old mode 100644 new mode 100755 diff --git a/drivers/video/msm/msm_fb_panel.c b/drivers/video/msm/msm_fb_panel.c index 8e6a8226..28698c12 100644 --- a/drivers/video/msm/msm_fb_panel.c +++ b/drivers/video/msm/msm_fb_panel.c @@ -78,6 +78,28 @@ int panel_next_off(struct platform_device *pdev) return ret; } +int panel_next_late_init(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_panel_data *pdata; + struct msm_fb_panel_data *next_pdata; + struct platform_device *next_pdev; + + pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data; + + if (pdata) { + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = (struct msm_fb_panel_data *) + next_pdev->dev.platform_data; + if ((next_pdata) && (next_pdata->late_init)) + ret = next_pdata->late_init(next_pdev); + } + } + + return ret; +} + struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, u32 type, u32 id) { diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h old mode 100644 new mode 100755 index 1d429a00..d8a7bbfe --- a/drivers/video/msm/msm_fb_panel.h +++ b/drivers/video/msm/msm_fb_panel.h @@ -58,6 +58,11 @@ typedef enum { MAX_PHYS_TARGET_NUM, } DISP_TARGET_PHYS; +enum { + BLT_SWITCH_TG_OFF, + BLT_SWITCH_TG_ON +}; + /* panel info type */ struct lcd_panel_info { __u32 vsync_enable; @@ -67,6 +72,8 @@ struct lcd_panel_info { __u32 v_pulse_width; __u32 hw_vsync_mode; __u32 vsync_notifier_period; + __u32 blt_ctrl; + __u32 blt_mode; __u32 rev; }; @@ -102,7 +109,7 @@ struct mipi_panel_info { char data_lane1; char data_lane2; char data_lane3; - char dlane_swap; + char dlane_swap; /* data lane swap */ char rgb_swap; char b_sel; char g_sel; @@ -170,7 +177,7 @@ struct msm_panel_info { __u32 frame_count; __u32 is_3d_panel; __u32 frame_rate; - + __u32 frame_interval; struct mddi_panel_info mddi; struct lcd_panel_info lcd; @@ -195,12 +202,25 @@ struct msm_fb_panel_data { /* function entry chain */ int (*on) (struct platform_device *pdev); int (*off) (struct platform_device *pdev); + int (*late_init) (struct platform_device *pdev); int (*glance_screen) (struct platform_device *pdev); int (*power_ctrl) (boolean enable); struct platform_device *next; int (*clk_func) (int enable); }; +enum { + MDP4_OVERLAY_BLT_SWITCH_TG_OFF, + MDP4_OVERLAY_BLT_SWITCH_TG_ON, + MDP4_OVERLAY_BLT_SWITCH_POLL +}; + +enum { + MDP4_OVERLAY_MODE_BLT_CTRL, + MDP4_OVERLAY_MODE_BLT_ALWAYS_ON, + MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF +}; + /*=========================================================================== FUNCTIONS PROTOTYPES ============================================================================*/ @@ -208,6 +228,7 @@ struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, u32 type, u32 id); int panel_next_on(struct platform_device *pdev); int panel_next_off(struct platform_device *pdev); +int panel_next_late_init(struct platform_device *pdev); int lcdc_device_register(struct msm_panel_info *pinfo); diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c index 4948e8bf..28eff62a 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * */ -#include +#include #include #include "vcd_ddl.h" #include "vcd_ddl_shared_mem.h" @@ -278,7 +278,7 @@ u32 ddl_decoder_dpb_init(struct ddl_client_context *ddl) memset(frame[i].vcd_frm.virtual + luma_size, 0x80808080, frame[i].vcd_frm.alloc_len - luma_size); - if (frame[i].vcd_frm.ion_flag == CACHED) { + if (frame[i].vcd_frm.ion_flag == ION_FLAG_CACHED) { msm_ion_do_cache_op( ddl_context->video_ion_client, frame[i].vcd_frm.buff_ion_handle, diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c index 32960f16..6129a06b 100644 --- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c +++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c @@ -84,7 +84,7 @@ void *ddl_pmem_alloc(struct ddl_buf_addr *addr, size_t sz, u32 alignment) ionflag = CACHED; kernel_vaddr = (unsigned long *) ion_map_kernel( ddl_context->video_ion_client, - addr->alloc_handle, ionflag); + addr->alloc_handle); if (IS_ERR_OR_NULL(kernel_vaddr)) { DDL_MSG_ERROR("%s() :DDL ION map failed\n", __func__); diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c index 9417d53d..1bfc6f80 100644 --- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c +++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c @@ -69,7 +69,7 @@ static void *res_trk_pmem_map if (res_trk_get_enable_ion() && addr->alloc_handle) { kernel_vaddr = (unsigned long *) ion_map_kernel( ddl_context->video_ion_client, - addr->alloc_handle, UNCACHED); + addr->alloc_handle); if (IS_ERR_OR_NULL(kernel_vaddr)) { DDL_MSG_ERROR("%s():DDL ION client map failed\n", __func__); diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h index 639cfcea..6cb9fe71 100644 --- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h +++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h @@ -14,7 +14,7 @@ #define _VIDEO_720P_RESOURCE_TRACKER_H_ #include -#include +#include #include "vcd_res_tracker_api.h" #ifdef CONFIG_MSM_BUS_SCALING #include diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c index aa5e72d3..0d29b8d5 100644 --- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c +++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c @@ -142,8 +142,7 @@ void ddl_pmem_alloc(struct ddl_buf_addr *buff_addr, size_t sz, u32 align) buff_addr->physical_base_addr = (u32 *)phyaddr; kernel_vaddr = (unsigned long *) ion_map_kernel( ddl_context->video_ion_client, - buff_addr->alloc_handle, - UNCACHED); + buff_addr->alloc_handle); if (IS_ERR_OR_NULL(kernel_vaddr)) { ERR("\n%s(): DDL ION map failed\n", __func__); goto unmap_ion_buffer; diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c index 5b398183..8e3a7359 100644 --- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c +++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c @@ -746,8 +746,10 @@ struct ion_client *res_trk_get_ion_client(void) u32 res_trk_get_mem_type(void) { - u32 mem_type = ION_HEAP(resource_context.memtype); - return mem_type; + if (resource_context.vidc_platform_data->enable_ion) + return (u32) ION_HEAP(resource_context.memtype); + else + return resource_context.memtype; } void res_trk_set_mem_type(enum ddl_mem_area mem_type) diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h index 5f18076d..e1781b68 100644 --- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h +++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h @@ -13,7 +13,7 @@ #ifndef _VIDEO_720P_RESOURCE_TRACKER_H_ #define _VIDEO_720P_RESOURCE_TRACKER_H_ #include -#include +#include #include "vcd_res_tracker_api.h" #define VCD_RESTRK_MIN_PERF_LEVEL 37900 diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c index 3aa4d40b..803de9fb 100644 --- a/drivers/video/msm/vidc/common/dec/vdec.c +++ b/drivers/video/msm/vidc/common/dec/vdec.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -844,10 +843,8 @@ static u32 vid_dec_set_h264_mv_buffers(struct video_client_ctx *client_ctx, { struct vcd_property_hdr vcd_property_hdr; struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL; - struct msm_mapped_buffer *mapped_buffer = NULL; u32 vcd_status = VCD_ERR_FAIL; - u32 len = 0, flags = 0; - struct file *file; + u32 len = 0; int rc = 0; unsigned long ionflag = 0; unsigned long buffer_size = 0; @@ -868,28 +865,8 @@ static u32 vid_dec_set_h264_mv_buffers(struct video_client_ctx *client_ctx, vcd_h264_mv_buffer->offset = mv_data->offset; if (!vcd_get_ion_status()) { - if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd, - (unsigned long *) (&(vcd_h264_mv_buffer-> - physical_addr)), - (unsigned long *) (&vcd_h264_mv_buffer-> - kernel_virtual_addr), - (unsigned long *) (&len), &file)) { - ERR("%s(): get_pmem_file failed\n", __func__); - return false; - } - put_pmem_file(file); - flags = MSM_SUBSYSTEM_MAP_IOVA; - mapped_buffer = msm_subsystem_map_buffer( - (unsigned long)vcd_h264_mv_buffer->physical_addr, len, - flags, vidc_mmu_subsystem, - sizeof(vidc_mmu_subsystem)/ - sizeof(unsigned int)); - if (IS_ERR(mapped_buffer)) { - pr_err("buffer map failed"); - return false; - } - vcd_h264_mv_buffer->client_data = (void *) mapped_buffer; - vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0]; + pr_err("PMEM not available\n"); + return false; } else { client_ctx->h264_mv_ion_handle = ion_import_dma_buf( client_ctx->user_ion_client, @@ -1471,7 +1448,6 @@ static long vid_dec_ioctl(struct file *file, u32 vcd_status; unsigned long kernel_vaddr, phy_addr, len; unsigned long ker_vaddr; - struct file *pmem_file; u32 result = true; void __user *arg = (void __user *)u_arg; int rc = 0; @@ -1786,12 +1762,8 @@ static long vid_dec_ioctl(struct file *file, } if (!vcd_get_ion_status()) { - if (get_pmem_file(seq_header.pmem_fd, - &phy_addr, &kernel_vaddr, &len, &pmem_file)) { - ERR("%s(): get_pmem_file failed\n", __func__); - return false; - } - put_pmem_file(pmem_file); + pr_err("PMEM Not available\n"); + return -EINVAL; } else { client_ctx->seq_hdr_ion_handle = ion_import_dma_buf( client_ctx->user_ion_client, @@ -1812,7 +1784,7 @@ static long vid_dec_ioctl(struct file *file, } ker_vaddr = (unsigned long) ion_map_kernel( client_ctx->user_ion_client, - client_ctx->seq_hdr_ion_handle, ionflag); + client_ctx->seq_hdr_ion_handle); if (!ker_vaddr) { ERR("%s():get_ION_kernel virtual addr fail\n", __func__); diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c index 29b74d17..816e645f 100644 --- a/drivers/video/msm/vidc/common/enc/venc.c +++ b/drivers/video/msm/vidc/common/enc/venc.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c index ff82d4bb..dda85136 100644 --- a/drivers/video/msm/vidc/common/enc/venc_internal.c +++ b/drivers/video/msm/vidc/common/enc/venc_internal.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -41,8 +40,6 @@ #endif #define ERR(x...) printk(KERN_ERR x) -static unsigned int vidc_mmu_subsystem[] = { - MSM_SUBSYSTEM_VIDEO}; u32 vid_enc_set_get_base_cfg(struct video_client_ctx *client_ctx, @@ -1577,7 +1574,12 @@ u32 vid_enc_set_buffer(struct video_client_ctx *client_ctx, enum vcd_buffer_type vcd_buffer_t = VCD_BUFFER_INPUT; enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT; u32 vcd_status = VCD_ERR_FAIL; - unsigned long kernel_vaddr, length = 0; + unsigned long kernel_vaddr, length, user_vaddr, phy_addr = 0; + int pmem_fd = 0; + struct ion_handle *buff_handle = NULL; + u32 ion_flag = 0; + struct file *file = NULL; + s32 buffer_index = 0; if (!client_ctx || !buffer_info) return false; @@ -1599,6 +1601,37 @@ u32 vid_enc_set_buffer(struct video_client_ctx *client_ctx, return false; } + /* + * Flush output buffers explcitly once, during registration. This ensures + * any pending CPU writes (if cleared after allocation) are + * committed right away, or else this may get flushed _after_ + * the hardware has written bitstream. rare bug, but can happen ! + */ + if (buffer == VEN_BUFFER_TYPE_OUTPUT) { + user_vaddr = (unsigned long)buffer_info->pbuffer; + if (!vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT, + true, &user_vaddr, &kernel_vaddr, + &phy_addr, &pmem_fd, &file, + &buffer_index)) { + ERR("%s(): vidc_lookup_addr_table failed\n", + __func__); + return false; + } + + ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT, + buffer_info->fd, kernel_vaddr, buffer_index, + &buff_handle); + + if (ion_flag == ION_FLAG_CACHED && buff_handle) { + msm_ion_do_cache_op( + client_ctx->user_ion_client, + buff_handle, + NULL, + (unsigned long) length, + ION_IOC_INV_CACHES); + } + } + vcd_status = vcd_set_buffer(client_ctx->vcd_handle, vcd_buffer_t, (u8 *) kernel_vaddr, buffer_info->sz); @@ -1765,11 +1798,9 @@ u32 vid_enc_set_recon_buffers(struct video_client_ctx *client_ctx, struct venc_recon_addr *venc_recon) { u32 vcd_status = VCD_ERR_FAIL; - u32 len, i, flags = 0; - struct file *file; + u32 len, i; struct vcd_property_hdr vcd_property_hdr; struct vcd_property_enc_recon_buffer *control = NULL; - struct msm_mapped_buffer *mapped_buffer = NULL; int rc = -1; unsigned long ionflag = 0; unsigned long iova = 0; @@ -1801,25 +1832,8 @@ u32 vid_enc_set_recon_buffers(struct video_client_ctx *client_ctx, control->user_virtual_addr = venc_recon->pbuffer; if (!vcd_get_ion_status()) { - if (get_pmem_file(control->pmem_fd, (unsigned long *) - (&(control->physical_addr)), (unsigned long *) - (&control->kernel_virtual_addr), - (unsigned long *) (&len), &file)) { - ERR("%s(): get_pmem_file failed\n", __func__); - return false; - } - put_pmem_file(file); - flags = MSM_SUBSYSTEM_MAP_IOVA; - mapped_buffer = msm_subsystem_map_buffer( - (unsigned long)control->physical_addr, len, - flags, vidc_mmu_subsystem, - sizeof(vidc_mmu_subsystem)/sizeof(unsigned int)); - if (IS_ERR(mapped_buffer)) { - pr_err("buffer map failed"); - return false; - } - control->client_data = (void *) mapped_buffer; - control->dev_addr = (u8 *)mapped_buffer->iova[0]; + pr_err("PMEM not available\n"); + return false; } else { client_ctx->recon_buffer_ion_handle[i] = ion_import_dma_buf( client_ctx->user_ion_client, control->pmem_fd); @@ -1837,8 +1851,7 @@ u32 vid_enc_set_recon_buffers(struct video_client_ctx *client_ctx, } control->kernel_virtual_addr = (u8 *) ion_map_kernel( client_ctx->user_ion_client, - client_ctx->recon_buffer_ion_handle[i], - ionflag); + client_ctx->recon_buffer_ion_handle[i]); if (!control->kernel_virtual_addr) { ERR("%s(): get_ION_kernel virtual addr fail\n", __func__); diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c index 870b8925..41ecce16 100644 --- a/drivers/video/msm/vidc/common/init/vidc_init.c +++ b/drivers/video/msm/vidc/common/init/vidc_init.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -49,7 +48,6 @@ static struct vidc_dev *vidc_device_p; static dev_t vidc_dev_num; static struct class *vidc_class; -static unsigned int vidc_mmu_subsystem[] = {MSM_SUBSYSTEM_VIDEO}; static const struct file_operations vidc_fops = { .owner = THIS_MODULE, @@ -565,9 +563,8 @@ u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx, unsigned long len, phys_addr; struct file *file = NULL; u32 *num_of_buffers = NULL; - u32 i, flags; + u32 i; struct buf_addr_table *buf_addr_table; - struct msm_mapped_buffer *mapped_buffer = NULL; struct ion_handle *buff_ion_handle = NULL; unsigned long ionflag = 0; unsigned long iova = 0; @@ -609,26 +606,8 @@ u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx, goto bail_out_add; } else { if (!vcd_get_ion_status()) { - if (get_pmem_file(pmem_fd, &phys_addr, - kernel_vaddr, &len, &file)) { - ERR("%s(): get_pmem_file failed\n", __func__); - goto bail_out_add; - } - put_pmem_file(file); - flags = (buffer == BUFFER_TYPE_INPUT) - ? MSM_SUBSYSTEM_MAP_IOVA : - MSM_SUBSYSTEM_MAP_IOVA|MSM_SUBSYSTEM_ALIGN_IOVA_8K; - mapped_buffer = msm_subsystem_map_buffer(phys_addr, - length, flags, vidc_mmu_subsystem, - sizeof(vidc_mmu_subsystem)/sizeof(unsigned int)); - if (IS_ERR(mapped_buffer)) { - pr_err("buffer map failed"); - goto bail_out_add; - } - buf_addr_table[*num_of_buffers].client_data = (void *) - mapped_buffer; - buf_addr_table[*num_of_buffers].dev_addr = - mapped_buffer->iova[0]; + pr_err("PMEM not available\n"); + return false; } else { buff_ion_handle = ion_import_dma_buf( client_ctx->user_ion_client, pmem_fd); @@ -647,8 +626,7 @@ u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx, *kernel_vaddr = (unsigned long) ion_map_kernel( client_ctx->user_ion_client, - buff_ion_handle, - ionflag); + buff_ion_handle); if (IS_ERR_OR_NULL((void *)*kernel_vaddr)) { ERR("%s():ION virtual addr fail\n", __func__); @@ -913,7 +891,9 @@ void vidc_timer_start(void *timer_handle, u32 time_out) struct vidc_timer *hw_timer = (struct vidc_timer *)timer_handle; DBG("%s(): start timer\n ", __func__); if (hw_timer) { - hw_timer->hw_timeout.expires = jiffies + 1*HZ; + //hw_timer->hw_timeout.expires = jiffies + 1*HZ; + hw_timer->hw_timeout.expires = jiffies + 10*HZ; + add_timer(&hw_timer->hw_timeout); } } diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h index 2dd69d84..c341e934 100644 --- a/drivers/video/msm/vidc/common/vcd/vcd_core.h +++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h @@ -13,7 +13,7 @@ #ifndef _VCD_CORE_H_ #define _VCD_CORE_H_ -#include +#include #include #include "vcd_ddl_api.h" diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c index 0eb2e0ea..300ef85a 100644 --- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c +++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c @@ -105,8 +105,7 @@ static int vcd_pmem_alloc(size_t sz, u8 **kernel_vaddr, u8 **phy_addr, } *kernel_vaddr = (u8 *) ion_map_kernel( cctxt->vcd_ion_client, - map_buffer->alloc_handle, - ionflag); + map_buffer->alloc_handle); if (!(*kernel_vaddr)) { pr_err("%s() ION map failed", __func__); goto ion_free_bailout; diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8aeadf6b..6af2a3e7 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -645,6 +645,11 @@ *(.security_initcall.init) \ VMLINUX_SYMBOL(__security_initcall_end) = .; +#define COMPAT_EXPORTS \ + VMLINUX_SYMBOL(__compat_exports_start) = .; \ + *(.exportcompat.init) \ + VMLINUX_SYMBOL(__compat_exports_end) = .; + #ifdef CONFIG_BLK_DEV_INITRD #define INIT_RAM_FS \ . = ALIGN(4); \ diff --git a/include/compat/linux/ath9k_platform.h b/include/compat/linux/ath9k_platform.h new file mode 100644 index 00000000..6e3f54f3 --- /dev/null +++ b/include/compat/linux/ath9k_platform.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos + * Copyright (c) 2009 Imre Kaloz + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#ifndef _LINUX_ATH9K_PLATFORM_H +#define _LINUX_ATH9K_PLATFORM_H + +#define ATH9K_PLAT_EEP_MAX_WORDS 2048 + +struct ath9k_platform_data { + u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; + u8 *macaddr; + + int led_pin; + u32 gpio_mask; + u32 gpio_val; + + bool is_clk_25mhz; + int (*get_mac_revision)(void); + int (*external_reset)(void); +}; + +#endif /* _LINUX_ATH9K_PLATFORM_H */ diff --git a/include/compat/linux/atomic.h b/include/compat/linux/atomic.h new file mode 100644 index 00000000..378b748f --- /dev/null +++ b/include/compat/linux/atomic.h @@ -0,0 +1,46 @@ +#ifndef _COMPAT_LINUX_ATOMIC_H +#define _COMPAT_LINUX_ATOMIC_H 1 + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) +#include_next +#else + +#include + +/** + * atomic_inc_not_zero_hint - increment if not null + * @v: pointer of type atomic_t + * @hint: probable value of the atomic before the increment + * + * This version of atomic_inc_not_zero() gives a hint of probable + * value of the atomic. This helps processor to not read the memory + * before doing the atomic read/modify/write cycle, lowering + * number of bus transactions on some arches. + * + * Returns: 0 if increment was not done, 1 otherwise. + */ +#ifndef atomic_inc_not_zero_hint +static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint) +{ + int val, c = hint; + + /* sanity test, should be removed by compiler if hint is a constant */ + if (!hint) + return atomic_inc_not_zero(v); + + do { + val = atomic_cmpxchg(v, c, c + 1); + if (val == c) + return 1; + c = val; + } while (c); + + return 0; +} +#endif + +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) */ + +#endif /* _COMPAT_LINUX_ATOMIC_H */ diff --git a/include/compat/linux/average.h b/include/compat/linux/average.h new file mode 100644 index 00000000..ece86ca3 --- /dev/null +++ b/include/compat/linux/average.h @@ -0,0 +1,5 @@ +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37)) +#include_next +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37)) */ diff --git a/include/compat/linux/bcma/bcma.h b/include/compat/linux/bcma/bcma.h new file mode 100644 index 00000000..4d4b59de --- /dev/null +++ b/include/compat/linux/bcma/bcma.h @@ -0,0 +1,277 @@ +#ifndef LINUX_BCMA_H_ +#define LINUX_BCMA_H_ + +#include +#include + +#include +#include +#include +#include /* SPROM sharing */ + +#include "bcma_regs.h" + +struct bcma_device; +struct bcma_bus; + +enum bcma_hosttype { + BCMA_HOSTTYPE_PCI, + BCMA_HOSTTYPE_SDIO, + BCMA_HOSTTYPE_SOC, +}; + +struct bcma_chipinfo { + u16 id; + u8 rev; + u8 pkg; +}; + +enum bcma_clkmode { + BCMA_CLKMODE_FAST, + BCMA_CLKMODE_DYNAMIC, +}; + +struct bcma_host_ops { + u8 (*read8)(struct bcma_device *core, u16 offset); + u16 (*read16)(struct bcma_device *core, u16 offset); + u32 (*read32)(struct bcma_device *core, u16 offset); + void (*write8)(struct bcma_device *core, u16 offset, u8 value); + void (*write16)(struct bcma_device *core, u16 offset, u16 value); + void (*write32)(struct bcma_device *core, u16 offset, u32 value); +#ifdef CONFIG_BCMA_BLOCKIO + void (*block_read)(struct bcma_device *core, void *buffer, + size_t count, u16 offset, u8 reg_width); + void (*block_write)(struct bcma_device *core, const void *buffer, + size_t count, u16 offset, u8 reg_width); +#endif + /* Agent ops */ + u32 (*aread32)(struct bcma_device *core, u16 offset); + void (*awrite32)(struct bcma_device *core, u16 offset, u32 value); +}; + +/* Core manufacturers */ +#define BCMA_MANUF_ARM 0x43B +#define BCMA_MANUF_MIPS 0x4A7 +#define BCMA_MANUF_BCM 0x4BF + +/* Core class values. */ +#define BCMA_CL_SIM 0x0 +#define BCMA_CL_EROM 0x1 +#define BCMA_CL_CORESIGHT 0x9 +#define BCMA_CL_VERIF 0xB +#define BCMA_CL_OPTIMO 0xD +#define BCMA_CL_GEN 0xE +#define BCMA_CL_PRIMECELL 0xF + +/* Core-ID values. */ +#define BCMA_CORE_OOB_ROUTER 0x367 /* Out of band */ +#define BCMA_CORE_INVALID 0x700 +#define BCMA_CORE_CHIPCOMMON 0x800 +#define BCMA_CORE_ILINE20 0x801 +#define BCMA_CORE_SRAM 0x802 +#define BCMA_CORE_SDRAM 0x803 +#define BCMA_CORE_PCI 0x804 +#define BCMA_CORE_MIPS 0x805 +#define BCMA_CORE_ETHERNET 0x806 +#define BCMA_CORE_V90 0x807 +#define BCMA_CORE_USB11_HOSTDEV 0x808 +#define BCMA_CORE_ADSL 0x809 +#define BCMA_CORE_ILINE100 0x80A +#define BCMA_CORE_IPSEC 0x80B +#define BCMA_CORE_UTOPIA 0x80C +#define BCMA_CORE_PCMCIA 0x80D +#define BCMA_CORE_INTERNAL_MEM 0x80E +#define BCMA_CORE_MEMC_SDRAM 0x80F +#define BCMA_CORE_OFDM 0x810 +#define BCMA_CORE_EXTIF 0x811 +#define BCMA_CORE_80211 0x812 +#define BCMA_CORE_PHY_A 0x813 +#define BCMA_CORE_PHY_B 0x814 +#define BCMA_CORE_PHY_G 0x815 +#define BCMA_CORE_MIPS_3302 0x816 +#define BCMA_CORE_USB11_HOST 0x817 +#define BCMA_CORE_USB11_DEV 0x818 +#define BCMA_CORE_USB20_HOST 0x819 +#define BCMA_CORE_USB20_DEV 0x81A +#define BCMA_CORE_SDIO_HOST 0x81B +#define BCMA_CORE_ROBOSWITCH 0x81C +#define BCMA_CORE_PARA_ATA 0x81D +#define BCMA_CORE_SATA_XORDMA 0x81E +#define BCMA_CORE_ETHERNET_GBIT 0x81F +#define BCMA_CORE_PCIE 0x820 +#define BCMA_CORE_PHY_N 0x821 +#define BCMA_CORE_SRAM_CTL 0x822 +#define BCMA_CORE_MINI_MACPHY 0x823 +#define BCMA_CORE_ARM_1176 0x824 +#define BCMA_CORE_ARM_7TDMI 0x825 +#define BCMA_CORE_PHY_LP 0x826 +#define BCMA_CORE_PMU 0x827 +#define BCMA_CORE_PHY_SSN 0x828 +#define BCMA_CORE_SDIO_DEV 0x829 +#define BCMA_CORE_ARM_CM3 0x82A +#define BCMA_CORE_PHY_HT 0x82B +#define BCMA_CORE_MIPS_74K 0x82C +#define BCMA_CORE_MAC_GBIT 0x82D +#define BCMA_CORE_DDR12_MEM_CTL 0x82E +#define BCMA_CORE_PCIE_RC 0x82F /* PCIe Root Complex */ +#define BCMA_CORE_OCP_OCP_BRIDGE 0x830 +#define BCMA_CORE_SHARED_COMMON 0x831 +#define BCMA_CORE_OCP_AHB_BRIDGE 0x832 +#define BCMA_CORE_SPI_HOST 0x833 +#define BCMA_CORE_I2S 0x834 +#define BCMA_CORE_SDR_DDR1_MEM_CTL 0x835 /* SDR/DDR1 memory controller core */ +#define BCMA_CORE_SHIM 0x837 /* SHIM component in ubus/6362 */ +#define BCMA_CORE_DEFAULT 0xFFF + +#define BCMA_MAX_NR_CORES 16 + +struct bcma_device { + struct bcma_bus *bus; + struct bcma_device_id id; + + struct device dev; + struct device *dma_dev; + + unsigned int irq; + bool dev_registered; + + u8 core_index; + + u32 addr; + u32 wrap; + + void __iomem *io_addr; + void __iomem *io_wrap; + + void *drvdata; + struct list_head list; +}; + +static inline void *bcma_get_drvdata(struct bcma_device *core) +{ + return core->drvdata; +} +static inline void bcma_set_drvdata(struct bcma_device *core, void *drvdata) +{ + core->drvdata = drvdata; +} + +struct bcma_driver { + const char *name; + const struct bcma_device_id *id_table; + + int (*probe)(struct bcma_device *dev); + void (*remove)(struct bcma_device *dev); + int (*suspend)(struct bcma_device *dev, pm_message_t state); + int (*resume)(struct bcma_device *dev); + void (*shutdown)(struct bcma_device *dev); + + struct device_driver drv; +}; +extern +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner); +#define bcma_driver_register(drv) \ + __bcma_driver_register(drv, THIS_MODULE) + +extern void bcma_driver_unregister(struct bcma_driver *drv); + +struct bcma_bus { + /* The MMIO area. */ + void __iomem *mmio; + + const struct bcma_host_ops *ops; + + enum bcma_hosttype hosttype; + union { + /* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */ + struct pci_dev *host_pci; + /* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */ + struct sdio_func *host_sdio; + }; + + struct bcma_chipinfo chipinfo; + + struct bcma_device *mapped_core; + struct list_head cores; + u8 nr_cores; + u8 init_done:1; + + struct bcma_drv_cc drv_cc; + struct bcma_drv_pci drv_pci; + struct bcma_drv_mips drv_mips; + + /* We decided to share SPROM struct with SSB as long as we do not need + * any hacks for BCMA. This simplifies drivers code. */ + struct ssb_sprom sprom; +}; + +extern inline u32 bcma_read8(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->read8(core, offset); +} +extern inline u32 bcma_read16(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->read16(core, offset); +} +extern inline u32 bcma_read32(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->read32(core, offset); +} +extern inline +void bcma_write8(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->write8(core, offset, value); +} +extern inline +void bcma_write16(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->write16(core, offset, value); +} +extern inline +void bcma_write32(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->write32(core, offset, value); +} +#ifdef CONFIG_BCMA_BLOCKIO +extern inline void bcma_block_read(struct bcma_device *core, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + core->bus->ops->block_read(core, buffer, count, offset, reg_width); +} +extern inline void bcma_block_write(struct bcma_device *core, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + core->bus->ops->block_write(core, buffer, count, offset, reg_width); +} +#endif +extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->aread32(core, offset); +} +extern inline +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->awrite32(core, offset, value); +} + +#define bcma_mask32(cc, offset, mask) \ + bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask)) +#define bcma_set32(cc, offset, set) \ + bcma_write32(cc, offset, bcma_read32(cc, offset) | (set)) +#define bcma_maskset32(cc, offset, mask, set) \ + bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set)) + +extern bool bcma_core_is_enabled(struct bcma_device *core); +extern void bcma_core_disable(struct bcma_device *core, u32 flags); +extern int bcma_core_enable(struct bcma_device *core, u32 flags); +extern void bcma_core_set_clockmode(struct bcma_device *core, + enum bcma_clkmode clkmode); +extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, + bool on); +#define BCMA_DMA_TRANSLATION_MASK 0xC0000000 +#define BCMA_DMA_TRANSLATION_NONE 0x00000000 +#define BCMA_DMA_TRANSLATION_DMA32_CMT 0x40000000 /* Client Mode Translation for 32-bit DMA */ +#define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */ +extern u32 bcma_core_dma_translation(struct bcma_device *core); + +#endif /* LINUX_BCMA_H_ */ diff --git a/include/compat/linux/bcma/bcma_driver_chipcommon.h b/include/compat/linux/bcma/bcma_driver_chipcommon.h new file mode 100644 index 00000000..1526d965 --- /dev/null +++ b/include/compat/linux/bcma/bcma_driver_chipcommon.h @@ -0,0 +1,390 @@ +#ifndef LINUX_BCMA_DRIVER_CC_H_ +#define LINUX_BCMA_DRIVER_CC_H_ + +/** ChipCommon core registers. **/ +#define BCMA_CC_ID 0x0000 +#define BCMA_CC_ID_ID 0x0000FFFF +#define BCMA_CC_ID_ID_SHIFT 0 +#define BCMA_CC_ID_REV 0x000F0000 +#define BCMA_CC_ID_REV_SHIFT 16 +#define BCMA_CC_ID_PKG 0x00F00000 +#define BCMA_CC_ID_PKG_SHIFT 20 +#define BCMA_CC_ID_NRCORES 0x0F000000 +#define BCMA_CC_ID_NRCORES_SHIFT 24 +#define BCMA_CC_ID_TYPE 0xF0000000 +#define BCMA_CC_ID_TYPE_SHIFT 28 +#define BCMA_CC_CAP 0x0004 /* Capabilities */ +#define BCMA_CC_CAP_NRUART 0x00000003 /* # of UARTs */ +#define BCMA_CC_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */ +#define BCMA_CC_CAP_UARTCLK 0x00000018 /* UART clock select */ +#define BCMA_CC_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */ +#define BCMA_CC_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */ +#define BCMA_CC_CAP_EXTBUS 0x000000C0 /* External buses present */ +#define BCMA_CC_CAP_FLASHT 0x00000700 /* Flash Type */ +#define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */ +#define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */ +#define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */ +#define BCMA_CC_FLASHT_NFLASH 0x00000200 +#define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */ +#define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */ +#define BCMA_PLLTYPE_NONE 0x00000000 +#define BCMA_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */ +#define BCMA_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */ +#define BCMA_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */ +#define BCMA_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */ +#define BCMA_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */ +#define BCMA_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */ +#define BCMA_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */ +#define BCMA_CC_CAP_PCTL 0x00040000 /* Power Control */ +#define BCMA_CC_CAP_OTPS 0x00380000 /* OTP size */ +#define BCMA_CC_CAP_OTPS_SHIFT 19 +#define BCMA_CC_CAP_OTPS_BASE 5 +#define BCMA_CC_CAP_JTAGM 0x00400000 /* JTAG master present */ +#define BCMA_CC_CAP_BROM 0x00800000 /* Internal boot ROM active */ +#define BCMA_CC_CAP_64BIT 0x08000000 /* 64-bit Backplane */ +#define BCMA_CC_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ +#define BCMA_CC_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ +#define BCMA_CC_CAP_SPROM 0x40000000 /* SPROM present */ +#define BCMA_CC_CORECTL 0x0008 +#define BCMA_CC_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ +#define BCMA_CC_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define BCMA_CC_CORECTL_UARTCLKEN 0x00000008 /* UART clock enable (rev >= 21) */ +#define BCMA_CC_BIST 0x000C +#define BCMA_CC_OTPS 0x0010 /* OTP status */ +#define BCMA_CC_OTPS_PROGFAIL 0x80000000 +#define BCMA_CC_OTPS_PROTECT 0x00000007 +#define BCMA_CC_OTPS_HW_PROTECT 0x00000001 +#define BCMA_CC_OTPS_SW_PROTECT 0x00000002 +#define BCMA_CC_OTPS_CID_PROTECT 0x00000004 +#define BCMA_CC_OTPC 0x0014 /* OTP control */ +#define BCMA_CC_OTPC_RECWAIT 0xFF000000 +#define BCMA_CC_OTPC_PROGWAIT 0x00FFFF00 +#define BCMA_CC_OTPC_PRW_SHIFT 8 +#define BCMA_CC_OTPC_MAXFAIL 0x00000038 +#define BCMA_CC_OTPC_VSEL 0x00000006 +#define BCMA_CC_OTPC_SELVL 0x00000001 +#define BCMA_CC_OTPP 0x0018 /* OTP prog */ +#define BCMA_CC_OTPP_COL 0x000000FF +#define BCMA_CC_OTPP_ROW 0x0000FF00 +#define BCMA_CC_OTPP_ROW_SHIFT 8 +#define BCMA_CC_OTPP_READERR 0x10000000 +#define BCMA_CC_OTPP_VALUE 0x20000000 +#define BCMA_CC_OTPP_READ 0x40000000 +#define BCMA_CC_OTPP_START 0x80000000 +#define BCMA_CC_OTPP_BUSY 0x80000000 +#define BCMA_CC_IRQSTAT 0x0020 +#define BCMA_CC_IRQMASK 0x0024 +#define BCMA_CC_IRQ_GPIO 0x00000001 /* gpio intr */ +#define BCMA_CC_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */ +#define BCMA_CC_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */ +#define BCMA_CC_CHIPCTL 0x0028 /* Rev >= 11 only */ +#define BCMA_CC_CHIPSTAT 0x002C /* Rev >= 11 only */ +#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */ +#define BCMA_CC_JCMD_START 0x80000000 +#define BCMA_CC_JCMD_BUSY 0x80000000 +#define BCMA_CC_JCMD_PAUSE 0x40000000 +#define BCMA_CC_JCMD0_ACC_MASK 0x0000F000 +#define BCMA_CC_JCMD0_ACC_IRDR 0x00000000 +#define BCMA_CC_JCMD0_ACC_DR 0x00001000 +#define BCMA_CC_JCMD0_ACC_IR 0x00002000 +#define BCMA_CC_JCMD0_ACC_RESET 0x00003000 +#define BCMA_CC_JCMD0_ACC_IRPDR 0x00004000 +#define BCMA_CC_JCMD0_ACC_PDR 0x00005000 +#define BCMA_CC_JCMD0_IRW_MASK 0x00000F00 +#define BCMA_CC_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */ +#define BCMA_CC_JCMD_ACC_IRDR 0x00000000 +#define BCMA_CC_JCMD_ACC_DR 0x00010000 +#define BCMA_CC_JCMD_ACC_IR 0x00020000 +#define BCMA_CC_JCMD_ACC_RESET 0x00030000 +#define BCMA_CC_JCMD_ACC_IRPDR 0x00040000 +#define BCMA_CC_JCMD_ACC_PDR 0x00050000 +#define BCMA_CC_JCMD_IRW_MASK 0x00001F00 +#define BCMA_CC_JCMD_IRW_SHIFT 8 +#define BCMA_CC_JCMD_DRW_MASK 0x0000003F +#define BCMA_CC_JIR 0x0034 /* Rev >= 10 only */ +#define BCMA_CC_JDR 0x0038 /* Rev >= 10 only */ +#define BCMA_CC_JCTL 0x003C /* Rev >= 10 only */ +#define BCMA_CC_JCTL_FORCE_CLK 4 /* Force clock */ +#define BCMA_CC_JCTL_EXT_EN 2 /* Enable external targets */ +#define BCMA_CC_JCTL_EN 1 /* Enable Jtag master */ +#define BCMA_CC_FLASHCTL 0x0040 +#define BCMA_CC_FLASHCTL_START 0x80000000 +#define BCMA_CC_FLASHCTL_BUSY BCMA_CC_FLASHCTL_START +#define BCMA_CC_FLASHADDR 0x0044 +#define BCMA_CC_FLASHDATA 0x0048 +#define BCMA_CC_BCAST_ADDR 0x0050 +#define BCMA_CC_BCAST_DATA 0x0054 +#define BCMA_CC_GPIOPULLUP 0x0058 /* Rev >= 20 only */ +#define BCMA_CC_GPIOPULLDOWN 0x005C /* Rev >= 20 only */ +#define BCMA_CC_GPIOIN 0x0060 +#define BCMA_CC_GPIOOUT 0x0064 +#define BCMA_CC_GPIOOUTEN 0x0068 +#define BCMA_CC_GPIOCTL 0x006C +#define BCMA_CC_GPIOPOL 0x0070 +#define BCMA_CC_GPIOIRQ 0x0074 +#define BCMA_CC_WATCHDOG 0x0080 +#define BCMA_CC_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define BCMA_CC_GPIOTIMER_OFFTIME 0x0000FFFF +#define BCMA_CC_GPIOTIMER_OFFTIME_SHIFT 0 +#define BCMA_CC_GPIOTIMER_ONTIME 0xFFFF0000 +#define BCMA_CC_GPIOTIMER_ONTIME_SHIFT 16 +#define BCMA_CC_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ +#define BCMA_CC_CLOCK_N 0x0090 +#define BCMA_CC_CLOCK_SB 0x0094 +#define BCMA_CC_CLOCK_PCI 0x0098 +#define BCMA_CC_CLOCK_M2 0x009C +#define BCMA_CC_CLOCK_MIPS 0x00A0 +#define BCMA_CC_CLKDIV 0x00A4 /* Rev >= 3 only */ +#define BCMA_CC_CLKDIV_SFLASH 0x0F000000 +#define BCMA_CC_CLKDIV_SFLASH_SHIFT 24 +#define BCMA_CC_CLKDIV_OTP 0x000F0000 +#define BCMA_CC_CLKDIV_OTP_SHIFT 16 +#define BCMA_CC_CLKDIV_JTAG 0x00000F00 +#define BCMA_CC_CLKDIV_JTAG_SHIFT 8 +#define BCMA_CC_CLKDIV_UART 0x000000FF +#define BCMA_CC_CAP_EXT 0x00AC /* Capabilities */ +#define BCMA_CC_PLLONDELAY 0x00B0 /* Rev >= 4 only */ +#define BCMA_CC_FREFSELDELAY 0x00B4 /* Rev >= 4 only */ +#define BCMA_CC_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */ +#define BCMA_CC_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */ +#define BCMA_CC_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */ +#define BCMA_CC_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */ +#define BCMA_CC_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */ +#define BCMA_CC_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define BCMA_CC_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ +#define BCMA_CC_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ +#define BCMA_CC_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */ +#define BCMA_CC_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */ +#define BCMA_CC_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define BCMA_CC_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define BCMA_CC_SLOWCLKCTL_CLKDIV_SHIFT 16 +#define BCMA_CC_SYSCLKCTL 0x00C0 /* Rev >= 3 only */ +#define BCMA_CC_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */ +#define BCMA_CC_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */ +#define BCMA_CC_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */ +#define BCMA_CC_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define BCMA_CC_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */ +#define BCMA_CC_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */ +#define BCMA_CC_SYSCLKCTL_CLKDIV_SHIFT 16 +#define BCMA_CC_CLKSTSTR 0x00C4 /* Rev >= 3 only */ +#define BCMA_CC_EROM 0x00FC +#define BCMA_CC_PCMCIA_CFG 0x0100 +#define BCMA_CC_PCMCIA_MEMWAIT 0x0104 +#define BCMA_CC_PCMCIA_ATTRWAIT 0x0108 +#define BCMA_CC_PCMCIA_IOWAIT 0x010C +#define BCMA_CC_IDE_CFG 0x0110 +#define BCMA_CC_IDE_MEMWAIT 0x0114 +#define BCMA_CC_IDE_ATTRWAIT 0x0118 +#define BCMA_CC_IDE_IOWAIT 0x011C +#define BCMA_CC_PROG_CFG 0x0120 +#define BCMA_CC_PROG_WAITCNT 0x0124 +#define BCMA_CC_FLASH_CFG 0x0128 +#define BCMA_CC_FLASH_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ +#define BCMA_CC_FLASH_WAITCNT 0x012C +/* 0x1E0 is defined as shared BCMA_CLKCTLST */ +#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ +#define BCMA_CC_UART0_DATA 0x0300 +#define BCMA_CC_UART0_IMR 0x0304 +#define BCMA_CC_UART0_FCR 0x0308 +#define BCMA_CC_UART0_LCR 0x030C +#define BCMA_CC_UART0_MCR 0x0310 +#define BCMA_CC_UART0_LSR 0x0314 +#define BCMA_CC_UART0_MSR 0x0318 +#define BCMA_CC_UART0_SCRATCH 0x031C +#define BCMA_CC_UART1_DATA 0x0400 +#define BCMA_CC_UART1_IMR 0x0404 +#define BCMA_CC_UART1_FCR 0x0408 +#define BCMA_CC_UART1_LCR 0x040C +#define BCMA_CC_UART1_MCR 0x0410 +#define BCMA_CC_UART1_LSR 0x0414 +#define BCMA_CC_UART1_MSR 0x0418 +#define BCMA_CC_UART1_SCRATCH 0x041C +/* PMU registers (rev >= 20) */ +#define BCMA_CC_PMU_CTL 0x0600 /* PMU control */ +#define BCMA_CC_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */ +#define BCMA_CC_PMU_CTL_ILP_DIV_SHIFT 16 +#define BCMA_CC_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */ +#define BCMA_CC_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */ +#define BCMA_CC_PMU_CTL_ALPREQEN 0x00000080 /* ALP req enable */ +#define BCMA_CC_PMU_CTL_XTALFREQ 0x0000007C /* Crystal freq */ +#define BCMA_CC_PMU_CTL_XTALFREQ_SHIFT 2 +#define BCMA_CC_PMU_CTL_ILPDIVEN 0x00000002 /* ILP div enable */ +#define BCMA_CC_PMU_CTL_LPOSEL 0x00000001 /* LPO sel */ +#define BCMA_CC_PMU_CAP 0x0604 /* PMU capabilities */ +#define BCMA_CC_PMU_CAP_REVISION 0x000000FF /* Revision mask */ +#define BCMA_CC_PMU_STAT 0x0608 /* PMU status */ +#define BCMA_CC_PMU_STAT_INTPEND 0x00000040 /* Interrupt pending */ +#define BCMA_CC_PMU_STAT_SBCLKST 0x00000030 /* Backplane clock status? */ +#define BCMA_CC_PMU_STAT_HAVEALP 0x00000008 /* ALP available */ +#define BCMA_CC_PMU_STAT_HAVEHT 0x00000004 /* HT available */ +#define BCMA_CC_PMU_STAT_RESINIT 0x00000003 /* Res init */ +#define BCMA_CC_PMU_RES_STAT 0x060C /* PMU res status */ +#define BCMA_CC_PMU_RES_PEND 0x0610 /* PMU res pending */ +#define BCMA_CC_PMU_TIMER 0x0614 /* PMU timer */ +#define BCMA_CC_PMU_MINRES_MSK 0x0618 /* PMU min res mask */ +#define BCMA_CC_PMU_MAXRES_MSK 0x061C /* PMU max res mask */ +#define BCMA_CC_PMU_RES_TABSEL 0x0620 /* PMU res table sel */ +#define BCMA_CC_PMU_RES_DEPMSK 0x0624 /* PMU res dep mask */ +#define BCMA_CC_PMU_RES_UPDNTM 0x0628 /* PMU res updown timer */ +#define BCMA_CC_PMU_RES_TIMER 0x062C /* PMU res timer */ +#define BCMA_CC_PMU_CLKSTRETCH 0x0630 /* PMU clockstretch */ +#define BCMA_CC_PMU_WATCHDOG 0x0634 /* PMU watchdog */ +#define BCMA_CC_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */ +#define BCMA_CC_PMU_RES_REQT 0x0644 /* PMU res req timer */ +#define BCMA_CC_PMU_RES_REQM 0x0648 /* PMU res req mask */ +#define BCMA_CC_CHIPCTL_ADDR 0x0650 +#define BCMA_CC_CHIPCTL_DATA 0x0654 +#define BCMA_CC_REGCTL_ADDR 0x0658 +#define BCMA_CC_REGCTL_DATA 0x065C +#define BCMA_CC_PLLCTL_ADDR 0x0660 +#define BCMA_CC_PLLCTL_DATA 0x0664 +#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */ +#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */ + +/* Divider allocation in 4716/47162/5356 */ +#define BCMA_CC_PMU5_MAINPLL_CPU 1 +#define BCMA_CC_PMU5_MAINPLL_MEM 2 +#define BCMA_CC_PMU5_MAINPLL_SSB 3 + +/* PLL usage in 4716/47162 */ +#define BCMA_CC_PMU4716_MAINPLL_PLL0 12 + +/* PLL usage in 5356/5357 */ +#define BCMA_CC_PMU5356_MAINPLL_PLL0 0 +#define BCMA_CC_PMU5357_MAINPLL_PLL0 0 + +/* 4706 PMU */ +#define BCMA_CC_PMU4706_MAINPLL_PLL0 0 + +/* ALP clock on pre-PMU chips */ +#define BCMA_CC_PMU_ALP_CLOCK 20000000 +/* HT clock for systems with PMU-enabled chipcommon */ +#define BCMA_CC_PMU_HT_CLOCK 80000000 + +/* PMU rev 5 (& 6) */ +#define BCMA_CC_PPL_P1P2_OFF 0 +#define BCMA_CC_PPL_P1_MASK 0x0f000000 +#define BCMA_CC_PPL_P1_SHIFT 24 +#define BCMA_CC_PPL_P2_MASK 0x00f00000 +#define BCMA_CC_PPL_P2_SHIFT 20 +#define BCMA_CC_PPL_M14_OFF 1 +#define BCMA_CC_PPL_MDIV_MASK 0x000000ff +#define BCMA_CC_PPL_MDIV_WIDTH 8 +#define BCMA_CC_PPL_NM5_OFF 2 +#define BCMA_CC_PPL_NDIV_MASK 0xfff00000 +#define BCMA_CC_PPL_NDIV_SHIFT 20 +#define BCMA_CC_PPL_FMAB_OFF 3 +#define BCMA_CC_PPL_MRAT_MASK 0xf0000000 +#define BCMA_CC_PPL_MRAT_SHIFT 28 +#define BCMA_CC_PPL_ABRAT_MASK 0x08000000 +#define BCMA_CC_PPL_ABRAT_SHIFT 27 +#define BCMA_CC_PPL_FDIV_MASK 0x07ffffff +#define BCMA_CC_PPL_PLLCTL_OFF 4 +#define BCMA_CC_PPL_PCHI_OFF 5 +#define BCMA_CC_PPL_PCHI_MASK 0x0000003f + +/* BCM4331 ChipControl numbers. */ +#define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */ +#define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */ +#define BCMA_CHIPCTL_4331_EXT_LNA BIT(2) /* 0 disable */ +#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15 BIT(3) /* sprom/gpio13-15 mux */ +#define BCMA_CHIPCTL_4331_EXTPA_EN BIT(4) /* 0 ext pa disable, 1 ext pa enabled */ +#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS BIT(5) /* set drive out GPIO_CLK on sprom_cs pin */ +#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS BIT(6) /* use sprom_cs pin as PCIE mdio interface */ +#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5 BIT(7) /* aband extpa will be at gpio2/5 and sprom_dout */ +#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN BIT(8) /* override core control on pipe_AuxClkEnable */ +#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN BIT(9) /* override core control on pipe_AuxPowerDown */ +#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN BIT(10) /* pcie_auxclkenable */ +#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN BIT(11) /* pcie_pipe_pllpowerdown */ +#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */ +#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */ + +/* Data for the PMU, if available. + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) + */ +struct bcma_chipcommon_pmu { + u8 rev; /* PMU revision */ + u32 crystalfreq; /* The active crystal frequency (in kHz) */ +}; + +#ifdef CONFIG_BCMA_DRIVER_MIPS +struct bcma_pflash { + u8 buswidth; + u32 window; + u32 window_size; +}; + +struct bcma_serial_port { + void *regs; + unsigned long clockspeed; + unsigned int irq; + unsigned int baud_base; + unsigned int reg_shift; +}; +#endif /* CONFIG_BCMA_DRIVER_MIPS */ + +struct bcma_drv_cc { + struct bcma_device *core; + u32 status; + u32 capabilities; + u32 capabilities_ext; + u8 setup_done:1; + /* Fast Powerup Delay constant */ + u16 fast_pwrup_delay; + struct bcma_chipcommon_pmu pmu; +#ifdef CONFIG_BCMA_DRIVER_MIPS + struct bcma_pflash pflash; + + int nr_serial_ports; + struct bcma_serial_port serial_ports[4]; +#endif /* CONFIG_BCMA_DRIVER_MIPS */ +}; + +/* Register access */ +#define bcma_cc_read32(cc, offset) \ + bcma_read32((cc)->core, offset) +#define bcma_cc_write32(cc, offset, val) \ + bcma_write32((cc)->core, offset, val) + +#define bcma_cc_mask32(cc, offset, mask) \ + bcma_cc_write32(cc, offset, bcma_cc_read32(cc, offset) & (mask)) +#define bcma_cc_set32(cc, offset, set) \ + bcma_cc_write32(cc, offset, bcma_cc_read32(cc, offset) | (set)) +#define bcma_cc_maskset32(cc, offset, mask, set) \ + bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set)) + +extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc); + +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc); +extern void bcma_chipco_resume(struct bcma_drv_cc *cc); + +void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); + +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, + u32 ticks); + +void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value); + +u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask); + +/* Chipcommon GPIO pin access. */ +u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask); +u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value); + +/* PMU support */ +extern void bcma_pmu_init(struct bcma_drv_cc *cc); + +extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, + u32 value); +extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, + u32 mask, u32 set); +extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, + u32 offset, u32 mask, u32 set); +extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, + u32 offset, u32 mask, u32 set); + +#endif /* LINUX_BCMA_DRIVER_CC_H_ */ diff --git a/include/compat/linux/bcma/bcma_driver_mips.h b/include/compat/linux/bcma/bcma_driver_mips.h new file mode 100644 index 00000000..c0043645 --- /dev/null +++ b/include/compat/linux/bcma/bcma_driver_mips.h @@ -0,0 +1,51 @@ +#ifndef LINUX_BCMA_DRIVER_MIPS_H_ +#define LINUX_BCMA_DRIVER_MIPS_H_ + +#define BCMA_MIPS_IPSFLAG 0x0F08 +/* which sbflags get routed to mips interrupt 1 */ +#define BCMA_MIPS_IPSFLAG_IRQ1 0x0000003F +#define BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0 +/* which sbflags get routed to mips interrupt 2 */ +#define BCMA_MIPS_IPSFLAG_IRQ2 0x00003F00 +#define BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8 +/* which sbflags get routed to mips interrupt 3 */ +#define BCMA_MIPS_IPSFLAG_IRQ3 0x003F0000 +#define BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16 +/* which sbflags get routed to mips interrupt 4 */ +#define BCMA_MIPS_IPSFLAG_IRQ4 0x3F000000 +#define BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24 + +/* MIPS 74K core registers */ +#define BCMA_MIPS_MIPS74K_CORECTL 0x0000 +#define BCMA_MIPS_MIPS74K_EXCEPTBASE 0x0004 +#define BCMA_MIPS_MIPS74K_BIST 0x000C +#define BCMA_MIPS_MIPS74K_INTMASK_INT0 0x0014 +#define BCMA_MIPS_MIPS74K_INTMASK(int) \ + ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0) +#define BCMA_MIPS_MIPS74K_NMIMASK 0x002C +#define BCMA_MIPS_MIPS74K_GPIOSEL 0x0040 +#define BCMA_MIPS_MIPS74K_GPIOOUT 0x0044 +#define BCMA_MIPS_MIPS74K_GPIOEN 0x0048 +#define BCMA_MIPS_MIPS74K_CLKCTLST 0x01E0 + +#define BCMA_MIPS_OOBSELOUTA30 0x100 + +struct bcma_device; + +struct bcma_drv_mips { + struct bcma_device *core; + u8 setup_done:1; + unsigned int assigned_irqs; +}; + +#ifdef CONFIG_BCMA_DRIVER_MIPS +extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); +#else +static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { } +#endif + +extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore); + +extern unsigned int bcma_core_mips_irq(struct bcma_device *dev); + +#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */ diff --git a/include/compat/linux/bcma/bcma_driver_pci.h b/include/compat/linux/bcma/bcma_driver_pci.h new file mode 100644 index 00000000..3871b668 --- /dev/null +++ b/include/compat/linux/bcma/bcma_driver_pci.h @@ -0,0 +1,91 @@ +#ifndef LINUX_BCMA_DRIVER_PCI_H_ +#define LINUX_BCMA_DRIVER_PCI_H_ + +#include + +struct pci_dev; + +/** PCI core registers. **/ +#define BCMA_CORE_PCI_CTL 0x0000 /* PCI Control */ +#define BCMA_CORE_PCI_CTL_RST_OE 0x00000001 /* PCI_RESET Output Enable */ +#define BCMA_CORE_PCI_CTL_RST 0x00000002 /* PCI_RESET driven out to pin */ +#define BCMA_CORE_PCI_CTL_CLK_OE 0x00000004 /* Clock gate Output Enable */ +#define BCMA_CORE_PCI_CTL_CLK 0x00000008 /* Gate for clock driven out to pin */ +#define BCMA_CORE_PCI_ARBCTL 0x0010 /* PCI Arbiter Control */ +#define BCMA_CORE_PCI_ARBCTL_INTERN 0x00000001 /* Use internal arbiter */ +#define BCMA_CORE_PCI_ARBCTL_EXTERN 0x00000002 /* Use external arbiter */ +#define BCMA_CORE_PCI_ARBCTL_PARKID 0x00000006 /* Mask, selects which agent is parked on an idle bus */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_LAST 0x00000000 /* Last requestor */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_4710 0x00000002 /* 4710 */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_EXT0 0x00000004 /* External requestor 0 */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_EXT1 0x00000006 /* External requestor 1 */ +#define BCMA_CORE_PCI_ISTAT 0x0020 /* Interrupt status */ +#define BCMA_CORE_PCI_ISTAT_INTA 0x00000001 /* PCI INTA# */ +#define BCMA_CORE_PCI_ISTAT_INTB 0x00000002 /* PCI INTB# */ +#define BCMA_CORE_PCI_ISTAT_SERR 0x00000004 /* PCI SERR# (write to clear) */ +#define BCMA_CORE_PCI_ISTAT_PERR 0x00000008 /* PCI PERR# (write to clear) */ +#define BCMA_CORE_PCI_ISTAT_PME 0x00000010 /* PCI PME# */ +#define BCMA_CORE_PCI_IMASK 0x0024 /* Interrupt mask */ +#define BCMA_CORE_PCI_IMASK_INTA 0x00000001 /* PCI INTA# */ +#define BCMA_CORE_PCI_IMASK_INTB 0x00000002 /* PCI INTB# */ +#define BCMA_CORE_PCI_IMASK_SERR 0x00000004 /* PCI SERR# */ +#define BCMA_CORE_PCI_IMASK_PERR 0x00000008 /* PCI PERR# */ +#define BCMA_CORE_PCI_IMASK_PME 0x00000010 /* PCI PME# */ +#define BCMA_CORE_PCI_MBOX 0x0028 /* Backplane to PCI Mailbox */ +#define BCMA_CORE_PCI_MBOX_F0_0 0x00000100 /* PCI function 0, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F0_1 0x00000200 /* PCI function 0, INT 1 */ +#define BCMA_CORE_PCI_MBOX_F1_0 0x00000400 /* PCI function 1, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F1_1 0x00000800 /* PCI function 1, INT 1 */ +#define BCMA_CORE_PCI_MBOX_F2_0 0x00001000 /* PCI function 2, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F2_1 0x00002000 /* PCI function 2, INT 1 */ +#define BCMA_CORE_PCI_MBOX_F3_0 0x00004000 /* PCI function 3, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F3_1 0x00008000 /* PCI function 3, INT 1 */ +#define BCMA_CORE_PCI_BCAST_ADDR 0x0050 /* Backplane Broadcast Address */ +#define BCMA_CORE_PCI_BCAST_ADDR_MASK 0x000000FF +#define BCMA_CORE_PCI_BCAST_DATA 0x0054 /* Backplane Broadcast Data */ +#define BCMA_CORE_PCI_GPIO_IN 0x0060 /* rev >= 2 only */ +#define BCMA_CORE_PCI_GPIO_OUT 0x0064 /* rev >= 2 only */ +#define BCMA_CORE_PCI_GPIO_ENABLE 0x0068 /* rev >= 2 only */ +#define BCMA_CORE_PCI_GPIO_CTL 0x006C /* rev >= 2 only */ +#define BCMA_CORE_PCI_SBTOPCI0 0x0100 /* Backplane to PCI translation 0 (sbtopci0) */ +#define BCMA_CORE_PCI_SBTOPCI0_MASK 0xFC000000 +#define BCMA_CORE_PCI_SBTOPCI1 0x0104 /* Backplane to PCI translation 1 (sbtopci1) */ +#define BCMA_CORE_PCI_SBTOPCI1_MASK 0xFC000000 +#define BCMA_CORE_PCI_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */ +#define BCMA_CORE_PCI_SBTOPCI2_MASK 0xC0000000 +#define BCMA_CORE_PCI_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */ +#define BCMA_CORE_PCI_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */ +#define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ +#define BCMA_CORE_PCI_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ +#define BCMA_CORE_PCI_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ + +/* SBtoPCIx */ +#define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000 +#define BCMA_CORE_PCI_SBTOPCI_IO 0x00000001 +#define BCMA_CORE_PCI_SBTOPCI_CFG0 0x00000002 +#define BCMA_CORE_PCI_SBTOPCI_CFG1 0x00000003 +#define BCMA_CORE_PCI_SBTOPCI_PREF 0x00000004 /* Prefetch enable */ +#define BCMA_CORE_PCI_SBTOPCI_BURST 0x00000008 /* Burst enable */ +#define BCMA_CORE_PCI_SBTOPCI_MRM 0x00000020 /* Memory Read Multiple */ +#define BCMA_CORE_PCI_SBTOPCI_RC 0x00000030 /* Read Command mask (rev >= 11) */ +#define BCMA_CORE_PCI_SBTOPCI_RC_READ 0x00000000 /* Memory read */ +#define BCMA_CORE_PCI_SBTOPCI_RC_READL 0x00000010 /* Memory read line */ +#define BCMA_CORE_PCI_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */ + +/* PCIcore specific boardflags */ +#define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ + +struct bcma_drv_pci { + struct bcma_device *core; + u8 setup_done:1; +}; + +/* Register access */ +#define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset) +#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) + +extern void bcma_core_pci_init(struct bcma_drv_pci *pc); +extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, + struct bcma_device *core, bool enable); + +#endif /* LINUX_BCMA_DRIVER_PCI_H_ */ diff --git a/include/compat/linux/bcma/bcma_regs.h b/include/compat/linux/bcma/bcma_regs.h new file mode 100644 index 00000000..9faae2ae --- /dev/null +++ b/include/compat/linux/bcma/bcma_regs.h @@ -0,0 +1,59 @@ +#ifndef LINUX_BCMA_REGS_H_ +#define LINUX_BCMA_REGS_H_ + +/* Some single registers are shared between many cores */ +/* BCMA_CLKCTLST: ChipCommon (rev >= 20), PCIe, 80211 */ +#define BCMA_CLKCTLST 0x01E0 /* Clock control and status */ +#define BCMA_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */ +#define BCMA_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */ +#define BCMA_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */ +#define BCMA_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ +#define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ +#define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ +#define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */ +#define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */ +#define BCMA_CLKCTLST_HAVEHT 0x00020000 /* HT available */ +#define BCMA_CLKCTLST_BP_ON_ALP 0x00040000 /* RO: running on ALP clock */ +#define BCMA_CLKCTLST_BP_ON_HT 0x00080000 /* RO: running on HT clock */ +#define BCMA_CLKCTLST_EXTRESST 0x07000000 /* Mask of external resource status */ +/* Is there any BCM4328 on BCMA bus? */ +#define BCMA_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */ +#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */ + +/* Agent registers (common for every core) */ +#define BCMA_IOCTL 0x0408 /* IO control */ +#define BCMA_IOCTL_CLK 0x0001 +#define BCMA_IOCTL_FGC 0x0002 +#define BCMA_IOCTL_CORE_BITS 0x3FFC +#define BCMA_IOCTL_PME_EN 0x4000 +#define BCMA_IOCTL_BIST_EN 0x8000 +#define BCMA_IOST 0x0500 /* IO status */ +#define BCMA_IOST_CORE_BITS 0x0FFF +#define BCMA_IOST_DMA64 0x1000 +#define BCMA_IOST_GATED_CLK 0x2000 +#define BCMA_IOST_BIST_ERROR 0x4000 +#define BCMA_IOST_BIST_DONE 0x8000 +#define BCMA_RESET_CTL 0x0800 +#define BCMA_RESET_CTL_RESET 0x0001 + +/* BCMA PCI config space registers. */ +#define BCMA_PCI_PMCSR 0x44 +#define BCMA_PCI_PE 0x100 +#define BCMA_PCI_BAR0_WIN 0x80 /* Backplane address space 0 */ +#define BCMA_PCI_BAR1_WIN 0x84 /* Backplane address space 1 */ +#define BCMA_PCI_SPROMCTL 0x88 /* SPROM control */ +#define BCMA_PCI_SPROMCTL_WE 0x10 /* SPROM write enable */ +#define BCMA_PCI_BAR1_CONTROL 0x8c /* Address space 1 burst control */ +#define BCMA_PCI_IRQS 0x90 /* PCI interrupts */ +#define BCMA_PCI_IRQMASK 0x94 /* PCI IRQ control and mask (pcirev >= 6 only) */ +#define BCMA_PCI_BACKPLANE_IRQS 0x98 /* Backplane Interrupts */ +#define BCMA_PCI_BAR0_WIN2 0xAC +#define BCMA_PCI_GPIO_IN 0xB0 /* GPIO Input (pcirev >= 3 only) */ +#define BCMA_PCI_GPIO_OUT 0xB4 /* GPIO Output (pcirev >= 3 only) */ +#define BCMA_PCI_GPIO_OUT_ENABLE 0xB8 /* GPIO Output Enable/Disable (pcirev >= 3 only) */ +#define BCMA_PCI_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define BCMA_PCI_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */ +#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */ + +#endif /* LINUX_BCMA_REGS_H_ */ diff --git a/include/compat/linux/bcma/bcma_soc.h b/include/compat/linux/bcma/bcma_soc.h new file mode 100644 index 00000000..4203c559 --- /dev/null +++ b/include/compat/linux/bcma/bcma_soc.h @@ -0,0 +1,16 @@ +#ifndef LINUX_BCMA_SOC_H_ +#define LINUX_BCMA_SOC_H_ + +#include + +struct bcma_soc { + struct bcma_bus bus; + struct bcma_device core_cc; + struct bcma_device core_mips; +}; + +int __init bcma_host_soc_register(struct bcma_soc *soc); + +int bcma_bus_register(struct bcma_bus *bus); + +#endif /* LINUX_BCMA_SOC_H_ */ diff --git a/include/compat/linux/bitops.h b/include/compat/linux/bitops.h new file mode 100644 index 00000000..aa76af18 --- /dev/null +++ b/include/compat/linux/bitops.h @@ -0,0 +1,211 @@ +#ifndef _LINUX_BITOPS_H +#define _LINUX_BITOPS_H +#include + +#ifdef __KERNEL__ +#define BIT(nr) (1UL << (nr)) +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BITS_PER_BYTE 8 +#ifndef BITS_TO_LONGS /* Older kernels define this already */ +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#endif +#endif + +extern unsigned int __sw_hweight8(unsigned int w); +extern unsigned int __sw_hweight16(unsigned int w); +extern unsigned int __sw_hweight32(unsigned int w); +extern unsigned long __sw_hweight64(__u64 w); + +/* + * Include this here because some architectures need generic_ffs/fls in + * scope + */ +#include + +#define for_each_set_bit(bit, addr, size) \ + for ((bit) = find_first_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +static __inline__ int get_bitmask_order(unsigned int count) +{ + int order; + + order = fls(count); + return order; /* We could be slightly more clever with -1 here... */ +} + +static __inline__ int get_count_order(unsigned int count) +{ + int order; + + order = fls(count) - 1; + if (count & (count - 1)) + order++; + return order; +} + +static inline unsigned long hweight_long(unsigned long w) +{ + return sizeof(w) == 4 ? hweight32(w) : hweight64(w); +} + +/** + * rol32 - rotate a 32-bit value left + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u32 rol32(__u32 word, unsigned int shift) +{ + return (word << shift) | (word >> (32 - shift)); +} + +/** + * ror32 - rotate a 32-bit value right + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u32 ror32(__u32 word, unsigned int shift) +{ + return (word >> shift) | (word << (32 - shift)); +} + +/** + * rol16 - rotate a 16-bit value left + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u16 rol16(__u16 word, unsigned int shift) +{ + return (word << shift) | (word >> (16 - shift)); +} + +/** + * ror16 - rotate a 16-bit value right + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u16 ror16(__u16 word, unsigned int shift) +{ + return (word >> shift) | (word << (16 - shift)); +} + +/** + * rol8 - rotate an 8-bit value left + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u8 rol8(__u8 word, unsigned int shift) +{ + return (word << shift) | (word >> (8 - shift)); +} + +/** + * ror8 - rotate an 8-bit value right + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u8 ror8(__u8 word, unsigned int shift) +{ + return (word >> shift) | (word << (8 - shift)); +} + +/** + * sign_extend32 - sign extend a 32-bit value using specified bit as sign-bit + * @value: value to sign extend + * @index: 0 based bit index (0<=index<32) to sign bit + */ +static inline __s32 sign_extend32(__u32 value, int index) +{ + __u8 shift = 31 - index; + return (__s32)(value << shift) >> shift; +} + +static inline unsigned fls_long(unsigned long l) +{ + if (sizeof(l) == 4) + return fls(l); + return fls64(l); +} + +/** + * __ffs64 - find first set bit in a 64 bit word + * @word: The 64 bit word + * + * On 64 bit arches this is a synomyn for __ffs + * The result is not defined if no bits are set, so check that @word + * is non-zero before calling this. + */ +static inline unsigned long __ffs64(u64 word) +{ +#if BITS_PER_LONG == 32 + if (((u32)word) == 0UL) + return __ffs((u32)(word >> 32)) + 32; +#elif BITS_PER_LONG != 64 +#error BITS_PER_LONG not 32 or 64 +#endif + return __ffs((unsigned long)word); +} + +#ifdef __KERNEL__ +#ifdef CONFIG_GENERIC_FIND_FIRST_BIT + +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit number of the first set bit. + */ +extern unsigned long find_first_bit(const unsigned long *addr, + unsigned long size); + +/** + * find_first_zero_bit - find the first cleared bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit number of the first cleared bit. + */ +extern unsigned long find_first_zero_bit(const unsigned long *addr, + unsigned long size); +#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */ + +#ifdef CONFIG_GENERIC_FIND_LAST_BIT +/** + * find_last_bit - find the last set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit number of the first set bit, or size. + */ +extern unsigned long find_last_bit(const unsigned long *addr, + unsigned long size); +#endif /* CONFIG_GENERIC_FIND_LAST_BIT */ + +#ifdef CONFIG_GENERIC_FIND_NEXT_BIT + +/** + * find_next_bit - find the next set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The bitmap size in bits + */ +extern unsigned long find_next_bit(const unsigned long *addr, + unsigned long size, unsigned long offset); + +/** + * find_next_zero_bit - find the next cleared bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The bitmap size in bits + */ + +extern unsigned long find_next_zero_bit(const unsigned long *addr, + unsigned long size, + unsigned long offset); + +#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */ +#endif /* __KERNEL__ */ +#endif diff --git a/include/compat/linux/compat-2.6.14.h b/include/compat/linux/compat-2.6.14.h new file mode 100644 index 00000000..1f19f7fe --- /dev/null +++ b/include/compat/linux/compat-2.6.14.h @@ -0,0 +1,13 @@ +#ifndef LINUX_26_14_COMPAT_H +#define LINUX_26_14_COMPAT_H + +#include + +/* Compat work for 2.6.14 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) + +typedef unsigned int gfp_t; + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) */ + +#endif /* LINUX_26_14_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.18.h b/include/compat/linux/compat-2.6.18.h new file mode 100644 index 00000000..5e0182b1 --- /dev/null +++ b/include/compat/linux/compat-2.6.18.h @@ -0,0 +1,13 @@ +#ifndef LINUX_26_18_COMPAT_H +#define LINUX_26_18_COMPAT_H + +#include + +/* Compat work for 2.6.18 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) + +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) */ + +#endif /* LINUX_26_18_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.19.h b/include/compat/linux/compat-2.6.19.h new file mode 100644 index 00000000..1e648c0a --- /dev/null +++ b/include/compat/linux/compat-2.6.19.h @@ -0,0 +1,24 @@ +#ifndef LINUX_26_19_COMPAT_H +#define LINUX_26_19_COMPAT_H + +#include + +/* Compat work for 2.6.19 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) + +#include + +static inline int +compat_kmem_cache_destroy(struct kmem_cache *cachep) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + return kmem_cache_destroy(cachep); +#else + kmem_cache_destroy(cachep); + return 0; +#endif +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) */ + +#endif /* LINUX_26_19_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.20.h b/include/compat/linux/compat-2.6.20.h new file mode 100644 index 00000000..14579e29 --- /dev/null +++ b/include/compat/linux/compat-2.6.20.h @@ -0,0 +1,21 @@ +#ifndef LINUX_26_20_COMPAT_H +#define LINUX_26_20_COMPAT_H + +#include + +/* Compat work for 2.6.20 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) + +#include + +typedef void (*work_func_t)(struct work_struct *work); +typedef void (*compat_work_func_t)(void *work); +static inline void (INIT_WORK)(struct work_struct *work, work_func_t func) +{ + INIT_WORK(work, (compat_work_func_t)func, work); +} +#undef INIT_WORK + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) */ + +#endif /* LINUX_26_20_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.21.h b/include/compat/linux/compat-2.6.21.h new file mode 100644 index 00000000..89ed6d9a --- /dev/null +++ b/include/compat/linux/compat-2.6.21.h @@ -0,0 +1,18 @@ +#ifndef LINUX_26_21_COMPAT_H +#define LINUX_26_21_COMPAT_H + +#include + +/* Compat work for 2.6.21 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + +#include + +#define register_sysctl_table(table) \ + ({ \ + register_sysctl_table((table), 0); \ + }) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) */ + +#endif /* LINUX_26_21_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.22.h b/include/compat/linux/compat-2.6.22.h new file mode 100644 index 00000000..7ca1b18e --- /dev/null +++ b/include/compat/linux/compat-2.6.22.h @@ -0,0 +1,104 @@ +#ifndef LINUX_26_22_COMPAT_H +#define LINUX_26_22_COMPAT_H + +#include + +/* Compat work for 2.6.21 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) + +#include +#include + +/* reuse ax25_ptr */ +#define ieee80211_ptr ax25_ptr + +#ifdef CONFIG_AX25 +#error Compat reuses the AX.25 pointer so that may not be enabled! +#endif + +static inline unsigned char *skb_mac_header(const struct sk_buff *skb) +{ + return skb->mac.raw; +} + +static inline void skb_set_mac_header(struct sk_buff *skb, int offset) +{ + skb->mac.raw = skb->data + offset; +} + +static inline void skb_reset_mac_header(struct sk_buff *skb) +{ + skb->mac.raw = skb->data; +} + +static inline void skb_reset_network_header(struct sk_buff *skb) +{ + skb->nh.raw = skb->data; +} + +static inline void skb_set_network_header(struct sk_buff *skb, int offset) +{ + skb->nh.raw = skb->data + offset; +} + +static inline void skb_set_transport_header(struct sk_buff *skb, int offset) +{ + skb->h.raw = skb->data + offset; +} + +static inline unsigned char *skb_transport_header(struct sk_buff *skb) +{ + return skb->h.raw; +} + +static inline unsigned char *skb_network_header(const struct sk_buff *skb) +{ + return skb->nh.raw; +} + +static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb) +{ + return skb->tail; +} + +static inline struct iphdr *ip_hdr(const struct sk_buff *skb) +{ + return (struct iphdr *)skb_network_header(skb); +} + +static inline void skb_copy_from_linear_data(const struct sk_buff *skb, + void *to, + const unsigned int len) +{ + memcpy(to, skb->data, len); +} + +static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb, + const int offset, void *to, + const unsigned int len) +{ + memcpy(to, skb->data + offset, len); +} + +#define __maybe_unused __attribute__((unused)) + +#define uninitialized_var(x) x = x + +/* This will lead to very weird behaviour... */ +#define NLA_BINARY NLA_STRING + +static inline int pci_set_mwi(struct pci_dev *dev) +{ + return -ENOSYS; +} + +static inline void pci_clear_mwi(struct pci_dev *dev) +{ +} + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) */ + +#endif /* LINUX_26_22_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.23.h b/include/compat/linux/compat-2.6.23.h new file mode 100644 index 00000000..fbfb470d --- /dev/null +++ b/include/compat/linux/compat-2.6.23.h @@ -0,0 +1,136 @@ +#ifndef LINUX_26_23_COMPAT_H +#define LINUX_26_23_COMPAT_H + +#include + +/* Compat work for < 2.6.23 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) + +#include +#include +#include +#include +#include + +/* + * Tell gcc if a function is cold. The compiler will assume any path + * directly leading to the call is unlikely. + */ + +#if !(__GNUC__ == 4 && __GNUC_MINOR__ < 3) +/* Mark functions as cold. gcc will assume any path leading to a call + * to them will be unlikely. This means a lot of manual unlikely()s + * are unnecessary now for any paths leading to the usual suspects + * like BUG(), printk(), panic() etc. [but let's keep them for now for + * older compilers] + * + * Early snapshots of gcc 4.3 don't support this and we can't detect this + * in the preprocessor, but we can live with this because they're unreleased. + * Maketime probing would be overkill here. + * + * gcc also has a __attribute__((__hot__)) to move hot functions into + * a special section, but I don't see any sense in this right now in + * the kernel context */ +#define __cold __attribute__((__cold__)) +#endif /* gcc 4.3 check */ + +#ifndef __cold +#define __cold +#endif + +/* Added as of 2.6.23 in include/linux/netdevice.h */ +#define alloc_netdev_mq(sizeof_priv, name, setup, queue) \ + alloc_netdev(sizeof_priv, name, setup) +#define NETIF_F_MULTI_QUEUE 16384 + +/* Added as of 2.6.23 on include/linux/netdevice.h */ +static inline int netif_is_multiqueue(const struct net_device *dev) +{ + return (!!(NETIF_F_MULTI_QUEUE & dev->features)); +} + +/* 2.6.23 fixed a bug in tcf_destroy_chain and the parameter changed */ +static inline void tcf_destroy_chain_compat(struct tcf_proto **fl) +{ + struct tcf_proto *tp; + + while ((tp = *fl) != NULL) { + *fl = tp->next; + tp->ops->destroy(tp); + module_put(tp->ops->owner); + kfree(tp); + } +} + +/* dev_mc_list was replaced with dev_addr_list as of 2.6.23, + * only new member added is da_synced. */ +#define dev_addr_list dev_mc_list +#define da_addr dmi_addr +#define da_addrlen dmi_addrlen +#define da_users dmi_users +#define da_gusers dmi_gusers + +/* dev_set_promiscuity() was moved to __dev_set_promiscuity() on 2.6.23 and + * dev_set_promiscuity() became a wrapper. */ +#define __dev_set_promiscuity dev_set_promiscuity + +/* Our own 2.6.22 port on compat.c */ +extern void dev_mc_unsync(struct net_device *to, struct net_device *from); +extern int dev_mc_sync(struct net_device *to, struct net_device *from); + +/* Our own 2.6.22 port on compat.c */ +extern void __dev_set_rx_mode(struct net_device *dev); + +/* Simple to add this */ +extern int cancel_delayed_work_sync(struct delayed_work *work); + +#define cancel_delayed_work_sync cancel_rearming_delayed_work + +#define debugfs_rename(a, b, c, d) 1 + +/* nl80211 requires multicast group support which is new and added on + * 2.6.23. We can't add support for it for older kernels to support it + * genl_family structure was changed. Lets just let through the + * genl_register_mc_group call. This means no multicast group suppport */ + +#define genl_register_mc_group(a, b) 0 + +/** + * struct genl_multicast_group - generic netlink multicast group + * @name: name of the multicast group, names are per-family + * @id: multicast group ID, assigned by the core, to use with + * genlmsg_multicast(). + * @list: list entry for linking + * @family: pointer to family, need not be set before registering + */ +struct genl_multicast_group +{ + struct genl_family *family; /* private */ + struct list_head list; /* private */ + char name[GENL_NAMSIZ]; + u32 id; +}; + + +/* Added as of 2.6.23 */ +int pci_try_set_mwi(struct pci_dev *dev); + +/* Added as of 2.6.23 */ +#ifdef CONFIG_PM_SLEEP +/* + * Tell the freezer that the current task should be frozen by it + */ +static inline void set_freezable(void) +{ + current->flags &= ~PF_NOFREEZE; +} + +#else +static inline void set_freezable(void) {} +#endif /* CONFIG_PM_SLEEP */ + +#else +#define tcf_destroy_chain_compat tcf_destroy_chain +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) */ + +#endif /* LINUX_26_23_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.24.h b/include/compat/linux/compat-2.6.24.h new file mode 100644 index 00000000..456dcb6c --- /dev/null +++ b/include/compat/linux/compat-2.6.24.h @@ -0,0 +1,247 @@ +#ifndef LINUX_26_24_COMPAT_H +#define LINUX_26_24_COMPAT_H + +#include + +/* Compat work for 2.6.21, 2.6.22 and 2.6.23 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + +#include +#include +#include +#include +#include +#include +#include + +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 +#define KEY_UWB 239 + +#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) + +struct proc_dir_entry; +struct net_device; +struct net { + atomic_t count; /* To decided when the network + * namespace should be freed. + */ + atomic_t use_count; /* To track references we + * destroy on demand + */ + struct list_head list; /* list of network namespaces */ + struct work_struct work; /* work struct for freeing */ + + struct proc_dir_entry *proc_net; + struct proc_dir_entry *proc_net_stat; + struct proc_dir_entry *proc_net_root; + + struct net_device *loopback_dev; /* The loopback */ + + struct list_head dev_base_head; + struct hlist_head *dev_name_head; + struct hlist_head *dev_index_head; +}; + +#ifdef CONFIG_NET +/* Init's network namespace */ +extern struct net init_net; +#define INIT_NET_NS(net_ns) .net_ns = &init_net, +#else +#define INIT_NET_NS(net_ns) +#endif + +/* Added on 2.6.24 in include/linux/types.h by Al viro on commit 142956af */ +typedef unsigned long uintptr_t; + +/* From include/linux/net.h */ +enum sock_shutdown_cmd { + SHUT_RD = 0, + SHUT_WR = 1, + SHUT_RDWR = 2, +}; + +#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,23)) /* Local check */ +/* Added as of 2.6.24 in include/linux/skbuff.h. + * + * Although 2.6.23 does support for CONFIG_NETDEVICES_MULTIQUEUE + * this helper was not added until 2.6.24. This implementation + * is exactly as it is on newer kernels. + * + * For older kernels we use the an internal mac80211 hack. + * For details see changes to include/net/mac80211.h through + * compat.diff and compat/mq_compat.h */ +static inline u16 skb_get_queue_mapping(struct sk_buff *skb) +{ +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + return skb->queue_mapping; +#else + return 0; +#endif +} +#endif /* Local 2.6.23 check */ + +/* On older kernels we handle this a bit differently, so we yield to that + * code for its implementation in mq_compat.h as we want to make + * use of the internal mac80211 __ieee80211_queue_stopped() which itself + * uses internal mac80211 data structure hacks. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)) /* Local check */ +/** + * netif_subqueue_stopped - test status of subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Check individual transmit queue of a device with multiple transmit queues. + */ +static inline int __netif_subqueue_stopped(const struct net_device *dev, + u16 queue_index) +{ +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + return test_bit(__LINK_STATE_XOFF, + &dev->egress_subqueue[queue_index].state); +#else + return 0; +#endif +} + +/* Note: although the backport implementation for netif_subqueue_stopped + * on older kernels is identical to upstream __netif_subqueue_stopped() + * (except for a const qualifier) we implement netif_subqueue_stopped() + * as part of mac80211 as it relies on internal mac80211 structures we + * use for MQ support. We this implement it in mq_compat.h */ + +#endif /* Local 2.6.23 check */ + +/* + * Force link bug if constructor is used, can't be done compatibly + * because constructor arguments were swapped since then! + */ +extern void __incompatible_kmem_cache_create(void); + +/* 2.6.21 and 2.6.22 kmem_cache_create() takes 6 arguments */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) +#define kmem_cache_create(name, objsize, align, flags, ctor) \ + ({ \ + if (ctor) __incompatible_kmem_cache_create(); \ + kmem_cache_create((name), (objsize), (align), \ + (flags), NULL, NULL); \ + }) +#endif + +/* 2.6.23 kmem_cache_create() takes 5 arguments */ +#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,23)) +#define kmem_cache_create(name, objsize, align, flags, ctor) \ + ({ \ + if (ctor) __incompatible_kmem_cache_create(); \ + kmem_cache_create((name), (objsize), (align), \ + (flags), NULL); \ + }) +#endif + +/* From include/linux/mod_devicetable.h */ + +/* SSB core, see drivers/ssb/ */ +#ifndef SSB_DEVICE +struct ssb_device_id { + __u16 vendor; + __u16 coreid; + __u8 revision; +}; +#define SSB_DEVICE(_vendor, _coreid, _revision) \ + { .vendor = _vendor, .coreid = _coreid, .revision = _revision, } +#define SSB_DEVTABLE_END \ + { 0, }, + +#define SSB_ANY_VENDOR 0xFFFF +#define SSB_ANY_ID 0xFFFF +#define SSB_ANY_REV 0xFF +#endif + + +/* Namespace stuff, introduced on 2.6.24 */ +#define dev_get_by_index(a, b) dev_get_by_index(b) +#define __dev_get_by_index(a, b) __dev_get_by_index(b) + +extern int eth_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len); +extern int eth_rebuild_header(struct sk_buff *skb); +extern void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, + unsigned char * haddr); +extern int eth_header_cache(struct neighbour *neigh, + struct hh_cache *hh); + +/* This structure is simply not present on 2.6.22 and 2.6.23 */ +struct header_ops { + int (*create) (struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len); + int (*parse)(const struct sk_buff *skb, unsigned char *haddr); + int (*rebuild)(struct sk_buff *skb); + #define HAVE_HEADER_CACHE + int (*cache)(struct neighbour *neigh, struct hh_cache *hh); + void (*cache_update)(struct hh_cache *hh, + struct net_device *dev, + unsigned char *haddr); +}; + +/* net/ieee80211/ieee80211_crypt_tkip uses sg_init_table. This was added on + * 2.6.24. CONFIG_DEBUG_SG was added in 2.6.24 as well, so lets just ignore + * the debug stuff. Note that adding this required changes to the struct + * scatterlist on include/asm/scatterlist*, so the right way to port this + * is to simply ignore the new structure changes and zero the scatterlist + * array. We lave the kdoc intact for reference. + */ + +/** + * sg_mark_end - Mark the end of the scatterlist + * @sg: SG entryScatterlist + * + * Description: + * Marks the passed in sg entry as the termination point for the sg + * table. A call to sg_next() on this entry will return NULL. + * + **/ +static inline void sg_mark_end(struct scatterlist *sg) +{ +#ifdef CONFIG_DEBUG_SG + BUG_ON(sg->sg_magic != SG_MAGIC); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + /* + * Set termination bit, clear potential chain bit + */ + sg->page_link |= 0x02; + sg->page_link &= ~0x01; +#endif +} + +/** + * sg_init_table - Initialize SG table + * @sgl: The SG table + * @nents: Number of entries in table + * + * Notes: + * If this is part of a chained sg table, sg_mark_end() should be + * used only on the last table part. + * + **/ +static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) +{ + memset(sgl, 0, sizeof(*sgl) * nents); +} + +/** + * usb_endpoint_num - get the endpoint's number + * @epd: endpoint to be checked + * + * Returns @epd's number: 0 to 15. + */ +static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd) +{ + return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) */ + +#endif /* LINUX_26_24_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.25.h b/include/compat/linux/compat-2.6.25.h new file mode 100644 index 00000000..c389ab2c --- /dev/null +++ b/include/compat/linux/compat-2.6.25.h @@ -0,0 +1,193 @@ +#ifndef LINUX_26_25_COMPAT_H +#define LINUX_26_25_COMPAT_H + +#include + +/* Compat work for 2.6.24 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * phys_addr_t was added as a generic arch typedef on 2.6.28, + * that backport is dealt with in compat-2.6.28.h + */ +#if defined(CONFIG_X86) || defined(CONFIG_X86_64) + +#if defined(CONFIG_64BIT) || defined(CONFIG_X86_PAE) || defined(CONFIG_PHYS_64BIT) +typedef u64 phys_addr_t; +#else +typedef u32 phys_addr_t; +#endif + +#endif /* x86 */ + +/* The macro below uses a const upstream, this differs */ + +/** + * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table + * @_table: device table name + * + * This macro is used to create a struct pci_device_id array (a device table) + * in a generic manner. + */ +#define DEFINE_PCI_DEVICE_TABLE(_table) \ + const struct pci_device_id _table[] __devinitdata + +/* + * Backport work for QoS dependencies (kernel/pm_qos_params.c) + * pm-qos stuff written by mark gross mgross@linux.intel.com. + * + * ipw2100 now makes use of: + * + * pm_qos_add_requirement(), + * pm_qos_update_requirement() and + * pm_qos_remove_requirement() from it + * + * mac80211 uses the network latency to determine if to enable or not + * dynamic PS. mac80211 also and registers a notifier for when + * the latency changes. Since older kernels do no thave pm-qos stuff + * we just implement it completley here and register it upon cfg80211 + * init. I haven't tested ipw2100 on 2.6.24 though. + * + * This pm-qos implementation is copied verbatim from the kernel + * written by mark gross mgross@linux.intel.com. You don't have + * to do anythinig to use pm-qos except use the same exported + * routines as used in newer kernels. The compat_pm_qos_power_init() + * defned below is used by the compat module to initialize pm-qos. + */ +int compat_pm_qos_power_init(void); +int compat_pm_qos_power_deinit(void); + +/* + * 2.6.25 adds PM_EVENT_HIBERNATE as well here but + * we don't have this on <= 2.6.23) + */ +#ifndef PM_EVENT_SLEEP /* some distribution have mucked with their own headers to add this.. */ +#define PM_EVENT_SLEEP (PM_EVENT_SUSPEND) +#endif + +/* Although we don't care about wimax this is needed for rfkill input stuff */ +#define KEY_WIMAX 246 + +/* Although pm_qos stuff is not implemented on <= 2.6.24 lets keep the define */ +#define PM_QOS_DEFAULT_VALUE -1 + +#define __WARN(foo) dump_stack() + +#define dev_emerg(dev, format, arg...) \ + dev_printk(KERN_EMERG , dev , format , ## arg) +#define dev_alert(dev, format, arg...) \ + dev_printk(KERN_ALERT , dev , format , ## arg) +#define dev_crit(dev, format, arg...) \ + dev_printk(KERN_CRIT , dev , format , ## arg) + +extern int __dev_addr_sync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count); +extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count); + +#define seq_file_net &init_net; + +enum nf_inet_hooks { + NF_INET_PRE_ROUTING = 0, + NF_INET_LOCAL_IN = 1, + NF_INET_FORWARD = 2, + NF_INET_LOCAL_OUT = 3, + NF_INET_POST_ROUTING = 4, + NF_INET_NUMHOOKS = 5 +}; + +/* The patch: + * commit 8b5f6883683c91ad7e1af32b7ceeb604d68e2865 + * Author: Marcin Slusarz + * Date: Fri Feb 8 04:20:12 2008 -0800 + * + * byteorder: move le32_add_cpu & friends from OCFS2 to core + * + * moves le*_add_cpu and be*_add_cpu functions from OCFS2 to core + * header (1st) and converted some existing code to it. We port + * it here as later kernels will most likely use it. + */ +static inline void le16_add_cpu(__le16 *var, u16 val) +{ + *var = cpu_to_le16(le16_to_cpu(*var) + val); +} + +static inline void le32_add_cpu(__le32 *var, u32 val) +{ + *var = cpu_to_le32(le32_to_cpu(*var) + val); +} + +static inline void le64_add_cpu(__le64 *var, u64 val) +{ + *var = cpu_to_le64(le64_to_cpu(*var) + val); +} + +static inline void be16_add_cpu(__be16 *var, u16 val) +{ + u16 v = be16_to_cpu(*var); + *var = cpu_to_be16(v + val); +} + +static inline void be32_add_cpu(__be32 *var, u32 val) +{ + u32 v = be32_to_cpu(*var); + *var = cpu_to_be32(v + val); +} + +static inline void be64_add_cpu(__be64 *var, u64 val) +{ + u64 v = be64_to_cpu(*var); + *var = cpu_to_be64(v + val); +} + +/* 2.6.25 changes hwrng_unregister()'s behaviour by supporting + * suspend of its parent device (the misc device, which is itself the + * hardware random number generator). It does this by passing a parameter to + * unregister_miscdev() which is not supported in older kernels. The suspend + * parameter allows us to enable access to the device's hardware + * number generator during suspend. As far as wireless is concerned this means + * if a driver goes to suspend it you won't have the HNR available in + * older kernels. */ +static inline void __hwrng_unregister(struct hwrng *rng, bool suspended) +{ + hwrng_unregister(rng); +} + +static inline void led_classdev_unregister_suspended(struct led_classdev *lcd) +{ + led_classdev_unregister(lcd); +} + +/** + * The following things are out of ./include/linux/kernel.h + * The new iwlwifi driver is using them. + */ +extern int strict_strtoul(const char *, unsigned int, unsigned long *); +extern int strict_strtol(const char *, unsigned int, long *); + +#else +/* + * Kernels >= 2.6.25 have pm-qos and its initialized as part of + * the bootup process + */ +static inline int compat_pm_qos_power_init(void) +{ + return 0; +} + +static inline int compat_pm_qos_power_deinit(void) +{ + return 0; +} +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) */ + +#endif /* LINUX_26_25_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.26.h b/include/compat/linux/compat-2.6.26.h new file mode 100644 index 00000000..177792a3 --- /dev/null +++ b/include/compat/linux/compat-2.6.26.h @@ -0,0 +1,455 @@ +#ifndef LINUX_26_26_COMPAT_H +#define LINUX_26_26_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) + +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) +#include +#endif +#include +#include +#include + +/* These jiffie helpers added as of 2.6.26 */ + +/* + * These four macros compare jiffies and 'a' for convenience. + */ + +/* time_is_before_jiffies(a) return true if a is before jiffies */ +#define time_is_before_jiffies(a) time_after(jiffies, a) + +/* time_is_after_jiffies(a) return true if a is after jiffies */ +#define time_is_after_jiffies(a) time_before(jiffies, a) + +/* time_is_before_eq_jiffies(a) return true if a is before or equal to jiffies*/ +#define time_is_before_eq_jiffies(a) time_after_eq(jiffies, a) + +/* time_is_after_eq_jiffies(a) return true if a is after or equal to jiffies*/ +#define time_is_after_eq_jiffies(a) time_before_eq(jiffies, a) + +/* This comes from include/linux/input.h */ +#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" + set = radio enabled */ + +/* From kernel.h */ +#define USHORT_MAX ((u16)(~0U)) +#define SHORT_MAX ((s16)(USHORT_MAX>>1)) +#define SHORT_MIN (-SHORT_MAX - 1) + +extern int dev_set_name(struct device *dev, const char *name, ...) + __attribute__((format(printf, 2, 3))); + +/** + * clamp - return a value clamped to a given range with strict typechecking + * @val: current value + * @min: minimum allowable value + * @max: maximum allowable value + * + * This macro does strict typechecking of min/max to make sure they are of the + * same type as val. See the unnecessary pointer comparisons. + */ +#define clamp(val, min, max) ({ \ + typeof(val) __val = (val); \ + typeof(min) __min = (min); \ + typeof(max) __max = (max); \ + (void) (&__val == &__min); \ + (void) (&__val == &__max); \ + __val = __val < __min ? __min: __val; \ + __val > __max ? __max: __val; }) + +/** + * clamp_t - return a value clamped to a given range using a given type + * @type: the type of variable to use + * @val: current value + * @min: minimum allowable value + * @max: maximum allowable value + * + * This macro does no typechecking and uses temporary variables of type + * 'type' to make all the comparisons. + */ +#define clamp_t(type, val, min, max) ({ \ + type __val = (val); \ + type __min = (min); \ + type __max = (max); \ + __val = __val < __min ? __min: __val; \ + __val > __max ? __max: __val; }) + + +/* from include/linux/device.h */ +/* device_create_drvdata() is new */ +extern struct device *device_create_drvdata(struct class *cls, + struct device *parent, + dev_t devt, + void *drvdata, + const char *fmt, ...) +__attribute__((format(printf, 5, 6))); + +/* This is from include/linux/list.h */ + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +/* This is from include/linux/device.h, which was added as of 2.6.26 */ +static inline const char *dev_name(struct device *dev) +{ + /* will be changed into kobject_name(&dev->kobj) in the near future */ + return dev->bus_id; +} + +/* This is from include/linux/kernel.h, which was added as of 2.6.26 */ + +/** + * clamp_val - return a value clamped to a given range using val's type + * @val: current value + * @min: minimum allowable value + * @max: maximum allowable value + * + * This macro does no typechecking and uses temporary variables of whatever + * type the input argument 'val' is. This is useful when val is an unsigned + * type and min and max are literals that will otherwise be assigned a signed + * integer type. + */ + +#define clamp_val(val, min, max) ({ \ + typeof(val) __val = (val); \ + typeof(val) __min = (min); \ + typeof(val) __max = (max); \ + __val = __val < __min ? __min: __val; \ + __val > __max ? __max: __val; }) + +/* This comes from include/net/net_namespace.h */ + +#ifdef CONFIG_NET_NS +static inline +int net_eq(const struct net *net1, const struct net *net2) +{ + return net1 == net2; +} +#else +static inline +int net_eq(const struct net *net1, const struct net *net2) +{ + return 1; +} +#endif + +static inline +void dev_net_set(struct net_device *dev, struct net *net) +{ +#ifdef CONFIG_NET_NS + release_net(dev->nd_net); + dev->nd_net = hold_net(net); +#endif +} + +static inline +struct net *sock_net(const struct sock *sk) +{ +#ifdef CONFIG_NET_NS + return sk->sk_net; +#else + return &init_net; +#endif +} + +/* This comes from include/linux/netdevice.h */ + +/* + * Net namespace inlines + */ +static inline +struct net *dev_net(const struct net_device *dev) +{ +#ifdef CONFIG_NET_NS + /* + * compat-wirelss backport note: + * For older kernels we may just need to always return init_net, + * not sure when we added dev->nd_net. + */ + return dev->nd_net; +#else + return &init_net; +#endif +} + + +/* + * 2.6.26 added its own unaligned API which the + * new drivers can use. Lets port it here by including it in older + * kernels and also deal with the architecture handling here. + */ + +#ifdef CONFIG_ALPHA + +#include +#include +#include + +#endif /* alpha */ +#ifdef CONFIG_ARM + +/* arm */ +#include +#include +#include + +#endif /* arm */ +#ifdef CONFIG_AVR32 + +/* + * AVR32 can handle some unaligned accesses, depending on the + * implementation. The AVR32 AP implementation can handle unaligned + * words, but halfwords must be halfword-aligned, and doublewords must + * be word-aligned. + * + * However, swapped word loads must be word-aligned so we can't + * optimize word loads in general. + */ + +#include +#include +#include + +#endif +#ifdef CONFIG_BLACKFIN + +#include +#include +#include + +#endif /* blackfin */ +#ifdef CONFIG_CRIS + +/* + * CRIS can do unaligned accesses itself. + */ +#include +#include + +#endif /* cris */ +#ifdef CONFIG_FRV + +#include +#include +#include + +#endif /* frv */ +#ifdef CONFIG_H8300 + +#include +#include +#include + +#endif /* h8300 */ +#ifdef CONFIG_IA64 + +#include +#include +#include + +#endif /* ia64 */ +#ifdef CONFIG_M32R + +#if defined(__LITTLE_ENDIAN__) +# include +# include +# include +#else +# include +# include +# include +#endif + +#endif /* m32r */ +#ifdef CONFIG_M68K /* this handles both m68k and m68knommu */ + +#ifdef CONFIG_COLDFIRE +#include +#include +#include +#else + +/* + * The m68k can do unaligned accesses itself. + */ +#include +#include +#endif + +#endif /* m68k and m68knommu */ +#ifdef CONFIG_MIPS + +#if defined(__MIPSEB__) +# include +# include +# include +# define get_unaligned __get_unaligned_be +# define put_unaligned __put_unaligned_be +#elif defined(__MIPSEL__) +# include +# include +# include +#endif + +#endif /* mips */ +#ifdef CONFIG_MN10300 + +#include +#include + +#endif /* mn10300 */ +#ifdef CONFIG_PARISC + +#include +#include +#include + +#endif /* parisc */ +#ifdef CONFIG_PPC +/* + * The PowerPC can do unaligned accesses itself in big endian mode. + */ +#include +#include + +#endif /* ppc */ +#ifdef CONFIG_S390 + +/* + * The S390 can do unaligned accesses itself. + */ +#include +#include + +#endif /* s390 */ +#ifdef CONFIG_SUPERH + +/* SH can't handle unaligned accesses. */ +#ifdef __LITTLE_ENDIAN__ +# include +# include +# include +#else +# include +# include +# include +#endif + +#endif /* sh - SUPERH */ +#ifdef CONFIG_SPARC + +/* sparc and sparc64 */ +#include +#include +#include + +#endif /* sparc */ +#ifdef CONFIG_UML + +#include "asm/arch/unaligned.h" + +#endif /* um - uml */ +#ifdef CONFIG_V850 + +#include +#include +#include + +#endif /* v850 */ +#ifdef CONFIG_X86 +/* + * The x86 can do unaligned accesses itself. + */ +#include +#include + +#endif /* x86 */ +#ifdef CONFIG_XTENSA + +#ifdef __XTENSA_EL__ +# include +# include +# include +#elif defined(__XTENSA_EB__) +# include +# include +# include +#else +# error processor byte order undefined! +#endif + +#endif /* xtensa */ + +#define PCIE_LINK_STATE_L0S 1 +#define PCIE_LINK_STATE_L1 2 +#define PCIE_LINK_STATE_CLKPM 4 + +static inline void pci_disable_link_state(struct pci_dev *pdev, int state) +{ +} +/* source: include/linux/pci-aspm.h */ + + +#if BITS_PER_LONG == 64 + +/** + * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder + * + * This is commonly provided by 32bit archs to provide an optimized 64bit + * divide. + */ +static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) +{ + *remainder = dividend % divisor; + return dividend / divisor; +} + +#elif BITS_PER_LONG == 32 + +#ifndef div_u64_rem +static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) +{ + *remainder = do_div(dividend, divisor); + return dividend; +} +#endif + +#endif /* BITS_PER_LONG */ + +/** + * div_u64 - unsigned 64bit divide with 32bit divisor + * + * This is the most common 64bit divide and should be used if possible, + * as many 32bit archs can optimize this variant better than a full 64bit + * divide. + */ +#ifndef div_u64 +static inline u64 div_u64(u64 dividend, u32 divisor) +{ + u32 remainder; + return div_u64_rem(dividend, divisor, &remainder); +} +#endif +/* source: include/math64.h */ + +#define hex_asc_lo(x) hex_asc((x) & 0x0f) +#define hex_asc_hi(x) hex_asc(((x) & 0xf0) >> 4) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) */ + +#endif /* LINUX_26_26_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.27.h b/include/compat/linux/compat-2.6.27.h new file mode 100644 index 00000000..22fadcd2 --- /dev/null +++ b/include/compat/linux/compat-2.6.27.h @@ -0,0 +1,261 @@ +#ifndef LINUX_26_27_COMPAT_H +#define LINUX_26_27_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)) + +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) +#include +#include +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_PM_CAP_PME_SHIFT 11 + +/* I can't find a more suitable replacement... */ +#define flush_work(work) cancel_work_sync(work) + +struct builtin_fw { + char *name; + void *data; + unsigned long size; +}; + +/* + * On older kernels we do not have net_device Multi Queue support, but + * since we no longer use MQ on mac80211 we can simply use the 0 queue. + * Note that if other fullmac drivers make use of this they then need + * to be backported somehow or deal with just 1 queueue from MQ. + */ +static inline void netif_tx_wake_all_queues(struct net_device *dev) +{ + netif_wake_queue(dev); +} +static inline void netif_tx_start_all_queues(struct net_device *dev) +{ + netif_start_queue(dev); +} +static inline void netif_tx_stop_all_queues(struct net_device *dev) +{ + netif_stop_queue(dev); +} + +/* Are all TX queues of the device empty? */ +static inline bool qdisc_all_tx_empty(const struct net_device *dev) +{ + return skb_queue_empty(&dev->qdisc->q); +} + +bool pci_pme_capable(struct pci_dev *dev, pci_power_t state); + +/* + * The net_device has a spin_lock on newer kernels, on older kernels we're out of luck + */ +#define netif_addr_lock_bh(dev) +#define netif_addr_unlock_bh(dev) + +/* + * To port this properly we'd have to port warn_slowpath_null(), + * which I'm lazy to do so just do a regular print for now. If you + * want to port this read kernel/panic.c + */ +#define __WARN_printf(arg...) do { printk(arg); __WARN(); } while (0) + +/* This is ported directly as-is on newer kernels */ +#ifndef WARN +#define WARN(condition, format...) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + __WARN_printf(format); \ + unlikely(__ret_warn_on); \ +}) +#endif + +/* On 2.6.27 a second argument was added, on older kernels we ignore it */ +#define dma_mapping_error(pdev, dma_addr) dma_mapping_error(dma_addr) +#define pci_dma_mapping_error(pdev, dma_addr) dma_mapping_error(pdev, dma_addr) + +/* This is from include/linux/ieee80211.h */ +#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 + +/* New link list changes added as of 2.6.27, needed for ath9k */ + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + + +/* __list_splice as re-implemented on 2.6.27, we backport it */ +static inline void __compat_list_splice_new_27(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __compat_list_splice_new_27(list, head->prev, head); +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __compat_list_splice_new_27(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) +extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); +extern unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) */ + +#define iwe_stream_add_value(info, event, value, ends, iwe, event_len) iwe_stream_add_value(event, value, ends, iwe, event_len) +#define iwe_stream_add_point(info, stream, ends, iwe, extra) iwe_stream_add_point(stream, ends, iwe, extra) +#define iwe_stream_add_event(info, stream, ends, iwe, event_len) iwe_stream_add_event(stream, ends, iwe, event_len) + +/* Flags available in struct iw_request_info */ +#define IW_REQUEST_FLAG_COMPAT 0x0001 /* Compat ioctl call */ + +static inline int iwe_stream_lcp_len(struct iw_request_info *info) +{ +#ifdef CONFIG_COMPAT + if (info->flags & IW_REQUEST_FLAG_COMPAT) + return IW_EV_COMPAT_LCP_LEN; +#endif + return IW_EV_LCP_LEN; +} + +#ifdef CONFIG_ARM + +/* + * The caller asks to handle a range between offset and offset + size, + * but we process a larger range from 0 to offset + size due to lack of + * offset support. + */ + +static inline void dma_sync_single_range_for_cpu(struct device *dev, + dma_addr_t handle, unsigned long offset, size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_cpu(dev, handle, offset + size, dir); +} + +static inline void dma_sync_single_range_for_device(struct device *dev, + dma_addr_t handle, unsigned long offset, size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_device(dev, handle, offset + size, dir); +} + +#endif /* arm */ + +#if defined(CONFIG_DEBUG_FS) +void debugfs_remove_recursive(struct dentry *dentry); +#else +static inline void debugfs_remove_recursive(struct dentry *dentry) +{ } +#endif + +#define device_create(cls, parent, devt, drvdata, fmt, ...) \ +({ \ + struct device *_dev; \ + _dev = (device_create)(cls, parent, devt, fmt, __VA_ARGS__); \ + dev_set_drvdata(_dev, drvdata); \ + _dev; \ +}) + +#define dev_name(dev) dev_name((struct device *)dev) + +static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep, + __u32 speed) +{ + ep->speed = (__u16)speed; +} + +static inline __u32 ethtool_cmd_speed(const struct ethtool_cmd *ep) +{ + return ep->speed; +} + +/** + * lower_32_bits - return bits 0-31 of a number + * @n: the number we're accessing + */ +#define lower_32_bits(n) ((u32)(n)) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)) */ + +#endif /* LINUX_26_27_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.28.h b/include/compat/linux/compat-2.6.28.h new file mode 100644 index 00000000..c0ca70b1 --- /dev/null +++ b/include/compat/linux/compat-2.6.28.h @@ -0,0 +1,264 @@ +#ifndef LINUX_26_28_COMPAT_H +#define LINUX_26_28_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) + +#include +#include +#include +#include + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif + +#include + +#if defined(CONFIG_X86) || defined(CONFIG_X86_64) || defined(CONFIG_PPC) +/* + * CONFIG_PHYS_ADDR_T_64BIT was added as new to all architectures + * as of 2.6.28 but x86 and ppc had it already. x86 only got phys_addr_t + * as of 2.6.25 but then is backported in compat-2.6.25.h + */ +#else +#if defined(CONFIG_64BIT) || defined(CONFIG_X86_PAE) || defned(CONFIG_PPC64) || defined(CONFIG_PHYS_64BIT) +#define CONFIG_PHYS_ADDR_T_64BIT 1 +typedef u64 phys_addr_t; +#else +typedef u32 phys_addr_t; +#endif + +#endif /* non x86 and ppc */ + +#ifndef WARN_ONCE +#define WARN_ONCE(condition, format...) ({ \ + static int __warned; \ + int __ret_warn_once = !!(condition); \ + \ + if (unlikely(__ret_warn_once)) \ + if (WARN(!__warned, format)) \ + __warned = 1; \ + unlikely(__ret_warn_once); \ +}) +#endif /* From include/asm-generic/bug.h */ + +#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) + +#include +#include +#include +#ifdef pcmcia_parse_tuple +#undef pcmcia_parse_tuple +#define pcmcia_parse_tuple(tuple, parse) pccard_parse_tuple(tuple, parse) +#endif + +/* From : include/pcmcia/ds.h */ +/* loop CIS entries for valid configuration */ +int pcmcia_loop_config(struct pcmcia_device *p_dev, + int (*conf_check) (struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data), + void *priv_data); + +#endif /* CONFIG_PCMCIA */ + +/* USB anchors were added as of 2.6.23 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)) + +#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE) +#if 0 +extern void usb_poison_urb(struct urb *urb); +#endif +extern void usb_unpoison_urb(struct urb *urb); + +#if 0 +extern void usb_poison_anchored_urbs(struct usb_anchor *anchor); +#endif + +extern int usb_anchor_empty(struct usb_anchor *anchor); +#endif /* CONFIG_USB */ +#endif + + +void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar); + +/** + * skb_queue_is_last - check if skb is the last entry in the queue + * @list: queue head + * @skb: buffer + * + * Returns true if @skb is the last buffer on the list. + */ +static inline bool skb_queue_is_last(const struct sk_buff_head *list, + const struct sk_buff *skb) +{ + return (skb->next == (struct sk_buff *) list); +} + +/** + * skb_queue_next - return the next packet in the queue + * @list: queue head + * @skb: current buffer + * + * Return the next packet in @list after @skb. It is only valid to + * call this if skb_queue_is_last() evaluates to false. + */ +static inline struct sk_buff *skb_queue_next(const struct sk_buff_head *list, + const struct sk_buff *skb) +{ + /* This BUG_ON may seem severe, but if we just return then we + * are going to dereference garbage. + */ + BUG_ON(skb_queue_is_last(list, skb)); + return skb->next; +} + +/** + * __skb_queue_head_init - initialize non-spinlock portions of sk_buff_head + * @list: queue to initialize + * + * This initializes only the list and queue length aspects of + * an sk_buff_head object. This allows to initialize the list + * aspects of an sk_buff_head without reinitializing things like + * the spinlock. It can also be used for on-stack sk_buff_head + * objects where the spinlock is known to not be used. + */ +static inline void __skb_queue_head_init(struct sk_buff_head *list) +{ + list->prev = list->next = (struct sk_buff *)list; + list->qlen = 0; +} + +static inline void __skb_queue_splice(const struct sk_buff_head *list, + struct sk_buff *prev, + struct sk_buff *next) +{ + struct sk_buff *first = list->next; + struct sk_buff *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * skb_queue_splice - join two skb lists, this is designed for stacks + * @list: the new list to add + * @head: the place to add it in the first list + */ +static inline void skb_queue_splice(const struct sk_buff_head *list, + struct sk_buff_head *head) +{ + if (!skb_queue_empty(list)) { + __skb_queue_splice(list, (struct sk_buff *) head, head->next); + head->qlen += list->qlen; + } +} + +/** + * skb_queue_splice - join two skb lists and reinitialise the emptied list + * @list: the new list to add + * @head: the place to add it in the first list + * + * The list at @list is reinitialised + */ +static inline void skb_queue_splice_init(struct sk_buff_head *list, + struct sk_buff_head *head) +{ + if (!skb_queue_empty(list)) { + __skb_queue_splice(list, (struct sk_buff *) head, head->next); + head->qlen += list->qlen; + __skb_queue_head_init(list); + } +} + +/** + * skb_queue_splice_tail - join two skb lists and reinitialise the emptied list + * @list: the new list to add + * @head: the place to add it in the first list + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void skb_queue_splice_tail_init(struct sk_buff_head *list, + struct sk_buff_head *head) +{ + if (!skb_queue_empty(list)) { + __skb_queue_splice(list, head->prev, (struct sk_buff *) head); + head->qlen += list->qlen; + __skb_queue_head_init(list); + } +} /* From include/linux/skbuff.h */ + +/** + * skb_queue_splice_tail - join two skb lists, each list being a queue + * @list: the new list to add + * @head: the place to add it in the first list + */ +static inline void skb_queue_splice_tail(const struct sk_buff_head *list, + struct sk_buff_head *head) +{ + if (!skb_queue_empty(list)) { + __skb_queue_splice(list, head->prev, (struct sk_buff *) head); + head->qlen += list->qlen; + } +} + +#ifndef DECLARE_TRACE + +#define TP_PROTO(args...) args +#define TP_ARGS(args...) args + +#define DECLARE_TRACE(name, proto, args) \ + static inline void _do_trace_##name(struct tracepoint *tp, proto) \ + { } \ + static inline void trace_##name(proto) \ + { } \ + static inline int register_trace_##name(void (*probe)(proto)) \ + { \ + return -ENOSYS; \ + } \ + static inline int unregister_trace_##name(void (*probe)(proto)) \ + { \ + return -ENOSYS; \ + } + +#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) +#define EXPORT_TRACEPOINT_SYMBOL(name) + + +#endif + +/* openSuse includes round_jiffies_up in it's kernel 2.6.27. + * This is needed to prevent conflicts with the openSuse definition. + */ +#define round_jiffies_up backport_round_jiffies_up + +unsigned long round_jiffies_up(unsigned long j); + +extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, + int off, int size); + +#define wake_up_interruptible_poll(x, m) \ + __wake_up(x, TASK_INTERRUPTIBLE, 1, (void *) (m)) + +extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); + +int pci_wake_from_d3(struct pci_dev *dev, bool enable); + +#define alloc_workqueue(name, flags, max_active) __create_workqueue(name, flags, max_active) + +#ifndef pr_fmt +#define pr_fmt(fmt) fmt +#endif + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) */ + +#endif /* LINUX_26_28_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.29.h b/include/compat/linux/compat-2.6.29.h new file mode 100644 index 00000000..1e538bbd --- /dev/null +++ b/include/compat/linux/compat-2.6.29.h @@ -0,0 +1,350 @@ +#ifndef LINUX_26_29_COMPAT_H +#define LINUX_26_29_COMPAT_H + +#include +#include +#include + +/* + * I kow this looks odd.. but 2.6.32 added the netdev_tx_t + * and we backport that there so inlcude that header first + * as we need it for the netdev ops. + */ +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) + +#include +#include +#include + +#if \ + defined(CONFIG_ALPHA) || defined(CONFIG_AVR32) || \ + defined(CONFIG_BLACKFIN) || defined(CONFIG_CRIS) || \ + defined(CONFIG_H8300) || defined(CONFIG_IA64) || \ + defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \ + defined(CONFIG_PARISC) || defined(CONFIG_S390) || \ + defined(CONFIG_PPC64) || defined(CONFIG_PPC32) || \ + defined(CONFIG_SUPERH) || defined(CONFIG_SPARC) || \ + defined(CONFIG_FRV) || defined(CONFIG_X86) || \ + defined(CONFIG_M32R) || defined(CONFIG_M68K) || \ + defined(CONFIG_MN10300) || defined(CONFIG_XTENSA) +#include +#else +typedef struct { + volatile int counter; +} atomic_t; + +#ifdef CONFIG_64BIT +typedef struct { + volatile long counter; +} atomic64_t; +#endif /* CONFIG_64BIT */ + +#endif + +#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ + +/* + * Older kernels do not have struct net_device_ops but what we can + * do is just define the data structure and use a caller to let us + * set the data structure's routines onto the old netdev, essentially + * doing it the old way. This avoids huge deltas on our backports. + */ + +/* + * This structure defines the management hooks for network devices. + * The following hooks can be defined; unless noted otherwise, they are + * optional and can be filled with a null pointer. + * + * int (*ndo_init)(struct net_device *dev); + * This function is called once when network device is registered. + * The network device can use this to any late stage initializaton + * or semantic validattion. It can fail with an error code which will + * be propogated back to register_netdev + * + * void (*ndo_uninit)(struct net_device *dev); + * This function is called when device is unregistered or when registration + * fails. It is not called if init fails. + * + * int (*ndo_open)(struct net_device *dev); + * This function is called when network device transistions to the up + * state. + * + * int (*ndo_stop)(struct net_device *dev); + * This function is called when network device transistions to the down + * state. + * + * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, + * struct net_device *dev); + * Called when a packet needs to be transmitted. + * Must return NETDEV_TX_OK , NETDEV_TX_BUSY. + * (can also return NETDEV_TX_LOCKED iff NETIF_F_LLTX) + * Required can not be NULL. + * + * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb); + * Called to decide which queue to when device supports multiple + * transmit queues. + * + * void (*ndo_change_rx_flags)(struct net_device *dev, int flags); + * This function is called to allow device receiver to make + * changes to configuration when multicast or promiscious is enabled. + * + * void (*ndo_set_rx_mode)(struct net_device *dev); + * This function is called device changes address list filtering. + * + * void (*ndo_set_multicast_list)(struct net_device *dev); + * This function is called when the multicast address list changes. + * + * int (*ndo_set_mac_address)(struct net_device *dev, void *addr); + * This function is called when the Media Access Control address + * needs to be changed. If this interface is not defined, the + * mac address can not be changed. + * + * int (*ndo_validate_addr)(struct net_device *dev); + * Test if Media Access Control address is valid for the device. + * + * int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); + * Called when a user request an ioctl which can't be handled by + * the generic interface code. If not defined ioctl's return + * not supported error code. + * + * int (*ndo_set_config)(struct net_device *dev, struct ifmap *map); + * Used to set network devices bus interface parameters. This interface + * is retained for legacy reason, new devices should use the bus + * interface (PCI) for low level management. + * + * int (*ndo_change_mtu)(struct net_device *dev, int new_mtu); + * Called when a user wants to change the Maximum Transfer Unit + * of a device. If not defined, any request to change MTU will + * will return an error. + * + * void (*ndo_tx_timeout)(struct net_device *dev); + * Callback uses when the transmitter has not made any progress + * for dev->watchdog ticks. + * + * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); + * Called when a user wants to get the network device usage + * statistics. If not defined, the counters in dev->stats will + * be used. + * + * void (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp); + * If device support VLAN receive accleration + * (ie. dev->features & NETIF_F_HW_VLAN_RX), then this function is called + * when vlan groups for the device changes. Note: grp is NULL + * if no vlan's groups are being used. + * + * void (*ndo_vlan_rx_add_vid)(struct net_device *dev, unsigned short vid); + * If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER) + * this function is called when a VLAN id is registered. + * + * void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); + * If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER) + * this function is called when a VLAN id is unregistered. + * + * void (*ndo_poll_controller)(struct net_device *dev); + * + * SR-IOV management functions. + * int (*ndo_set_vf_mac)(struct net_device *dev, int vf, u8* mac); + * int (*ndo_set_vf_vlan)(struct net_device *dev, int vf, u16 vlan, u8 qos); + * int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate); + * int (*ndo_get_vf_config)(struct net_device *dev, + * int vf, struct ifla_vf_info *ivf); + */ +#define HAVE_NET_DEVICE_OPS +struct net_device_ops { + int (*ndo_init)(struct net_device *dev); + void (*ndo_uninit)(struct net_device *dev); + int (*ndo_open)(struct net_device *dev); + int (*ndo_stop)(struct net_device *dev); + netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, + struct net_device *dev); + u16 (*ndo_select_queue)(struct net_device *dev, + struct sk_buff *skb); + void (*ndo_change_rx_flags)(struct net_device *dev, + int flags); + void (*ndo_set_rx_mode)(struct net_device *dev); + void (*ndo_set_multicast_list)(struct net_device *dev); + int (*ndo_set_mac_address)(struct net_device *dev, + void *addr); + int (*ndo_validate_addr)(struct net_device *dev); + int (*ndo_do_ioctl)(struct net_device *dev, + struct ifreq *ifr, int cmd); + int (*ndo_set_config)(struct net_device *dev, + struct ifmap *map); + int (*ndo_change_mtu)(struct net_device *dev, + int new_mtu); + int (*ndo_neigh_setup)(struct net_device *dev, + struct neigh_parms *); + void (*ndo_tx_timeout) (struct net_device *dev); + + struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); + + void (*ndo_vlan_rx_register)(struct net_device *dev, + struct vlan_group *grp); + void (*ndo_vlan_rx_add_vid)(struct net_device *dev, + unsigned short vid); + void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, + unsigned short vid); +#ifdef CONFIG_NET_POLL_CONTROLLER + void (*ndo_poll_controller)(struct net_device *dev); +#endif + int (*ndo_set_vf_mac)(struct net_device *dev, + int queue, u8 *mac); + int (*ndo_set_vf_vlan)(struct net_device *dev, + int queue, u16 vlan, u8 qos); + int (*ndo_set_vf_tx_rate)(struct net_device *dev, + int vf, int rate); +/* + * The struct ifla_vf_info was added via b280da8d54b8d82b52f368a8703b7ada6c1744d5 + * on the v2.6.34-rc1~233^2~338 release + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) + int (*ndo_get_vf_config)(struct net_device *dev, + int vf, + struct ifla_vf_info *ivf); +#endif +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + int (*ndo_fcoe_enable)(struct net_device *dev); + int (*ndo_fcoe_disable)(struct net_device *dev); + int (*ndo_fcoe_ddp_setup)(struct net_device *dev, + u16 xid, + struct scatterlist *sgl, + unsigned int sgc); + int (*ndo_fcoe_ddp_done)(struct net_device *dev, + u16 xid); +#define NETDEV_FCOE_WWNN 0 +#define NETDEV_FCOE_WWPN 1 + int (*ndo_fcoe_get_wwn)(struct net_device *dev, + u64 *wwn, int type); +#endif +}; + +void netdev_attach_ops(struct net_device *dev, + const struct net_device_ops *ops); + +/** + * skb_queue_is_first - check if skb is the first entry in the queue + * @list: queue head + * @skb: buffer + * + * Returns true if @skb is the first buffer on the list. + */ +static inline bool skb_queue_is_first(const struct sk_buff_head *list, + const struct sk_buff *skb) +{ + return (skb->prev == (struct sk_buff *) list); +} + +/** + * skb_queue_prev - return the prev packet in the queue + * @list: queue head + * @skb: current buffer + * + * Return the prev packet in @list before @skb. It is only valid to + * call this if skb_queue_is_first() evaluates to false. + */ +static inline struct sk_buff *skb_queue_prev(const struct sk_buff_head *list, + const struct sk_buff *skb) +{ + /* This BUG_ON may seem severe, but if we just return then we + * are going to dereference garbage. + */ + BUG_ON(skb_queue_is_first(list, skb)); + return skb->prev; +} + + +static inline struct net_device_stats *dev_get_stats(struct net_device *dev) +{ + return dev->get_stats(dev); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)) +#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE) +extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor); +#endif /* CONFIG_USB */ +#endif + +#define DIV_ROUND_CLOSEST(x, divisor)( \ +{ \ + typeof(divisor) __divisor = divisor; \ + (((x) + ((__divisor) / 2)) / (__divisor)); \ +} \ +) + +extern int eth_mac_addr(struct net_device *dev, void *p); +extern int eth_change_mtu(struct net_device *dev, int new_mtu); +extern int eth_validate_addr(struct net_device *dev); + +#ifdef CONFIG_NET_NS + +static inline void write_pnet(struct net **pnet, struct net *net) +{ + *pnet = net; +} + +static inline struct net *read_pnet(struct net * const *pnet) +{ + return *pnet; +} + +#else + +#define write_pnet(pnet, net) do { (void)(net);} while (0) +#define read_pnet(pnet) (&init_net) + +/* + * swap - swap value of @a and @b + */ +#define swap(a, b) \ + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) + +#endif + +extern int init_dummy_netdev(struct net_device *dev); + +#define compat_pci_suspend(fn) \ + int fn##_compat(struct pci_dev *pdev, pm_message_t state) \ + { \ + int r; \ + \ + r = fn(&pdev->dev); \ + if (r) \ + return r; \ + \ + pci_save_state(pdev); \ + pci_disable_device(pdev); \ + pci_set_power_state(pdev, PCI_D3hot); \ + \ + return 0; \ + } + +#define compat_pci_resume(fn) \ + int fn##_compat(struct pci_dev *pdev) \ + { \ + int r; \ + \ + pci_set_power_state(pdev, PCI_D0); \ + r = pci_enable_device(pdev); \ + if (r) \ + return r; \ + pci_restore_state(pdev); \ + \ + return fn(&pdev->dev); \ + } + +#else + +static inline void netdev_attach_ops(struct net_device *dev, + const struct net_device_ops *ops) +{ + dev->netdev_ops = ops; +} + +#define compat_pci_suspend(fn) +#define compat_pci_resume(fn) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) */ + +#endif /* LINUX_26_29_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.30.h b/include/compat/linux/compat-2.6.30.h new file mode 100644 index 00000000..28f3d54a --- /dev/null +++ b/include/compat/linux/compat-2.6.30.h @@ -0,0 +1,47 @@ +#ifndef LINUX_26_30_COMPAT_H +#define LINUX_26_30_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + +#include + +#ifndef TP_PROTO +#define TP_PROTO(args...) TPPROTO(args) +#endif +#ifndef TP_ARGS +#define TP_ARGS(args...) TPARGS(args) +#endif + +#define IRQ_WAKE_THREAD (2) + +/* From : include/linux/pm.h */ +/* How to reorder dpm_list after device_move() */ +enum dpm_order { + DPM_ORDER_NONE, + DPM_ORDER_DEV_AFTER_PARENT, + DPM_ORDER_PARENT_BEFORE_DEV, + DPM_ORDER_DEV_LAST, +}; + +static inline void dev_set_uevent_suppress(struct device *dev, int val) +{ + dev->uevent_suppress = val; +} + +/* + * Print a one-time message (analogous to WARN_ONCE() et al): + */ +#define printk_once(x...) ({ \ + static bool __print_once; \ + \ + if (!__print_once) { \ + __print_once = true; \ + printk(x); \ + } \ +}) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) */ + +#endif /* LINUX_26_30_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.31.h b/include/compat/linux/compat-2.6.31.h new file mode 100644 index 00000000..25db973d --- /dev/null +++ b/include/compat/linux/compat-2.6.31.h @@ -0,0 +1,221 @@ +#ifndef LINUX_26_31_COMPAT_H +#define LINUX_26_31_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) + +#include +#include +#include +#include +#include +#include + +/* + * These macros allow us to backport rfkill without any + * changes on cfg80211 through compat.diff. Note that this + * file will be included by rfkill_backport.h so we must + * not conflict with things there. + */ +#define rfkill_get_led_trigger_name backport_rfkill_get_led_trigger_name +#define rfkill_set_led_trigger_name backport_rfkill_set_led_trigger_name +#define rfkill_set_hw_state backport_rfkill_set_hw_state +#define rfkill_set_sw_state backport_rfkill_set_sw_state +#define rfkill_init_sw_state backport_rfkill_init_sw_state +#define rfkill_set_states backport_rfkill_set_states +#define rfkill_pause_polling backport_rfkill_pause_polling +#define rfkill_resume_polling backport_rfkill_resume_polling +#define rfkill_blocked backport_rfkill_blocked +#define rfkill_alloc backport_rfkill_alloc +#define rfkill_register backport_rfkill_register +#define rfkill_unregister backport_rfkill_unregister +#define rfkill_destroy backport_rfkill_destroy + +#ifndef ERFKILL +#if !defined(CONFIG_ALPHA) && !defined(CONFIG_MIPS) && !defined(CONFIG_PARISC) && !defined(CONFIG_SPARC) +#define ERFKILL 132 /* Operation not possible due to RF-kill */ +#endif +#ifdef CONFIG_ALPHA +#define ERFKILL 138 /* Operation not possible due to RF-kill */ +#endif +#ifdef CONFIG_MIPS +#define ERFKILL 167 /* Operation not possible due to RF-kill */ +#endif +#ifdef CONFIG_PARISC +#define ERFKILL 256 /* Operation not possible due to RF-kill */ +#endif +#ifdef CONFIG_SPARC +#define ERFKILL 134 /* Operation not possible due to RF-kill */ +#endif +#endif + +#ifndef NETDEV_PRE_UP +#define NETDEV_PRE_UP 0x000D +#endif + +#ifndef SDIO_DEVICE_ID_MARVELL_8688WLAN +#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104 +#endif + +struct compat_threaded_irq { + unsigned int irq; + irq_handler_t handler; + irq_handler_t thread_fn; + void *dev_id; + char wq_name[64]; + struct workqueue_struct *wq; + struct work_struct work; +}; + +/* + * kmemleak was introduced on 2.6.31, since older kernels do not have + * we simply ignore its tuning. + */ +static inline void kmemleak_ignore(const void *ptr) +{ + return; +} + +static inline void kmemleak_not_leak(const void *ptr) +{ + return; +} + +static inline void kmemleak_no_scan(const void *ptr) +{ + return; +} + +/* + * Added via adf30907d63893e4208dfe3f5c88ae12bc2f25d5 + * + * There is no _sk_dst on older kernels, so just set the + * old dst to NULL and release it directly. + */ +static inline void skb_dst_drop(struct sk_buff *skb) +{ + dst_release(skb->dst); + skb->dst = NULL; +} + +static inline struct dst_entry *skb_dst(const struct sk_buff *skb) +{ + return (struct dst_entry *)skb->dst; +} + +static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) +{ + skb->dst = dst; +} + +static inline struct rtable *skb_rtable(const struct sk_buff *skb) +{ + return (struct rtable *)skb_dst(skb); +} + +/* Backport threaded IRQ support */ + +static inline +void compat_irq_work(struct work_struct *work) +{ + struct compat_threaded_irq *comp = container_of(work, struct compat_threaded_irq, work); + comp->thread_fn(comp->irq, comp->dev_id); +} + +static inline +irqreturn_t compat_irq_dispatcher(int irq, void *dev_id) +{ + struct compat_threaded_irq *comp = dev_id; + irqreturn_t res; + + res = comp->handler(irq, comp->dev_id); + if (res == IRQ_WAKE_THREAD) { + queue_work(comp->wq, &comp->work); + res = IRQ_HANDLED; + } + + return res; +} + +static inline +int compat_request_threaded_irq(struct compat_threaded_irq *comp, + unsigned int irq, + irq_handler_t handler, + irq_handler_t thread_fn, + unsigned long flags, + const char *name, + void *dev_id) +{ + comp->irq = irq; + comp->handler = handler; + comp->thread_fn = thread_fn; + comp->dev_id = dev_id; + INIT_WORK(&comp->work, compat_irq_work); + + if (!comp->wq) { + snprintf(comp->wq_name, sizeof(comp->wq_name), + "compirq/%u-%s", irq, name); + comp->wq = create_singlethread_workqueue(comp->wq_name); + if (!comp->wq) { + printk(KERN_ERR "Failed to create compat-threaded-IRQ workqueue %s\n", + comp->wq_name); + return -ENOMEM; + } + } + return request_irq(irq, compat_irq_dispatcher, flags, name, comp); +} + +static inline +void compat_free_threaded_irq(struct compat_threaded_irq *comp) +{ + free_irq(comp->irq, comp); +} + +static inline +void compat_destroy_threaded_irq(struct compat_threaded_irq *comp) +{ + if (comp->wq) + destroy_workqueue(comp->wq); + comp->wq = NULL; +} + +static inline +void compat_synchronize_threaded_irq(struct compat_threaded_irq *comp) +{ + synchronize_irq(comp->irq); + cancel_work_sync(&comp->work); +} + +/** + * list_entry_rcu - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * This primitive may safely run concurrently with the _rcu list-mutation + * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). + */ +#define list_entry_rcu(ptr, type, member) \ + container_of(rcu_dereference(ptr), type, member) + +#define skb_walk_frags(skb, iter) \ + for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) + +#ifndef CONFIG_64BIT + +typedef struct { + long long counter; +} atomic64_t; + +extern long long atomic64_read(const atomic64_t *v); +extern long long atomic64_add_return(long long a, atomic64_t *v); + +#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) + +#endif + + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) */ + +#endif /* LINUX_26_31_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.32.h b/include/compat/linux/compat-2.6.32.h new file mode 100644 index 00000000..3506291d --- /dev/null +++ b/include/compat/linux/compat-2.6.32.h @@ -0,0 +1,129 @@ +#ifndef LINUX_26_32_COMPAT_H +#define LINUX_26_32_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)) + +#include +#include +#include +#include +#include + +#define SDIO_VENDOR_ID_INTEL 0x0089 +#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 +#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403 +#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404 +#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405 +#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406 + +static inline void flush_delayed_work(struct delayed_work *dwork) +{ + if (del_timer_sync(&dwork->timer)) { + /* + * This is what would happen on 2.6.32 but since we don't have + * access to the singlethread_cpu we can't really backport this, + * so avoid really *flush*ing the work... Oh well. Any better ideas? + + struct cpu_workqueue_struct *cwq; + cwq = wq_per_cpu(keventd_wq, get_cpu()); + __queue_work(cwq, &dwork->work); + put_cpu(); + + */ + } + flush_work(&dwork->work); +} + +/* + * struct genl_multicast_group was made netns aware through + * patch "genetlink: make netns aware" by johannes, we just + * force this to always use the default init_net + */ +#define genl_info_net(x) &init_net +/* Just use init_net for older kernels */ +#define get_net_ns_by_pid(x) &init_net + +/* net namespace is lost */ +#define genlmsg_multicast_netns(a, b, c, d, e) genlmsg_multicast(b, c, d, e) +#define genlmsg_multicast_allns(a, b, c, d) genlmsg_multicast(a, b, c, d) +#define genlmsg_unicast(net, skb, pid) genlmsg_unicast(skb, pid) + +#define dev_change_net_namespace(a, b, c) (-EOPNOTSUPP) + +#define SET_NETDEV_DEVTYPE(netdev, type) + +#ifdef __KERNEL__ +/* Driver transmit return codes */ +enum netdev_tx { + BACKPORT_NETDEV_TX_OK = NETDEV_TX_OK, /* driver took care of packet */ + BACKPORT_NETDEV_TX_BUSY = NETDEV_TX_BUSY, /* driver tx path was busy*/ + BACKPORT_NETDEV_TX_LOCKED = NETDEV_TX_LOCKED, /* driver tx lock was already taken */ +}; +typedef enum netdev_tx netdev_tx_t; +#endif /* __KERNEL__ */ + +/* + * dev_pm_ops is only available on kernels >= 2.6.29, for + * older kernels we rely on reverting the work to old + * power management style stuff. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +/* + * Use this if you want to use the same suspend and resume callbacks for suspend + * to RAM and hibernation. + */ +#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ +struct dev_pm_ops name = { \ + .suspend = suspend_fn, \ + .resume = resume_fn, \ + .freeze = suspend_fn, \ + .thaw = resume_fn, \ + .poweroff = suspend_fn, \ + .restore = resume_fn, \ +} +#else +#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) +#endif /* >= 2.6.29 */ + +#define wireless_send_event(a, b, c, d) wireless_send_event(a, b, c, (char * ) d) + +/* The export symbol in changed in compat/patches/15-symbol-export-conflicts.patch */ +#define ieee80211_rx(hw, skb) mac80211_ieee80211_rx(hw, skb) + +#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) + +#define lockdep_assert_held(l) do { } while (0) + +/* + * Similar to the struct tm in userspace , but it needs to be here so + * that the kernel source is self contained. + */ +struct tm { + /* + * the number of seconds after the minute, normally in the range + * 0 to 59, but can be up to 60 to allow for leap seconds + */ + int tm_sec; + /* the number of minutes after the hour, in the range 0 to 59*/ + int tm_min; + /* the number of hours past midnight, in the range 0 to 23 */ + int tm_hour; + /* the day of the month, in the range 1 to 31 */ + int tm_mday; + /* the number of months since January, in the range 0 to 11 */ + int tm_mon; + /* the number of years since 1900 */ + long tm_year; + /* the number of days since Sunday, in the range 0 to 6 */ + int tm_wday; + /* the number of days since January 1, in the range 0 to 365 */ + int tm_yday; +}; + +void time_to_tm(time_t totalsecs, int offset, struct tm *result); + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)) */ + +#endif /* LINUX_26_32_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.33.h b/include/compat/linux/compat-2.6.33.h new file mode 100644 index 00000000..c900a6fc --- /dev/null +++ b/include/compat/linux/compat-2.6.33.h @@ -0,0 +1,172 @@ +#ifndef LINUX_26_33_COMPAT_H +#define LINUX_26_33_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) + +#include +#include +#if defined(CONFIG_PCCARD) || defined(CONFIG_PCCARD_MODULE) +#include +#include +#include +#endif +#include +#include + +#if defined(CONFIG_COMPAT_FIRMWARE_CLASS) +#define release_firmware compat_release_firmware +#define request_firmware compat_request_firmware +#define request_firmware_nowait compat_request_firmware_nowait +#endif + +#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) +int compat_request_firmware(const struct firmware **fw, const char *name, + struct device *device); +int compat_request_firmware_nowait( + struct module *module, int uevent, + const char *name, struct device *device, gfp_t gfp, void *context, + void (*cont)(const struct firmware *fw, void *context)); + +void compat_release_firmware(const struct firmware *fw); +#else +static inline int compat_request_firmware(const struct firmware **fw, + const char *name, + struct device *device) +{ + return -EINVAL; +} +static inline int request_firmware_nowait( + struct module *module, int uevent, + const char *name, struct device *device, gfp_t gfp, void *context, + void (*cont)(const struct firmware *fw, void *context)) +{ + return -EINVAL; +} + +static inline void compat_release_firmware(const struct firmware *fw) +{ +} +#endif + +/* mask KEY_RFKILL as RHEL6 backports this */ +#if !defined(KEY_RFKILL) +#define KEY_RFKILL 247 /* Key that controls all radios */ +#endif + +#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */ +/* source: include/linux/if.h */ + +/* this will never happen on older kernels */ +#define NETDEV_POST_INIT 0xffff + +/* mask netdev_alloc_skb_ip_align as debian squeeze also backports this */ +#define netdev_alloc_skb_ip_align(a, b) compat_netdev_alloc_skb_ip_align(a, b) + +static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length) +{ + struct sk_buff *skb = netdev_alloc_skb(dev, length + NET_IP_ALIGN); + + if (NET_IP_ALIGN && skb) + skb_reserve(skb, NET_IP_ALIGN); + return skb; +} + +#if defined(CONFIG_PCCARD) || defined(CONFIG_PCCARD_MODULE) + +#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) + +#define pcmcia_request_window(a, b, c) pcmcia_request_window(&a, b, c) + +#define pcmcia_map_mem_page(a, b, c) pcmcia_map_mem_page(b, c) + +/* loop over CIS entries */ +int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code, + int (*loop_tuple) (struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data), + void *priv_data); + +#endif /* CONFIG_PCMCIA */ + +/* loop over CIS entries */ +int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function, + cisdata_t code, cisparse_t *parse, void *priv_data, + int (*loop_tuple) (tuple_t *tuple, + cisparse_t *parse, + void *priv_data)); + +#endif /* CONFIG_PCCARD */ + +/** + * list_for_each_entry_continue_rcu - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue_rcu(pos, head, member) \ + for (pos = list_entry_rcu(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry_rcu(pos->member.next, typeof(*pos), member)) + +#define sock_recv_ts_and_drops(msg, sk, skb) sock_recv_timestamp(msg, sk, skb) + +/* mask pci_pcie_cap as debian squeeze also backports this */ +#define pci_pcie_cap(a) compat_pci_pcie_cap(a) + +/** + * pci_pcie_cap - get the saved PCIe capability offset + * @dev: PCI device + * + * PCIe capability offset is calculated at PCI device initialization + * time and saved in the data structure. This function returns saved + * PCIe capability offset. Using this instead of pci_find_capability() + * reduces unnecessary search in the PCI configuration space. If you + * need to calculate PCIe capability offset from raw device for some + * reasons, please use pci_find_capability() instead. + */ +static inline int pci_pcie_cap(struct pci_dev *dev) +{ + return pci_find_capability(dev, PCI_CAP_ID_EXP); +} + +/* mask pci_is_pcie as RHEL6 backports this */ +#define pci_is_pcie(a) compat_pci_is_pcie(a) + +/** + * pci_is_pcie - check if the PCI device is PCI Express capable + * @dev: PCI device + * + * Retrun true if the PCI device is PCI Express capable, false otherwise. + */ +static inline bool pci_is_pcie(struct pci_dev *dev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + return dev->is_pcie; +#else + return !!pci_pcie_cap(dev); +#endif +} + +#ifdef __GNUC__ +#define __always_unused __attribute__((unused)) +#else +#define __always_unused /* unimplemented */ +#endif + +/* mask IS_ERR_OR_NULL as debian squeeze also backports this */ +#define IS_ERR_OR_NULL(a) compat_IS_ERR_OR_NULL(a) + +static inline long __must_check IS_ERR_OR_NULL(const void *ptr) +{ + return !ptr || IS_ERR_VALUE((unsigned long)ptr); +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)) */ + +#endif /* LINUX_26_33_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.34.h b/include/compat/linux/compat-2.6.34.h new file mode 100644 index 00000000..da242ce0 --- /dev/null +++ b/include/compat/linux/compat-2.6.34.h @@ -0,0 +1,309 @@ +#ifndef LINUX_26_34_COMPAT_H +#define LINUX_26_34_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) + +#include +#include + +#define netdev_mc_count(dev) ((dev)->mc_count) +#define netdev_mc_empty(dev) (netdev_mc_count(dev) == 0) + +#define netdev_for_each_mc_addr(mclist, dev) \ + for (mclist = dev->mc_list; mclist; mclist = mclist->next) +/* source: include/linux/netdevice.h */ + + +/* Logging, debugging and troubleshooting/diagnostic helpers. */ + +/* netdev_printk helpers, similar to dev_printk */ + +#ifndef netdev_name +#define netdev_name(__dev) \ + ((__dev->reg_state != NETREG_REGISTERED) ? \ + "(unregistered net_device)" : __dev->name) +#endif + +#define netdev_printk(level, netdev, format, args...) \ + dev_printk(level, (netdev)->dev.parent, \ + "%s: " format, \ + netdev_name(netdev), ##args) + +#define netdev_emerg(dev, format, args...) \ + netdev_printk(KERN_EMERG, dev, format, ##args) +#define netdev_alert(dev, format, args...) \ + netdev_printk(KERN_ALERT, dev, format, ##args) +#define netdev_crit(dev, format, args...) \ + netdev_printk(KERN_CRIT, dev, format, ##args) +#define netdev_err(dev, format, args...) \ + netdev_printk(KERN_ERR, dev, format, ##args) +#define netdev_warn(dev, format, args...) \ + netdev_printk(KERN_WARNING, dev, format, ##args) +#define netdev_notice(dev, format, args...) \ + netdev_printk(KERN_NOTICE, dev, format, ##args) +#define netdev_info(dev, format, args...) \ + netdev_printk(KERN_INFO, dev, format, ##args) + +/* mask netdev_dbg as RHEL6 backports this */ +#if !defined(netdev_dbg) + +#if defined(DEBUG) +#define netdev_dbg(__dev, format, args...) \ + netdev_printk(KERN_DEBUG, __dev, format, ##args) +#elif defined(CONFIG_DYNAMIC_DEBUG) +#define netdev_dbg(__dev, format, args...) \ +do { \ + dynamic_dev_dbg((__dev)->dev.parent, "%s: " format, \ + netdev_name(__dev), ##args); \ +} while (0) +#else +#define netdev_dbg(__dev, format, args...) \ +({ \ + if (0) \ + netdev_printk(KERN_DEBUG, __dev, format, ##args); \ + 0; \ +}) +#endif + +#endif + +/* mask netdev_vdbg as RHEL6 backports this */ +#if !defined(netdev_dbg) + +#if defined(VERBOSE_DEBUG) +#define netdev_vdbg netdev_dbg +#else + +#define netdev_vdbg(dev, format, args...) \ +({ \ + if (0) \ + netdev_printk(KERN_DEBUG, dev, format, ##args); \ + 0; \ +}) +#endif + +#endif + +/* + * netdev_WARN() acts like dev_printk(), but with the key difference + * of using a WARN/WARN_ON to get the message out, including the + * file/line information and a backtrace. + */ +#define netdev_WARN(dev, format, args...) \ + WARN(1, "netdevice: %s\n" format, netdev_name(dev), ##args); + +/* netif printk helpers, similar to netdev_printk */ + +#define netif_printk(priv, type, level, dev, fmt, args...) \ +do { \ + if (netif_msg_##type(priv)) \ + netdev_printk(level, (dev), fmt, ##args); \ +} while (0) + +#define netif_emerg(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_EMERG, dev, fmt, ##args) +#define netif_alert(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_ALERT, dev, fmt, ##args) +#define netif_crit(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_CRIT, dev, fmt, ##args) +#define netif_err(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_ERR, dev, fmt, ##args) +#define netif_warn(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_WARNING, dev, fmt, ##args) +#define netif_notice(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_NOTICE, dev, fmt, ##args) +#define netif_info(priv, type, dev, fmt, args...) \ + netif_printk(priv, type, KERN_INFO, (dev), fmt, ##args) + +/* mask netif_dbg as RHEL6 backports this */ +#if !defined(netif_dbg) + +#if defined(DEBUG) +#define netif_dbg(priv, type, dev, format, args...) \ + netif_printk(priv, type, KERN_DEBUG, dev, format, ##args) +#elif defined(CONFIG_DYNAMIC_DEBUG) +#define netif_dbg(priv, type, netdev, format, args...) \ +do { \ + if (netif_msg_##type(priv)) \ + dynamic_dev_dbg((netdev)->dev.parent, \ + "%s: " format, \ + netdev_name(netdev), ##args); \ +} while (0) +#else +#define netif_dbg(priv, type, dev, format, args...) \ +({ \ + if (0) \ + netif_printk(priv, type, KERN_DEBUG, dev, format, ##args); \ + 0; \ +}) +#endif + +#endif + +/* mask netif_vdbg as RHEL6 backports this */ +#if !defined(netif_vdbg) + +#if defined(VERBOSE_DEBUG) +#define netif_vdbg netdev_dbg +#else +#define netif_vdbg(priv, type, dev, format, args...) \ +({ \ + if (0) \ + netif_printk(KERN_DEBUG, dev, format, ##args); \ + 0; \ +}) +#endif +#endif +/* source: include/linux/netdevice.h */ + + +static inline void device_lock(struct device *dev) +{ +#if defined(CONFIG_PREEMPT_RT) || defined(CONFIG_PREEMPT_DESKTOP) + mutex_lock(&dev->mutex); +#else + down(&dev->sem); +#endif +} + +static inline int device_trylock(struct device *dev) +{ +#if defined(CONFIG_PREEMPT_RT) || defined(CONFIG_PREEMPT_DESKTOP) + return mutex_trylock(&dev->mutex); +#else + return down_trylock(&dev->sem); +#endif +} + +static inline void device_unlock(struct device *dev) +{ +#if defined(CONFIG_PREEMPT_RT) || defined(CONFIG_PREEMPT_DESKTOP) + mutex_unlock(&dev->mutex); +#else + up(&dev->sem); +#endif +} + +#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) +#define PCMCIA_DEVICE_PROD_ID3(v3, vh3) { \ + .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID3, \ + .prod_id = { NULL, NULL, (v3), NULL }, \ + .prod_id_hash = { 0, 0, (vh3), 0 }, } +#endif + +#define rcu_dereference_check(p, c) rcu_dereference(p) + +/** + * sysfs_attr_init - initialize a dynamically allocated sysfs attribute + * @attr: struct attribute to initialize + * + * Initialize a dynamically allocated struct attribute so we can + * make lockdep happy. This is a new requirement for attributes + * and initially this is only needed when lockdep is enabled. + * Lockdep gives a nice error when your attribute is added to + * sysfs if you don't have this. + */ +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define sysfs_attr_init(attr) \ +do { \ + static struct lock_class_key __key; \ + \ + (attr)->key = &__key; \ +} while(0) +#else +#define sysfs_attr_init(attr) do {} while(0) +#endif + +/** + * sysfs_bin_attr_init - initialize a dynamically allocated bin_attribute + * @attr: struct bin_attribute to initialize + * + * Initialize a dynamically allocated struct bin_attribute so we + * can make lockdep happy. This is a new requirement for + * attributes and initially this is only needed when lockdep is + * enabled. Lockdep gives a nice error when your attribute is + * added to sysfs if you don't have this. + */ +#define sysfs_bin_attr_init(bin_attr) sysfs_attr_init(&(bin_attr)->attr) + +#define usb_alloc_coherent(dev, size, mem_flags, dma) usb_buffer_alloc(dev, size, mem_flags, dma) +#define usb_free_coherent(dev, size, addr, dma) usb_buffer_free(dev, size, addr, dma) + +/* only include this if DEFINE_DMA_UNMAP_ADDR is not set as debian squeeze also backports this */ +#ifndef DEFINE_DMA_UNMAP_ADDR +#ifdef CONFIG_NEED_DMA_MAP_STATE +#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME +#define DEFINE_DMA_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME +#define dma_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME) +#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL)) +#define dma_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME) +#define dma_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL)) +#else +#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) +#define DEFINE_DMA_UNMAP_LEN(LEN_NAME) +#define dma_unmap_addr(PTR, ADDR_NAME) (0) +#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +#define dma_unmap_len(PTR, LEN_NAME) (0) +#define dma_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) +#endif +#endif + +/* mask dma_set_coherent_mask as debian squeeze also backports this */ +#define dma_set_coherent_mask(a, b) compat_dma_set_coherent_mask(a, b) + +static inline int dma_set_coherent_mask(struct device *dev, u64 mask) +{ + if (!dma_supported(dev, mask)) + return -EIO; + dev->coherent_dma_mask = mask; + return 0; +} + +/* USB autosuspend and autoresume */ +static inline int usb_enable_autosuspend(struct usb_device *udev) +{ return 0; } +static inline int usb_disable_autosuspend(struct usb_device *udev) +{ return 0; } + +#define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */ +#define sdio_set_host_pm_flags(a, b) 0 + +#define rcu_dereference_protected(p, c) (p) +#define rcu_access_pointer(p) ACCESS_ONCE(p) + +#define rcu_dereference_raw(p) rcu_dereference(p) + +#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ + +/* + * This looks more complex than it should be. But we need to + * get the type for the ~ right in round_down (it needs to be + * as wide as the result!), and we want to evaluate the macro + * arguments just once each. + */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define round_down(x, y) ((x) & ~__round_mask(x, y)) + +static inline int rcu_read_lock_held(void) +{ + return 1; +} + +#ifdef CONFIG_PROVE_LOCKING +/* + * Obviously, this is wrong. But the base kernel will have rtnl_mutex + * declared static, with no way to access it. I think this is the best + * we can do... + */ +static inline int lockdep_rtnl_is_held(void) +{ + return 1; +} +#endif /* #ifdef CONFIG_PROVE_LOCKING */ + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) */ + +#endif /* LINUX_26_34_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.35.h b/include/compat/linux/compat-2.6.35.h new file mode 100644 index 00000000..5e43002f --- /dev/null +++ b/include/compat/linux/compat-2.6.35.h @@ -0,0 +1,48 @@ +#ifndef LINUX_26_35_COMPAT_H +#define LINUX_26_35_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) +#include +#include +#include +#include + +/* added on linux/kernel.h */ +#define USHRT_MAX ((u16)(~0U)) +#define SHRT_MAX ((s16)(USHRT_MAX>>1)) +#define SHRT_MIN ((s16)(-SHRT_MAX - 1)) + +#define SDIO_BUS_ECSI 0x20 /* Enable continuous SPI interrupt */ +#define SDIO_BUS_SCSI 0x40 /* Support continuous SPI interrupt */ + +#define netdev_hw_addr dev_mc_list + +static inline wait_queue_head_t *sk_sleep(struct sock *sk) +{ + return sk->sk_sleep; +} + +#define sdio_writeb_readb(func, write_byte, addr, err_ret) sdio_readb(func, addr, err_ret) + +/* mask hex_to_bin as RHEL6 backports this */ +#define hex_to_bin(a) compat_hex_to_bin(a) + +int hex_to_bin(char ch); + +extern loff_t noop_llseek(struct file *file, loff_t offset, int origin); + +#define pm_qos_request(_qos) pm_qos_requirement(_qos) + +static inline struct usb_host_endpoint * +usb_pipe_endpoint(struct usb_device *dev, unsigned int pipe) +{ + struct usb_host_endpoint **eps; + eps = usb_pipein(pipe) ? dev->ep_in : dev->ep_out; + return eps[usb_pipeendpoint(pipe)]; +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) */ + +#endif /* LINUX_26_35_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.36.h b/include/compat/linux/compat-2.6.36.h new file mode 100644 index 00000000..314fb353 --- /dev/null +++ b/include/compat/linux/compat-2.6.36.h @@ -0,0 +1,172 @@ +#ifndef LINUX_26_36_COMPAT_H +#define LINUX_26_36_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) + +#include +#include +#include +#include +#include + +#define kparam_block_sysfs_write(a) +#define kparam_unblock_sysfs_write(a) + +/* mask va_format as RHEL6 backports this */ +#define va_format compat_va_format + +struct va_format { + const char *fmt; + va_list *va; +}; + +#define device_rename(dev, new_name) device_rename(dev, (char *)new_name) + +#ifdef CONFIG_COMPAT_USB_URB_THREAD_FIX +#define usb_scuttle_anchored_urbs(anchor) compat_usb_scuttle_anchored_urbs(anchor) +#define usb_get_from_anchor(anchor) compat_usb_get_from_anchor(anchor) +#define usb_unlink_anchored_urbs(anchor) compat_usb_unlink_anchored_urbs(anchor) + +extern void compat_usb_unlink_anchored_urbs(struct usb_anchor *anchor); +extern struct urb *compat_usb_get_from_anchor(struct usb_anchor *anchor); +extern void compat_usb_scuttle_anchored_urbs(struct usb_anchor *anchor); +#endif + +/** + * pcmcia_read_config_byte() - read a byte from a card configuration register + * + * pcmcia_read_config_byte() reads a byte from a configuration register in + * attribute memory. + */ +static inline int pcmcia_read_config_byte(struct pcmcia_device *p_dev, off_t where, u8 *val) +{ + int ret; + conf_reg_t reg = { 0, CS_READ, where, 0 }; + ret = pcmcia_access_configuration_register(p_dev, ®); + *val = reg.Value; + return ret; +} + +/** + * pcmcia_write_config_byte() - write a byte to a card configuration register + * + * pcmcia_write_config_byte() writes a byte to a configuration register in + * attribute memory. + */ +static inline int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val) +{ + conf_reg_t reg = { 0, CS_WRITE, where, val }; + return pcmcia_access_configuration_register(p_dev, ®); +} + +struct pm_qos_request_list { + u32 qos; + void *request; +}; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) + +#define pm_qos_add_request(_req, _class, _value) do { \ + (_req)->request = #_req; \ + (_req)->qos = _class; \ + pm_qos_add_requirement((_class), (_req)->request, (_value)); \ + } while(0) + +#define pm_qos_update_request(_req, _value) \ + pm_qos_update_requirement((_req)->qos, (_req)->request, (_value)) + +#define pm_qos_remove_request(_req) \ + pm_qos_remove_requirement((_req)->qos, (_req)->request) + +#else + +#define pm_qos_add_request(_req, _class, _value) do { \ + (_req)->request = pm_qos_add_request((_class), (_value)); \ + } while (0) + +#define pm_qos_update_request(_req, _value) \ + pm_qos_update_request((_req)->request, (_value)) + +#define pm_qos_remove_request(_req) \ + pm_qos_remove_request((_req)->request) + +#endif + +/* + * Dummy printk for disabled debugging statements to use whilst maintaining + * gcc's format and side-effect checking. + */ +static inline __attribute__ ((format (printf, 1, 2))) +int no_printk(const char *s, ...) { return 0; } + +#ifndef alloc_workqueue +#define alloc_workqueue(name, flags, max_active) __create_workqueue(name, flags, max_active, 0) +#endif + +#define EXTPROC 0200000 +#define TIOCPKT_IOCTL 64 + +static inline void tty_lock(void) __acquires(kernel_lock) +{ +#ifdef CONFIG_LOCK_KERNEL + /* kernel_locked is 1 for !CONFIG_LOCK_KERNEL */ + WARN_ON(kernel_locked()); +#endif + lock_kernel(); +} +static inline void tty_unlock(void) __releases(kernel_lock) +{ + unlock_kernel(); +} +#define tty_locked() (kernel_locked()) + +#define usleep_range(_min, _max) msleep((_max) / 1000) + +#define __rcu + +static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {} + +static inline bool skb_defer_rx_timestamp(struct sk_buff *skb) +{ + return false; +} + +static inline void skb_tx_timestamp(struct sk_buff *skb) +{ +} + +extern struct workqueue_struct *system_nrt_wq; + +void compat_system_workqueue_create(void); +void compat_system_workqueue_destroy(void); + +#define br_port_exists(dev) (dev->br_port) + +#else + +static inline void compat_system_workqueue_create(void) +{ +} + +static inline void compat_system_workqueue_destroy(void) +{ +} + +/* + * This is not part of The 2.6.37 kernel yet but we + * we use it to optimize the backport code we + * need to implement. Instead of using ifdefs + * to check what version of the check we use + * we just replace all checks on current code + * with this. I'll submit this upstream too, that + * way all we'd have to do is to implement this + * for older kernels, then we would not have to + * edit the upstrema code for backport efforts. + */ +#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) */ + +#endif /* LINUX_26_36_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.37.h b/include/compat/linux/compat-2.6.37.h new file mode 100644 index 00000000..c19e7818 --- /dev/null +++ b/include/compat/linux/compat-2.6.37.h @@ -0,0 +1,140 @@ +#ifndef LINUX_26_37_COMPAT_H +#define LINUX_26_37_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) + +#include +#include + +#define SDIO_CLASS_BT_AMP 0x09 /* Type-A Bluetooth AMP interface */ + +extern struct kobj_ns_type_operations net_ns_type_operations; + +/* mask skb_checksum_none_assert as RHEL6 backports this */ +#define skb_checksum_none_assert(a) compat_skb_checksum_none_assert(a) + +/** + * skb_checksum_none_assert - make sure skb ip_summed is CHECKSUM_NONE + * @skb: skb to check + * + * fresh skbs have their ip_summed set to CHECKSUM_NONE. + * Instead of forcing ip_summed to CHECKSUM_NONE, we can + * use this helper, to document places where we make this assertion. + */ +static inline void skb_checksum_none_assert(struct sk_buff *skb) +{ +#ifdef DEBUG + BUG_ON(skb->ip_summed != CHECKSUM_NONE); +#endif +} + +#define pcmcia_enable_device(link) pcmcia_request_configuration(link, &link->conf) + +#include + +struct compat_genl_info { + struct genl_info *info; + + u32 snd_seq; + u32 snd_pid; + struct genlmsghdr *genlhdr; + struct nlattr **attrs; + void *user_ptr[2]; +}; +#define genl_info compat_genl_info + +struct compat_genl_ops { + struct genl_ops ops; + + u8 cmd; + u8 internal_flags; + unsigned int flags; + const struct nla_policy *policy; + + int (*doit)(struct sk_buff *skb, struct genl_info *info); + int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb); + int (*done)(struct netlink_callback *cb); +}; +#define genl_ops compat_genl_ops + +struct compat_genl_family { + struct genl_family family; + + struct list_head list; + + unsigned int id, hdrsize, version, maxattr; + const char *name; + bool netnsok; + + struct nlattr **attrbuf; + + int (*pre_doit)(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); + + void (*post_doit)(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); +}; + +#define genl_family compat_genl_family + +#define genl_register_family_with_ops compat_genl_register_family_with_ops + +int genl_register_family_with_ops(struct genl_family *family, + struct genl_ops *ops, size_t n_ops); + +#define genl_unregister_family compat_genl_unregister_family + +int genl_unregister_family(struct genl_family *family); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) +#define genl_info_net(_info) genl_info_net((_info)->info) +#endif + +#define genlmsg_reply(_msg, _info) genlmsg_reply(_msg, (_info)->info) +#define genlmsg_put(_skb, _pid, _seq, _fam, _flags, _cmd) genlmsg_put(_skb, _pid, _seq, &(_fam)->family, _flags, _cmd) +#define genl_register_mc_group(_fam, _grp) genl_register_mc_group(&(_fam)->family, _grp) +#define genl_unregister_mc_group(_fam, _grp) genl_unregister_mc_group(&(_fam)->family, _grp) + + +extern void led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off); + +#define led_classdev_unregister compat_led_classdev_unregister +extern void compat_led_classdev_unregister(struct led_classdev *led_cdev); + +#define led_brightness_set compat_led_brightness_set +extern void compat_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness); + +#define alloc_ordered_workqueue(name, flags) create_singlethread_workqueue(name) + +#define netdev_refcnt_read(a) atomic_read(&a->refcnt) + +/* mask vzalloc as RHEL6 backports this */ +#define vzalloc(a) compat_vzalloc(a) + +extern void *vzalloc(unsigned long size); + +#define rtnl_dereference(p) \ + rcu_dereference_protected(p, lockdep_rtnl_is_held()) + +/** + * RCU_INIT_POINTER() - initialize an RCU protected pointer + * + * Initialize an RCU-protected pointer in such a way to avoid RCU-lockdep + * splats. + */ +#define RCU_INIT_POINTER(p, v) \ + p = (typeof(*v) __force __rcu *)(v) + +static inline bool skb_has_frag_list(const struct sk_buff *skb) +{ + return skb_shinfo(skb)->frag_list != NULL; +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) */ + +#endif /* LINUX_26_37_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.38.h b/include/compat/linux/compat-2.6.38.h new file mode 100644 index 00000000..63f9dd6a --- /dev/null +++ b/include/compat/linux/compat-2.6.38.h @@ -0,0 +1,95 @@ +#ifndef LINUX_26_38_COMPAT_H +#define LINUX_26_38_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)) + +#include +#include +#include + +/* rename member in struct mmc_host in include/linux/mmc/host.h */ +#define max_segs max_hw_segs + + +/* Exponentially weighted moving average (EWMA) */ + +/* For more documentation see lib/average.c */ + +struct ewma { + unsigned long internal; + unsigned long factor; + unsigned long weight; +}; + +extern void ewma_init(struct ewma *avg, unsigned long factor, + unsigned long weight); + +extern struct ewma *ewma_add(struct ewma *avg, unsigned long val); + +/** + * ewma_read() - Get average value + * @avg: Average structure + * + * Returns the average value held in @avg. + */ +static inline unsigned long ewma_read(const struct ewma *avg) +{ + return DIV_ROUND_CLOSEST(avg->internal, avg->factor); +} + +#define pr_warn pr_warning +#define create_freezable_workqueue create_freezeable_workqueue + +static inline int skb_checksum_start_offset(const struct sk_buff *skb) +{ + return skb->csum_start - skb_headroom(skb); +} + +/* from include/linux/printk.h */ +#define pr_emerg_once(fmt, ...) \ + printk_once(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) +#define pr_alert_once(fmt, ...) \ + printk_once(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) +#define pr_crit_once(fmt, ...) \ + printk_once(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) +#define pr_err_once(fmt, ...) \ + printk_once(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) +#define pr_warn_once(fmt, ...) \ + printk_once(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) +#define pr_notice_once(fmt, ...) \ + printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) +#define pr_info_once(fmt, ...) \ + printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) +#define pr_cont_once(fmt, ...) \ + printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__) +#if defined(DEBUG) +#define pr_debug_once(fmt, ...) \ + printk_once(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) +#else +#define pr_debug_once(fmt, ...) \ + no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) +#endif + +/* include/linux/netdevice.h */ +#define alloc_netdev_mqs(sizeof_priv, name, setup, txqs, rxqs) \ + alloc_netdev_mq(sizeof_priv, name, setup, \ + max_t(unsigned int, txqs, rxqs)) + +#define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */ + +/** + * is_unicast_ether_addr - Determine if the Ethernet address is unicast + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is a unicast address. + */ +static inline int is_unicast_ether_addr(const u8 *addr) +{ + return !is_multicast_ether_addr(addr); +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)) */ + +#endif /* LINUX_26_38_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.39.h b/include/compat/linux/compat-2.6.39.h new file mode 100644 index 00000000..406f8ebf --- /dev/null +++ b/include/compat/linux/compat-2.6.39.h @@ -0,0 +1,169 @@ +#ifndef LINUX_26_39_COMPAT_H +#define LINUX_26_39_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) + +#include +#include +#include + +#define tiocmget(tty) tiocmget(tty, NULL) +#define tiocmset(tty, set, clear) tiocmset(tty, NULL, set, clear) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) +extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) */ + +static inline int irq_set_irq_wake(unsigned int irq, unsigned int on) +{ + return set_irq_wake(irq, on); +} +static inline int irq_set_chip(unsigned int irq, struct irq_chip *chip) +{ + return set_irq_chip(irq, chip); +} +static inline int irq_set_handler_data(unsigned int irq, void *data) +{ + return set_irq_data(irq, data); +} +static inline int irq_set_chip_data(unsigned int irq, void *data) +{ + return set_irq_chip_data(irq, data); +} +static inline int irq_set_irq_type(unsigned int irq, unsigned int type) +{ + return set_irq_type(irq, type); +} +static inline int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) +{ + return set_irq_msi(irq, entry); +} +static inline struct irq_chip *irq_get_chip(unsigned int irq) +{ + return get_irq_chip(irq); +} +static inline void *irq_get_chip_data(unsigned int irq) +{ + return get_irq_chip_data(irq); +} +static inline void *irq_get_handler_data(unsigned int irq) +{ + return get_irq_data(irq); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) +static inline void *irq_data_get_irq_handler_data(struct irq_data *d) +{ + return irq_data_get_irq_data(d); +} +#endif + +static inline struct msi_desc *irq_get_msi_desc(unsigned int irq) +{ + return get_irq_msi(irq); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) +static inline void irq_set_noprobe(unsigned int irq) +{ + set_irq_noprobe(irq); +} +static inline void irq_set_probe(unsigned int irq) +{ + set_irq_probe(irq); +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static inline struct irq_chip *irq_desc_get_chip(struct irq_desc *desc) +{ + return get_irq_desc_chip(desc); +} +static inline void *irq_desc_get_handler_data(struct irq_desc *desc) +{ + return get_irq_desc_data(desc); +} + +static inline void *irq_desc_get_chip_data(struct irq_desc *desc) +{ + return get_irq_desc_chip_data(desc); +} + +static inline struct msi_desc *irq_desc_get_msi_desc(struct irq_desc *desc) +{ + return get_irq_desc_msi(desc); +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) */ + +/* + * kstrto* was included in kernel 2.6.38.4 and causes conflicts with the + * version included in compat-wireless. We use strict_strtol to check if + * kstrto* is already available. + */ +#ifndef strict_strtol +/* Internal, do not use. */ +int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res); +int __must_check _kstrtol(const char *s, unsigned int base, long *res); + +int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res); +int __must_check kstrtoll(const char *s, unsigned int base, long long *res); +static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res) +{ + /* + * We want to shortcut function call, but + * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0. + */ + if (sizeof(unsigned long) == sizeof(unsigned long long) && + __alignof__(unsigned long) == __alignof__(unsigned long long)) + return kstrtoull(s, base, (unsigned long long *)res); + else + return _kstrtoul(s, base, res); +} + +static inline int __must_check kstrtol(const char *s, unsigned int base, long *res) +{ + /* + * We want to shortcut function call, but + * __builtin_types_compatible_p(long, long long) = 0. + */ + if (sizeof(long) == sizeof(long long) && + __alignof__(long) == __alignof__(long long)) + return kstrtoll(s, base, (long long *)res); + else + return _kstrtol(s, base, res); +} + +int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res); +int __must_check kstrtoint(const char *s, unsigned int base, int *res); + +static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res) +{ + return kstrtoull(s, base, res); +} + +static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res) +{ + return kstrtoll(s, base, res); +} + +static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res) +{ + return kstrtouint(s, base, res); +} + +static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res) +{ + return kstrtoint(s, base, res); +} + +int __must_check kstrtou16(const char *s, unsigned int base, u16 *res); +int __must_check kstrtos16(const char *s, unsigned int base, s16 *res); +int __must_check kstrtou8(const char *s, unsigned int base, u8 *res); +int __must_check kstrtos8(const char *s, unsigned int base, s8 *res); +#endif /* ifndef strict_strtol */ + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) */ + +#endif /* LINUX_26_39_COMPAT_H */ diff --git a/include/compat/linux/compat-2.6.h b/include/compat/linux/compat-2.6.h new file mode 100644 index 00000000..e25aa51c --- /dev/null +++ b/include/compat/linux/compat-2.6.h @@ -0,0 +1,44 @@ +#ifndef LINUX_26_COMPAT_H +#define LINUX_26_COMPAT_H + +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) +#include +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) +#include +#else +#include +#endif +#include + +/* + * Each compat file represents compatibility code for new kernel + * code introduced for *that* kernel revision. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* LINUX_26_COMPAT_H */ diff --git a/include/compat/linux/compat-3.0.h b/include/compat/linux/compat-3.0.h new file mode 100644 index 00000000..22ab5399 --- /dev/null +++ b/include/compat/linux/compat-3.0.h @@ -0,0 +1,130 @@ +#ifndef LINUX_3_0_COMPAT_H +#define LINUX_3_0_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) + +#include + +/* + * since commit 1c5cae815d19ffe02bdfda1260949ef2b1806171 + * "net: call dev_alloc_name from register_netdevice" dev_alloc_name is + * called automatically. This is not implemented in older kernel + * versions so it will result in device wrong names. + */ +static inline int register_netdevice_name(struct net_device *dev) +{ + int err; + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + return err; + } + + return register_netdevice(dev); +} + +#define register_netdevice(dev) register_netdevice_name(dev) + +/* BCMA core, see drivers/bcma/ */ +#ifndef BCMA_CORE +/* Broadcom's specific AMBA core, see drivers/bcma/ */ +struct bcma_device_id { + __u16 manuf; + __u16 id; + __u8 rev; + __u8 class; +}; +#define BCMA_CORE(_manuf, _id, _rev, _class) \ + { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, } +#define BCMA_CORETABLE_END \ + { 0, }, + +#define BCMA_ANY_MANUF 0xFFFF +#define BCMA_ANY_ID 0xFFFF +#define BCMA_ANY_REV 0xFF +#define BCMA_ANY_CLASS 0xFF +#endif /* BCMA_CORE */ + +int mac_pton(const char *s, u8 *mac); + +int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res); +int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res); +int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res); +int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res); +int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res); +int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res); +int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res); +int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res); +int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res); +int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res); + +static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res) +{ + return kstrtoull_from_user(s, count, base, res); +} + +static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res) +{ + return kstrtoll_from_user(s, count, base, res); +} + +static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res) +{ + return kstrtouint_from_user(s, count, base, res); +} + +static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res) +{ + return kstrtoint_from_user(s, count, base, res); +} + +/* + * This adds a nested function everywhere kfree_rcu() was called. This + * function frees the memory and is given as a function to call_rcu(). + * The rcu callback could happen every time also after the module was + * unloaded and this will cause problems. + */ +#define kfree_rcu(data, rcuhead) do { \ + void __kfree_rcu_fn(struct rcu_head *rcu_head) \ + { \ + void *___ptr; \ + ___ptr = container_of(rcu_head, typeof(*(data)), rcuhead);\ + kfree(___ptr); \ + } \ + call_rcu(&(data)->rcuhead, __kfree_rcu_fn); \ + } while (0) + +#ifdef MODULE + +/* + * The define overwriting module_exit is based on the original module_exit + * which looks like this: + * #define module_exit(exitfn) \ + * static inline exitcall_t __exittest(void) \ + * { return exitfn; } \ + * void cleanup_module(void) __attribute__((alias(#exitfn))); + * + * We replaced the call to the actual function exitfn() with a call to our + * function which calls the original exitfn() and then rcu_barrier() + * + * As a module will not be unloaded that ofter it should not have a big + * performance impact when rcu_barrier() is called on every module exit, + * also when no kfree_rcu() backport is used in that module. + */ +#undef module_exit +#define module_exit(exitfn) \ + static void __exit __exit_compat(void) \ + { \ + exitfn(); \ + rcu_barrier(); \ + } \ + void cleanup_module(void) __attribute__((alias("__exit_compat"))); + +#endif + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) */ + +#endif /* LINUX_3_0_COMPAT_H */ diff --git a/include/compat/linux/compat-3.1.h b/include/compat/linux/compat-3.1.h new file mode 100644 index 00000000..5b00ac96 --- /dev/null +++ b/include/compat/linux/compat-3.1.h @@ -0,0 +1,49 @@ +#ifndef LINUX_3_1_COMPAT_H +#define LINUX_3_1_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)) + +#include + +#define genl_dump_check_consistent(cb, user_hdr, family) + +#define IFF_TX_SKB_SHARING 0x10000 /* The interface supports sharing + * skbs on transmit */ + +#define PCMCIA_DEVICE_MANF_CARD_PROD_ID3(manf, card, v3, vh3) { \ + .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \ + PCMCIA_DEV_ID_MATCH_CARD_ID| \ + PCMCIA_DEV_ID_MATCH_PROD_ID3, \ + .manf_id = (manf), \ + .card_id = (card), \ + .prod_id = { NULL, NULL, (v3), NULL }, \ + .prod_id_hash = { 0, 0, (vh3), 0 }, } + +/* + * This has been defined in include/linux/security.h for some time, but was + * only given an EXPORT_SYMBOL for 3.1. Add a compat_* definition to avoid + * breaking the compile. + */ +#define security_sk_clone(a, b) compat_security_sk_clone(a, b) + +static inline void security_sk_clone(const struct sock *sk, struct sock *newsk) +{ +} + +/* + * In many versions, several architectures do not seem to include an + * atomic64_t implementation, and do not include the software emulation from + * asm-generic/atomic64_t. + * Detect and handle this here. + */ +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)) && !defined(ATOMIC64_INIT) && !defined(CONFIG_X86) && !((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) && defined(CONFIG_ARM) && !defined(CONFIG_GENERIC_ATOMIC64)) +#include +#endif + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)) */ + +#endif /* LINUX_3_1_COMPAT_H */ diff --git a/include/compat/linux/compat-3.2.h b/include/compat/linux/compat-3.2.h new file mode 100644 index 00000000..cb14f0b1 --- /dev/null +++ b/include/compat/linux/compat-3.2.h @@ -0,0 +1,81 @@ +#ifndef LINUX_3_2_COMPAT_H +#define LINUX_3_2_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)) + +#include +#include + +#define PMSG_IS_AUTO(msg) (((msg).event & PM_EVENT_AUTO) != 0) + +/** + * skb_frag_page - retrieve the page refered to by a paged fragment + * @frag: the paged fragment + * + * Returns the &struct page associated with @frag. + */ +static inline struct page *skb_frag_page(const skb_frag_t *frag) +{ + return frag->page; +} + +/** + * skb_frag_dma_map - maps a paged fragment via the DMA API + * @device: the device to map the fragment to + * @frag: the paged fragment to map + * @offset: the offset within the fragment (starting at the + * fragment's own offset) + * @size: the number of bytes to map + * @direction: the direction of the mapping (%PCI_DMA_*) + * + * Maps the page associated with @frag to @device. + */ +static inline dma_addr_t skb_frag_dma_map(struct device *dev, + const skb_frag_t *frag, + size_t offset, size_t size, + enum dma_data_direction dir) +{ + return dma_map_page(dev, skb_frag_page(frag), + frag->page_offset + offset, size, dir); +} + +#define ETH_P_TDLS 0x890D /* TDLS */ + +static inline unsigned int skb_frag_size(const skb_frag_t *frag) +{ + return frag->size; +} + +static inline char *hex_byte_pack(char *buf, u8 byte) +{ + *buf++ = hex_asc_hi(byte); + *buf++ = hex_asc_lo(byte); + return buf; +} + +/* module_platform_driver() - Helper macro for drivers that don't do + * anything special in module init/exit. This eliminates a lot of + * boilerplate. Each module may only use this macro once, and + * calling it replaces module_init() and module_exit() + */ +#define module_platform_driver(__platform_driver) \ + module_driver(__platform_driver, platform_driver_register, \ + platform_driver_unregister) + +static inline void *dma_zalloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + void *ret = dma_alloc_coherent(dev, size, dma_handle, flag); + if (ret) + memset(ret, 0, size); + return ret; +} + +extern int __netdev_printk(const char *level, const struct net_device *dev, + struct va_format *vaf); + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)) */ + +#endif /* LINUX_3_2_COMPAT_H */ diff --git a/include/compat/linux/compat-3.3.h b/include/compat/linux/compat-3.3.h new file mode 100644 index 00000000..4965f234 --- /dev/null +++ b/include/compat/linux/compat-3.3.h @@ -0,0 +1,56 @@ +#ifndef LINUX_3_3_COMPAT_H +#define LINUX_3_3_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)) + +/* include to override NL80211_FEATURE_SK_TX_STATUS */ +#include + +static inline void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) +{ + WARN_ON(1); +} +#define NL80211_FEATURE_SK_TX_STATUS 0 + +typedef u32 netdev_features_t; + +/* source include/linux/device.h */ +/** + * module_driver() - Helper macro for drivers that don't do anything + * special in module init/exit. This eliminates a lot of boilerplate. + * Each module may only use this macro once, and calling it replaces + * module_init() and module_exit(). + * + * Use this macro to construct bus specific macros for registering + * drivers, and do not use it on its own. + */ +#define module_driver(__driver, __register, __unregister) \ +static int __init __driver##_init(void) \ +{ \ + return __register(&(__driver)); \ +} \ +module_init(__driver##_init); \ +static void __exit __driver##_exit(void) \ +{ \ + __unregister(&(__driver)); \ +} \ +module_exit(__driver##_exit); + +/* source include/linux/usb.h */ +/** + * module_usb_driver() - Helper macro for registering a USB driver + * @__usb_driver: usb_driver struct + * + * Helper macro for USB drivers which do not do anything special in module + * init/exit. This eliminates a lot of boilerplate. Each module may only + * use this macro once, and calling it replaces module_init() and module_exit() + */ +#define module_usb_driver(__usb_driver) \ + module_driver(__usb_driver, usb_register, \ + usb_deregister) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)) */ + +#endif /* LINUX_3_3_COMPAT_H */ diff --git a/include/compat/linux/compat-3.4.h b/include/compat/linux/compat-3.4.h new file mode 100644 index 00000000..1b723742 --- /dev/null +++ b/include/compat/linux/compat-3.4.h @@ -0,0 +1,80 @@ +#ifndef LINUX_3_4_COMPAT_H +#define LINUX_3_4_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) + +#include +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) +#define skb_add_rx_frag(skb, i, page, off, size, truesize) \ + v2_6_28_skb_add_rx_frag(skb, i, page, off, size) +#else +#define skb_add_rx_frag(skb, i, page, off, size, truesize) \ + skb_add_rx_frag(skb, i, page, off, size) +#endif + +#ifdef CONFIG_X86_X32_ABI +#define COMPAT_USE_64BIT_TIME \ + (!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)) +#else +#define COMPAT_USE_64BIT_TIME 0 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)) +static inline void eth_hw_addr_random(struct net_device *dev) +{ +#error eth_hw_addr_random() needs to be implemented for < 2.6.12 +} +#else /* kernels >= 2.6.12 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) +static inline void eth_hw_addr_random(struct net_device *dev) +{ + get_random_bytes(dev->dev_addr, ETH_ALEN); + dev->dev_addr[0] &= 0xfe; /* clear multicast bit */ + dev->dev_addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ +} +#else /* kernels >= 2.6.31 */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) +/* So this is 2.6.31..2.6.35 */ + +/* Just have the flags present, they won't really mean anything though */ +#define NET_ADDR_PERM 0 /* address is permanent (default) */ +#define NET_ADDR_RANDOM 1 /* address is generated randomly */ +#define NET_ADDR_STOLEN 2 /* address is stolen from other device */ + +static inline void eth_hw_addr_random(struct net_device *dev) +{ + random_ether_addr(dev->dev_addr); +} + +#else /* 2.6.36 and on */ +static inline void eth_hw_addr_random(struct net_device *dev) +{ + dev_hw_addr_random(dev, dev->dev_addr); +} +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) */ + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) */ +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)) */ + +/* source include/linux/pci.h */ +/** + * module_pci_driver() - Helper macro for registering a PCI driver + * @__pci_driver: pci_driver struct + * + * Helper macro for PCI drivers which do not do anything special in module + * init/exit. This eliminates a lot of boilerplate. Each module may only + * use this macro once, and calling it replaces module_init() and module_exit() + */ +#define module_pci_driver(__pci_driver) \ + module_driver(__pci_driver, pci_register_driver, \ + pci_unregister_driver) + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) */ + +#endif /* LINUX_5_4_COMPAT_H */ diff --git a/include/compat/linux/compat-3.5.h b/include/compat/linux/compat-3.5.h new file mode 100644 index 00000000..9c10a428 --- /dev/null +++ b/include/compat/linux/compat-3.5.h @@ -0,0 +1,13 @@ +#ifndef LINUX_3_5_COMPAT_H +#define LINUX_3_5_COMPAT_H + +#include +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)) + +extern int simple_open(struct inode *inode, struct file *file); + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)) */ + +#endif /* LINUX_3_5_COMPAT_H */ diff --git a/include/compat/linux/compat_autoconf.h b/include/compat/linux/compat_autoconf.h new file mode 100644 index 00000000..813755c6 --- /dev/null +++ b/include/compat/linux/compat_autoconf.h @@ -0,0 +1,37 @@ +#ifndef COMPAT_AUTOCONF_INCLUDED +#define COMPAT_AUTOCONF_INCLUDED + +/* + * This is an example of a compat autconf header file that gets + * automatically generated by your projet. You will only need this + * if you are working with a lot of config options. + * + * Your project will likely just override this, or leave this as-is. + */ + +/* + * Example automatically generated C config: don't edit + * Thu Dec 10 10:34:11 PST 2009 + * compat-wireless-2.6: master-2009-11-19-5-gb4fd4dd + * linux-2.6: next-20091208 + */ +//#define COMPAT_PROJECT_FOO_RELEASE "master-2009-11-19-5-gb4fd4dd" +//#define COMPAT_UPSTREAM_FOO_KERNEL_RELEASE "next-20091208" + +/* Example kernel version minimum requirement */ +//#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) +//#error Compat-wireless requirement: Linux >= 2,6,10 +//#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) */ + +/* Example hard requirement */ +//#error Compat-wireless requirement: CONFIG_WIRELESS_EXT must be enabled in your kernel +//#endif /* CONFIG_WIRELESS_EXT */ + +/* + * Example of how to match your external modules kconfig options into this. + * You'll need something to generate this for you. + */ +//#ifndef CONFIG_FOO_BAR +//#define CONFIG_FOO_BAR 1 + +#endif /* COMPAT_AUTOCONF_INCLUDED */ diff --git a/include/compat/linux/cordic.h b/include/compat/linux/cordic.h new file mode 100644 index 00000000..f932093e --- /dev/null +++ b/include/compat/linux/cordic.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, 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. + */ +#ifndef __CORDIC_H_ +#define __CORDIC_H_ + +#include + +/** + * struct cordic_iq - i/q coordinate. + * + * @i: real part of coordinate (in phase). + * @q: imaginary part of coordinate (quadrature). + */ +struct cordic_iq { + s32 i; + s32 q; +}; + +/** + * cordic_calc_iq() - calculates the i/q coordinate for given angle. + * + * @theta: angle in degrees for which i/q coordinate is to be calculated. + * @coord: function output parameter holding the i/q coordinate. + * + * The function calculates the i/q coordinate for a given angle using + * cordic algorithm. The coordinate consists of a real (i) and an + * imaginary (q) part. The real part is essentially the cosine of the + * angle and the imaginary part is the sine of the angle. The returned + * values are scaled by 2^16 for precision. The range for theta is + * for -180 degrees to +180 degrees. Passed values outside this range are + * converted before doing the actual calculation. + */ +struct cordic_iq cordic_calc_iq(s32 theta); + +#endif /* __CORDIC_H_ */ diff --git a/include/compat/linux/crc8.h b/include/compat/linux/crc8.h new file mode 100644 index 00000000..13c8dabb --- /dev/null +++ b/include/compat/linux/crc8.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, 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. + */ +#ifndef __CRC8_H_ +#define __CRC8_H_ + +#include + +/* see usage of this value in crc8() description */ +#define CRC8_INIT_VALUE 0xFF + +/* + * Return value of crc8() indicating valid message+crc. This is true + * if a CRC is inverted before transmission. The CRC computed over the + * whole received bitstream is _table[x], where x is the bit pattern + * of the modification (almost always 0xff). + */ +#define CRC8_GOOD_VALUE(_table) (_table[0xFF]) + +/* required table size for crc8 algorithm */ +#define CRC8_TABLE_SIZE 256 + +/* helper macro assuring right table size is used */ +#define DECLARE_CRC8_TABLE(_table) \ + static u8 _table[CRC8_TABLE_SIZE] + +/** + * crc8_populate_lsb - fill crc table for given polynomial in regular bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + * + * This function fills the provided table according the polynomial provided for + * regular bit order (lsb first). Polynomials in CRC algorithms are typically + * represented as shown below. + * + * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1 + * + * For lsb first direction x^7 maps to the lsb. So the polynomial is as below. + * + * - lsb first: poly = 10101011(1) = 0xAB + */ +void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial); + +/** + * crc8_populate_msb - fill crc table for given polynomial in reverse bit order. + * + * @table: table to be filled. + * @polynomial: polynomial for which table is to be filled. + * + * This function fills the provided table according the polynomial provided for + * reverse bit order (msb first). Polynomials in CRC algorithms are typically + * represented as shown below. + * + * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1 + * + * For msb first direction x^7 maps to the msb. So the polynomial is as below. + * + * - msb first: poly = (1)11010101 = 0xD5 + */ +void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial); + +/** + * crc8() - calculate a crc8 over the given input data. + * + * @table: crc table used for calculation. + * @pdata: pointer to data buffer. + * @nbytes: number of bytes in data buffer. + * @crc: previous returned crc8 value. + * + * The CRC8 is calculated using the polynomial given in crc8_populate_msb() + * or crc8_populate_lsb(). + * + * The caller provides the initial value (either %CRC8_INIT_VALUE + * or the previous returned value) to allow for processing of + * discontiguous blocks of data. When generating the CRC the + * caller is responsible for complementing the final return value + * and inserting it into the byte stream. When validating a byte + * stream (including CRC8), a final return value of %CRC8_GOOD_VALUE + * indicates the byte stream data can be considered valid. + * + * Reference: + * "A Painless Guide to CRC Error Detection Algorithms", ver 3, Aug 1993 + * Williams, Ross N., rossross.net + * (see URL http://www.ross.net/crc/download/crc_v3.txt). + */ +u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc); + +#endif /* __CRC8_H_ */ diff --git a/include/compat/linux/eeprom_93cx6.h b/include/compat/linux/eeprom_93cx6.h new file mode 100644 index 00000000..c4627cbd --- /dev/null +++ b/include/compat/linux/eeprom_93cx6.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2004 - 2006 rt2x00 SourceForge Project + + + 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. + */ + +/* + Module: eeprom_93cx6 + Abstract: EEPROM reader datastructures for 93cx6 chipsets. + Supported chipsets: 93c46, 93c56 and 93c66. + */ + +/* + * EEPROM operation defines. + */ +#define PCI_EEPROM_WIDTH_93C46 6 +#define PCI_EEPROM_WIDTH_93C56 8 +#define PCI_EEPROM_WIDTH_93C66 8 +#define PCI_EEPROM_WIDTH_93C86 8 +#define PCI_EEPROM_WIDTH_OPCODE 3 +#define PCI_EEPROM_WRITE_OPCODE 0x05 +#define PCI_EEPROM_READ_OPCODE 0x06 +#define PCI_EEPROM_EWDS_OPCODE 0x10 +#define PCI_EEPROM_EWEN_OPCODE 0x13 + +/** + * struct eeprom_93cx6 - control structure for setting the commands + * for reading the eeprom data. + * @data: private pointer for the driver. + * @register_read(struct eeprom_93cx6 *eeprom): handler to + * read the eeprom register, this function should set all reg_* fields. + * @register_write(struct eeprom_93cx6 *eeprom): handler to + * write to the eeprom register by using all reg_* fields. + * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines + * @reg_data_in: register field to indicate data input + * @reg_data_out: register field to indicate data output + * @reg_data_clock: register field to set the data clock + * @reg_chip_select: register field to set the chip select + * + * This structure is used for the communication between the driver + * and the eeprom_93cx6 handlers for reading the eeprom. + */ +struct eeprom_93cx6 { + void *data; + + void (*register_read)(struct eeprom_93cx6 *eeprom); + void (*register_write)(struct eeprom_93cx6 *eeprom); + + int width; + + char reg_data_in; + char reg_data_out; + char reg_data_clock; + char reg_chip_select; +}; + +extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, + const u8 word, u16 *data); +extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, + const u8 word, __le16 *data, const u16 words); diff --git a/include/compat/linux/export.h b/include/compat/linux/export.h new file mode 100644 index 00000000..a0ced3ea --- /dev/null +++ b/include/compat/linux/export.h @@ -0,0 +1,12 @@ +#ifndef _COMPAT_LINUX_EXPORT_H +#define _COMPAT_LINUX_EXPORT_H 1 + +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)) +#include_next +#else +#include +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) */ + +#endif /* _COMPAT_LINUX_EXPORT_H */ diff --git a/include/compat/linux/ieee80211.h b/include/compat/linux/ieee80211.h new file mode 100644 index 00000000..66cedf6e --- /dev/null +++ b/include/compat/linux/ieee80211.h @@ -0,0 +1,1852 @@ +/* + * IEEE 802.11 defines + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * Copyright (c) 2005, Devicescape Software, Inc. + * Copyright (c) 2006, Michael Wu + * + * 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 LINUX_IEEE80211_H +#define LINUX_IEEE80211_H + +#include +#include + +/* + * DS bit usage + * + * TA = transmitter address + * RA = receiver address + * DA = destination address + * SA = source address + * + * ToDS FromDS A1(RA) A2(TA) A3 A4 Use + * ----------------------------------------------------------------- + * 0 0 DA SA BSSID - IBSS/DLS + * 0 1 DA BSSID SA - AP -> STA + * 1 0 BSSID SA DA - AP <- STA + * 1 1 RA TA DA SA unspecified (WDS) + */ + +#define FCS_LEN 4 + +#define IEEE80211_FCTL_VERS 0x0003 +#define IEEE80211_FCTL_FTYPE 0x000c +#define IEEE80211_FCTL_STYPE 0x00f0 +#define IEEE80211_FCTL_TODS 0x0100 +#define IEEE80211_FCTL_FROMDS 0x0200 +#define IEEE80211_FCTL_MOREFRAGS 0x0400 +#define IEEE80211_FCTL_RETRY 0x0800 +#define IEEE80211_FCTL_PM 0x1000 +#define IEEE80211_FCTL_MOREDATA 0x2000 +#define IEEE80211_FCTL_PROTECTED 0x4000 +#define IEEE80211_FCTL_ORDER 0x8000 + +#define IEEE80211_SCTL_FRAG 0x000F +#define IEEE80211_SCTL_SEQ 0xFFF0 + +#define IEEE80211_FTYPE_MGMT 0x0000 +#define IEEE80211_FTYPE_CTL 0x0004 +#define IEEE80211_FTYPE_DATA 0x0008 + +/* management */ +#define IEEE80211_STYPE_ASSOC_REQ 0x0000 +#define IEEE80211_STYPE_ASSOC_RESP 0x0010 +#define IEEE80211_STYPE_REASSOC_REQ 0x0020 +#define IEEE80211_STYPE_REASSOC_RESP 0x0030 +#define IEEE80211_STYPE_PROBE_REQ 0x0040 +#define IEEE80211_STYPE_PROBE_RESP 0x0050 +#define IEEE80211_STYPE_BEACON 0x0080 +#define IEEE80211_STYPE_ATIM 0x0090 +#define IEEE80211_STYPE_DISASSOC 0x00A0 +#define IEEE80211_STYPE_AUTH 0x00B0 +#define IEEE80211_STYPE_DEAUTH 0x00C0 +#define IEEE80211_STYPE_ACTION 0x00D0 + +/* control */ +#define IEEE80211_STYPE_BACK_REQ 0x0080 +#define IEEE80211_STYPE_BACK 0x0090 +#define IEEE80211_STYPE_PSPOLL 0x00A0 +#define IEEE80211_STYPE_RTS 0x00B0 +#define IEEE80211_STYPE_CTS 0x00C0 +#define IEEE80211_STYPE_ACK 0x00D0 +#define IEEE80211_STYPE_CFEND 0x00E0 +#define IEEE80211_STYPE_CFENDACK 0x00F0 + +/* data */ +#define IEEE80211_STYPE_DATA 0x0000 +#define IEEE80211_STYPE_DATA_CFACK 0x0010 +#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 +#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 +#define IEEE80211_STYPE_NULLFUNC 0x0040 +#define IEEE80211_STYPE_CFACK 0x0050 +#define IEEE80211_STYPE_CFPOLL 0x0060 +#define IEEE80211_STYPE_CFACKPOLL 0x0070 +#define IEEE80211_STYPE_QOS_DATA 0x0080 +#define IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 +#define IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 +#define IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 +#define IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 +#define IEEE80211_STYPE_QOS_CFACK 0x00D0 +#define IEEE80211_STYPE_QOS_CFPOLL 0x00E0 +#define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 + + +/* miscellaneous IEEE 802.11 constants */ +#define IEEE80211_MAX_FRAG_THRESHOLD 2352 +#define IEEE80211_MAX_RTS_THRESHOLD 2353 +#define IEEE80211_MAX_AID 2007 +#define IEEE80211_MAX_TIM_LEN 251 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + 802.11e clarifies the figure in section 7.1.2. The frame body is + up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */ +#define IEEE80211_MAX_DATA_LEN 2304 +/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ +#define IEEE80211_MAX_FRAME_LEN 2352 + +#define IEEE80211_MAX_SSID_LEN 32 + +#define IEEE80211_MAX_MESH_ID_LEN 32 + +#define IEEE80211_QOS_CTL_LEN 2 +/* 1d tag mask */ +#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 +/* TID mask */ +#define IEEE80211_QOS_CTL_TID_MASK 0x000f +/* EOSP */ +#define IEEE80211_QOS_CTL_EOSP 0x0010 +/* ACK policy */ +#define IEEE80211_QOS_CTL_ACK_POLICY_NORMAL 0x0000 +#define IEEE80211_QOS_CTL_ACK_POLICY_NOACK 0x0020 +#define IEEE80211_QOS_CTL_ACK_POLICY_NO_EXPL 0x0040 +#define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK 0x0060 +#define IEEE80211_QOS_CTL_ACK_POLICY_MASK 0x0060 +/* A-MSDU 802.11n */ +#define IEEE80211_QOS_CTL_A_MSDU_PRESENT 0x0080 +/* Mesh Control 802.11s */ +#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100 + +/* U-APSD queue for WMM IEs sent by AP */ +#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) +#define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK 0x0f + +/* U-APSD queues for WMM IEs sent by STA */ +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO (1<<0) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI (1<<1) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK (1<<2) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE (1<<3) +#define IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK 0x0f + +/* U-APSD max SP length for WMM IEs sent by STA */ +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0x00 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_2 0x01 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_4 0x02 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_6 0x03 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03 +#define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5 + +#define IEEE80211_HT_CTL_LEN 4 + +struct ieee80211_hdr { + __le16 frame_control; + __le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + __le16 seq_ctrl; + u8 addr4[6]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_3addr { + __le16 frame_control; + __le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + __le16 seq_ctrl; +} __attribute__ ((packed)); + +struct ieee80211_qos_hdr { + __le16 frame_control; + __le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + __le16 seq_ctrl; + __le16 qos_ctrl; +} __attribute__ ((packed)); + +/** + * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_tods(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_TODS)) != 0; +} + +/** + * ieee80211_has_fromds - check if IEEE80211_FCTL_FROMDS is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_fromds(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FROMDS)) != 0; +} + +/** + * ieee80211_has_a4 - check if IEEE80211_FCTL_TODS and IEEE80211_FCTL_FROMDS are set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_a4(__le16 fc) +{ + __le16 tmp = cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); + return (fc & tmp) == tmp; +} + +/** + * ieee80211_has_morefrags - check if IEEE80211_FCTL_MOREFRAGS is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_morefrags(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) != 0; +} + +/** + * ieee80211_has_retry - check if IEEE80211_FCTL_RETRY is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_retry(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_RETRY)) != 0; +} + +/** + * ieee80211_has_pm - check if IEEE80211_FCTL_PM is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_pm(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_PM)) != 0; +} + +/** + * ieee80211_has_moredata - check if IEEE80211_FCTL_MOREDATA is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_moredata(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) != 0; +} + +/** + * ieee80211_has_protected - check if IEEE80211_FCTL_PROTECTED is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_protected(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_PROTECTED)) != 0; +} + +/** + * ieee80211_has_order - check if IEEE80211_FCTL_ORDER is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_has_order(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_ORDER)) != 0; +} + +/** + * ieee80211_is_mgmt - check if type is IEEE80211_FTYPE_MGMT + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_mgmt(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT); +} + +/** + * ieee80211_is_ctl - check if type is IEEE80211_FTYPE_CTL + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_ctl(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL); +} + +/** + * ieee80211_is_data - check if type is IEEE80211_FTYPE_DATA + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_data(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_DATA); +} + +/** + * ieee80211_is_data_qos - check if type is IEEE80211_FTYPE_DATA and IEEE80211_STYPE_QOS_DATA is set + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_data_qos(__le16 fc) +{ + /* + * mask with QOS_DATA rather than IEEE80211_FCTL_STYPE as we just need + * to check the one bit + */ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_STYPE_QOS_DATA)) == + cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA); +} + +/** + * ieee80211_is_data_present - check if type is IEEE80211_FTYPE_DATA and has data + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_data_present(__le16 fc) +{ + /* + * mask with 0x40 and test that that bit is clear to only return true + * for the data-containing substypes. + */ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | 0x40)) == + cpu_to_le16(IEEE80211_FTYPE_DATA); +} + +/** + * ieee80211_is_assoc_req - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ASSOC_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_assoc_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_REQ); +} + +/** + * ieee80211_is_assoc_resp - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ASSOC_RESP + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_assoc_resp(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_RESP); +} + +/** + * ieee80211_is_reassoc_req - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_REASSOC_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_reassoc_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); +} + +/** + * ieee80211_is_reassoc_resp - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_REASSOC_RESP + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_reassoc_resp(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_RESP); +} + +/** + * ieee80211_is_probe_req - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_PROBE_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_probe_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ); +} + +/** + * ieee80211_is_probe_resp - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_PROBE_RESP + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_probe_resp(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); +} + +/** + * ieee80211_is_beacon - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_BEACON + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_beacon(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); +} + +/** + * ieee80211_is_atim - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ATIM + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_atim(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ATIM); +} + +/** + * ieee80211_is_disassoc - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_DISASSOC + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_disassoc(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC); +} + +/** + * ieee80211_is_auth - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_AUTH + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_auth(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); +} + +/** + * ieee80211_is_deauth - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_DEAUTH + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_deauth(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); +} + +/** + * ieee80211_is_action - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ACTION + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_action(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); +} + +/** + * ieee80211_is_back_req - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_BACK_REQ + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_back_req(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); +} + +/** + * ieee80211_is_back - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_BACK + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_back(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK); +} + +/** + * ieee80211_is_pspoll - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_PSPOLL + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_pspoll(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); +} + +/** + * ieee80211_is_rts - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_RTS + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_rts(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); +} + +/** + * ieee80211_is_cts - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_CTS + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_cts(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); +} + +/** + * ieee80211_is_ack - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_ACK + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_ack(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK); +} + +/** + * ieee80211_is_cfend - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_CFEND + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_cfend(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CFEND); +} + +/** + * ieee80211_is_cfendack - check if IEEE80211_FTYPE_CTL && IEEE80211_STYPE_CFENDACK + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_cfendack(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CFENDACK); +} + +/** + * ieee80211_is_nullfunc - check if frame is a regular (non-QoS) nullfunc frame + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_nullfunc(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC); +} + +/** + * ieee80211_is_qos_nullfunc - check if frame is a QoS nullfunc frame + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_qos_nullfunc(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); +} + +struct ieee80211s_hdr { + u8 flags; + u8 ttl; + __le32 seqnum; + u8 eaddr1[6]; + u8 eaddr2[6]; +} __attribute__ ((packed)); + +/* Mesh flags */ +#define MESH_FLAGS_AE_A4 0x1 +#define MESH_FLAGS_AE_A5_A6 0x2 +#define MESH_FLAGS_AE 0x3 +#define MESH_FLAGS_PS_DEEP 0x4 + +/** + * struct ieee80211_quiet_ie + * + * This structure refers to "Quiet information element" + */ +struct ieee80211_quiet_ie { + u8 count; + u8 period; + __le16 duration; + __le16 offset; +} __attribute__ ((packed)); + +/** + * struct ieee80211_msrment_ie + * + * This structure refers to "Measurement Request/Report information element" + */ +struct ieee80211_msrment_ie { + u8 token; + u8 mode; + u8 type; + u8 request[0]; +} __attribute__ ((packed)); + +/** + * struct ieee80211_channel_sw_ie + * + * This structure refers to "Channel Switch Announcement information element" + */ +struct ieee80211_channel_sw_ie { + u8 mode; + u8 new_ch_num; + u8 count; +} __attribute__ ((packed)); + +/** + * struct ieee80211_tim + * + * This structure refers to "Traffic Indication Map information element" + */ +struct ieee80211_tim_ie { + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + /* variable size: 1 - 251 bytes */ + u8 virtual_map[1]; +} __attribute__ ((packed)); + +/** + * struct ieee80211_meshconf_ie + * + * This structure refers to "Mesh Configuration information element" + */ +struct ieee80211_meshconf_ie { + u8 meshconf_psel; + u8 meshconf_pmetric; + u8 meshconf_congest; + u8 meshconf_synch; + u8 meshconf_auth; + u8 meshconf_form; + u8 meshconf_cap; +} __attribute__ ((packed)); + +/** + * struct ieee80211_rann_ie + * + * This structure refers to "Root Announcement information element" + */ +struct ieee80211_rann_ie { + u8 rann_flags; + u8 rann_hopcount; + u8 rann_ttl; + u8 rann_addr[6]; + u32 rann_seq; + u32 rann_interval; + u32 rann_metric; +} __attribute__ ((packed)); + +enum ieee80211_rann_flags { + RANN_FLAG_IS_GATE = 1 << 0, +}; + +#define WLAN_SA_QUERY_TR_ID_LEN 2 + +struct ieee80211_mgmt { + __le16 frame_control; + __le16 duration; + u8 da[6]; + u8 sa[6]; + u8 bssid[6]; + __le16 seq_ctrl; + union { + struct { + __le16 auth_alg; + __le16 auth_transaction; + __le16 status_code; + /* possibly followed by Challenge text */ + u8 variable[0]; + } __attribute__ ((packed)) auth; + struct { + __le16 reason_code; + } __attribute__ ((packed)) deauth; + struct { + __le16 capab_info; + __le16 listen_interval; + /* followed by SSID and Supported rates */ + u8 variable[0]; + } __attribute__ ((packed)) assoc_req; + struct { + __le16 capab_info; + __le16 status_code; + __le16 aid; + /* followed by Supported rates */ + u8 variable[0]; + } __attribute__ ((packed)) assoc_resp, reassoc_resp; + struct { + __le16 capab_info; + __le16 listen_interval; + u8 current_ap[6]; + /* followed by SSID and Supported rates */ + u8 variable[0]; + } __attribute__ ((packed)) reassoc_req; + struct { + __le16 reason_code; + } __attribute__ ((packed)) disassoc; + struct { + __le64 timestamp; + __le16 beacon_int; + __le16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params, TIM */ + u8 variable[0]; + } __attribute__ ((packed)) beacon; + struct { + /* only variable items: SSID, Supported rates */ + u8 variable[0]; + } __attribute__ ((packed)) probe_req; + struct { + __le64 timestamp; + __le16 beacon_int; + __le16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params */ + u8 variable[0]; + } __attribute__ ((packed)) probe_resp; + struct { + u8 category; + union { + struct { + u8 action_code; + u8 dialog_token; + u8 status_code; + u8 variable[0]; + } __attribute__ ((packed)) wme_action; + struct{ + u8 action_code; + u8 element_id; + u8 length; + struct ieee80211_channel_sw_ie sw_elem; + } __attribute__((packed)) chan_switch; + struct{ + u8 action_code; + u8 dialog_token; + u8 element_id; + u8 length; + struct ieee80211_msrment_ie msr_elem; + } __attribute__((packed)) measurement; + struct{ + u8 action_code; + u8 dialog_token; + __le16 capab; + __le16 timeout; + __le16 start_seq_num; + } __attribute__((packed)) addba_req; + struct{ + u8 action_code; + u8 dialog_token; + __le16 status; + __le16 capab; + __le16 timeout; + } __attribute__((packed)) addba_resp; + struct{ + u8 action_code; + __le16 params; + __le16 reason_code; + } __attribute__((packed)) delba; + struct { + u8 action_code; + u8 variable[0]; + } __attribute__((packed)) self_prot; + struct{ + u8 action_code; + u8 variable[0]; + } __attribute__((packed)) mesh_action; + struct { + u8 action; + u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; + } __attribute__ ((packed)) sa_query; + struct { + u8 action; + u8 smps_control; + } __attribute__ ((packed)) ht_smps; + struct { + u8 action_code; + u8 dialog_token; + __le16 capability; + u8 variable[0]; + } __packed tdls_discover_resp; + } u; + } __attribute__ ((packed)) action; + } u; +} __attribute__ ((packed)); + +/* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */ +#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 + +/* mgmt header + 1 byte category code */ +#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u) + + +/* Management MIC information element (IEEE 802.11w) */ +struct ieee80211_mmie { + u8 element_id; + u8 length; + __le16 key_id; + u8 sequence_number[6]; + u8 mic[8]; +} __attribute__ ((packed)); + +struct ieee80211_vendor_ie { + u8 element_id; + u8 len; + u8 oui[3]; + u8 oui_type; +} __packed; + +/* Control frames */ +struct ieee80211_rts { + __le16 frame_control; + __le16 duration; + u8 ra[6]; + u8 ta[6]; +} __attribute__ ((packed)); + +struct ieee80211_cts { + __le16 frame_control; + __le16 duration; + u8 ra[6]; +} __attribute__ ((packed)); + +struct ieee80211_pspoll { + __le16 frame_control; + __le16 aid; + u8 bssid[6]; + u8 ta[6]; +} __attribute__ ((packed)); + +/* TDLS */ + +/* Link-id information element */ +struct ieee80211_tdls_lnkie { + u8 ie_type; /* Link Identifier IE */ + u8 ie_len; + u8 bssid[6]; + u8 init_sta[6]; + u8 resp_sta[6]; +} __packed; + +struct ieee80211_tdls_data { + u8 da[6]; + u8 sa[6]; + __be16 ether_type; + u8 payload_type; + u8 category; + u8 action_code; + union { + struct { + u8 dialog_token; + __le16 capability; + u8 variable[0]; + } __packed setup_req; + struct { + __le16 status_code; + u8 dialog_token; + __le16 capability; + u8 variable[0]; + } __packed setup_resp; + struct { + __le16 status_code; + u8 dialog_token; + u8 variable[0]; + } __packed setup_cfm; + struct { + __le16 reason_code; + u8 variable[0]; + } __packed teardown; + struct { + u8 dialog_token; + u8 variable[0]; + } __packed discover_req; + } u; +} __packed; + +/** + * struct ieee80211_bar - HT Block Ack Request + * + * This structure refers to "HT BlockAckReq" as + * described in 802.11n draft section 7.2.1.7.1 + */ +struct ieee80211_bar { + __le16 frame_control; + __le16 duration; + __u8 ra[6]; + __u8 ta[6]; + __le16 control; + __le16 start_seq_num; +} __attribute__((packed)); + +/* 802.11 BAR control masks */ +#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 +#define IEEE80211_BAR_CTRL_MULTI_TID 0x0002 +#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 +#define IEEE80211_BAR_CTRL_TID_INFO_MASK 0xf000 +#define IEEE80211_BAR_CTRL_TID_INFO_SHIFT 12 + +#define IEEE80211_HT_MCS_MASK_LEN 10 + +/** + * struct ieee80211_mcs_info - MCS information + * @rx_mask: RX mask + * @rx_highest: highest supported RX rate. If set represents + * the highest supported RX data rate in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. + * @tx_params: TX parameters + */ +struct ieee80211_mcs_info { + u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN]; + __le16 rx_highest; + u8 tx_params; + u8 reserved[3]; +} __attribute__((packed)); + +/* 802.11n HT capability MSC set */ +#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff +#define IEEE80211_HT_MCS_TX_DEFINED 0x01 +#define IEEE80211_HT_MCS_TX_RX_DIFF 0x02 +/* value 0 == 1 stream etc */ +#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK 0x0C +#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT 2 +#define IEEE80211_HT_MCS_TX_MAX_STREAMS 4 +#define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION 0x10 + +/* + * 802.11n D5.0 20.3.5 / 20.6 says: + * - indices 0 to 7 and 32 are single spatial stream + * - 8 to 31 are multiple spatial streams using equal modulation + * [8..15 for two streams, 16..23 for three and 24..31 for four] + * - remainder are multiple spatial streams using unequal modulation + */ +#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33 +#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \ + (IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8) + +/** + * struct ieee80211_ht_cap - HT capabilities + * + * This structure is the "HT capabilities element" as + * described in 802.11n D5.0 7.3.2.57 + */ +struct ieee80211_ht_cap { + __le16 cap_info; + u8 ampdu_params_info; + + /* 16 bytes MCS information */ + struct ieee80211_mcs_info mcs; + + __le16 extended_ht_cap_info; + __le32 tx_BF_cap_info; + u8 antenna_selection_info; +} __attribute__ ((packed)); + +/* 802.11n HT capabilities masks (for cap_info) */ +#define IEEE80211_HT_CAP_LDPC_CODING 0x0001 +#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 +#define IEEE80211_HT_CAP_SM_PS 0x000C +#define IEEE80211_HT_CAP_SM_PS_SHIFT 2 +#define IEEE80211_HT_CAP_GRN_FLD 0x0010 +#define IEEE80211_HT_CAP_SGI_20 0x0020 +#define IEEE80211_HT_CAP_SGI_40 0x0040 +#define IEEE80211_HT_CAP_TX_STBC 0x0080 +#define IEEE80211_HT_CAP_RX_STBC 0x0300 +#define IEEE80211_HT_CAP_RX_STBC_SHIFT 8 +#define IEEE80211_HT_CAP_DELAY_BA 0x0400 +#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 +#define IEEE80211_HT_CAP_RESERVED 0x2000 +#define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000 +#define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 + +/* 802.11n HT extended capabilities masks (for extended_ht_cap_info) */ +#define IEEE80211_HT_EXT_CAP_PCO 0x0001 +#define IEEE80211_HT_EXT_CAP_PCO_TIME 0x0006 +#define IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT 1 +#define IEEE80211_HT_EXT_CAP_MCS_FB 0x0300 +#define IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT 8 +#define IEEE80211_HT_EXT_CAP_HTC_SUP 0x0400 +#define IEEE80211_HT_EXT_CAP_RD_RESPONDER 0x0800 + +/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ +#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 +#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C +#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2 + +/* + * Maximum length of AMPDU that the STA can receive. + * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) + */ +enum ieee80211_max_ampdu_length_exp { + IEEE80211_HT_MAX_AMPDU_8K = 0, + IEEE80211_HT_MAX_AMPDU_16K = 1, + IEEE80211_HT_MAX_AMPDU_32K = 2, + IEEE80211_HT_MAX_AMPDU_64K = 3 +}; + +#define IEEE80211_HT_MAX_AMPDU_FACTOR 13 + +/* Minimum MPDU start spacing */ +enum ieee80211_min_mpdu_spacing { + IEEE80211_HT_MPDU_DENSITY_NONE = 0, /* No restriction */ + IEEE80211_HT_MPDU_DENSITY_0_25 = 1, /* 1/4 usec */ + IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 usec */ + IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 usec */ + IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 usec */ + IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4 usec */ + IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8 usec */ + IEEE80211_HT_MPDU_DENSITY_16 = 7 /* 16 usec */ +}; + +/** + * struct ieee80211_ht_info - HT information + * + * This structure is the "HT information element" as + * described in 802.11n D5.0 7.3.2.58 + */ +struct ieee80211_ht_info { + u8 control_chan; + u8 ht_param; + __le16 operation_mode; + __le16 stbc_param; + u8 basic_set[16]; +} __attribute__ ((packed)); + +/* for ht_param */ +#define IEEE80211_HT_PARAM_CHA_SEC_OFFSET 0x03 +#define IEEE80211_HT_PARAM_CHA_SEC_NONE 0x00 +#define IEEE80211_HT_PARAM_CHA_SEC_ABOVE 0x01 +#define IEEE80211_HT_PARAM_CHA_SEC_BELOW 0x03 +#define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY 0x04 +#define IEEE80211_HT_PARAM_RIFS_MODE 0x08 +#define IEEE80211_HT_PARAM_SPSMP_SUPPORT 0x10 +#define IEEE80211_HT_PARAM_SERV_INTERVAL_GRAN 0xE0 + +/* for operation_mode */ +#define IEEE80211_HT_OP_MODE_PROTECTION 0x0003 +#define IEEE80211_HT_OP_MODE_PROTECTION_NONE 0 +#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER 1 +#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ 2 +#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3 +#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004 +#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010 + +/* for stbc_param */ +#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040 +#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT 0x0080 +#define IEEE80211_HT_STBC_PARAM_STBC_BEACON 0x0100 +#define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT 0x0200 +#define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE 0x0400 +#define IEEE80211_HT_STBC_PARAM_PCO_PHASE 0x0800 + + +/* block-ack parameters */ +#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 +#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C +#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0 +#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 +#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 + +/* + * A-PMDU buffer sizes + * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) + */ +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_MAX_AMPDU_BUF 0x40 + + +/* Spatial Multiplexing Power Save Modes (for capability) */ +#define WLAN_HT_CAP_SM_PS_STATIC 0 +#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 +#define WLAN_HT_CAP_SM_PS_INVALID 2 +#define WLAN_HT_CAP_SM_PS_DISABLED 3 + +/* for SM power control field lower two bits */ +#define WLAN_HT_SMPS_CONTROL_DISABLED 0 +#define WLAN_HT_SMPS_CONTROL_STATIC 1 +#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 +#define WLAN_AUTH_FT 2 +#define WLAN_AUTH_SAE 3 +#define WLAN_AUTH_LEAP 128 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_ESS (1<<0) +#define WLAN_CAPABILITY_IBSS (1<<1) + +/* + * A mesh STA sets the ESS and IBSS capability bits to zero. + * however, this holds true for p2p probe responses (in the p2p_find + * phase) as well. + */ +#define WLAN_CAPABILITY_IS_STA_BSS(cap) \ + (!((cap) & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS))) + +#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) +#define WLAN_CAPABILITY_PRIVACY (1<<4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) +#define WLAN_CAPABILITY_PBCC (1<<6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) + +/* 802.11h */ +#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) +#define WLAN_CAPABILITY_QOS (1<<9) +#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) +#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) +/* measurement */ +#define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0) +#define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1) +#define IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED (1<<2) + +#define IEEE80211_SPCT_MSR_RPRT_TYPE_BASIC 0 +#define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1 +#define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2 + + +/* 802.11g ERP information element */ +#define WLAN_ERP_NON_ERP_PRESENT (1<<0) +#define WLAN_ERP_USE_PROTECTION (1<<1) +#define WLAN_ERP_BARKER_PREAMBLE (1<<2) + +/* WLAN_ERP_BARKER_PREAMBLE values */ +enum { + WLAN_ERP_PREAMBLE_SHORT = 0, + WLAN_ERP_PREAMBLE_LONG = 1, +}; + +/* Status codes */ +enum ieee80211_statuscode { + WLAN_STATUS_SUCCESS = 0, + WLAN_STATUS_UNSPECIFIED_FAILURE = 1, + WLAN_STATUS_CAPS_UNSUPPORTED = 10, + WLAN_STATUS_REASSOC_NO_ASSOC = 11, + WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, + WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, + WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, + WLAN_STATUS_CHALLENGE_FAIL = 15, + WLAN_STATUS_AUTH_TIMEOUT = 16, + WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, + WLAN_STATUS_ASSOC_DENIED_RATES = 18, + /* 802.11b */ + WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, + WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, + WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, + /* 802.11h */ + WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, + WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, + WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, + /* 802.11g */ + WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, + WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, + /* 802.11w */ + WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY = 30, + WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION = 31, + /* 802.11i */ + WLAN_STATUS_INVALID_IE = 40, + WLAN_STATUS_INVALID_GROUP_CIPHER = 41, + WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, + WLAN_STATUS_INVALID_AKMP = 43, + WLAN_STATUS_UNSUPP_RSN_VERSION = 44, + WLAN_STATUS_INVALID_RSN_IE_CAP = 45, + WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, + /* 802.11e */ + WLAN_STATUS_UNSPECIFIED_QOS = 32, + WLAN_STATUS_ASSOC_DENIED_NOBANDWIDTH = 33, + WLAN_STATUS_ASSOC_DENIED_LOWACK = 34, + WLAN_STATUS_ASSOC_DENIED_UNSUPP_QOS = 35, + WLAN_STATUS_REQUEST_DECLINED = 37, + WLAN_STATUS_INVALID_QOS_PARAM = 38, + WLAN_STATUS_CHANGE_TSPEC = 39, + WLAN_STATUS_WAIT_TS_DELAY = 47, + WLAN_STATUS_NO_DIRECT_LINK = 48, + WLAN_STATUS_STA_NOT_PRESENT = 49, + WLAN_STATUS_STA_NOT_QSTA = 50, + /* 802.11s */ + WLAN_STATUS_ANTI_CLOG_REQUIRED = 76, + WLAN_STATUS_FCG_NOT_SUPP = 78, + WLAN_STATUS_STA_NO_TBTT = 78, +}; + + +/* Reason codes */ +enum ieee80211_reasoncode { + WLAN_REASON_UNSPECIFIED = 1, + WLAN_REASON_PREV_AUTH_NOT_VALID = 2, + WLAN_REASON_DEAUTH_LEAVING = 3, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, + WLAN_REASON_DISASSOC_AP_BUSY = 5, + WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, + WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, + WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, + /* 802.11h */ + WLAN_REASON_DISASSOC_BAD_POWER = 10, + WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, + /* 802.11i */ + WLAN_REASON_INVALID_IE = 13, + WLAN_REASON_MIC_FAILURE = 14, + WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, + WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, + WLAN_REASON_IE_DIFFERENT = 17, + WLAN_REASON_INVALID_GROUP_CIPHER = 18, + WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, + WLAN_REASON_INVALID_AKMP = 20, + WLAN_REASON_UNSUPP_RSN_VERSION = 21, + WLAN_REASON_INVALID_RSN_IE_CAP = 22, + WLAN_REASON_IEEE8021X_FAILED = 23, + WLAN_REASON_CIPHER_SUITE_REJECTED = 24, + /* 802.11e */ + WLAN_REASON_DISASSOC_UNSPECIFIED_QOS = 32, + WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH = 33, + WLAN_REASON_DISASSOC_LOW_ACK = 34, + WLAN_REASON_DISASSOC_QAP_EXCEED_TXOP = 35, + WLAN_REASON_QSTA_LEAVE_QBSS = 36, + WLAN_REASON_QSTA_NOT_USE = 37, + WLAN_REASON_QSTA_REQUIRE_SETUP = 38, + WLAN_REASON_QSTA_TIMEOUT = 39, + WLAN_REASON_QSTA_CIPHER_NOT_SUPP = 45, + /* 802.11s */ + WLAN_REASON_MESH_PEER_CANCELED = 52, + WLAN_REASON_MESH_MAX_PEERS = 53, + WLAN_REASON_MESH_CONFIG = 54, + WLAN_REASON_MESH_CLOSE = 55, + WLAN_REASON_MESH_MAX_RETRIES = 56, + WLAN_REASON_MESH_CONFIRM_TIMEOUT = 57, + WLAN_REASON_MESH_INVALID_GTK = 58, + WLAN_REASON_MESH_INCONSISTENT_PARAM = 59, + WLAN_REASON_MESH_INVALID_SECURITY = 60, + WLAN_REASON_MESH_PATH_ERROR = 61, + WLAN_REASON_MESH_PATH_NOFORWARD = 62, + WLAN_REASON_MESH_PATH_DEST_UNREACHABLE = 63, + WLAN_REASON_MAC_EXISTS_IN_MBSS = 64, + WLAN_REASON_MESH_CHAN_REGULATORY = 65, + WLAN_REASON_MESH_CHAN = 66, +}; + + +/* Information Element IDs */ +enum ieee80211_eid { + WLAN_EID_SSID = 0, + WLAN_EID_SUPP_RATES = 1, + WLAN_EID_FH_PARAMS = 2, + WLAN_EID_DS_PARAMS = 3, + WLAN_EID_CF_PARAMS = 4, + WLAN_EID_TIM = 5, + WLAN_EID_IBSS_PARAMS = 6, + WLAN_EID_CHALLENGE = 16, + + WLAN_EID_COUNTRY = 7, + WLAN_EID_HP_PARAMS = 8, + WLAN_EID_HP_TABLE = 9, + WLAN_EID_REQUEST = 10, + + WLAN_EID_QBSS_LOAD = 11, + WLAN_EID_EDCA_PARAM_SET = 12, + WLAN_EID_TSPEC = 13, + WLAN_EID_TCLAS = 14, + WLAN_EID_SCHEDULE = 15, + WLAN_EID_TS_DELAY = 43, + WLAN_EID_TCLAS_PROCESSING = 44, + WLAN_EID_QOS_CAPA = 46, + /* 802.11z */ + WLAN_EID_LINK_ID = 101, + /* 802.11s */ + WLAN_EID_MESH_CONFIG = 113, + WLAN_EID_MESH_ID = 114, + WLAN_EID_LINK_METRIC_REPORT = 115, + WLAN_EID_CONGESTION_NOTIFICATION = 116, + WLAN_EID_PEER_MGMT = 117, + WLAN_EID_CHAN_SWITCH_PARAM = 118, + WLAN_EID_MESH_AWAKE_WINDOW = 119, + WLAN_EID_BEACON_TIMING = 120, + WLAN_EID_MCCAOP_SETUP_REQ = 121, + WLAN_EID_MCCAOP_SETUP_RESP = 122, + WLAN_EID_MCCAOP_ADVERT = 123, + WLAN_EID_MCCAOP_TEARDOWN = 124, + WLAN_EID_GANN = 125, + WLAN_EID_RANN = 126, + WLAN_EID_PREQ = 130, + WLAN_EID_PREP = 131, + WLAN_EID_PERR = 132, + WLAN_EID_PXU = 137, + WLAN_EID_PXUC = 138, + WLAN_EID_AUTH_MESH_PEER_EXCH = 139, + WLAN_EID_MIC = 140, + + WLAN_EID_PWR_CONSTRAINT = 32, + WLAN_EID_PWR_CAPABILITY = 33, + WLAN_EID_TPC_REQUEST = 34, + WLAN_EID_TPC_REPORT = 35, + WLAN_EID_SUPPORTED_CHANNELS = 36, + WLAN_EID_CHANNEL_SWITCH = 37, + WLAN_EID_MEASURE_REQUEST = 38, + WLAN_EID_MEASURE_REPORT = 39, + WLAN_EID_QUIET = 40, + WLAN_EID_IBSS_DFS = 41, + + WLAN_EID_ERP_INFO = 42, + WLAN_EID_EXT_SUPP_RATES = 50, + + WLAN_EID_HT_CAPABILITY = 45, + WLAN_EID_HT_INFORMATION = 61, + + WLAN_EID_RSN = 48, + WLAN_EID_MMIE = 76, + WLAN_EID_WPA = 221, + WLAN_EID_GENERIC = 221, + WLAN_EID_VENDOR_SPECIFIC = 221, + WLAN_EID_QOS_PARAMETER = 222, + + WLAN_EID_AP_CHAN_REPORT = 51, + WLAN_EID_NEIGHBOR_REPORT = 52, + WLAN_EID_RCPI = 53, + WLAN_EID_BSS_AVG_ACCESS_DELAY = 63, + WLAN_EID_ANTENNA_INFO = 64, + WLAN_EID_RSNI = 65, + WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66, + WLAN_EID_BSS_AVAILABLE_CAPACITY = 67, + WLAN_EID_BSS_AC_ACCESS_DELAY = 68, + WLAN_EID_RRM_ENABLED_CAPABILITIES = 70, + WLAN_EID_MULTIPLE_BSSID = 71, + WLAN_EID_BSS_COEX_2040 = 72, + WLAN_EID_OVERLAP_BSS_SCAN_PARAM = 74, + WLAN_EID_EXT_CAPABILITY = 127, + + WLAN_EID_MOBILITY_DOMAIN = 54, + WLAN_EID_FAST_BSS_TRANSITION = 55, + WLAN_EID_TIMEOUT_INTERVAL = 56, + WLAN_EID_RIC_DATA = 57, + WLAN_EID_RIC_DESCRIPTOR = 75, + + WLAN_EID_DSE_REGISTERED_LOCATION = 58, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, + WLAN_EID_EXT_CHANSWITCH_ANN = 60, +}; + +/* Action category code */ +enum ieee80211_category { + WLAN_CATEGORY_SPECTRUM_MGMT = 0, + WLAN_CATEGORY_QOS = 1, + WLAN_CATEGORY_DLS = 2, + WLAN_CATEGORY_BACK = 3, + WLAN_CATEGORY_PUBLIC = 4, + WLAN_CATEGORY_HT = 7, + WLAN_CATEGORY_SA_QUERY = 8, + WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, + WLAN_CATEGORY_TDLS = 12, + WLAN_CATEGORY_MESH_ACTION = 13, + WLAN_CATEGORY_MULTIHOP_ACTION = 14, + WLAN_CATEGORY_SELF_PROTECTED = 15, + WLAN_CATEGORY_WMM = 17, + WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, + WLAN_CATEGORY_VENDOR_SPECIFIC = 127, +}; + +/* SPECTRUM_MGMT action code */ +enum ieee80211_spectrum_mgmt_actioncode { + WLAN_ACTION_SPCT_MSR_REQ = 0, + WLAN_ACTION_SPCT_MSR_RPRT = 1, + WLAN_ACTION_SPCT_TPC_REQ = 2, + WLAN_ACTION_SPCT_TPC_RPRT = 3, + WLAN_ACTION_SPCT_CHL_SWITCH = 4, +}; + +/* HT action codes */ +enum ieee80211_ht_actioncode { + WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0, + WLAN_HT_ACTION_SMPS = 1, + WLAN_HT_ACTION_PSMP = 2, + WLAN_HT_ACTION_PCO_PHASE = 3, + WLAN_HT_ACTION_CSI = 4, + WLAN_HT_ACTION_NONCOMPRESSED_BF = 5, + WLAN_HT_ACTION_COMPRESSED_BF = 6, + WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, +}; + +/* Self Protected Action codes */ +enum ieee80211_self_protected_actioncode { + WLAN_SP_RESERVED = 0, + WLAN_SP_MESH_PEERING_OPEN = 1, + WLAN_SP_MESH_PEERING_CONFIRM = 2, + WLAN_SP_MESH_PEERING_CLOSE = 3, + WLAN_SP_MGK_INFORM = 4, + WLAN_SP_MGK_ACK = 5, +}; + +/* Mesh action codes */ +enum ieee80211_mesh_actioncode { + WLAN_MESH_ACTION_LINK_METRIC_REPORT, + WLAN_MESH_ACTION_HWMP_PATH_SELECTION, + WLAN_MESH_ACTION_GATE_ANNOUNCEMENT, + WLAN_MESH_ACTION_CONGESTION_CONTROL_NOTIFICATION, + WLAN_MESH_ACTION_MCCA_SETUP_REQUEST, + WLAN_MESH_ACTION_MCCA_SETUP_REPLY, + WLAN_MESH_ACTION_MCCA_ADVERTISEMENT_REQUEST, + WLAN_MESH_ACTION_MCCA_ADVERTISEMENT, + WLAN_MESH_ACTION_MCCA_TEARDOWN, + WLAN_MESH_ACTION_TBTT_ADJUSTMENT_REQUEST, + WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE, +}; + +/* Security key length */ +enum ieee80211_key_len { + WLAN_KEY_LEN_WEP40 = 5, + WLAN_KEY_LEN_WEP104 = 13, + WLAN_KEY_LEN_CCMP = 16, + WLAN_KEY_LEN_TKIP = 32, + WLAN_KEY_LEN_AES_CMAC = 16, +}; + +/* Public action codes */ +enum ieee80211_pub_actioncode { + WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14, +}; + +/* TDLS action codes */ +enum ieee80211_tdls_actioncode { + WLAN_TDLS_SETUP_REQUEST = 0, + WLAN_TDLS_SETUP_RESPONSE = 1, + WLAN_TDLS_SETUP_CONFIRM = 2, + WLAN_TDLS_TEARDOWN = 3, + WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4, + WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5, + WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6, + WLAN_TDLS_PEER_PSM_REQUEST = 7, + WLAN_TDLS_PEER_PSM_RESPONSE = 8, + WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9, + WLAN_TDLS_DISCOVERY_REQUEST = 10, +}; + +/* + * TDLS capabililites to be enabled in the 5th byte of the + * @WLAN_EID_EXT_CAPABILITY information element + */ +#define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) +#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) + +/* TDLS specific payload type in the LLC/SNAP header */ +#define WLAN_TDLS_SNAP_RFTYPE 0x2 + +/** + * enum - mesh path selection protocol identifier + * + * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol + * @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will + * be specified in a vendor specific information element + */ +enum { + IEEE80211_PATH_PROTOCOL_HWMP = 0, + IEEE80211_PATH_PROTOCOL_VENDOR = 255, +}; + +/** + * enum - mesh path selection metric identifier + * + * @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric + * @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be + * specified in a vendor specific information element + */ +enum { + IEEE80211_PATH_METRIC_AIRTIME = 0, + IEEE80211_PATH_METRIC_VENDOR = 255, +}; + + +/* + * IEEE 802.11-2007 7.3.2.9 Country information element + * + * Minimum length is 8 octets, ie len must be evenly + * divisible by 2 + */ + +/* Although the spec says 8 I'm seeing 6 in practice */ +#define IEEE80211_COUNTRY_IE_MIN_LEN 6 + +/* The Country String field of the element shall be 3 octets in length */ +#define IEEE80211_COUNTRY_STRING_LEN 3 + +/* + * For regulatory extension stuff see IEEE 802.11-2007 + * Annex I (page 1141) and Annex J (page 1147). Also + * review 7.3.2.9. + * + * When dot11RegulatoryClassesRequired is true and the + * first_channel/reg_extension_id is >= 201 then the IE + * compromises of the 'ext' struct represented below: + * + * - Regulatory extension ID - when generating IE this just needs + * to be monotonically increasing for each triplet passed in + * the IE + * - Regulatory class - index into set of rules + * - Coverage class - index into air propagation time (Table 7-27), + * in microseconds, you can compute the air propagation time from + * the index by multiplying by 3, so index 10 yields a propagation + * of 10 us. Valid values are 0-31, values 32-255 are not defined + * yet. A value of 0 inicates air propagation of <= 1 us. + * + * See also Table I.2 for Emission limit sets and table + * I.3 for Behavior limit sets. Table J.1 indicates how to map + * a reg_class to an emission limit set and behavior limit set. + */ +#define IEEE80211_COUNTRY_EXTENSION_ID 201 + +/* + * Channels numbers in the IE must be monotonically increasing + * if dot11RegulatoryClassesRequired is not true. + * + * If dot11RegulatoryClassesRequired is true consecutive + * subband triplets following a regulatory triplet shall + * have monotonically increasing first_channel number fields. + * + * Channel numbers shall not overlap. + * + * Note that max_power is signed. + */ +struct ieee80211_country_ie_triplet { + union { + struct { + u8 first_channel; + u8 num_channels; + s8 max_power; + } __attribute__ ((packed)) chans; + struct { + u8 reg_extension_id; + u8 reg_class; + u8 coverage_class; + } __attribute__ ((packed)) ext; + }; +} __attribute__ ((packed)); + +enum ieee80211_timeout_interval_type { + WLAN_TIMEOUT_REASSOC_DEADLINE = 1 /* 802.11r */, + WLAN_TIMEOUT_KEY_LIFETIME = 2 /* 802.11r */, + WLAN_TIMEOUT_ASSOC_COMEBACK = 3 /* 802.11w */, +}; + +/* BACK action code */ +enum ieee80211_back_actioncode { + WLAN_ACTION_ADDBA_REQ = 0, + WLAN_ACTION_ADDBA_RESP = 1, + WLAN_ACTION_DELBA = 2, +}; + +/* BACK (block-ack) parties */ +enum ieee80211_back_parties { + WLAN_BACK_RECIPIENT = 0, + WLAN_BACK_INITIATOR = 1, +}; + +/* SA Query action */ +enum ieee80211_sa_query_action { + WLAN_ACTION_SA_QUERY_REQUEST = 0, + WLAN_ACTION_SA_QUERY_RESPONSE = 1, +}; + + +/* cipher suite selectors */ +#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 +#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 +#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 +/* reserved: 0x000FAC03 */ +#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 +#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 +#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 + +#define WLAN_CIPHER_SUITE_SMS4 0x00147201 + +/* AKM suite selectors */ +#define WLAN_AKM_SUITE_8021X 0x000FAC01 +#define WLAN_AKM_SUITE_PSK 0x000FAC02 +#define WLAN_AKM_SUITE_SAE 0x000FAC08 +#define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09 + +#define WLAN_MAX_KEY_LEN 32 + +#define WLAN_PMKID_LEN 16 + +#define WLAN_OUI_WFA 0x506f9a +#define WLAN_OUI_TYPE_WFA_P2P 9 + +/* + * WMM/802.11e Tspec Element + */ +#define IEEE80211_WMM_IE_TSPEC_TID_MASK 0x0F +#define IEEE80211_WMM_IE_TSPEC_TID_SHIFT 1 + +enum ieee80211_tspec_status_code { + IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED = 0, + IEEE80211_TSPEC_STATUS_ADDTS_INVAL_PARAMS = 0x1, +}; + +struct ieee80211_tspec_ie { + u8 element_id; + u8 len; + u8 oui[3]; + u8 oui_type; + u8 oui_subtype; + u8 version; + __le16 tsinfo; + u8 tsinfo_resvd; + __le16 nominal_msdu; + __le16 max_msdu; + __le32 min_service_int; + __le32 max_service_int; + __le32 inactivity_int; + __le32 suspension_int; + __le32 service_start_time; + __le32 min_data_rate; + __le32 mean_data_rate; + __le32 peak_data_rate; + __le32 max_burst_size; + __le32 delay_bound; + __le32 min_phy_rate; + __le16 sba; + __le16 medium_time; +} __packed; + +/** + * ieee80211_get_qos_ctl - get pointer to qos control bytes + * @hdr: the frame + * + * The qos ctrl bytes come after the frame_control, duration, seq_num + * and 3 or 4 addresses of length ETH_ALEN. + * 3 addr: 2 + 2 + 2 + 3*6 = 24 + * 4 addr: 2 + 2 + 2 + 4*6 = 30 + */ +static inline u8 *ieee80211_get_qos_ctl(struct ieee80211_hdr *hdr) +{ + if (ieee80211_has_a4(hdr->frame_control)) + return (u8 *)hdr + 30; + else + return (u8 *)hdr + 24; +} + +/** + * ieee80211_get_SA - get pointer to SA + * @hdr: the frame + * + * Given an 802.11 frame, this function returns the offset + * to the source address (SA). It does not verify that the + * header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + */ +static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) +{ + if (ieee80211_has_a4(hdr->frame_control)) + return hdr->addr4; + if (ieee80211_has_fromds(hdr->frame_control)) + return hdr->addr3; + return hdr->addr2; +} + +/** + * ieee80211_get_DA - get pointer to DA + * @hdr: the frame + * + * Given an 802.11 frame, this function returns the offset + * to the destination address (DA). It does not verify that + * the header is long enough to contain the address, and the + * header must be long enough to contain the frame control + * field. + */ +static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) +{ + if (ieee80211_has_tods(hdr->frame_control)) + return hdr->addr3; + else + return hdr->addr1; +} + +/** + * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame + * @hdr: the frame (buffer must include at least the first octet of payload) + */ +static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) +{ + if (ieee80211_is_disassoc(hdr->frame_control) || + ieee80211_is_deauth(hdr->frame_control)) + return true; + + if (ieee80211_is_action(hdr->frame_control)) { + u8 *category; + + /* + * Action frames, excluding Public Action frames, are Robust + * Management Frames. However, if we are looking at a Protected + * frame, skip the check since the data may be encrypted and + * the frame has already been found to be a Robust Management + * Frame (by the other end). + */ + if (ieee80211_has_protected(hdr->frame_control)) + return true; + category = ((u8 *) hdr) + 24; + return *category != WLAN_CATEGORY_PUBLIC && + *category != WLAN_CATEGORY_HT && + *category != WLAN_CATEGORY_SELF_PROTECTED && + *category != WLAN_CATEGORY_VENDOR_SPECIFIC; + } + + return false; +} + +/** + * ieee80211_fhss_chan_to_freq - get channel frequency + * @channel: the FHSS channel + * + * Convert IEEE802.11 FHSS channel to frequency (MHz) + * Ref IEEE 802.11-2007 section 14.6 + */ +static inline int ieee80211_fhss_chan_to_freq(int channel) +{ + if ((channel > 1) && (channel < 96)) + return channel + 2400; + else + return -1; +} + +/** + * ieee80211_freq_to_fhss_chan - get channel + * @freq: the channels frequency + * + * Convert frequency (MHz) to IEEE802.11 FHSS channel + * Ref IEEE 802.11-2007 section 14.6 + */ +static inline int ieee80211_freq_to_fhss_chan(int freq) +{ + if ((freq > 2401) && (freq < 2496)) + return freq - 2400; + else + return -1; +} + +/** + * ieee80211_dsss_chan_to_freq - get channel center frequency + * @channel: the DSSS channel + * + * Convert IEEE802.11 DSSS channel to the center frequency (MHz). + * Ref IEEE 802.11-2007 section 15.6 + */ +static inline int ieee80211_dsss_chan_to_freq(int channel) +{ + if ((channel > 0) && (channel < 14)) + return 2407 + (channel * 5); + else if (channel == 14) + return 2484; + else + return -1; +} + +/** + * ieee80211_freq_to_dsss_chan - get channel + * @freq: the frequency + * + * Convert frequency (MHz) to IEEE802.11 DSSS channel + * Ref IEEE 802.11-2007 section 15.6 + * + * This routine selects the channel with the closest center frequency. + */ +static inline int ieee80211_freq_to_dsss_chan(int freq) +{ + if ((freq >= 2410) && (freq < 2475)) + return (freq - 2405) / 5; + else if ((freq >= 2482) && (freq < 2487)) + return 14; + else + return -1; +} + +/* Convert IEEE802.11 HR DSSS channel to frequency (MHz) and back + * Ref IEEE 802.11-2007 section 18.4.6.2 + * + * The channels and frequencies are the same as those defined for DSSS + */ +#define ieee80211_hr_chan_to_freq(chan) ieee80211_dsss_chan_to_freq(chan) +#define ieee80211_freq_to_hr_chan(freq) ieee80211_freq_to_dsss_chan(freq) + +/* Convert IEEE802.11 ERP channel to frequency (MHz) and back + * Ref IEEE 802.11-2007 section 19.4.2 + */ +#define ieee80211_erp_chan_to_freq(chan) ieee80211_hr_chan_to_freq(chan) +#define ieee80211_freq_to_erp_chan(freq) ieee80211_freq_to_hr_chan(freq) + +/** + * ieee80211_ofdm_chan_to_freq - get channel center frequency + * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz + * @channel: the OFDM channel + * + * Convert IEEE802.11 OFDM channel to center frequency (MHz) + * Ref IEEE 802.11-2007 section 17.3.8.3.2 + */ +static inline int ieee80211_ofdm_chan_to_freq(int s_freq, int channel) +{ + if ((channel > 0) && (channel <= 200) && + (s_freq >= 4000)) + return s_freq + (channel * 5); + else + return -1; +} + +/** + * ieee80211_freq_to_ofdm_channel - get channel + * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz + * @freq: the frequency + * + * Convert frequency (MHz) to IEEE802.11 OFDM channel + * Ref IEEE 802.11-2007 section 17.3.8.3.2 + * + * This routine selects the channel with the closest center frequency. + */ +static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq) +{ + if ((freq > (s_freq + 2)) && (freq <= (s_freq + 1202)) && + (s_freq >= 4000)) + return (freq + 2 - s_freq) / 5; + else + return -1; +} + +/** + * ieee80211_tu_to_usec - convert time units (TU) to microseconds + * @tu: the TUs + */ +static inline unsigned long ieee80211_tu_to_usec(unsigned long tu) +{ + return 1024 * tu; +} + +/** + * ieee80211_check_tim - check if AID bit is set in TIM + * @tim: the TIM IE + * @tim_len: length of the TIM IE + * @aid: the AID to look for + */ +static inline bool ieee80211_check_tim(struct ieee80211_tim_ie *tim, + u8 tim_len, u16 aid) +{ + u8 mask; + u8 index, indexn1, indexn2; + + if (unlikely(!tim || tim_len < sizeof(*tim))) + return false; + + aid &= 0x3fff; + index = aid / 8; + mask = 1 << (aid & 7); + + indexn1 = tim->bitmap_ctrl & 0xfe; + indexn2 = tim_len + indexn1 - 4; + + if (index < indexn1 || index > indexn2) + return false; + + index -= indexn1; + + return !!(tim->virtual_map[index] & mask); +} + +#endif /* LINUX_IEEE80211_H */ diff --git a/include/compat/linux/kfifo.h b/include/compat/linux/kfifo.h new file mode 100644 index 00000000..e30bb546 --- /dev/null +++ b/include/compat/linux/kfifo.h @@ -0,0 +1,857 @@ +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) +#include_next +#else +/* + * A generic kernel FIFO implementation + * + * Copyright (C) 2009/2010 Stefani Seibold + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LINUX_KFIFO_H +#define _LINUX_KFIFO_H + +/* + * How to porting drivers to the new generic FIFO API: + * + * - Modify the declaration of the "struct kfifo *" object into a + * in-place "struct kfifo" object + * - Init the in-place object with kfifo_alloc() or kfifo_init() + * Note: The address of the in-place "struct kfifo" object must be + * passed as the first argument to this functions + * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get + * into kfifo_out + * - Replace the use of kfifo_put into kfifo_in_spinlocked and kfifo_get + * into kfifo_out_spinlocked + * Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc + * must be passed now to the kfifo_in_spinlocked and kfifo_out_spinlocked + * as the last parameter + * - The formerly __kfifo_* functions are renamed into kfifo_* + */ + +/* + * Note about locking : There is no locking required until only * one reader + * and one writer is using the fifo and no kfifo_reset() will be * called + * kfifo_reset_out() can be safely used, until it will be only called + * in the reader thread. + * For multiple writer and one reader there is only a need to lock the writer. + * And vice versa for only one writer and multiple reader there is only a need + * to lock the reader. + */ + +#include +#include +#include +#include + +struct __kfifo { + unsigned int in; + unsigned int out; + unsigned int mask; + unsigned int esize; + void *data; +}; + +#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \ + union { \ + struct __kfifo kfifo; \ + datatype *type; \ + char (*rectype)[recsize]; \ + ptrtype *ptr; \ + const ptrtype *ptr_const; \ + } + +#define __STRUCT_KFIFO(type, size, recsize, ptrtype) \ +{ \ + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \ +} + +#define STRUCT_KFIFO(type, size) \ + struct __STRUCT_KFIFO(type, size, 0, type) + +#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \ +{ \ + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ + type buf[0]; \ +} + +#define STRUCT_KFIFO_PTR(type) \ + struct __STRUCT_KFIFO_PTR(type, 0, type) + +/* + * define compatibility "struct kfifo" for dynamic allocated fifos + */ +struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void); + +#define STRUCT_KFIFO_REC_1(size) \ + struct __STRUCT_KFIFO(unsigned char, size, 1, void) + +#define STRUCT_KFIFO_REC_2(size) \ + struct __STRUCT_KFIFO(unsigned char, size, 2, void) + +/* + * define kfifo_rec types + */ +struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void); +struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void); + +/* + * helper macro to distinguish between real in place fifo where the fifo + * array is a part of the structure and the fifo type where the array is + * outside of the fifo structure. + */ +#define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo)) + +/** + * DECLARE_KFIFO_PTR - macro to declare a fifo pointer object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + */ +#define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) fifo + +/** + * DECLARE_KFIFO - macro to declare a fifo object + * @fifo: name of the declared fifo + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + */ +#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo + +/** + * INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO + * @fifo: name of the declared fifo datatype + */ +#define INIT_KFIFO(fifo) \ +(void)({ \ + typeof(&(fifo)) __tmp = &(fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __kfifo->in = 0; \ + __kfifo->out = 0; \ + __kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\ + __kfifo->esize = sizeof(*__tmp->buf); \ + __kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \ +}) + +/** + * DEFINE_KFIFO - macro to define and initialize a fifo + * @fifo: name of the declared fifo datatype + * @type: type of the fifo elements + * @size: the number of elements in the fifo, this must be a power of 2 + * + * Note: the macro can be used for global and local fifo data type variables. + */ +#define DEFINE_KFIFO(fifo, type, size) \ + DECLARE_KFIFO(fifo, type, size) = \ + (typeof(fifo)) { \ + { \ + { \ + .in = 0, \ + .out = 0, \ + .mask = __is_kfifo_ptr(&(fifo)) ? \ + 0 : \ + ARRAY_SIZE((fifo).buf) - 1, \ + .esize = sizeof(*(fifo).buf), \ + .data = __is_kfifo_ptr(&(fifo)) ? \ + NULL : \ + (fifo).buf, \ + } \ + } \ + } + + +static inline unsigned int __must_check +__kfifo_uint_must_check_helper(unsigned int val) +{ + return val; +} + +static inline int __must_check +__kfifo_int_must_check_helper(int val) +{ + return val; +} + +/** + * kfifo_initialized - Check if the fifo is initialized + * @fifo: address of the fifo to check + * + * Return %true if fifo is initialized, otherwise %false. + * Assumes the fifo was 0 before. + */ +#define kfifo_initialized(fifo) ((fifo)->kfifo.mask) + +/** + * kfifo_esize - returns the size of the element managed by the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_esize(fifo) ((fifo)->kfifo.esize) + +/** + * kfifo_recsize - returns the size of the record length field + * @fifo: address of the fifo to be used + */ +#define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype)) + +/** + * kfifo_size - returns the size of the fifo in elements + * @fifo: address of the fifo to be used + */ +#define kfifo_size(fifo) ((fifo)->kfifo.mask + 1) + +/** + * kfifo_reset - removes the entire fifo content + * @fifo: address of the fifo to be used + * + * Note: usage of kfifo_reset() is dangerous. It should be only called when the + * fifo is exclusived locked or when it is secured that no other thread is + * accessing the fifo. + */ +#define kfifo_reset(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->kfifo.in = __tmp->kfifo.out = 0; \ +}) + +/** + * kfifo_reset_out - skip fifo content + * @fifo: address of the fifo to be used + * + * Note: The usage of kfifo_reset_out() is safe until it will be only called + * from the reader thread and there is only one concurrent reader. Otherwise + * it is dangerous and must be handled in the same way as kfifo_reset(). + */ +#define kfifo_reset_out(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + __tmp->kfifo.out = __tmp->kfifo.in; \ +}) + +/** + * kfifo_len - returns the number of used elements in the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_len(fifo) \ +({ \ + typeof((fifo) + 1) __tmpl = (fifo); \ + __tmpl->kfifo.in - __tmpl->kfifo.out; \ +}) + +/** + * kfifo_is_empty - returns true if the fifo is empty + * @fifo: address of the fifo to be used + */ +#define kfifo_is_empty(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + __tmpq->kfifo.in == __tmpq->kfifo.out; \ +}) + +/** + * kfifo_is_full - returns true if the fifo is full + * @fifo: address of the fifo to be used + */ +#define kfifo_is_full(fifo) \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + kfifo_len(__tmpq) > __tmpq->kfifo.mask; \ +}) + +/** + * kfifo_avail - returns the number of unused elements in the fifo + * @fifo: address of the fifo to be used + */ +#define kfifo_avail(fifo) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmpq = (fifo); \ + const size_t __recsize = sizeof(*__tmpq->rectype); \ + unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \ + (__recsize) ? ((__avail <= __recsize) ? 0 : \ + __kfifo_max_r(__avail - __recsize, __recsize)) : \ + __avail; \ +}) \ +) + +/** + * kfifo_skip - skip output data + * @fifo: address of the fifo to be used + */ +#define kfifo_skip(fifo) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__recsize) \ + __kfifo_skip_r(__kfifo, __recsize); \ + else \ + __kfifo->out++; \ +}) + +/** + * kfifo_peek_len - gets the size of the next fifo record + * @fifo: address of the fifo to be used + * + * This function returns the size of the next fifo record in number of bytes. + */ +#define kfifo_peek_len(fifo) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (!__recsize) ? kfifo_len(__tmp) * sizeof(*__tmp->type) : \ + __kfifo_len_r(__kfifo, __recsize); \ +}) \ +) + +/** + * kfifo_alloc - dynamically allocates a new fifo buffer + * @fifo: pointer to the fifo + * @size: the number of elements in the fifo, this must be a power of 2 + * @gfp_mask: get_free_pages mask, passed to kmalloc() + * + * This macro dynamically allocates a new fifo buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * The fifo will be release with kfifo_free(). + * Return 0 if no error, otherwise an error code. + */ +#define kfifo_alloc(fifo, size, gfp_mask) \ +__kfifo_int_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __is_kfifo_ptr(__tmp) ? \ + __kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \ + -EINVAL; \ +}) \ +) + +/** + * kfifo_free - frees the fifo + * @fifo: the fifo to be freed + */ +#define kfifo_free(fifo) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__is_kfifo_ptr(__tmp)) \ + __kfifo_free(__kfifo); \ +}) + +/** + * kfifo_init - initialize a fifo using a preallocated buffer + * @fifo: the fifo to assign the buffer + * @buffer: the preallocated buffer to be used + * @size: the size of the internal buffer, this have to be a power of 2 + * + * This macro initialize a fifo using a preallocated buffer. + * + * The numer of elements will be rounded-up to a power of 2. + * Return 0 if no error, otherwise an error code. + */ +#define kfifo_init(fifo, buffer, size) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + __is_kfifo_ptr(__tmp) ? \ + __kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \ + -EINVAL; \ +}) + +/** + * kfifo_put - put data into the fifo + * @fifo: address of the fifo to be used + * @val: the data to be added + * + * This macro copies the given value into the fifo. + * It returns 0 if the fifo was full. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_put(fifo, val) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \ + __dummy = (typeof(__val))NULL; \ + } \ + if (__recsize) \ + __ret = __kfifo_in_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_full(__tmp); \ + if (__ret) { \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->in & __tmp->kfifo.mask] = \ + *(typeof(__tmp->type))__val; \ + smp_wmb(); \ + __kfifo->in++; \ + } \ + } \ + __ret; \ +}) + +/** + * kfifo_get - get data from the fifo + * @fifo: address of the fifo to be used + * @val: the var where to store the data to be added + * + * This macro reads the data from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_get(fifo, val) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) \ + __val = (typeof(__tmp->ptr))0; \ + if (__recsize) \ + __ret = __kfifo_out_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->out & __tmp->kfifo.mask]; \ + smp_wmb(); \ + __kfifo->out++; \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * kfifo_peek - get data from the fifo without removing + * @fifo: address of the fifo to be used + * @val: the var where to store the data to be added + * + * This reads the data from the fifo without removing it from the fifo. + * It returns 0 if the fifo was empty. Otherwise it returns the number + * processed elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_peek(fifo, val) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ + unsigned int __ret; \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) \ + __val = (typeof(__tmp->ptr))NULL; \ + if (__recsize) \ + __ret = __kfifo_out_peek_r(__kfifo, __val, sizeof(*__val), \ + __recsize); \ + else { \ + __ret = !kfifo_is_empty(__tmp); \ + if (__ret) { \ + *(typeof(__tmp->type))__val = \ + (__is_kfifo_ptr(__tmp) ? \ + ((typeof(__tmp->type))__kfifo->data) : \ + (__tmp->buf) \ + )[__kfifo->out & __tmp->kfifo.mask]; \ + smp_wmb(); \ + } \ + } \ + __ret; \ +}) \ +) + +/** + * kfifo_in - put data into the fifo + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * + * This macro copies the given buffer into the fifo and returns the + * number of copied elements. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_in(fifo, buf, n) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \ + __dummy = (typeof(__buf))NULL; \ + } \ + (__recsize) ?\ + __kfifo_in_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_in(__kfifo, __buf, __n); \ +}) + +/** + * kfifo_in_spinlocked - put data into the fifo using a spinlock for locking + * @fifo: address of the fifo to be used + * @buf: the data to be added + * @n: number of elements to be added + * @lock: pointer to the spinlock to use for locking + * + * This macro copies the given values buffer into the fifo and returns the + * number of copied elements. + */ +#define kfifo_in_spinlocked(fifo, buf, n, lock) \ +({ \ + unsigned long __flags; \ + unsigned int __ret; \ + spin_lock_irqsave(lock, __flags); \ + __ret = kfifo_in(fifo, buf, n); \ + spin_unlock_irqrestore(lock, __flags); \ + __ret; \ +}) + +/* alias for kfifo_in_spinlocked, will be removed in a future release */ +#define kfifo_in_locked(fifo, buf, n, lock) \ + kfifo_in_spinlocked(fifo, buf, n, lock) + +/** + * kfifo_out - get data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get some data from the fifo and return the numbers of elements + * copied. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr) __dummy = NULL; \ + __buf = __dummy; \ + } \ + (__recsize) ?\ + __kfifo_out_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_out(__kfifo, __buf, __n); \ +}) \ +) + +/** + * kfifo_out_spinlocked - get data from the fifo using a spinlock for locking + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * @lock: pointer to the spinlock to use for locking + * + * This macro get the data from the fifo and return the numbers of elements + * copied. + */ +#define kfifo_out_spinlocked(fifo, buf, n, lock) \ +__kfifo_uint_must_check_helper( \ +({ \ + unsigned long __flags; \ + unsigned int __ret; \ + spin_lock_irqsave(lock, __flags); \ + __ret = kfifo_out(fifo, buf, n); \ + spin_unlock_irqrestore(lock, __flags); \ + __ret; \ +}) \ +) + +/* alias for kfifo_out_spinlocked, will be removed in a future release */ +#define kfifo_out_locked(fifo, buf, n, lock) \ + kfifo_out_spinlocked(fifo, buf, n, lock) + +/** + * kfifo_from_user - puts some data from user space into the fifo + * @fifo: address of the fifo to be used + * @from: pointer to the data to be added + * @len: the length of the data to be added + * @copied: pointer to output variable to store the number of copied bytes + * + * This macro copies at most @len bytes from the @from into the + * fifo, depending of the available space and returns -EFAULT/0. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_from_user(fifo, from, len, copied) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + const void __user *__from = (from); \ + unsigned int __len = (len); \ + unsigned int *__copied = (copied); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_from_user_r(__kfifo, __from, __len, __copied, __recsize) : \ + __kfifo_from_user(__kfifo, __from, __len, __copied); \ +}) \ +) + +/** + * kfifo_to_user - copies data from the fifo into user space + * @fifo: address of the fifo to be used + * @to: where the data must be copied + * @len: the size of the destination buffer + * @copied: pointer to output variable to store the number of copied bytes + * + * This macro copies at most @len bytes from the fifo into the + * @to buffer and returns -EFAULT/0. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_to_user(fifo, to, len, copied) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + void __user *__to = (to); \ + unsigned int __len = (len); \ + unsigned int *__copied = (copied); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \ + __kfifo_to_user(__kfifo, __to, __len, __copied); \ +}) \ +) + +/** + * kfifo_dma_in_prepare - setup a scatterlist for DMA input + * @fifo: address of the fifo to be used + * @sgl: pointer to the scatterlist array + * @nents: number of entries in the scatterlist array + * @len: number of elements to transfer + * + * This macro fills a scatterlist for DMA input. + * It returns the number entries in the scatterlist array. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macros. + */ +#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct scatterlist *__sgl = (sgl); \ + int __nents = (nents); \ + unsigned int __len = (len); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \ + __kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len); \ +}) + +/** + * kfifo_dma_in_finish - finish a DMA IN operation + * @fifo: address of the fifo to be used + * @len: number of bytes to received + * + * This macro finish a DMA IN operation. The in counter will be updated by + * the len parameter. No error checking will be done. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macros. + */ +#define kfifo_dma_in_finish(fifo, len) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + unsigned int __len = (len); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__recsize) \ + __kfifo_dma_in_finish_r(__kfifo, __len, __recsize); \ + else \ + __kfifo->in += __len / sizeof(*__tmp->type); \ +}) + +/** + * kfifo_dma_out_prepare - setup a scatterlist for DMA output + * @fifo: address of the fifo to be used + * @sgl: pointer to the scatterlist array + * @nents: number of entries in the scatterlist array + * @len: number of elements to transfer + * + * This macro fills a scatterlist for DMA output which at most @len bytes + * to transfer. + * It returns the number entries in the scatterlist array. + * A zero means there is no space available and the scatterlist is not filled. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macros. + */ +#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + struct scatterlist *__sgl = (sgl); \ + int __nents = (nents); \ + unsigned int __len = (len); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \ + __kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len); \ +}) + +/** + * kfifo_dma_out_finish - finish a DMA OUT operation + * @fifo: address of the fifo to be used + * @len: number of bytes transferd + * + * This macro finish a DMA OUT operation. The out counter will be updated by + * the len parameter. No error checking will be done. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macros. + */ +#define kfifo_dma_out_finish(fifo, len) \ +(void)({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + unsigned int __len = (len); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (__recsize) \ + __kfifo_dma_out_finish_r(__kfifo, __recsize); \ + else \ + __kfifo->out += __len / sizeof(*__tmp->type); \ +}) + +/** + * kfifo_out_peek - gets some data from the fifo + * @fifo: address of the fifo to be used + * @buf: pointer to the storage buffer + * @n: max. number of elements to get + * + * This macro get the data from the fifo and return the numbers of elements + * copied. The data is not removed from the fifo. + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out_peek(fifo, buf, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ + unsigned long __n = (n); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + if (0) { \ + typeof(__tmp->ptr) __dummy __attribute__ ((unused)) = NULL; \ + __buf = __dummy; \ + } \ + (__recsize) ? \ + __kfifo_out_peek_r(__kfifo, __buf, __n, __recsize) : \ + __kfifo_out_peek(__kfifo, __buf, __n); \ +}) \ +) + +extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, + size_t esize, gfp_t gfp_mask); + +extern void __kfifo_free(struct __kfifo *fifo); + +extern int __kfifo_init(struct __kfifo *fifo, void *buffer, + unsigned int size, size_t esize); + +extern unsigned int __kfifo_in(struct __kfifo *fifo, + const void *buf, unsigned int len); + +extern unsigned int __kfifo_out(struct __kfifo *fifo, + void *buf, unsigned int len); + +extern int __kfifo_from_user(struct __kfifo *fifo, + const void __user *from, unsigned long len, unsigned int *copied); + +extern int __kfifo_to_user(struct __kfifo *fifo, + void __user *to, unsigned long len, unsigned int *copied); + +extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo, + struct scatterlist *sgl, int nents, unsigned int len); + +extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, + struct scatterlist *sgl, int nents, unsigned int len); + +extern unsigned int __kfifo_out_peek(struct __kfifo *fifo, + void *buf, unsigned int len); + +extern unsigned int __kfifo_in_r(struct __kfifo *fifo, + const void *buf, unsigned int len, size_t recsize); + +extern unsigned int __kfifo_out_r(struct __kfifo *fifo, + void *buf, unsigned int len, size_t recsize); + +extern int __kfifo_from_user_r(struct __kfifo *fifo, + const void __user *from, unsigned long len, unsigned int *copied, + size_t recsize); + +extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to, + unsigned long len, unsigned int *copied, size_t recsize); + +extern unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo, + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize); + +extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo, + unsigned int len, size_t recsize); + +extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize); + +extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize); + +extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize); + +extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize); + +extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, + void *buf, unsigned int len, size_t recsize); + +extern unsigned int __kfifo_max_r(unsigned int len, size_t recsize); + +#endif +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) */ diff --git a/include/compat/linux/math64.h b/include/compat/linux/math64.h new file mode 100644 index 00000000..eb9e8e15 --- /dev/null +++ b/include/compat/linux/math64.h @@ -0,0 +1,10 @@ +#ifndef _COMPAT_LINUX_MATH64_H +#define _COMPAT_LINUX_MATH64_H 1 + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)) +#include_next +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)) */ + +#endif /* _COMPAT_LINUX_MATH64_H */ diff --git a/include/compat/linux/nl80211.h b/include/compat/linux/nl80211.h new file mode 100644 index 00000000..bcf8e8c2 --- /dev/null +++ b/include/compat/linux/nl80211.h @@ -0,0 +1,2963 @@ +#ifndef __LINUX_NL80211_H +#define __LINUX_NL80211_H +/* + * 802.11 netlink interface public header + * + * Copyright 2006-2010 Johannes Berg + * Copyright 2008 Michael Wu + * Copyright 2008 Luis Carlos Cobo + * Copyright 2008 Michael Buesch + * Copyright 2008, 2009 Luis R. Rodriguez + * Copyright 2008 Jouni Malinen + * Copyright 2008 Colin McCabe + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + * + */ + +#include + +/** + * DOC: Station handling + * + * Stations are added per interface, but a special case exists with VLAN + * interfaces. When a station is bound to an AP interface, it may be moved + * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). + * The station is still assumed to belong to the AP interface it was added + * to. + * + * TODO: need more info? + */ + +/** + * DOC: Frame transmission/registration support + * + * Frame transmission and registration support exists to allow userspace + * management entities such as wpa_supplicant react to management frames + * that are not being handled by the kernel. This includes, for example, + * certain classes of action frames that cannot be handled in the kernel + * for various reasons. + * + * Frame registration is done on a per-interface basis and registrations + * cannot be removed other than by closing the socket. It is possible to + * specify a registration filter to register, for example, only for a + * certain type of action frame. In particular with action frames, those + * that userspace registers for will not be returned as unhandled by the + * driver, so that the registered application has to take responsibility + * for doing that. + * + * The type of frame that can be registered for is also dependent on the + * driver and interface type. The frame types are advertised in wiphy + * attributes so applications know what to expect. + * + * NOTE: When an interface changes type while registrations are active, + * these registrations are ignored until the interface type is + * changed again. This means that changing the interface type can + * lead to a situation that couldn't otherwise be produced, but + * any such registrations will be dormant in the sense that they + * will not be serviced, i.e. they will not receive any frames. + * + * Frame transmission allows userspace to send for example the required + * responses to action frames. It is subject to some sanity checking, + * but many frames can be transmitted. When a frame was transmitted, its + * status is indicated to the sending socket. + * + * For more technical details, see the corresponding command descriptions + * below. + */ + +/** + * DOC: Virtual interface / concurrency capabilities + * + * Some devices are able to operate with virtual MACs, they can have + * more than one virtual interface. The capability handling for this + * is a bit complex though, as there may be a number of restrictions + * on the types of concurrency that are supported. + * + * To start with, each device supports the interface types listed in + * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the + * types there no concurrency is implied. + * + * Once concurrency is desired, more attributes must be observed: + * To start with, since some interface types are purely managed in + * software, like the AP-VLAN type in mac80211 for example, there's + * an additional list of these, they can be added at any time and + * are only restricted by some semantic restrictions (e.g. AP-VLAN + * cannot be added without a corresponding AP interface). This list + * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute. + * + * Further, the list of supported combinations is exported. This is + * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically, + * it exports a list of "groups", and at any point in time the + * interfaces that are currently active must fall into any one of + * the advertised groups. Within each group, there are restrictions + * on the number of interfaces of different types that are supported + * and also the number of different channels, along with potentially + * some other restrictions. See &enum nl80211_if_combination_attrs. + * + * All together, these attributes define the concurrency of virtual + * interfaces that a given device supports. + */ + +/** + * enum nl80211_commands - supported nl80211 commands + * + * @NL80211_CMD_UNSPEC: unspecified command to catch errors + * + * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request + * to get a list of all present wiphys. + * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or + * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, + * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT, + * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. + * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL + * instead, the support here is for backward compatibility only. + * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request + * or rename notification. Has attributes %NL80211_ATTR_WIPHY and + * %NL80211_ATTR_WIPHY_NAME. + * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes + * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. + * + * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; + * either a dump request on a %NL80211_ATTR_WIPHY or a specific get + * on an %NL80211_ATTR_IFINDEX is supported. + * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. + * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response + * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, + * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also + * be sent from userspace to request creation of a new virtual interface, + * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and + * %NL80211_ATTR_IFNAME. + * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from + * userspace to request deletion of a virtual interface, then requires + * attribute %NL80211_ATTR_IFINDEX. + * + * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. + * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, + * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. + * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, + * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER, + * and %NL80211_ATTR_KEY_SEQ attributes. + * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX + * or %NL80211_ATTR_MAC. + * + * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a + * %NL80222_CMD_NEW_BEACON message) + * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface + * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, + * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. + * Following attributes are provided for drivers that generate full Beacon + * and Probe Response frames internally: %NL80211_ATTR_SSID, + * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, + * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, + * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP, + * %NL80211_ATTR_IE_ASSOC_RESP. + * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, + * parameters are like for %NL80211_CMD_SET_BEACON. + * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it + * + * @NL80211_CMD_GET_STATION: Get station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_STATION: Set station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all stations, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * + * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by + * %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP. + * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by + * %NL80211_ATTR_MAC. + * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all mesh paths, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by + * %NL80211_ATTR_IFINDEX. + * + * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set + * regulatory domain. + * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command + * after being queried by the kernel. CRDA replies by sending a regulatory + * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our + * current alpha2 if it found a match. It also provides + * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each + * regulatory rule is a nested set of attributes given by + * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and + * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by + * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and + * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. + * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain + * to the specified ISO/IEC 3166-1 alpha2 country code. The core will + * store this as a valid request and then query userspace for it. + * + * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the + * interface identified by %NL80211_ATTR_IFINDEX + * + * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the + * interface identified by %NL80211_ATTR_IFINDEX + * + * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The + * interface is identified with %NL80211_ATTR_IFINDEX and the management + * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be + * added to the end of the specified management frame is specified with + * %NL80211_ATTR_IE. If the command succeeds, the requested data will be + * added to all specified management frames generated by + * kernel/firmware/driver. + * Note: This command has been removed and it is only reserved at this + * point to avoid re-using existing command number. The functionality this + * command was planned for has been provided with cleaner design with the + * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN, + * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE, + * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE. + * + * @NL80211_CMD_GET_SCAN: get scan results + * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * probe requests at CCK rate or not. + * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to + * NL80211_CMD_GET_SCAN and on the "scan" multicast group) + * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, + * partial scan results may be available + * + * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain + * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL. + * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) + * are passed, they are used in the probe requests. For + * broadcast, a broadcast SSID must be passed (ie. an empty + * string). If no SSID is passed, no probe requests are sent and + * a passive scan is performed. %NL80211_ATTR_SCAN_FREQUENCIES, + * if passed, define which channels should be scanned; if not + * passed, all channels allowed for the current regulatory domain + * are used. Extra IEs can also be passed from the userspace by + * using the %NL80211_ATTR_IE attribute. + * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT + * if scheduled scan is not running. + * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan + * results available. + * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has + * stopped. The driver may issue this event at any time during a + * scheduled scan. One reason for stopping the scan is if the hardware + * does not support starting an association or a normal scan while running + * a scheduled scan. This event is also sent when the + * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface + * is brought down while a scheduled scan was running. + * + * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation + * or noise level + * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to + * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) + * + * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain + * has been changed and provides details of the request information + * that caused the change such as who initiated the regulatory request + * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx + * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if + * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or + * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain + * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is + * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on + * to (%NL80211_ATTR_REG_ALPHA2). + * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon + * has been found while world roaming thus enabling active scan or + * any mode of operation that initiates TX (beacons) on a channel + * where we would not have been able to do either before. As an example + * if you are world roaming (regulatory domain set to world or if your + * driver is using a custom world roaming regulatory domain) and while + * doing a passive scan on the 5 GHz band you find an AP there (if not + * on a DFS channel) you will now be able to actively scan for that AP + * or use AP mode on your card on that same channel. Note that this will + * never be used for channels 1-11 on the 2 GHz band as they are always + * enabled world wide. This beacon hint is only sent if your device had + * either disabled active scanning or beaconing on a channel. We send to + * userspace the wiphy on which we removed a restriction from + * (%NL80211_ATTR_WIPHY) and the channel on which this occurred + * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER) + * the beacon hint was processed. + * + * @NL80211_CMD_AUTHENTICATE: authentication request and notification. + * This command is used both as a command (request to authenticate) and + * as an event on the "mlme" multicast group indicating completion of the + * authentication process. + * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the + * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and + * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify + * the SSID (mainly for association, but is included in authentication + * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used + * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE + * is used to specify the authentication type. %NL80211_ATTR_IE is used to + * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs) + * to be added to the frame. + * When used as an event, this reports reception of an Authentication + * frame in station and IBSS modes when the local MLME processed the + * frame, i.e., it was for the local STA and was received in correct + * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the + * MLME SAP interface (kernel providing MLME, userspace SME). The + * included %NL80211_ATTR_FRAME attribute contains the management frame + * (including both the header and frame body, but not FCS). This event is + * also used to indicate if the authentication attempt timed out. In that + * case the %NL80211_ATTR_FRAME attribute is replaced with a + * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which + * pending authentication timed out). + * @NL80211_CMD_ASSOCIATE: association request and notification; like + * NL80211_CMD_AUTHENTICATE but for Association and Reassociation + * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request, + * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). + * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like + * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to + * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication + * primitives). + * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like + * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to + * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives). + * + * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael + * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the + * event includes %NL80211_ATTR_MAC to describe the source MAC address of + * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key + * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and + * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this + * event matches with MLME-MICHAELMICFAILURE.indication() primitive + * + * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a + * FREQ attribute (for the initial frequency if no peer can be found) + * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those + * should be fixed rather than automatically determined. Can only be + * executed on a network interface that is UP, and fixed BSSID/FREQ + * may be rejected. Another optional parameter is the beacon interval, + * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not + * given defaults to 100 TU (102.4ms). + * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is + * determined by the network interface. + * + * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute + * to identify the device, and the TESTDATA blob attribute to pass through + * to the driver. + * + * @NL80211_CMD_CONNECT: connection request and notification; this command + * requests to connect to a specified network but without separating + * auth and assoc steps. For this, you need to specify the SSID in a + * %NL80211_ATTR_SSID attribute, and can optionally specify the association + * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC, + * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, + * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. + * Background scan period can optionally be + * specified in %NL80211_ATTR_BG_SCAN_PERIOD, + * if not specified default background scan configuration + * in driver is used and if period value is 0, bg scan will be disabled. + * This attribute is ignored if driver does not support roam scan. + * It is also sent as an event, with the BSSID and response IEs when the + * connection is established or failed to be established. This can be + * determined by the STATUS_CODE attribute. + * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), + * sent as an event when the card/driver roamed by itself. + * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify + * userspace that a connection was dropped by the AP or due to other + * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and + * %NL80211_ATTR_REASON_CODE attributes are used. + * + * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices + * associated with this wiphy must be down and will follow. + * + * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified + * channel for the specified amount of time. This can be used to do + * off-channel operations like transmit a Public Action frame and wait for + * a response while being associated to an AP on another channel. + * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus + * radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the + * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be + * optionally used to specify additional channel parameters. + * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds + * to remain on the channel. This command is also used as an event to + * notify when the requested duration starts (it may take a while for the + * driver to schedule this time due to other concurrent needs for the + * radio). + * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) + * that will be included with any events pertaining to this request; + * the cookie is also used to cancel the request. + * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a + * pending remain-on-channel duration if the desired operation has been + * completed prior to expiration of the originally requested duration. + * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the + * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to + * uniquely identify the request. + * This command is also used as an event to notify when a requested + * remain-on-channel duration has expired. + * + * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX + * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface + * and @NL80211_ATTR_TX_RATES the set of allowed rates. + * + * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames + * (via @NL80211_CMD_FRAME) for processing in userspace. This command + * requires an interface index, a frame type attribute (optional for + * backward compatibility reasons, if not given assumes action frames) + * and a match attribute containing the first few bytes of the frame + * that should match, e.g. a single byte for only a category match or + * four bytes for vendor frames including the OUI. The registration + * cannot be dropped, but is removed automatically when the netlink + * socket is closed. Multiple registrations can be made. + * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for + * backward compatibility + * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This + * command is used both as a request to transmit a management frame and + * as an event indicating reception of a frame that was not processed in + * kernel code, but is for us (i.e., which may need to be processed in a + * user space application). %NL80211_ATTR_FRAME is used to specify the + * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and + * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on + * which channel the frame is to be transmitted or was received. If this + * channel is not the current channel (remain-on-channel or the + * operational channel) the device will switch to the given channel and + * transmit the frame, optionally waiting for a response for the time + * specified using %NL80211_ATTR_DURATION. When called, this operation + * returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the + * TX status event pertaining to the TX request. + * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the + * management frames at CCK rate or not in 2GHz band. + * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this + * command may be used with the corresponding cookie to cancel the wait + * time if it is known that it is no longer necessary. + * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility. + * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame + * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies + * the TX command and %NL80211_ATTR_FRAME includes the contents of the + * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged + * the frame. + * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for + * backward compatibility. + * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command + * is used to configure connection quality monitoring notification trigger + * levels. + * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This + * command is used as an event to indicate the that a trigger level was + * reached. + * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ + * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed + * by %NL80211_ATTR_IFINDEX) shall operate on. + * In case multiple channels are supported by the device, the mechanism + * with which it switches channels is implementation-defined. + * When a monitor interface is given, it can only switch channel while + * no other interfaces are operating to avoid disturbing the operation + * of any other interfaces, and other interfaces will again take + * precedence when they are used. + * + * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. + * + * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial + * mesh config parameters may be given. + * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the + * network is determined by the network interface. + * + * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame + * notification. This event is used to indicate that an unprotected + * deauthentication frame was dropped when MFP is in use. + * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame + * notification. This event is used to indicate that an unprotected + * disassociation frame was dropped when MFP is in use. + * + * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a + * beacon or probe response from a compatible mesh peer. This is only + * sent while no station information (sta_info) exists for the new peer + * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On + * reception of this notification, userspace may decide to create a new + * station (@NL80211_CMD_NEW_STATION). To stop this notification from + * reoccurring, the userspace authentication daemon may want to create the + * new station with the AUTHENTICATED flag unset and maybe change it later + * depending on the authentication result. + * + * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings. + * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings. + * Since wireless is more complex than wired ethernet, it supports + * various triggers. These triggers can be configured through this + * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For + * more background information, see + * http://wireless.kernel.org/en/users/Documentation/WoWLAN. + * + * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver + * the necessary information for supporting GTK rekey offload. This + * feature is typically used during WoWLAN. The configuration data + * is contained in %NL80211_ATTR_REKEY_DATA (which is nested and + * contains the data in sub-attributes). After rekeying happened, + * this command may also be sent by the driver as an MLME event to + * inform userspace of the new replay counter. + * + * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace + * of PMKSA caching dandidates. + * + * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * + * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP + * (or GO) interface (i.e. hostapd) to ask for unexpected frames to + * implement sending deauth to stations that send unexpected class 3 + * frames. Also used as the event sent by the kernel when such a frame + * is received. + * For the event, the %NL80211_ATTR_MAC attribute carries the TA and + * other attributes like the interface index are present. + * If used as the command it must have an interface index and you can + * only unsubscribe from the event by closing the socket. Subscription + * is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events. + * + * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the + * associated station identified by %NL80211_ATTR_MAC sent a 4addr frame + * and wasn't already in a 4-addr VLAN. The event will be sent similarly + * to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener. + * + * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface + * by sending a null data frame to it and reporting when the frame is + * acknowleged. This is used to allow timing out inactive clients. Uses + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a + * direct reply with an %NL80211_ATTR_COOKIE that is later used to match + * up the event with the request. The event includes the same data and + * has %NL80211_ATTR_ACK set if the frame was ACKed. + * + * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from + * other BSSes when any interfaces are in AP mode. This helps implement + * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME + * messages. Note that per PHY only one application may register. + * + * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels + * independently of the userspace SME, send this event indicating + * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with + * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. + * + * @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to + * notify userspace that AP has rejected the connection request from a + * station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON + * is used for this. + * + * @NL80211_CMD_BTCOEX: Send BTCOEX command to firmware. This is + * used by the firmware to be aware of BT traffic and share radio + * between WiFi and BT. + * + * @NL80211_ATTR_STA_CAPA_REQ: Restrict only particular mode capable station + * to connect (applicable only in AP mode). For example, this can be used + * to allow only the remote station which supports 11G only mode to connect + * to the AP. Currently used with %NL80211_CMD_NEW_BEACON command, + * see &enum nl80211_sta_capab_req_options. + * + * @NL80211_CMD_SET_MAC_ACL: sets a list of mac addresses for access control. + * This is to be used with the drivers advertising the support of mac + * address based access control. The list of mac addresses defined by + * %NL80211_ATTR_MAC_ADDRS would replace any existing acl list in driver + * for a particular acl policy specified by %NL80211_ATTR_ACL_POLICY. + * When the passed list of mac address is empty for a particular acl + * policy, driver has to clear corresponding acl list. This command is + * used in AP/P2P GO mode. Driver has to make sure it's acl lists are + * cleared during %NL80211_CMD_START_AP and NL80211_CMD_STOP_AP. + * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +enum nl80211_commands { +/* don't change the order or add anything between, this is ABI! */ + NL80211_CMD_UNSPEC, + + NL80211_CMD_GET_WIPHY, /* can dump */ + NL80211_CMD_SET_WIPHY, + NL80211_CMD_NEW_WIPHY, + NL80211_CMD_DEL_WIPHY, + + NL80211_CMD_GET_INTERFACE, /* can dump */ + NL80211_CMD_SET_INTERFACE, + NL80211_CMD_NEW_INTERFACE, + NL80211_CMD_DEL_INTERFACE, + + NL80211_CMD_GET_KEY, + NL80211_CMD_SET_KEY, + NL80211_CMD_NEW_KEY, + NL80211_CMD_DEL_KEY, + + NL80211_CMD_GET_BEACON, + NL80211_CMD_SET_BEACON, + NL80211_CMD_NEW_BEACON, + NL80211_CMD_DEL_BEACON, + + NL80211_CMD_GET_STATION, + NL80211_CMD_SET_STATION, + NL80211_CMD_NEW_STATION, + NL80211_CMD_DEL_STATION, + + NL80211_CMD_GET_MPATH, + NL80211_CMD_SET_MPATH, + NL80211_CMD_NEW_MPATH, + NL80211_CMD_DEL_MPATH, + + NL80211_CMD_SET_BSS, + + NL80211_CMD_SET_REG, + NL80211_CMD_REQ_SET_REG, + + NL80211_CMD_GET_MESH_CONFIG, + NL80211_CMD_SET_MESH_CONFIG, + + NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */, + + NL80211_CMD_GET_REG, + + NL80211_CMD_GET_SCAN, + NL80211_CMD_TRIGGER_SCAN, + NL80211_CMD_NEW_SCAN_RESULTS, + NL80211_CMD_SCAN_ABORTED, + + NL80211_CMD_REG_CHANGE, + + NL80211_CMD_AUTHENTICATE, + NL80211_CMD_ASSOCIATE, + NL80211_CMD_DEAUTHENTICATE, + NL80211_CMD_DISASSOCIATE, + + NL80211_CMD_MICHAEL_MIC_FAILURE, + + NL80211_CMD_REG_BEACON_HINT, + + NL80211_CMD_JOIN_IBSS, + NL80211_CMD_LEAVE_IBSS, + + NL80211_CMD_TESTMODE, + + NL80211_CMD_CONNECT, + NL80211_CMD_ROAM, + NL80211_CMD_DISCONNECT, + + NL80211_CMD_SET_WIPHY_NETNS, + + NL80211_CMD_GET_SURVEY, + NL80211_CMD_NEW_SURVEY_RESULTS, + + NL80211_CMD_SET_PMKSA, + NL80211_CMD_DEL_PMKSA, + NL80211_CMD_FLUSH_PMKSA, + + NL80211_CMD_REMAIN_ON_CHANNEL, + NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + + NL80211_CMD_SET_TX_BITRATE_MASK, + + NL80211_CMD_REGISTER_FRAME, + NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME, + NL80211_CMD_FRAME, + NL80211_CMD_ACTION = NL80211_CMD_FRAME, + NL80211_CMD_FRAME_TX_STATUS, + NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS, + + NL80211_CMD_SET_POWER_SAVE, + NL80211_CMD_GET_POWER_SAVE, + + NL80211_CMD_SET_CQM, + NL80211_CMD_NOTIFY_CQM, + + NL80211_CMD_SET_CHANNEL, + NL80211_CMD_SET_WDS_PEER, + + NL80211_CMD_FRAME_WAIT_CANCEL, + + NL80211_CMD_JOIN_MESH, + NL80211_CMD_LEAVE_MESH, + + NL80211_CMD_UNPROT_DEAUTHENTICATE, + NL80211_CMD_UNPROT_DISASSOCIATE, + + NL80211_CMD_NEW_PEER_CANDIDATE, + + NL80211_CMD_GET_WOWLAN, + NL80211_CMD_SET_WOWLAN, + + NL80211_CMD_START_SCHED_SCAN, + NL80211_CMD_STOP_SCHED_SCAN, + NL80211_CMD_SCHED_SCAN_RESULTS, + NL80211_CMD_SCHED_SCAN_STOPPED, + + NL80211_CMD_SET_REKEY_OFFLOAD, + + NL80211_CMD_PMKSA_CANDIDATE, + + NL80211_CMD_TDLS_OPER, + NL80211_CMD_TDLS_MGMT, + + NL80211_CMD_UNEXPECTED_FRAME, + + NL80211_CMD_PROBE_CLIENT, + + NL80211_CMD_REGISTER_BEACONS, + + NL80211_CMD_UNEXPECTED_4ADDR_FRAME, + + NL80211_CMD_SET_NOACK_MAP, /* just to maintain ABI with CH_SWITCH_NOTIFY */ + + NL80211_CMD_CH_SWITCH_NOTIFY, + + NL80211_CMD_CONN_FAILED, + + NL80211_CMD_SET_MAC_ACL, + + NL80211_CMD_BTCOEX, + + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ + __NL80211_CMD_AFTER_LAST, + NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 +}; + +/* + * Allow user space programs to use #ifdef on new commands by defining them + * here + */ +#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS +#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE +#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE +#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE +#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE +#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE +#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE +#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT + +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + +/* source-level API compatibility */ +#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG +#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG +#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE + +/** + * enum nl80211_attrs - nl80211 netlink attributes + * + * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors + * + * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. + * /sys/class/ieee80211//index + * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) + * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz + * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ + * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): + * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including + * this attribute) + * NL80211_CHAN_HT20 = HT20 only + * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel + * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel + * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is + * less than or equal to the RTS threshold; allowed range: 1..255; + * dot11ShortRetryLimit; u8 + * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is + * greater than the RTS threshold; allowed range: 1..255; + * dot11ShortLongLimit; u8 + * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum + * length in octets for frames; allowed range: 256..8000, disable + * fragmentation with (u32)-1; dot11FragmentationThreshold; u32 + * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length + * larger than or equal to this use RTS/CTS handshake); allowed range: + * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 + * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 + * section 7.3.2.9; dot11CoverageClass; u8 + * + * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on + * @NL80211_ATTR_IFNAME: network interface name + * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype + * + * @NL80211_ATTR_MAC: MAC address (various uses) + * + * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of + * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC + * keys + * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) + * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 + * section 7.3.2.25.1, e.g. 0x000FAC04) + * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and + * CCMP keys, each six bytes in little endian + * + * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU + * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing + * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE + * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE + * + * @NL80211_ATTR_STA_AID: Association ID for the station (u16) + * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2) + * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by + * IEEE 802.11 7.3.1.6 (u16). + * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported + * rates as defined by IEEE 802.11 7.3.2.2 but without the length + * restriction (at most %NL80211_MAX_SUPP_RATES). + * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station + * to, or the AP interface the station was originally added to to. + * @NL80211_ATTR_STA_INFO: information about a station, part of station info + * given for %NL80211_CMD_GET_STATION, nested attribute containing + * info as possible, see &enum nl80211_sta_info. + * + * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, + * consisting of a nested array. + * + * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). + * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link. + * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. + * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path + * info given for %NL80211_CMD_GET_MPATH, nested attribute described at + * &enum nl80211_mpath_info. + * + * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_mntr_flags. + * + * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the + * current regulatory domain should be set to or is already set to. + * For example, 'CR', for Costa Rica. This attribute is used by the kernel + * to query the CRDA to retrieve one regulatory domain. This attribute can + * also be used by userspace to query the kernel for the currently set + * regulatory domain. We chose an alpha2 as that is also used by the + * IEEE-802.11d country information element to identify a country. + * Users can also simply ask the wireless core to set regulatory domain + * to a specific alpha2. + * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory + * rules. + * + * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) + * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled + * (u8, 0 or 1) + * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled + * (u8, 0 or 1) + * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic + * rates in format defined by IEEE 802.11 7.3.2.2 but without the length + * restriction (at most %NL80211_MAX_SUPP_RATES). + * + * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION) + * + * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all + * supported interface types, each a flag attribute with the number + * of the interface mode. + * + * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for + * %NL80211_CMD_SET_MGMT_EXTRA_IE. + * + * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with + * %NL80211_CMD_SET_MGMT_EXTRA_IE). + * + * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with + * a single scan request, a wiphy attribute. + * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can + * scan with a single scheduled scan request, a wiphy attribute. + * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements + * that can be added to a scan request + * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information + * elements that can be added to a scheduled scan request + * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be + * used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute. + * + * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) + * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive + * scanning and include a zero-length SSID (wildcard) for wildcard scan + * @NL80211_ATTR_BSS: scan result BSS + * + * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain + * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_* + * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently + * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*) + * + * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies + * an array of command numbers (i.e. a mapping index to command number) + * that the driver for the given wiphy supports. + * + * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header + * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and + * NL80211_CMD_ASSOCIATE events + * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets) + * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type, + * represented as a u32 + * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and + * %NL80211_CMD_DISASSOCIATE, u16 + * + * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as + * a u32 + * + * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change + * due to considerations from a beacon hint. This attribute reflects + * the state of the channel _before_ the beacon hint processing. This + * attributes consists of a nested attribute containing + * NL80211_FREQUENCY_ATTR_* + * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change + * due to considerations from a beacon hint. This attribute reflects + * the state of the channel _after_ the beacon hint processing. This + * attributes consists of a nested attribute containing + * NL80211_FREQUENCY_ATTR_* + * + * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported + * cipher suites + * + * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look + * for other networks on different channels + * + * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this + * is used, e.g., with %NL80211_CMD_AUTHENTICATE event + * + * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is + * used for the association (&enum nl80211_mfp, represented as a u32); + * this attribute can be used + * with %NL80211_CMD_ASSOCIATE request + * + * @NL80211_ATTR_STA_FLAGS2: Attribute containing a + * &struct nl80211_sta_flag_update. + * + * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls + * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in + * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE + * request, the driver will assume that the port is unauthorized until + * authorized by user space. Otherwise, port is marked authorized by + * default in station mode. + * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the + * ethertype that will be used for key negotiation. It can be + * specified with the associate and connect commands. If it is not + * specified, the value defaults to 0x888E (PAE, 802.1X). This + * attribute is also used as a flag in the wiphy information to + * indicate that protocols other than PAE are supported. + * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with + * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom + * ethertype frames used for key negotiation must not be encrypted. + * + * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. + * We recommend using nested, driver-specific attributes within this. + * + * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT + * event was due to the AP disconnecting the station, and not due to + * a local disconnect request. + * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT + * event (u16) + * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating + * that protected APs should be used. This is also used with NEW_BEACON to + * indicate that the BSS is to use protection. + * + * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON + * to indicate which unicast key ciphers will be used with the connection + * (an array of u32). + * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which group key cipher will be used with the connection (a + * u32). + * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which WPA version(s) the AP we want to associate with is using + * (a u32 with flags from &enum nl80211_wpa_versions). + * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to + * indicate which key management algorithm(s) to use (an array of u32). + * + * @NL80211_ATTR_REQ_IE: (Re)association request information elements as + * sent out by the card, for ROAM and successful CONNECT events. + * @NL80211_ATTR_RESP_IE: (Re)association response information elements as + * sent by peer, for ROAM and successful CONNECT events. + * + * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE + * commands to specify using a reassociate frame + * + * @NL80211_ATTR_KEY: key information in a nested attribute with + * %NL80211_KEY_* sub-attributes + * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect() + * and join_ibss(), key information is in a nested attribute each + * with %NL80211_KEY_* sub-attributes + * + * @NL80211_ATTR_PID: Process ID of a network namespace. + * + * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for + * dumps. This number increases whenever the object list being + * dumped changes, and as such userspace can verify that it has + * obtained a complete and consistent snapshot by verifying that + * all dump messages contain the same generation number. If it + * changed then the list changed and the dump should be repeated + * completely from scratch. + * + * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface + * + * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of + * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute + * containing info as possible, see &enum survey_info. + * + * @NL80211_ATTR_PMKID: PMK material for PMKSA caching. + * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can + * cache, a wiphy attribute. + * + * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. + * @NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION: Device attribute that + * specifies the maximum duration that can be requested with the + * remain-on-channel operation, in milliseconds, u32. + * + * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. + * + * @NL80211_ATTR_TX_RATES: Nested set of attributes + * (enum nl80211_tx_rate_attributes) describing TX rates per band. The + * enum nl80211_band value is used as the index (nla_type() of the nested + * data. If a band is not included, it will be configured to allow all + * rates based on negotiated supported rates information. This attribute + * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. + * + * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain + * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. + * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the + * @NL80211_CMD_REGISTER_FRAME command. + * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a + * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing + * information about which frame types can be transmitted with + * %NL80211_CMD_FRAME. + * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a + * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing + * information about which frame types can be registered for RX. + * + * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was + * acknowledged by the recipient. + * + * @NL80211_ATTR_CQM: connection quality monitor configuration in a + * nested attribute with %NL80211_ATTR_CQM_* sub-attributes. + * + * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command + * is requesting a local authentication/association state change without + * invoking actual management frame exchange. This can be used with + * NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE, + * NL80211_CMD_DISASSOCIATE. + * + * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations + * connected to this BSS. + * + * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See + * &enum nl80211_tx_power_setting for possible values. + * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units. + * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING + * for non-automatic settings. + * + * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly + * means support for per-station GTKs. + * + * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting. + * This can be used to mask out antennas which are not attached or should + * not be used for transmitting. If an antenna is not selected in this + * bitmap the hardware is not allowed to transmit on this antenna. + * + * Each bit represents one antenna, starting with antenna 1 at the first + * bit. Depending on which antennas are selected in the bitmap, 802.11n + * drivers can derive which chainmasks to use (if all antennas belonging to + * a particular chain are disabled this chain should be disabled) and if + * a chain has diversity antennas wether diversity should be used or not. + * HT capabilities (STBC, TX Beamforming, Antenna selection) can be + * derived from the available chains after applying the antenna mask. + * Non-802.11n drivers can derive wether to use diversity or not. + * Drivers may reject configurations or RX/TX mask combinations they cannot + * support by returning -EINVAL. + * + * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving. + * This can be used to mask out antennas which are not attached or should + * not be used for receiving. If an antenna is not selected in this bitmap + * the hardware should not be configured to receive on this antenna. + * For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available + * for configuration as TX antennas via the above parameters. + * + * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available + * for configuration as RX antennas via the above parameters. + * + * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS + * + * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be + * transmitted on another channel when the channel given doesn't match + * the current channel. If the current channel doesn't match and this + * flag isn't set, the frame will be rejected. This is also used as an + * nl80211 capability flag. + * + * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16) + * + * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags + * attributes, specifying what a key should be set as default as. + * See &enum nl80211_key_default_types. + * + * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters. These cannot be + * changed once the mesh is active. + * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute + * containing attributes from &enum nl80211_meshconf_params. + * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver + * allows auth frames in a mesh to be passed to userspace for processing via + * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. + * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as + * defined in &enum nl80211_plink_state. Used when userspace is + * driving the peer link management state machine. + * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. + * + * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy + * capabilities, the supported WoWLAN triggers + * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to + * indicate which WoW triggers should be enabled. This is also + * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN + * triggers. + + * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan + * cycles, in msecs. + + * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more + * sets of attributes to match during scheduled scans. Only BSSs + * that match any of the sets will be reported. These are + * pass-thru filter rules. + * For a match to succeed, the BSS must match all attributes of a + * set. Since not every hardware supports matching all types of + * attributes, there is no guarantee that the reported BSSs are + * fully complying with the match sets and userspace needs to be + * able to ignore them by itself. + * Thus, the implementation is somewhat hardware-dependent, but + * this is only an optimization and the userspace application + * needs to handle all the non-filtered results anyway. + * If the match attributes don't make sense when combined with + * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID + * is included in the probe request, but the match attributes + * will never let it go through), -EINVAL may be returned. + * If ommited, no filtering is done. + * + * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported + * interface combinations. In each nested item, it contains attributes + * defined in &enum nl80211_if_combination_attrs. + * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like + * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that + * are managed in software: interfaces of these types aren't subject to + * any restrictions in their number or combinations. + * + * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information + * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data. + * + * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan, + * nested array attribute containing an entry for each band, with the entry + * being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but + * without the length restriction (at most %NL80211_MAX_SUPP_RATES). + * + * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon + * and Probe Response (when response to wildcard Probe Request); see + * &enum nl80211_hidden_ssid, represented as a u32 + * + * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame. + * This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to + * provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the + * driver (or firmware) replies to Probe Request frames. + * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association + * Response frames. This is used with %NL80211_CMD_NEW_BEACON and + * %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into + * (Re)Association Response frames when the driver (or firmware) replies to + * (Re)Association Request frames. + * + * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration + * of the station, see &enum nl80211_sta_wme_attr. + * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working + * as AP. + * + * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of + * roaming to another AP in the same ESS if the signal lever is low. + * + * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching + * candidate information, see &enum nl80211_pmksa_candidate_attr. + * + * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not + * for management frames transmission. In order to avoid p2p probe/action + * frames are being transmitted at CCK rate in 2GHz band, the user space + * applications use this attribute. + * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and + * %NL80211_CMD_FRAME commands. + * + * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup + * request, link setup confirm, link teardown, etc.). Values are + * described in the TDLS (802.11z) specification. + * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a + * TDLS conversation between two devices. + * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see + * &enum nl80211_tdls_operation, represented as a u8. + * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate + * as a TDLS peer sta. + * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown + * procedures should be performed by sending TDLS packets via + * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be + * used for asking the driver to perform a TDLS operation. + * + * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices + * that have AP support to indicate that they have the AP SME integrated + * with support for the features listed in this attribute, see + * &enum nl80211_ap_sme_features. + * + * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells + * the driver to not wait for an acknowledgement. Note that due to this, + * it will also not give a status callback nor return a cookie. This is + * mostly useful for probe responses to save airtime. + * + * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from + * &enum nl80211_feature_flags and is advertised in wiphy information. + * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe + * + * requests while operating in AP-mode. + * This attribute holds a bitmap of the supported protocols for + * offloading (see &enum nl80211_probe_resp_offload_support_attr). + * + * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire + * probe-response frame. The DA field in the 802.11 header is zero-ed out, + * to be filled by the FW. + * + * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds + * or 0 to disable background scan. + * + * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices + * that don't have a netdev (u64) + * + * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from + * userspace. If unset it is assumed the hint comes directly from + * a user. If set code could specify exactly what type of source + * was used to provide the hint. For the different types of + * allowed user regulatory hints see nl80211_user_reg_hint_type. + * + * @NL80211_ATTR_CONN_FAILED_REASON: The reason for which AP has rejected + * the connection request from a station. nl80211_connect_failed_reason + * enum has different reasons of connection failure. + * + * @NL80211_ATTR_BTCOEX_DATA: BT coex wmi command. + * + * @NL80211_ATTR_ACS: Enable automatic channel selection by the driver + * for AP/GO mode. + * + * @NL80211_ATTR_MAC_ACL: u8 attribute to enable or disable mac address + * based access control in driver, needs to be used with the drivers + * which advertise this support. + * + * @NL80211_ATTR_MAC_ADDRS: Nested attribute with mac addresses used for ACL. + * + * @NL80211_ATTR_ACL_POLICY: policy of access control, + * see &enum nl80211_acl_policy_attr. + * + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use + */ +enum nl80211_attrs { +/* don't change the order or add anything between, this is ABI! */ + NL80211_ATTR_UNSPEC, + + NL80211_ATTR_WIPHY, + NL80211_ATTR_WIPHY_NAME, + + NL80211_ATTR_IFINDEX, + NL80211_ATTR_IFNAME, + NL80211_ATTR_IFTYPE, + + NL80211_ATTR_MAC, + + NL80211_ATTR_KEY_DATA, + NL80211_ATTR_KEY_IDX, + NL80211_ATTR_KEY_CIPHER, + NL80211_ATTR_KEY_SEQ, + NL80211_ATTR_KEY_DEFAULT, + + NL80211_ATTR_BEACON_INTERVAL, + NL80211_ATTR_DTIM_PERIOD, + NL80211_ATTR_BEACON_HEAD, + NL80211_ATTR_BEACON_TAIL, + + NL80211_ATTR_STA_AID, + NL80211_ATTR_STA_FLAGS, + NL80211_ATTR_STA_LISTEN_INTERVAL, + NL80211_ATTR_STA_SUPPORTED_RATES, + NL80211_ATTR_STA_VLAN, + NL80211_ATTR_STA_INFO, + + NL80211_ATTR_WIPHY_BANDS, + + NL80211_ATTR_MNTR_FLAGS, + + NL80211_ATTR_MESH_ID, + NL80211_ATTR_STA_PLINK_ACTION, + NL80211_ATTR_MPATH_NEXT_HOP, + NL80211_ATTR_MPATH_INFO, + + NL80211_ATTR_BSS_CTS_PROT, + NL80211_ATTR_BSS_SHORT_PREAMBLE, + NL80211_ATTR_BSS_SHORT_SLOT_TIME, + + NL80211_ATTR_HT_CAPABILITY, + + NL80211_ATTR_SUPPORTED_IFTYPES, + + NL80211_ATTR_REG_ALPHA2, + NL80211_ATTR_REG_RULES, + + NL80211_ATTR_MESH_CONFIG, + + NL80211_ATTR_BSS_BASIC_RATES, + + NL80211_ATTR_WIPHY_TXQ_PARAMS, + NL80211_ATTR_WIPHY_FREQ, + NL80211_ATTR_WIPHY_CHANNEL_TYPE, + + NL80211_ATTR_KEY_DEFAULT_MGMT, + + NL80211_ATTR_MGMT_SUBTYPE, + NL80211_ATTR_IE, + + NL80211_ATTR_MAX_NUM_SCAN_SSIDS, + + NL80211_ATTR_SCAN_FREQUENCIES, + NL80211_ATTR_SCAN_SSIDS, + NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */ + NL80211_ATTR_BSS, + + NL80211_ATTR_REG_INITIATOR, + NL80211_ATTR_REG_TYPE, + + NL80211_ATTR_SUPPORTED_COMMANDS, + + NL80211_ATTR_FRAME, + NL80211_ATTR_SSID, + NL80211_ATTR_AUTH_TYPE, + NL80211_ATTR_REASON_CODE, + + NL80211_ATTR_KEY_TYPE, + + NL80211_ATTR_MAX_SCAN_IE_LEN, + NL80211_ATTR_CIPHER_SUITES, + + NL80211_ATTR_FREQ_BEFORE, + NL80211_ATTR_FREQ_AFTER, + + NL80211_ATTR_FREQ_FIXED, + + + NL80211_ATTR_WIPHY_RETRY_SHORT, + NL80211_ATTR_WIPHY_RETRY_LONG, + NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + NL80211_ATTR_WIPHY_RTS_THRESHOLD, + + NL80211_ATTR_TIMED_OUT, + + NL80211_ATTR_USE_MFP, + + NL80211_ATTR_STA_FLAGS2, + + NL80211_ATTR_CONTROL_PORT, + + NL80211_ATTR_TESTDATA, + + NL80211_ATTR_PRIVACY, + + NL80211_ATTR_DISCONNECTED_BY_AP, + NL80211_ATTR_STATUS_CODE, + + NL80211_ATTR_CIPHER_SUITES_PAIRWISE, + NL80211_ATTR_CIPHER_SUITE_GROUP, + NL80211_ATTR_WPA_VERSIONS, + NL80211_ATTR_AKM_SUITES, + + NL80211_ATTR_REQ_IE, + NL80211_ATTR_RESP_IE, + + NL80211_ATTR_PREV_BSSID, + + NL80211_ATTR_KEY, + NL80211_ATTR_KEYS, + + NL80211_ATTR_PID, + + NL80211_ATTR_4ADDR, + + NL80211_ATTR_SURVEY_INFO, + + NL80211_ATTR_PMKID, + NL80211_ATTR_MAX_NUM_PMKIDS, + + NL80211_ATTR_DURATION, + + NL80211_ATTR_COOKIE, + + NL80211_ATTR_WIPHY_COVERAGE_CLASS, + + NL80211_ATTR_TX_RATES, + + NL80211_ATTR_FRAME_MATCH, + + NL80211_ATTR_ACK, + + NL80211_ATTR_PS_STATE, + + NL80211_ATTR_CQM, + + NL80211_ATTR_LOCAL_STATE_CHANGE, + + NL80211_ATTR_AP_ISOLATE, + + NL80211_ATTR_WIPHY_TX_POWER_SETTING, + NL80211_ATTR_WIPHY_TX_POWER_LEVEL, + + NL80211_ATTR_TX_FRAME_TYPES, + NL80211_ATTR_RX_FRAME_TYPES, + NL80211_ATTR_FRAME_TYPE, + + NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + + NL80211_ATTR_SUPPORT_IBSS_RSN, + + NL80211_ATTR_WIPHY_ANTENNA_TX, + NL80211_ATTR_WIPHY_ANTENNA_RX, + + NL80211_ATTR_MCAST_RATE, + + NL80211_ATTR_OFFCHANNEL_TX_OK, + + NL80211_ATTR_BSS_HT_OPMODE, + + NL80211_ATTR_KEY_DEFAULT_TYPES, + + NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, + + NL80211_ATTR_MESH_SETUP, + + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, + NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, + + NL80211_ATTR_SUPPORT_MESH_AUTH, + NL80211_ATTR_STA_PLINK_STATE, + + NL80211_ATTR_WOWLAN_TRIGGERS, + NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, + + NL80211_ATTR_SCHED_SCAN_INTERVAL, + + NL80211_ATTR_INTERFACE_COMBINATIONS, + NL80211_ATTR_SOFTWARE_IFTYPES, + + NL80211_ATTR_REKEY_DATA, + + NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, + NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, + + NL80211_ATTR_SCAN_SUPP_RATES, + + NL80211_ATTR_HIDDEN_SSID, + + NL80211_ATTR_IE_PROBE_RESP, + NL80211_ATTR_IE_ASSOC_RESP, + + NL80211_ATTR_STA_WME, + NL80211_ATTR_SUPPORT_AP_UAPSD, + + NL80211_ATTR_ROAM_SUPPORT, + + NL80211_ATTR_SCHED_SCAN_MATCH, + NL80211_ATTR_MAX_MATCH_SETS, + + NL80211_ATTR_PMKSA_CANDIDATE, + + NL80211_ATTR_TX_NO_CCK_RATE, + + NL80211_ATTR_TDLS_ACTION, + NL80211_ATTR_TDLS_DIALOG_TOKEN, + NL80211_ATTR_TDLS_OPERATION, + NL80211_ATTR_TDLS_SUPPORT, + NL80211_ATTR_TDLS_EXTERNAL_SETUP, + + NL80211_ATTR_DEVICE_AP_SME, + + NL80211_ATTR_DONT_WAIT_FOR_ACK, + + NL80211_ATTR_FEATURE_FLAGS, + + NL80211_ATTR_PROBE_RESP_OFFLOAD, + + NL80211_ATTR_PROBE_RESP, + + NL80211_ATTR_DFS_REGION, + + NL80211_ATTR_DISABLE_HT, + + NL80211_ATTR_HT_CAPABILITY_MASK, + + NL80211_ATTR_NOACK_MAP, + + NL80211_ATTR_INACTIVITY_TIMEOUT, + + NL80211_ATTR_RX_SIGNAL_DBM, + + NL80211_ATTR_BG_SCAN_PERIOD, + + NL80211_ATTR_WDEV, + + NL80211_ATTR_USER_REG_HINT_TYPE, + + NL80211_ATTR_CONN_FAILED_REASON, + + NL80211_ATTR_STA_CAP_REQ, + + NL80211_ATTR_ACS, + + NL80211_ATTR_MAC_ACL, + + NL80211_ATTR_MAC_ADDRS, + + NL80211_ATTR_ACL_POLICY, + + NL80211_ATTR_BTCOEX_DATA, + + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, + NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 +}; + +/* source-level API compatibility */ +#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION +#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG + +/* + * Allow user space programs to use #ifdef on new attributes by defining them + * here + */ +#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT +#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY +#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES +#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS +#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ +#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE +#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE +#define NL80211_ATTR_IE NL80211_ATTR_IE +#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR +#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE +#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME +#define NL80211_ATTR_SSID NL80211_ATTR_SSID +#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE +#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE +#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE +#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP +#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS +#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES +#define NL80211_ATTR_KEY NL80211_ATTR_KEY +#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS +#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + +#define NL80211_MAX_SUPP_RATES 32 +#define NL80211_MAX_SUPP_HT_RATES 77 +#define NL80211_MAX_SUPP_REG_RULES 32 +#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 +#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 +#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 +#define NL80211_HT_CAPABILITY_LEN 26 + +#define NL80211_MAX_NR_CIPHER_SUITES 5 +#define NL80211_MAX_NR_AKM_SUITES 2 + +#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 + +/* default RSSI threshold for scan results if none specified. */ +#define NL80211_SCAN_RSSI_THOLD_OFF -300 + +#define NL80211_CQM_TXE_MAX_INTVL 1800 + +/** + * enum nl80211_iftype - (virtual) interface types + * + * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides + * @NL80211_IFTYPE_ADHOC: independent BSS member + * @NL80211_IFTYPE_STATION: managed BSS member + * @NL80211_IFTYPE_AP: access point + * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces + * are a bit special in that they must always be tied to a pre-existing + * AP type interface. + * @NL80211_IFTYPE_WDS: wireless distribution interface + * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames + * @NL80211_IFTYPE_MESH_POINT: mesh point + * @NL80211_IFTYPE_P2P_CLIENT: P2P client + * @NL80211_IFTYPE_P2P_GO: P2P group owner + * @NL80211_IFTYPE_MAX: highest interface type number currently defined + * @NUM_NL80211_IFTYPES: number of defined interface types + * + * These values are used with the %NL80211_ATTR_IFTYPE + * to set the type of an interface. + * + */ +enum nl80211_iftype { + NL80211_IFTYPE_UNSPECIFIED, + NL80211_IFTYPE_ADHOC, + NL80211_IFTYPE_STATION, + NL80211_IFTYPE_AP, + NL80211_IFTYPE_AP_VLAN, + NL80211_IFTYPE_WDS, + NL80211_IFTYPE_MONITOR, + NL80211_IFTYPE_MESH_POINT, + NL80211_IFTYPE_P2P_CLIENT, + NL80211_IFTYPE_P2P_GO, + + /* keep last */ + NUM_NL80211_IFTYPES, + NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1 +}; + +/** + * enum nl80211_sta_flags - station flags + * + * Station flags. When a station is added to an AP interface, it is + * assumed to be already associated (and hence authenticated.) + * + * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved + * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) + * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames + * with short barker preamble + * @NL80211_STA_FLAG_WME: station is WME/QoS capable + * @NL80211_STA_FLAG_MFP: station uses management frame protection + * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated + * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer + * @NL80211_STA_FLAG_MAX: highest station flag number currently defined + * @__NL80211_STA_FLAG_AFTER_LAST: internal use + */ +enum nl80211_sta_flags { + __NL80211_STA_FLAG_INVALID, + NL80211_STA_FLAG_AUTHORIZED, + NL80211_STA_FLAG_SHORT_PREAMBLE, + NL80211_STA_FLAG_WME, + NL80211_STA_FLAG_MFP, + NL80211_STA_FLAG_AUTHENTICATED, + NL80211_STA_FLAG_TDLS_PEER, + + /* keep last */ + __NL80211_STA_FLAG_AFTER_LAST, + NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 +}; + +/** + * struct nl80211_sta_flag_update - station flags mask/set + * @mask: mask of station flags to set + * @set: which values to set them to + * + * Both mask and set contain bits as per &enum nl80211_sta_flags. + */ +struct nl80211_sta_flag_update { + __u32 mask; + __u32 set; +} __attribute__((packed)); + +/** + * enum nl80211_rate_info - bitrate information + * + * These attribute types are used with %NL80211_STA_INFO_TXRATE + * when getting information about the bitrate of a station. + * + * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved + * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) + * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) + * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate + * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval + * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined + * @__NL80211_RATE_INFO_AFTER_LAST: internal use + */ +enum nl80211_rate_info { + __NL80211_RATE_INFO_INVALID, + NL80211_RATE_INFO_BITRATE, + NL80211_RATE_INFO_MCS, + NL80211_RATE_INFO_40_MHZ_WIDTH, + NL80211_RATE_INFO_SHORT_GI, + + /* keep last */ + __NL80211_RATE_INFO_AFTER_LAST, + NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_sta_bss_param - BSS information collected by STA + * + * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM + * when getting information about the bitrate of a station. + * + * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved + * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag) + * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: whether short preamble is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: whether short slot time is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8) + * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16) + * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined + * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use + */ +enum nl80211_sta_bss_param { + __NL80211_STA_BSS_PARAM_INVALID, + NL80211_STA_BSS_PARAM_CTS_PROT, + NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, + NL80211_STA_BSS_PARAM_DTIM_PERIOD, + NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + + /* keep last */ + __NL80211_STA_BSS_PARAM_AFTER_LAST, + NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1 +}; + +/** + * enum nl80211_sta_info - station information + * + * These attribute types are used with %NL80211_ATTR_STA_INFO + * when getting information about a station. + * + * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved + * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) + * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) + * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) + * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) + * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute + * containing info as possible, see &enum nl80211_rate_info + * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) + * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this + * station) + * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station) + * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station) + * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) + * @NL80211_STA_INFO_LLID: the station's mesh LLID + * @NL80211_STA_INFO_PLID: the station's mesh PLID + * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station + * (see %enum nl80211_plink_state) + * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested + * attribute, like NL80211_STA_INFO_TX_BITRATE. + * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute + * containing info as possible, see &enum nl80211_sta_bss_param + * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected + * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update. + * @__NL80211_STA_INFO_AFTER_LAST: internal + * @NL80211_STA_INFO_MAX: highest possible station info attribute + */ +enum nl80211_sta_info { + __NL80211_STA_INFO_INVALID, + NL80211_STA_INFO_INACTIVE_TIME, + NL80211_STA_INFO_RX_BYTES, + NL80211_STA_INFO_TX_BYTES, + NL80211_STA_INFO_LLID, + NL80211_STA_INFO_PLID, + NL80211_STA_INFO_PLINK_STATE, + NL80211_STA_INFO_SIGNAL, + NL80211_STA_INFO_TX_BITRATE, + NL80211_STA_INFO_RX_PACKETS, + NL80211_STA_INFO_TX_PACKETS, + NL80211_STA_INFO_TX_RETRIES, + NL80211_STA_INFO_TX_FAILED, + NL80211_STA_INFO_SIGNAL_AVG, + NL80211_STA_INFO_RX_BITRATE, + NL80211_STA_INFO_BSS_PARAM, + NL80211_STA_INFO_CONNECTED_TIME, + NL80211_STA_INFO_STA_FLAGS, + + /* keep last */ + __NL80211_STA_INFO_AFTER_LAST, + NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mpath_flags - nl80211 mesh path flags + * + * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active + * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running + * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN + * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set + * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded + */ +enum nl80211_mpath_flags { + NL80211_MPATH_FLAG_ACTIVE = 1<<0, + NL80211_MPATH_FLAG_RESOLVING = 1<<1, + NL80211_MPATH_FLAG_SN_VALID = 1<<2, + NL80211_MPATH_FLAG_FIXED = 1<<3, + NL80211_MPATH_FLAG_RESOLVED = 1<<4, +}; + +/** + * enum nl80211_mpath_info - mesh path information + * + * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting + * information about a mesh path. + * + * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved + * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination + * @NL80211_MPATH_INFO_SN: destination sequence number + * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path + * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now + * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in + * &enum nl80211_mpath_flags; + * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec + * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries + * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number + * currently defind + * @__NL80211_MPATH_INFO_AFTER_LAST: internal use + */ +enum nl80211_mpath_info { + __NL80211_MPATH_INFO_INVALID, + NL80211_MPATH_INFO_FRAME_QLEN, + NL80211_MPATH_INFO_SN, + NL80211_MPATH_INFO_METRIC, + NL80211_MPATH_INFO_EXPTIME, + NL80211_MPATH_INFO_FLAGS, + NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, + NL80211_MPATH_INFO_DISCOVERY_RETRIES, + + /* keep last */ + __NL80211_MPATH_INFO_AFTER_LAST, + NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_band_attr - band attributes + * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, + * an array of nested frequency attributes + * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, + * an array of nested bitrate attributes + * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as + * defined in 802.11n + * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE + * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n + * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n + * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined + * @__NL80211_BAND_ATTR_AFTER_LAST: internal use + */ +enum nl80211_band_attr { + __NL80211_BAND_ATTR_INVALID, + NL80211_BAND_ATTR_FREQS, + NL80211_BAND_ATTR_RATES, + + NL80211_BAND_ATTR_HT_MCS_SET, + NL80211_BAND_ATTR_HT_CAPA, + NL80211_BAND_ATTR_HT_AMPDU_FACTOR, + NL80211_BAND_ATTR_HT_AMPDU_DENSITY, + + /* keep last */ + __NL80211_BAND_ATTR_AFTER_LAST, + NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 +}; + +#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA + +/** + * enum nl80211_frequency_attr - frequency attributes + * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz + * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current + * regulatory domain. + * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is + * permitted on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm + * (100 * dBm). + * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number + * currently defined + * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use + */ +enum nl80211_frequency_attr { + __NL80211_FREQUENCY_ATTR_INVALID, + NL80211_FREQUENCY_ATTR_FREQ, + NL80211_FREQUENCY_ATTR_DISABLED, + NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, + NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_RADAR, + NL80211_FREQUENCY_ATTR_MAX_TX_POWER, + + /* keep last */ + __NL80211_FREQUENCY_ATTR_AFTER_LAST, + NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 +}; + +#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER + +/** + * enum nl80211_bitrate_attr - bitrate attributes + * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps + * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported + * in 2.4 GHz band. + * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number + * currently defined + * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use + */ +enum nl80211_bitrate_attr { + __NL80211_BITRATE_ATTR_INVALID, + NL80211_BITRATE_ATTR_RATE, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, + + /* keep last */ + __NL80211_BITRATE_ATTR_AFTER_LAST, + NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_initiator - Indicates the initiator of a reg domain request + * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world + * regulatory domain. + * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the + * regulatory domain. + * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the + * wireless core it thinks its knows the regulatory domain we should be in. + * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an + * 802.11 country information element with regulatory information it + * thinks we should consider. cfg80211 only processes the country + * code from the IE, and relies on the regulatory domain information + * structure passed by userspace (CRDA) from our wireless-regdb. + * If a channel is enabled but the country code indicates it should + * be disabled we disable the channel and re-enable it upon disassociation. + */ +enum nl80211_reg_initiator { + NL80211_REGDOM_SET_BY_CORE, + NL80211_REGDOM_SET_BY_USER, + NL80211_REGDOM_SET_BY_DRIVER, + NL80211_REGDOM_SET_BY_COUNTRY_IE, +}; + +/** + * enum nl80211_reg_type - specifies the type of regulatory domain + * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains + * to a specific country. When this is set you can count on the + * ISO / IEC 3166 alpha2 country code being valid. + * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory + * domain. + * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom + * driver specific world regulatory domain. These do not apply system-wide + * and are only applicable to the individual devices which have requested + * them to be applied. + * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product + * of an intersection between two regulatory domains -- the previously + * set regulatory domain on the system and the last accepted regulatory + * domain request to be processed. + */ +enum nl80211_reg_type { + NL80211_REGDOM_TYPE_COUNTRY, + NL80211_REGDOM_TYPE_WORLD, + NL80211_REGDOM_TYPE_CUSTOM_WORLD, + NL80211_REGDOM_TYPE_INTERSECTION, +}; + +/** + * enum nl80211_reg_rule_attr - regulatory rule attributes + * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional + * considerations for a given frequency range. These are the + * &enum nl80211_reg_rule_flags. + * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory + * rule in KHz. This is not a center of frequency but an actual regulatory + * band edge. + * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule + * in KHz. This is not a center a frequency but an actual regulatory + * band edge. + * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this + * frequency range, in KHz. + * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain + * for a given frequency range. The value is in mBi (100 * dBi). + * If you don't have one then don't send this. + * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for + * a given frequency range. The value is in mBm (100 * dBm). + * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number + * currently defined + * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use + */ +enum nl80211_reg_rule_attr { + __NL80211_REG_RULE_ATTR_INVALID, + NL80211_ATTR_REG_RULE_FLAGS, + + NL80211_ATTR_FREQ_RANGE_START, + NL80211_ATTR_FREQ_RANGE_END, + NL80211_ATTR_FREQ_RANGE_MAX_BW, + + NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, + NL80211_ATTR_POWER_RULE_MAX_EIRP, + + /* keep last */ + __NL80211_REG_RULE_ATTR_AFTER_LAST, + NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_sched_scan_match_attr - scheduled scan match attributes + * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, + * only report BSS with matching SSID. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a + * BSS in scan results. Filtering is turned off if not specified. + * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter + * attribute number currently defined + * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use + */ +enum nl80211_sched_scan_match_attr { + __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID, + + NL80211_SCHED_SCAN_MATCH_ATTR_SSID, + NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, + + /* keep last */ + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, + NL80211_SCHED_SCAN_MATCH_ATTR_MAX = + __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1 +}; + +/* only for backward compatibility */ +#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID + +/** + * enum nl80211_reg_rule_flags - regulatory rule flags + * + * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed + * @NL80211_RRF_NO_CCK: CCK modulation not allowed + * @NL80211_RRF_NO_INDOOR: indoor operation not allowed + * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed + * @NL80211_RRF_DFS: DFS support is required to be used + * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links + * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links + * @NL80211_RRF_PASSIVE_SCAN: passive scan is required + * @NL80211_RRF_NO_IBSS: no IBSS is allowed + */ +enum nl80211_reg_rule_flags { + NL80211_RRF_NO_OFDM = 1<<0, + NL80211_RRF_NO_CCK = 1<<1, + NL80211_RRF_NO_INDOOR = 1<<2, + NL80211_RRF_NO_OUTDOOR = 1<<3, + NL80211_RRF_DFS = 1<<4, + NL80211_RRF_PTP_ONLY = 1<<5, + NL80211_RRF_PTMP_ONLY = 1<<6, + NL80211_RRF_PASSIVE_SCAN = 1<<7, + NL80211_RRF_NO_IBSS = 1<<8, +}; + +/** + * enum nl80211_survey_info - survey information + * + * These attribute types are used with %NL80211_ATTR_SURVEY_INFO + * when getting information about a survey. + * + * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved + * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel + * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) + * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used + * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio + * spent on this channel + * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary + * channel was sensed busy (either due to activity or energy detect) + * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension + * channel was sensed busy + * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent + * receiving data + * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent + * transmitting data + * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number + * currently defined + * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use + */ +enum nl80211_survey_info { + __NL80211_SURVEY_INFO_INVALID, + NL80211_SURVEY_INFO_FREQUENCY, + NL80211_SURVEY_INFO_NOISE, + NL80211_SURVEY_INFO_IN_USE, + NL80211_SURVEY_INFO_CHANNEL_TIME, + NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, + NL80211_SURVEY_INFO_CHANNEL_TIME_RX, + NL80211_SURVEY_INFO_CHANNEL_TIME_TX, + + /* keep last */ + __NL80211_SURVEY_INFO_AFTER_LAST, + NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mntr_flags - monitor configuration flags + * + * Monitor configuration flags. + * + * @__NL80211_MNTR_FLAG_INVALID: reserved + * + * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS + * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @NL80211_MNTR_FLAG_CONTROL: pass control frames + * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering + * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. + * overrides all other flags. + * + * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use + * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag + */ +enum nl80211_mntr_flags { + __NL80211_MNTR_FLAG_INVALID, + NL80211_MNTR_FLAG_FCSFAIL, + NL80211_MNTR_FLAG_PLCPFAIL, + NL80211_MNTR_FLAG_CONTROL, + NL80211_MNTR_FLAG_OTHER_BSS, + NL80211_MNTR_FLAG_COOK_FRAMES, + + /* keep last */ + __NL80211_MNTR_FLAG_AFTER_LAST, + NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 +}; + +/** + * enum nl80211_meshconf_params - mesh configuration parameters + * + * Mesh configuration parameters. These can be changed while the mesh is + * active. + * + * @__NL80211_MESHCONF_INVALID: internal use + * + * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in + * millisecond units, used by the Peer Link Open message + * + * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in + * millisecond units, used by the peer link management to close a peer link + * + * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in + * millisecond units + * + * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed + * on this mesh interface + * + * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link + * open retries that can be sent to establish a new peer link instance in a + * mesh + * + * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh + * point. + * + * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically + * open peer links when we detect compatible mesh peers. + * + * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames + * containing a PREQ that an MP can send to a particular destination (path + * target) + * + * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths + * (in milliseconds) + * + * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait + * until giving up on a path discovery (in milliseconds) + * + * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh + * points receiving a PREQ shall consider the forwarding information from the + * root to be valid. (TU = time unit) + * + * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in + * TUs) during which an MP can send only one action frame containing a PREQ + * reference element + * + * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) + * that it takes for an HWMP information element to propagate across the mesh + * + * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not + * + * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a + * source mesh point for path selection elements. + * + * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between + * root announcements are transmitted. + * + * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has + * access to a broader network beyond the MBSS. This is done via Root + * Announcement frames. + * + * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute + * + * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use + */ +enum nl80211_meshconf_params { + __NL80211_MESHCONF_INVALID, + NL80211_MESHCONF_RETRY_TIMEOUT, + NL80211_MESHCONF_CONFIRM_TIMEOUT, + NL80211_MESHCONF_HOLDING_TIMEOUT, + NL80211_MESHCONF_MAX_PEER_LINKS, + NL80211_MESHCONF_MAX_RETRIES, + NL80211_MESHCONF_TTL, + NL80211_MESHCONF_AUTO_OPEN_PLINKS, + NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + NL80211_MESHCONF_PATH_REFRESH_TIME, + NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + NL80211_MESHCONF_HWMP_ROOTMODE, + NL80211_MESHCONF_ELEMENT_TTL, + NL80211_MESHCONF_HWMP_RANN_INTERVAL, + NL80211_MESHCONF_GATE_ANNOUNCEMENTS, + + /* keep last */ + __NL80211_MESHCONF_ATTR_AFTER_LAST, + NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mesh_setup_params - mesh setup parameters + * + * Mesh setup parameters. These are used to start/join a mesh and cannot be + * changed while the mesh is active. + * + * @__NL80211_MESH_SETUP_INVALID: Internal use + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a + * vendor specific path selection algorithm or disable it to use the default + * HWMP. + * + * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a + * vendor specific path metric or disable it to use the default Airtime + * metric. + * + * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a + * robust security network ie, or a vendor specific information element that + * vendors will use to identify the path selection methods and metrics in use. + * + * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication + * daemon will be authenticating mesh candidates. + * + * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication + * daemon will be securing peer link frames. AMPE is a secured version of Mesh + * Peering Management (MPM) and is implemented with the assistance of a + * userspace daemon. When this flag is set, the kernel will send peer + * management frames to a userspace daemon that will implement AMPE + * functionality (security capabilities selection, key confirmation, and key + * management). When the flag is unset (default), the kernel can autonomously + * complete (unsecured) mesh peering without the need of a userspace daemon. + * + * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number + * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use + */ +enum nl80211_mesh_setup_params { + __NL80211_MESH_SETUP_INVALID, + NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, + NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, + NL80211_MESH_SETUP_IE, + NL80211_MESH_SETUP_USERSPACE_AUTH, + NL80211_MESH_SETUP_USERSPACE_AMPE, + + /* keep last */ + __NL80211_MESH_SETUP_ATTR_AFTER_LAST, + NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_txq_attr - TX queue parameter attributes + * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved + * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) + * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning + * disabled + * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] + * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal + * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number + */ +enum nl80211_txq_attr { + __NL80211_TXQ_ATTR_INVALID, + NL80211_TXQ_ATTR_QUEUE, + NL80211_TXQ_ATTR_TXOP, + NL80211_TXQ_ATTR_CWMIN, + NL80211_TXQ_ATTR_CWMAX, + NL80211_TXQ_ATTR_AIFS, + + /* keep last */ + __NL80211_TXQ_ATTR_AFTER_LAST, + NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 +}; + +enum nl80211_txq_q { + NL80211_TXQ_Q_VO, + NL80211_TXQ_Q_VI, + NL80211_TXQ_Q_BE, + NL80211_TXQ_Q_BK +}; + +enum nl80211_channel_type { + NL80211_CHAN_NO_HT, + NL80211_CHAN_HT20, + NL80211_CHAN_HT40MINUS, + NL80211_CHAN_HT40PLUS +}; + +/** + * enum nl80211_bss - netlink attributes for a BSS + * + * @__NL80211_BSS_INVALID: invalid + * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets) + * @NL80211_BSS_FREQUENCY: frequency in MHz (u32) + * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64) + * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) + * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) + * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the + * raw information elements from the probe response/beacon (bin); + * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are + * from a Probe Response frame; otherwise they are from a Beacon frame. + * However, if the driver does not indicate the source of the IEs, these + * IEs may be from either frame subtype. + * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon + * in mBm (100 * dBm) (s32) + * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon + * in unspecified units, scaled to 0..100 (u8) + * @NL80211_BSS_STATUS: status, if this BSS is "used" + * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms + * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information + * elements from a Beacon frame (bin); not present if no Beacon frame has + * yet been received + * @__NL80211_BSS_AFTER_LAST: internal + * @NL80211_BSS_MAX: highest BSS attribute + */ +enum nl80211_bss { + __NL80211_BSS_INVALID, + NL80211_BSS_BSSID, + NL80211_BSS_FREQUENCY, + NL80211_BSS_TSF, + NL80211_BSS_BEACON_INTERVAL, + NL80211_BSS_CAPABILITY, + NL80211_BSS_INFORMATION_ELEMENTS, + NL80211_BSS_SIGNAL_MBM, + NL80211_BSS_SIGNAL_UNSPEC, + NL80211_BSS_STATUS, + NL80211_BSS_SEEN_MS_AGO, + NL80211_BSS_BEACON_IES, + + /* keep last */ + __NL80211_BSS_AFTER_LAST, + NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 +}; + +/** + * enum nl80211_bss_status - BSS "status" + * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS. + * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS. + * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS. + * + * The BSS status is a BSS attribute in scan dumps, which + * indicates the status the interface has wrt. this BSS. + */ +enum nl80211_bss_status { + NL80211_BSS_STATUS_AUTHENTICATED, + NL80211_BSS_STATUS_ASSOCIATED, + NL80211_BSS_STATUS_IBSS_JOINED, +}; + +/** + * enum nl80211_auth_type - AuthenticationType + * + * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication + * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) + * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) + * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) + * @__NL80211_AUTHTYPE_NUM: internal + * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm + * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by + * trying multiple times); this is invalid in netlink -- leave out + * the attribute for this on CONNECT commands. + */ +enum nl80211_auth_type { + NL80211_AUTHTYPE_OPEN_SYSTEM, + NL80211_AUTHTYPE_SHARED_KEY, + NL80211_AUTHTYPE_FT, + NL80211_AUTHTYPE_NETWORK_EAP, + + /* keep last */ + __NL80211_AUTHTYPE_NUM, + NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1, + NL80211_AUTHTYPE_AUTOMATIC +}; + +/** + * enum nl80211_key_type - Key Type + * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key + * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key + * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS) + * @NUM_NL80211_KEYTYPES: number of defined key types + */ +enum nl80211_key_type { + NL80211_KEYTYPE_GROUP, + NL80211_KEYTYPE_PAIRWISE, + NL80211_KEYTYPE_PEERKEY, + + NUM_NL80211_KEYTYPES +}; + +/** + * enum nl80211_mfp - Management frame protection state + * @NL80211_MFP_NO: Management frame protection not used + * @NL80211_MFP_REQUIRED: Management frame protection required + */ +enum nl80211_mfp { + NL80211_MFP_NO, + NL80211_MFP_REQUIRED, +}; + +enum nl80211_wpa_versions { + NL80211_WPA_VERSION_1 = 1 << 0, + NL80211_WPA_VERSION_2 = 1 << 1, +}; + +/** + * enum nl80211_key_default_types - key default types + * @__NL80211_KEY_DEFAULT_TYPE_INVALID: invalid + * @NL80211_KEY_DEFAULT_TYPE_UNICAST: key should be used as default + * unicast key + * @NL80211_KEY_DEFAULT_TYPE_MULTICAST: key should be used as default + * multicast key + * @NUM_NL80211_KEY_DEFAULT_TYPES: number of default types + */ +enum nl80211_key_default_types { + __NL80211_KEY_DEFAULT_TYPE_INVALID, + NL80211_KEY_DEFAULT_TYPE_UNICAST, + NL80211_KEY_DEFAULT_TYPE_MULTICAST, + + NUM_NL80211_KEY_DEFAULT_TYPES +}; + +/** + * enum nl80211_key_attributes - key attributes + * @__NL80211_KEY_INVALID: invalid + * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of + * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC + * keys + * @NL80211_KEY_IDX: key ID (u8, 0-3) + * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 + * section 7.3.2.25.1, e.g. 0x000FAC04) + * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and + * CCMP keys, each six bytes in little endian + * @NL80211_KEY_DEFAULT: flag indicating default key + * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key + * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not + * specified the default depends on whether a MAC address was + * given with the command using the key or not (u32) + * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags + * attributes, specifying what a key should be set as default as. + * See &enum nl80211_key_default_types. + * @__NL80211_KEY_AFTER_LAST: internal + * @NL80211_KEY_MAX: highest key attribute + */ +enum nl80211_key_attributes { + __NL80211_KEY_INVALID, + NL80211_KEY_DATA, + NL80211_KEY_IDX, + NL80211_KEY_CIPHER, + NL80211_KEY_SEQ, + NL80211_KEY_DEFAULT, + NL80211_KEY_DEFAULT_MGMT, + NL80211_KEY_TYPE, + NL80211_KEY_DEFAULT_TYPES, + + /* keep last */ + __NL80211_KEY_AFTER_LAST, + NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 +}; + +/** + * enum nl80211_tx_rate_attributes - TX rate set attributes + * @__NL80211_TXRATE_INVALID: invalid + * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection + * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with + * 1 = 500 kbps) but without the IE length restriction (at most + * %NL80211_MAX_SUPP_RATES in a single array). + * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * in an array of MCS numbers. + * @__NL80211_TXRATE_AFTER_LAST: internal + * @NL80211_TXRATE_MAX: highest TX rate attribute + */ +enum nl80211_tx_rate_attributes { + __NL80211_TXRATE_INVALID, + NL80211_TXRATE_LEGACY, + NL80211_TXRATE_MCS, + + /* keep last */ + __NL80211_TXRATE_AFTER_LAST, + NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 +}; + +/** + * enum nl80211_band - Frequency band + * @NL80211_BAND_2GHZ: 2.4 GHz ISM band + * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) + */ +enum nl80211_band { + NL80211_BAND_2GHZ, + NL80211_BAND_5GHZ, +}; + +enum nl80211_ps_state { + NL80211_PS_DISABLED, + NL80211_PS_ENABLED, +}; + +/** + * enum nl80211_attr_cqm - connection quality monitor attributes + * @__NL80211_ATTR_CQM_INVALID: invalid + * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies + * the threshold for the RSSI level at which an event will be sent. Zero + * to disable. + * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies + * the minimum amount the RSSI level must change after an event before a + * new event may be issued (to reduce effects of RSSI oscillation). + * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event + * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many + * consecutive packets were not acknowledged by the peer + * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures + * during the given %NL80211_ATTR_CQM_TXE_INTVL before an + * %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and + * %NL80211_ATTR_CQM_TXE_PKTS is generated. + * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given + * %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is + * checked. + * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic + * interval in which %NL80211_ATTR_CQM_TXE_PKTS and + * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an + * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. + * @__NL80211_ATTR_CQM_AFTER_LAST: internal + * @NL80211_ATTR_CQM_MAX: highest key attribute + */ +enum nl80211_attr_cqm { + __NL80211_ATTR_CQM_INVALID, + NL80211_ATTR_CQM_RSSI_THOLD, + NL80211_ATTR_CQM_RSSI_HYST, + NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, + NL80211_ATTR_CQM_PKT_LOSS_EVENT, + NL80211_ATTR_CQM_TXE_RATE, + NL80211_ATTR_CQM_TXE_PKTS, + NL80211_ATTR_CQM_TXE_INTVL, + + /* keep last */ + __NL80211_ATTR_CQM_AFTER_LAST, + NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1 +}; + +/** + * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event + * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the + * configured threshold + * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the + * configured threshold + */ +enum nl80211_cqm_rssi_threshold_event { + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, +}; + + +/** + * enum nl80211_tx_power_setting - TX power adjustment + * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power + * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter + * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter + */ +enum nl80211_tx_power_setting { + NL80211_TX_POWER_AUTOMATIC, + NL80211_TX_POWER_LIMITED, + NL80211_TX_POWER_FIXED, +}; + +/** + * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute + * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute + * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has + * a zero bit are ignored + * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have + * a bit for each byte in the pattern. The lowest-order bit corresponds + * to the first byte of the pattern, but the bytes of the pattern are + * in a little-endian-like format, i.e. the 9th byte of the pattern + * corresponds to the lowest-order bit in the second byte of the mask. + * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where + * xx indicates "don't care") would be represented by a pattern of + * twelve zero bytes, and a mask of "0xed,0x07". + * Note that the pattern matching is done as though frames were not + * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked + * first (including SNAP header unpacking) and then matched. + * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes + * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number + */ +enum nl80211_wowlan_packet_pattern_attr { + __NL80211_WOWLAN_PKTPAT_INVALID, + NL80211_WOWLAN_PKTPAT_MASK, + NL80211_WOWLAN_PKTPAT_PATTERN, + + NUM_NL80211_WOWLAN_PKTPAT, + MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, +}; + +/** + * struct nl80211_wowlan_pattern_support - pattern support information + * @max_patterns: maximum number of patterns supported + * @min_pattern_len: minimum length of each pattern + * @max_pattern_len: maximum length of each pattern + * + * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when + * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the + * capability information given by the kernel to userspace. + */ +struct nl80211_wowlan_pattern_support { + __u32 max_patterns; + __u32 min_pattern_len; + __u32 max_pattern_len; +} __attribute__((packed)); + +/** + * enum nl80211_wowlan_triggers - WoWLAN trigger definitions + * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes + * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put + * the chip into a special state -- works best with chips that have + * support for low-power operation already (flag) + * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect + * is detected is implementation-specific (flag) + * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed + * by 16 repetitions of MAC addr, anywhere in payload) (flag) + * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns + * which are passed in an array of nested attributes, each nested attribute + * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. + * Each pattern defines a wakeup packet. The matching is done on the MSDU, + * i.e. as though the packet was an 802.3 packet, so the pattern matching + * is done after the packet is converted to the MSDU. + * + * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute + * carrying a &struct nl80211_wowlan_pattern_support. + * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be + * used when setting, used only to indicate that GTK rekeying is supported + * by the device (flag) + * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if + * done by the device) (flag) + * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request + * packet (flag) + * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag) + * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released + * (on devices that have rfkill in the device) (flag) + * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers + * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number + */ +enum nl80211_wowlan_triggers { + __NL80211_WOWLAN_TRIG_INVALID, + NL80211_WOWLAN_TRIG_ANY, + NL80211_WOWLAN_TRIG_DISCONNECT, + NL80211_WOWLAN_TRIG_MAGIC_PKT, + NL80211_WOWLAN_TRIG_PKT_PATTERN, + NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED, + NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, + NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, + NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, + NL80211_WOWLAN_TRIG_RFKILL_RELEASE, + + /* keep last */ + NUM_NL80211_WOWLAN_TRIG, + MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 +}; + +/** + * enum nl80211_iface_limit_attrs - limit attributes + * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) + * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that + * can be chosen from this set of interface types (u32) + * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a + * flag attribute for each interface type in this set + * @NUM_NL80211_IFACE_LIMIT: number of attributes + * @MAX_NL80211_IFACE_LIMIT: highest attribute number + */ +enum nl80211_iface_limit_attrs { + NL80211_IFACE_LIMIT_UNSPEC, + NL80211_IFACE_LIMIT_MAX, + NL80211_IFACE_LIMIT_TYPES, + + /* keep last */ + NUM_NL80211_IFACE_LIMIT, + MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1 +}; + +/** + * enum nl80211_if_combination_attrs -- interface combination attributes + * + * @NL80211_IFACE_COMB_UNSPEC: (reserved) + * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits + * for given interface types, see &enum nl80211_iface_limit_attrs. + * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of + * interfaces that can be created in this group. This number doesn't + * apply to interfaces purely managed in software, which are listed + * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE. + * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that + * beacon intervals within this group must be all the same even for + * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt + * the infrastructure network's beacon interval. + * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many + * different channels may be used within this group. + * @NUM_NL80211_IFACE_COMB: number of attributes + * @MAX_NL80211_IFACE_COMB: highest attribute number + * + * Examples: + * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 + * => allows an AP and a STA that must match BIs + * + * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 + * => allows 8 of AP/GO + * + * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 + * => allows two STAs on different channels + * + * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 + * => allows a STA plus three P2P interfaces + * + * The list of these four possiblities could completely be contained + * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate + * that any of these groups must match. + * + * "Combinations" of just a single interface will not be listed here, + * a single interface of any valid interface type is assumed to always + * be possible by itself. This means that implicitly, for each valid + * interface type, the following group always exists: + * numbers = [ #{} <= 1 ], channels = 1, max = 1 + */ +enum nl80211_if_combination_attrs { + NL80211_IFACE_COMB_UNSPEC, + NL80211_IFACE_COMB_LIMITS, + NL80211_IFACE_COMB_MAXNUM, + NL80211_IFACE_COMB_STA_AP_BI_MATCH, + NL80211_IFACE_COMB_NUM_CHANNELS, + + /* keep last */ + NUM_NL80211_IFACE_COMB, + MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1 +}; + + +/** + * enum nl80211_plink_state - state of a mesh peer link finite state machine + * + * @NL80211_PLINK_LISTEN: initial state, considered the implicit + * state of non existant mesh peer links + * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to + * this mesh peer + * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received + * from this mesh peer + * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been + * received from this mesh peer + * @NL80211_PLINK_ESTAB: mesh peer link is established + * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled + * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh + * plink are discarded + * @NUM_NL80211_PLINK_STATES: number of peer link states + * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states + */ +enum nl80211_plink_state { + NL80211_PLINK_LISTEN, + NL80211_PLINK_OPN_SNT, + NL80211_PLINK_OPN_RCVD, + NL80211_PLINK_CNF_RCVD, + NL80211_PLINK_ESTAB, + NL80211_PLINK_HOLDING, + NL80211_PLINK_BLOCKED, + + /* keep last */ + NUM_NL80211_PLINK_STATES, + MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 +}; + +#define NL80211_KCK_LEN 16 +#define NL80211_KEK_LEN 16 +#define NL80211_REPLAY_CTR_LEN 8 + +/** + * enum nl80211_rekey_data - attributes for GTK rekey offload + * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes + * @NL80211_REKEY_DATA_KEK: key encryption key (binary) + * @NL80211_REKEY_DATA_KCK: key confirmation key (binary) + * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary) + * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal) + * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal) + */ +enum nl80211_rekey_data { + __NL80211_REKEY_DATA_INVALID, + NL80211_REKEY_DATA_KEK, + NL80211_REKEY_DATA_KCK, + NL80211_REKEY_DATA_REPLAY_CTR, + + /* keep last */ + NUM_NL80211_REKEY_DATA, + MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1 +}; + +/** + * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID + * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in + * Beacon frames) + * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element + * in Beacon frames + * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID + * element in Beacon frames but zero out each byte in the SSID + */ +enum nl80211_hidden_ssid { + NL80211_HIDDEN_SSID_NOT_IN_USE, + NL80211_HIDDEN_SSID_ZERO_LEN, + NL80211_HIDDEN_SSID_ZERO_CONTENTS +}; + +/** + * enum nl80211_sta_wme_attr - station WME attributes + * @__NL80211_STA_WME_INVALID: invalid number for nested attribute + * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format + * is the same as the AC bitmap in the QoS info field. + * @NL80211_STA_WME_MAX_SP: max service period. the format is the same + * as the MAX_SP field in the QoS info field (but already shifted down). + * @__NL80211_STA_WME_AFTER_LAST: internal + * @NL80211_STA_WME_MAX: highest station WME attribute + */ +enum nl80211_sta_wme_attr { + __NL80211_STA_WME_INVALID, + NL80211_STA_WME_UAPSD_QUEUES, + NL80211_STA_WME_MAX_SP, + + /* keep last */ + __NL80211_STA_WME_AFTER_LAST, + NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1 +}; + +/** + * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates + * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes + * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher + * priority) + * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets) + * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag) + * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes + * (internal) + * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute + * (internal) + */ +enum nl80211_pmksa_candidate_attr { + __NL80211_PMKSA_CANDIDATE_INVALID, + NL80211_PMKSA_CANDIDATE_INDEX, + NL80211_PMKSA_CANDIDATE_BSSID, + NL80211_PMKSA_CANDIDATE_PREAUTH, + + /* keep last */ + NUM_NL80211_PMKSA_CANDIDATE, + MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 +}; + +/** + * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION + * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request + * @NL80211_TDLS_SETUP: Setup TDLS link + * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established + * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link + * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link + */ +enum nl80211_tdls_operation { + NL80211_TDLS_DISCOVERY_REQ, + NL80211_TDLS_SETUP, + NL80211_TDLS_TEARDOWN, + NL80211_TDLS_ENABLE_LINK, + NL80211_TDLS_DISABLE_LINK, +}; + +/* + * enum nl80211_ap_sme_features - device-integrated AP features + * Reserved for future use, no bits are defined in + * NL80211_ATTR_DEVICE_AP_SME yet. +enum nl80211_ap_sme_features { +}; + */ + +/** + * enum nl80211_feature_flags - device/driver features + * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back + * TX status to the socket error queue when requested with the + * socket option. + * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates. + * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up + * the connected inactive stations in AP mode. + * @NL80211_FEATURE_MAC_ACL: Driver does MAC address based access control + * in AP/P2P GO mode. + */ +enum nl80211_feature_flags { + NL80211_FEATURE_SK_TX_STATUS = 1 << 0, + NL80211_FEATURE_HT_IBSS = 1 << 1, + NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, + NL80211_FEATURE_MAC_ACL = 1 << 3, +}; + +/** + * enum nl80211_probe_resp_offload_support_attr - optional supported + * protocols for probe-response offloading by the driver/FW. + * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute. + * Each enum value represents a bit in the bitmap of supported + * protocols. Typically a subset of probe-requests belonging to a + * supported protocol will be excluded from offload and uploaded + * to the host. + * + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2 + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P + * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u + */ +enum nl80211_probe_resp_offload_support_attr { + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS = 1<<0, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 = 1<<1, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P = 1<<2, + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3, +}; + +enum nl80211_btcoex_cmds { + NL80211_WMI_SET_BT_STATUS = 0, + NL80211_WMI_SET_BT_PARAMS, + NL80211_WMI_SET_BT_FT_ANT, + NL80211_WMI_SET_COLOCATED_BT_DEV, + NL80211_WMI_SET_BT_INQUIRY_PAGE_CONFIG, + NL80211_WMI_SET_BT_SCO_CONFIG, + NL80211_WMI_SET_BT_A2DP_CONFIG, + NL80211_WMI_SET_BT_ACLCOEX_CONFIG, + NL80211_WMI_SET_BT_DEBUG, + NL80211_WMI_SET_BT_OPSTATUS, + NL80211_WMI_GET_BT_CONFIG, + NL80211_WMI_GET_BT_STATS, + NL80211_WMI_BT_MAX, +}; + +/** + * enum sta_capab_req_options - values for %NL80211_ATTR_STA_CAPA_REQ. + * @NL80211_STA_CAP_REQ_11BONLY: Allow IEEE 802.11b only stations to associate. + * @NL80211_STA_CAP_REQ_11GONLY: Allow IEEE 802.11g only stations to associate. + */ +enum nl80211_sta_capab_req_options { + NL80211_STA_CAP_REQ_11BONLY = 1<<0, + NL80211_STA_CAP_REQ_11GONLY = 1<<1, +}; + +/** + * enum nl80211_acl_policy_attr - The access control policy which needs to be + * applied on an acl list set by %NL80211_CMD_SET_MAC_ACL. To be used + * with %NL80211_ATTR_ACL_POLICY. + * + * @NL80211_ACL_POLICY_ACCEPT: Allow the station to authenticate. + * @NL80211_ACL_POLICY_DENY: Block the station from authentication + */ +enum nl80211_acl_policy_attr { + NL80211_ACL_POLICY_ACCEPT, + NL80211_ACL_POLICY_DENY, +}; + +/** + * enum nl80211_connect_failed_reason - connection request failed reasons + * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be + * handled by the AP is reached. + * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Client's MAC is in the AP's blocklist. + * @NL80211_CONN_FAIL_NEW_CLIENT: Client's MAC is not available either in + * the accept list or in the deny list. + * */ +enum nl80211_connect_failed_reason { + NL80211_CONN_FAIL_MAX_CLIENTS, + NL80211_CONN_FAIL_BLOCKED_CLIENT, + NL80211_CONN_FAIL_NEW_CLIENT, +}; + +#endif /* __LINUX_NL80211_H */ diff --git a/include/compat/linux/of.h b/include/compat/linux/of.h new file mode 100644 index 00000000..c5dc87c2 --- /dev/null +++ b/include/compat/linux/of.h @@ -0,0 +1,16 @@ +#ifndef _COMPAT_LINUX_OF_H +#define _COMPAT_LINUX_OF_H 1 + +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) +#include_next +#else + +#ifdef CONFIG_OF +#include_next +#endif /* CONFIG_OF */ + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) */ + +#endif /* _COMPAT_LINUX_OF_H */ diff --git a/include/compat/linux/pci-aspm.h b/include/compat/linux/pci-aspm.h new file mode 100644 index 00000000..2bc6efb3 --- /dev/null +++ b/include/compat/linux/pci-aspm.h @@ -0,0 +1,5 @@ +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)) +#include_next +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)) */ diff --git a/include/compat/linux/pci_ids.h b/include/compat/linux/pci_ids.h new file mode 100644 index 00000000..172ba703 --- /dev/null +++ b/include/compat/linux/pci_ids.h @@ -0,0 +1,2879 @@ +/* + * PCI Class, Vendor and Device IDs + * + * Please keep sorted. + * + * Do not add new entries to this file unless the definitions + * are shared between multiple drivers. + */ + +/* Device classes and subclasses */ + +#define PCI_CLASS_NOT_DEFINED 0x0000 +#define PCI_CLASS_NOT_DEFINED_VGA 0x0001 + +#define PCI_BASE_CLASS_STORAGE 0x01 +#define PCI_CLASS_STORAGE_SCSI 0x0100 +#define PCI_CLASS_STORAGE_IDE 0x0101 +#define PCI_CLASS_STORAGE_FLOPPY 0x0102 +#define PCI_CLASS_STORAGE_IPI 0x0103 +#define PCI_CLASS_STORAGE_RAID 0x0104 +#define PCI_CLASS_STORAGE_SATA 0x0106 +#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601 +#define PCI_CLASS_STORAGE_SAS 0x0107 +#define PCI_CLASS_STORAGE_OTHER 0x0180 + +#define PCI_BASE_CLASS_NETWORK 0x02 +#define PCI_CLASS_NETWORK_ETHERNET 0x0200 +#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201 +#define PCI_CLASS_NETWORK_FDDI 0x0202 +#define PCI_CLASS_NETWORK_ATM 0x0203 +#define PCI_CLASS_NETWORK_OTHER 0x0280 + +#define PCI_BASE_CLASS_DISPLAY 0x03 +#define PCI_CLASS_DISPLAY_VGA 0x0300 +#define PCI_CLASS_DISPLAY_XGA 0x0301 +#define PCI_CLASS_DISPLAY_3D 0x0302 +#define PCI_CLASS_DISPLAY_OTHER 0x0380 + +#define PCI_BASE_CLASS_MULTIMEDIA 0x04 +#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400 +#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 +#define PCI_CLASS_MULTIMEDIA_PHONE 0x0402 +#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480 + +#define PCI_BASE_CLASS_MEMORY 0x05 +#define PCI_CLASS_MEMORY_RAM 0x0500 +#define PCI_CLASS_MEMORY_FLASH 0x0501 +#define PCI_CLASS_MEMORY_OTHER 0x0580 + +#define PCI_BASE_CLASS_BRIDGE 0x06 +#define PCI_CLASS_BRIDGE_HOST 0x0600 +#define PCI_CLASS_BRIDGE_ISA 0x0601 +#define PCI_CLASS_BRIDGE_EISA 0x0602 +#define PCI_CLASS_BRIDGE_MC 0x0603 +#define PCI_CLASS_BRIDGE_PCI 0x0604 +#define PCI_CLASS_BRIDGE_PCMCIA 0x0605 +#define PCI_CLASS_BRIDGE_NUBUS 0x0606 +#define PCI_CLASS_BRIDGE_CARDBUS 0x0607 +#define PCI_CLASS_BRIDGE_RACEWAY 0x0608 +#define PCI_CLASS_BRIDGE_OTHER 0x0680 + +#define PCI_BASE_CLASS_COMMUNICATION 0x07 +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 +#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701 +#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702 +#define PCI_CLASS_COMMUNICATION_MODEM 0x0703 +#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 + +#define PCI_BASE_CLASS_SYSTEM 0x08 +#define PCI_CLASS_SYSTEM_PIC 0x0800 +#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010 +#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020 +#define PCI_CLASS_SYSTEM_DMA 0x0801 +#define PCI_CLASS_SYSTEM_TIMER 0x0802 +#define PCI_CLASS_SYSTEM_RTC 0x0803 +#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804 +#define PCI_CLASS_SYSTEM_SDHCI 0x0805 +#define PCI_CLASS_SYSTEM_OTHER 0x0880 + +#define PCI_BASE_CLASS_INPUT 0x09 +#define PCI_CLASS_INPUT_KEYBOARD 0x0900 +#define PCI_CLASS_INPUT_PEN 0x0901 +#define PCI_CLASS_INPUT_MOUSE 0x0902 +#define PCI_CLASS_INPUT_SCANNER 0x0903 +#define PCI_CLASS_INPUT_GAMEPORT 0x0904 +#define PCI_CLASS_INPUT_OTHER 0x0980 + +#define PCI_BASE_CLASS_DOCKING 0x0a +#define PCI_CLASS_DOCKING_GENERIC 0x0a00 +#define PCI_CLASS_DOCKING_OTHER 0x0a80 + +#define PCI_BASE_CLASS_PROCESSOR 0x0b +#define PCI_CLASS_PROCESSOR_386 0x0b00 +#define PCI_CLASS_PROCESSOR_486 0x0b01 +#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02 +#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10 +#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 +#define PCI_CLASS_PROCESSOR_MIPS 0x0b30 +#define PCI_CLASS_PROCESSOR_CO 0x0b40 + +#define PCI_BASE_CLASS_SERIAL 0x0c +#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00 +#define PCI_CLASS_SERIAL_FIREWIRE_OHCI 0x0c0010 +#define PCI_CLASS_SERIAL_ACCESS 0x0c01 +#define PCI_CLASS_SERIAL_SSA 0x0c02 +#define PCI_CLASS_SERIAL_USB 0x0c03 +#define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300 +#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310 +#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320 +#define PCI_CLASS_SERIAL_USB_XHCI 0x0c0330 +#define PCI_CLASS_SERIAL_FIBER 0x0c04 +#define PCI_CLASS_SERIAL_SMBUS 0x0c05 + +#define PCI_BASE_CLASS_WIRELESS 0x0d +#define PCI_CLASS_WIRELESS_RF_CONTROLLER 0x0d10 +#define PCI_CLASS_WIRELESS_WHCI 0x0d1010 + +#define PCI_BASE_CLASS_INTELLIGENT 0x0e +#define PCI_CLASS_INTELLIGENT_I2O 0x0e00 + +#define PCI_BASE_CLASS_SATELLITE 0x0f +#define PCI_CLASS_SATELLITE_TV 0x0f00 +#define PCI_CLASS_SATELLITE_AUDIO 0x0f01 +#define PCI_CLASS_SATELLITE_VOICE 0x0f03 +#define PCI_CLASS_SATELLITE_DATA 0x0f04 + +#define PCI_BASE_CLASS_CRYPT 0x10 +#define PCI_CLASS_CRYPT_NETWORK 0x1000 +#define PCI_CLASS_CRYPT_ENTERTAINMENT 0x1001 +#define PCI_CLASS_CRYPT_OTHER 0x1080 + +#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11 +#define PCI_CLASS_SP_DPIO 0x1100 +#define PCI_CLASS_SP_OTHER 0x1180 + +#define PCI_CLASS_OTHERS 0xff + +/* Vendors and devices. Sort key: vendor first, device next. */ + +#define PCI_VENDOR_ID_TTTECH 0x0357 +#define PCI_DEVICE_ID_TTTECH_MC322 0x000a + +#define PCI_VENDOR_ID_DYNALINK 0x0675 +#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702 + +#define PCI_VENDOR_ID_BERKOM 0x0871 +#define PCI_DEVICE_ID_BERKOM_A1T 0xffa1 +#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xffa2 +#define PCI_DEVICE_ID_BERKOM_A4T 0xffa4 +#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xffa8 + +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508 +#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc +#define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae10 +#define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32 +#define PCI_DEVICE_ID_COMPAQ_NETEL10 0xae34 +#define PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE 0xae33 +#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I 0xae35 +#define PCI_DEVICE_ID_COMPAQ_NETEL100D 0xae40 +#define PCI_DEVICE_ID_COMPAQ_NETEL100PI 0xae43 +#define PCI_DEVICE_ID_COMPAQ_NETEL100I 0xb011 +#define PCI_DEVICE_ID_COMPAQ_CISS 0xb060 +#define PCI_DEVICE_ID_COMPAQ_CISSB 0xb178 +#define PCI_DEVICE_ID_COMPAQ_CISSC 0x46 +#define PCI_DEVICE_ID_COMPAQ_THUNDER 0xf130 +#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B 0xf150 + +#define PCI_VENDOR_ID_NCR 0x1000 +#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 +#define PCI_DEVICE_ID_NCR_53C810 0x0001 +#define PCI_DEVICE_ID_NCR_53C820 0x0002 +#define PCI_DEVICE_ID_NCR_53C825 0x0003 +#define PCI_DEVICE_ID_NCR_53C815 0x0004 +#define PCI_DEVICE_ID_LSI_53C810AP 0x0005 +#define PCI_DEVICE_ID_NCR_53C860 0x0006 +#define PCI_DEVICE_ID_LSI_53C1510 0x000a +#define PCI_DEVICE_ID_NCR_53C896 0x000b +#define PCI_DEVICE_ID_NCR_53C895 0x000c +#define PCI_DEVICE_ID_NCR_53C885 0x000d +#define PCI_DEVICE_ID_NCR_53C875 0x000f +#define PCI_DEVICE_ID_NCR_53C1510 0x0010 +#define PCI_DEVICE_ID_LSI_53C895A 0x0012 +#define PCI_DEVICE_ID_LSI_53C875A 0x0013 +#define PCI_DEVICE_ID_LSI_53C1010_33 0x0020 +#define PCI_DEVICE_ID_LSI_53C1010_66 0x0021 +#define PCI_DEVICE_ID_LSI_53C1030 0x0030 +#define PCI_DEVICE_ID_LSI_1030_53C1035 0x0032 +#define PCI_DEVICE_ID_LSI_53C1035 0x0040 +#define PCI_DEVICE_ID_NCR_53C875J 0x008f +#define PCI_DEVICE_ID_LSI_FC909 0x0621 +#define PCI_DEVICE_ID_LSI_FC929 0x0622 +#define PCI_DEVICE_ID_LSI_FC929_LAN 0x0623 +#define PCI_DEVICE_ID_LSI_FC919 0x0624 +#define PCI_DEVICE_ID_LSI_FC919_LAN 0x0625 +#define PCI_DEVICE_ID_LSI_FC929X 0x0626 +#define PCI_DEVICE_ID_LSI_FC939X 0x0642 +#define PCI_DEVICE_ID_LSI_FC949X 0x0640 +#define PCI_DEVICE_ID_LSI_FC949ES 0x0646 +#define PCI_DEVICE_ID_LSI_FC919X 0x0628 +#define PCI_DEVICE_ID_NCR_YELLOWFIN 0x0701 +#define PCI_DEVICE_ID_LSI_61C102 0x0901 +#define PCI_DEVICE_ID_LSI_63C815 0x1000 +#define PCI_DEVICE_ID_LSI_SAS1064 0x0050 +#define PCI_DEVICE_ID_LSI_SAS1064R 0x0411 +#define PCI_DEVICE_ID_LSI_SAS1066 0x005E +#define PCI_DEVICE_ID_LSI_SAS1068 0x0054 +#define PCI_DEVICE_ID_LSI_SAS1064A 0x005C +#define PCI_DEVICE_ID_LSI_SAS1064E 0x0056 +#define PCI_DEVICE_ID_LSI_SAS1066E 0x005A +#define PCI_DEVICE_ID_LSI_SAS1068E 0x0058 +#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 + +#define PCI_VENDOR_ID_ATI 0x1002 +/* Mach64 */ +#define PCI_DEVICE_ID_ATI_68800 0x4158 +#define PCI_DEVICE_ID_ATI_215CT222 0x4354 +#define PCI_DEVICE_ID_ATI_210888CX 0x4358 +#define PCI_DEVICE_ID_ATI_215ET222 0x4554 +/* Mach64 / Rage */ +#define PCI_DEVICE_ID_ATI_215GB 0x4742 +#define PCI_DEVICE_ID_ATI_215GD 0x4744 +#define PCI_DEVICE_ID_ATI_215GI 0x4749 +#define PCI_DEVICE_ID_ATI_215GP 0x4750 +#define PCI_DEVICE_ID_ATI_215GQ 0x4751 +#define PCI_DEVICE_ID_ATI_215XL 0x4752 +#define PCI_DEVICE_ID_ATI_215GT 0x4754 +#define PCI_DEVICE_ID_ATI_215GTB 0x4755 +#define PCI_DEVICE_ID_ATI_215_IV 0x4756 +#define PCI_DEVICE_ID_ATI_215_IW 0x4757 +#define PCI_DEVICE_ID_ATI_215_IZ 0x475A +#define PCI_DEVICE_ID_ATI_210888GX 0x4758 +#define PCI_DEVICE_ID_ATI_215_LB 0x4c42 +#define PCI_DEVICE_ID_ATI_215_LD 0x4c44 +#define PCI_DEVICE_ID_ATI_215_LG 0x4c47 +#define PCI_DEVICE_ID_ATI_215_LI 0x4c49 +#define PCI_DEVICE_ID_ATI_215_LM 0x4c4D +#define PCI_DEVICE_ID_ATI_215_LN 0x4c4E +#define PCI_DEVICE_ID_ATI_215_LR 0x4c52 +#define PCI_DEVICE_ID_ATI_215_LS 0x4c53 +#define PCI_DEVICE_ID_ATI_264_LT 0x4c54 +/* Mach64 VT */ +#define PCI_DEVICE_ID_ATI_264VT 0x5654 +#define PCI_DEVICE_ID_ATI_264VU 0x5655 +#define PCI_DEVICE_ID_ATI_264VV 0x5656 +/* Rage128 GL */ +#define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245 +#define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246 +#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247 +/* Rage128 VR */ +#define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b +#define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c +#define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345 +#define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346 +#define PCI_DEVICE_ID_ATI_RAGE128_SG 0x5347 +#define PCI_DEVICE_ID_ATI_RAGE128_SH 0x5348 +#define PCI_DEVICE_ID_ATI_RAGE128_SK 0x534b +#define PCI_DEVICE_ID_ATI_RAGE128_SL 0x534c +#define PCI_DEVICE_ID_ATI_RAGE128_SM 0x534d +#define PCI_DEVICE_ID_ATI_RAGE128_SN 0x534e +/* Rage128 Ultra */ +#define PCI_DEVICE_ID_ATI_RAGE128_TF 0x5446 +#define PCI_DEVICE_ID_ATI_RAGE128_TL 0x544c +#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452 +#define PCI_DEVICE_ID_ATI_RAGE128_TS 0x5453 +#define PCI_DEVICE_ID_ATI_RAGE128_TT 0x5454 +#define PCI_DEVICE_ID_ATI_RAGE128_TU 0x5455 +/* Rage128 M3 */ +#define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45 +#define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46 +/* Rage128 M4 */ +#define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46 +#define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c +/* Rage128 Pro GL */ +#define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041 +#define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042 +#define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043 +#define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044 +#define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045 +#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 +/* Rage128 Pro VR */ +#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047 +#define PCI_DEVICE_ID_ATI_RAGE128_PH 0x5048 +#define PCI_DEVICE_ID_ATI_RAGE128_PI 0x5049 +#define PCI_DEVICE_ID_ATI_RAGE128_PJ 0x504A +#define PCI_DEVICE_ID_ATI_RAGE128_PK 0x504B +#define PCI_DEVICE_ID_ATI_RAGE128_PL 0x504C +#define PCI_DEVICE_ID_ATI_RAGE128_PM 0x504D +#define PCI_DEVICE_ID_ATI_RAGE128_PN 0x504E +#define PCI_DEVICE_ID_ATI_RAGE128_PO 0x504F +#define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050 +#define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051 +#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 +#define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053 +#define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054 +#define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055 +#define PCI_DEVICE_ID_ATI_RAGE128_PV 0x5056 +#define PCI_DEVICE_ID_ATI_RAGE128_PW 0x5057 +#define PCI_DEVICE_ID_ATI_RAGE128_PX 0x5058 +/* Rage128 M4 */ +/* Radeon R100 */ +#define PCI_DEVICE_ID_ATI_RADEON_QD 0x5144 +#define PCI_DEVICE_ID_ATI_RADEON_QE 0x5145 +#define PCI_DEVICE_ID_ATI_RADEON_QF 0x5146 +#define PCI_DEVICE_ID_ATI_RADEON_QG 0x5147 +/* Radeon RV100 (VE) */ +#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159 +#define PCI_DEVICE_ID_ATI_RADEON_QZ 0x515a +/* Radeon R200 (8500) */ +#define PCI_DEVICE_ID_ATI_RADEON_QL 0x514c +#define PCI_DEVICE_ID_ATI_RADEON_QN 0x514e +#define PCI_DEVICE_ID_ATI_RADEON_QO 0x514f +#define PCI_DEVICE_ID_ATI_RADEON_Ql 0x516c +#define PCI_DEVICE_ID_ATI_RADEON_BB 0x4242 +/* Radeon R200 (9100) */ +#define PCI_DEVICE_ID_ATI_RADEON_QM 0x514d +/* Radeon RV200 (7500) */ +#define PCI_DEVICE_ID_ATI_RADEON_QW 0x5157 +#define PCI_DEVICE_ID_ATI_RADEON_QX 0x5158 +/* Radeon NV-100 */ +/* Radeon RV250 (9000) */ +#define PCI_DEVICE_ID_ATI_RADEON_Id 0x4964 +#define PCI_DEVICE_ID_ATI_RADEON_Ie 0x4965 +#define PCI_DEVICE_ID_ATI_RADEON_If 0x4966 +#define PCI_DEVICE_ID_ATI_RADEON_Ig 0x4967 +/* Radeon RV280 (9200) */ +#define PCI_DEVICE_ID_ATI_RADEON_Ya 0x5961 +#define PCI_DEVICE_ID_ATI_RADEON_Yd 0x5964 +/* Radeon R300 (9500) */ +/* Radeon R300 (9700) */ +#define PCI_DEVICE_ID_ATI_RADEON_ND 0x4e44 +#define PCI_DEVICE_ID_ATI_RADEON_NE 0x4e45 +#define PCI_DEVICE_ID_ATI_RADEON_NF 0x4e46 +#define PCI_DEVICE_ID_ATI_RADEON_NG 0x4e47 +/* Radeon R350 (9800) */ +/* Radeon RV350 (9600) */ +/* Radeon M6 */ +#define PCI_DEVICE_ID_ATI_RADEON_LY 0x4c59 +#define PCI_DEVICE_ID_ATI_RADEON_LZ 0x4c5a +/* Radeon M7 */ +#define PCI_DEVICE_ID_ATI_RADEON_LW 0x4c57 +#define PCI_DEVICE_ID_ATI_RADEON_LX 0x4c58 +/* Radeon M9 */ +#define PCI_DEVICE_ID_ATI_RADEON_Ld 0x4c64 +#define PCI_DEVICE_ID_ATI_RADEON_Le 0x4c65 +#define PCI_DEVICE_ID_ATI_RADEON_Lf 0x4c66 +#define PCI_DEVICE_ID_ATI_RADEON_Lg 0x4c67 +/* Radeon */ +/* RadeonIGP */ +#define PCI_DEVICE_ID_ATI_RS100 0xcab0 +#define PCI_DEVICE_ID_ATI_RS200 0xcab2 +#define PCI_DEVICE_ID_ATI_RS200_B 0xcbb2 +#define PCI_DEVICE_ID_ATI_RS250 0xcab3 +#define PCI_DEVICE_ID_ATI_RS300_100 0x5830 +#define PCI_DEVICE_ID_ATI_RS300_133 0x5831 +#define PCI_DEVICE_ID_ATI_RS300_166 0x5832 +#define PCI_DEVICE_ID_ATI_RS300_200 0x5833 +#define PCI_DEVICE_ID_ATI_RS350_100 0x7830 +#define PCI_DEVICE_ID_ATI_RS350_133 0x7831 +#define PCI_DEVICE_ID_ATI_RS350_166 0x7832 +#define PCI_DEVICE_ID_ATI_RS350_200 0x7833 +#define PCI_DEVICE_ID_ATI_RS400_100 0x5a30 +#define PCI_DEVICE_ID_ATI_RS400_133 0x5a31 +#define PCI_DEVICE_ID_ATI_RS400_166 0x5a32 +#define PCI_DEVICE_ID_ATI_RS400_200 0x5a33 +#define PCI_DEVICE_ID_ATI_RS480 0x5950 +/* ATI IXP Chipset */ +#define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349 +#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353 +#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363 +#define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369 +#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e +#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372 +#define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376 +#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379 +#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a +#define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380 +#define PCI_DEVICE_ID_ATI_SBX00_SMBUS 0x4385 +#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c +#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390 +#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c + +#define PCI_VENDOR_ID_VLSI 0x1004 +#define PCI_DEVICE_ID_VLSI_82C592 0x0005 +#define PCI_DEVICE_ID_VLSI_82C593 0x0006 +#define PCI_DEVICE_ID_VLSI_82C594 0x0007 +#define PCI_DEVICE_ID_VLSI_82C597 0x0009 +#define PCI_DEVICE_ID_VLSI_82C541 0x000c +#define PCI_DEVICE_ID_VLSI_82C543 0x000d +#define PCI_DEVICE_ID_VLSI_82C532 0x0101 +#define PCI_DEVICE_ID_VLSI_82C534 0x0102 +#define PCI_DEVICE_ID_VLSI_82C535 0x0104 +#define PCI_DEVICE_ID_VLSI_82C147 0x0105 +#define PCI_DEVICE_ID_VLSI_VAS96011 0x0702 + +/* AMD RD890 Chipset */ +#define PCI_DEVICE_ID_RD890_IOMMU 0x5a23 + +#define PCI_VENDOR_ID_ADL 0x1005 +#define PCI_DEVICE_ID_ADL_2301 0x2301 + +#define PCI_VENDOR_ID_NS 0x100b +#define PCI_DEVICE_ID_NS_87415 0x0002 +#define PCI_DEVICE_ID_NS_87560_LIO 0x000e +#define PCI_DEVICE_ID_NS_87560_USB 0x0012 +#define PCI_DEVICE_ID_NS_83815 0x0020 +#define PCI_DEVICE_ID_NS_83820 0x0022 +#define PCI_DEVICE_ID_NS_CS5535_ISA 0x002b +#define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d +#define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e +#define PCI_DEVICE_ID_NS_CS5535_USB 0x002f +#define PCI_DEVICE_ID_NS_GX_VIDEO 0x0030 +#define PCI_DEVICE_ID_NS_SATURN 0x0035 +#define PCI_DEVICE_ID_NS_SCx200_BRIDGE 0x0500 +#define PCI_DEVICE_ID_NS_SCx200_SMI 0x0501 +#define PCI_DEVICE_ID_NS_SCx200_IDE 0x0502 +#define PCI_DEVICE_ID_NS_SCx200_AUDIO 0x0503 +#define PCI_DEVICE_ID_NS_SCx200_VIDEO 0x0504 +#define PCI_DEVICE_ID_NS_SCx200_XBUS 0x0505 +#define PCI_DEVICE_ID_NS_SC1100_BRIDGE 0x0510 +#define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511 +#define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 +#define PCI_DEVICE_ID_NS_87410 0xd001 + +#define PCI_DEVICE_ID_NS_GX_HOST_BRIDGE 0x0028 + +#define PCI_VENDOR_ID_TSENG 0x100c +#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202 +#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205 +#define PCI_DEVICE_ID_TSENG_W32P_c 0x3206 +#define PCI_DEVICE_ID_TSENG_W32P_d 0x3207 +#define PCI_DEVICE_ID_TSENG_ET6000 0x3208 + +#define PCI_VENDOR_ID_WEITEK 0x100e +#define PCI_DEVICE_ID_WEITEK_P9000 0x9001 +#define PCI_DEVICE_ID_WEITEK_P9100 0x9100 + +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_DEC_BRD 0x0001 +#define PCI_DEVICE_ID_DEC_TULIP 0x0002 +#define PCI_DEVICE_ID_DEC_TGA 0x0004 +#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 +#define PCI_DEVICE_ID_DEC_TGA2 0x000D +#define PCI_DEVICE_ID_DEC_FDDI 0x000F +#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 +#define PCI_DEVICE_ID_DEC_21142 0x0019 +#define PCI_DEVICE_ID_DEC_21052 0x0021 +#define PCI_DEVICE_ID_DEC_21150 0x0022 +#define PCI_DEVICE_ID_DEC_21152 0x0024 +#define PCI_DEVICE_ID_DEC_21153 0x0025 +#define PCI_DEVICE_ID_DEC_21154 0x0026 +#define PCI_DEVICE_ID_DEC_21285 0x1065 +#define PCI_DEVICE_ID_COMPAQ_42XX 0x0046 + +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#define PCI_DEVICE_ID_CIRRUS_7548 0x0038 +#define PCI_DEVICE_ID_CIRRUS_5430 0x00a0 +#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4 +#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8 +#define PCI_DEVICE_ID_CIRRUS_5436 0x00ac +#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8 +#define PCI_DEVICE_ID_CIRRUS_5480 0x00bc +#define PCI_DEVICE_ID_CIRRUS_5462 0x00d0 +#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4 +#define PCI_DEVICE_ID_CIRRUS_5465 0x00d6 +#define PCI_DEVICE_ID_CIRRUS_6729 0x1100 +#define PCI_DEVICE_ID_CIRRUS_6832 0x1110 +#define PCI_DEVICE_ID_CIRRUS_7543 0x1202 +#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 +#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 +#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 + +#define PCI_VENDOR_ID_IBM 0x1014 +#define PCI_DEVICE_ID_IBM_TR 0x0018 +#define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e +#define PCI_DEVICE_ID_IBM_CPC710_PCI64 0x00fc +#define PCI_DEVICE_ID_IBM_SNIPE 0x0180 +#define PCI_DEVICE_ID_IBM_CITRINE 0x028C +#define PCI_DEVICE_ID_IBM_GEMSTONE 0xB166 +#define PCI_DEVICE_ID_IBM_OBSIDIAN 0x02BD +#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1 0x0031 +#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2 0x0219 +#define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX 0x021A +#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM 0x0251 +#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361 +#define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252 + +#define PCI_SUBVENDOR_ID_IBM 0x1014 +#define PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT 0x03d4 + +#define PCI_VENDOR_ID_UNISYS 0x1018 +#define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C + +#define PCI_VENDOR_ID_COMPEX2 0x101a /* pci.ids says "AT&T GIS (NCR)" */ +#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 + +#define PCI_VENDOR_ID_WD 0x101c +#define PCI_DEVICE_ID_WD_90C 0xc24a + +#define PCI_VENDOR_ID_AMI 0x101e +#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 +#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 +#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 + +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_K8_NB 0x1100 +#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP 0x1101 +#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL 0x1102 +#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103 +#define PCI_DEVICE_ID_AMD_10H_NB_HT 0x1200 +#define PCI_DEVICE_ID_AMD_10H_NB_MAP 0x1201 +#define PCI_DEVICE_ID_AMD_10H_NB_DRAM 0x1202 +#define PCI_DEVICE_ID_AMD_10H_NB_MISC 0x1203 +#define PCI_DEVICE_ID_AMD_10H_NB_LINK 0x1204 +#define PCI_DEVICE_ID_AMD_11H_NB_HT 0x1300 +#define PCI_DEVICE_ID_AMD_11H_NB_MAP 0x1301 +#define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302 +#define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303 +#define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304 +#define PCI_DEVICE_ID_AMD_15H_NB_F3 0x1603 +#define PCI_DEVICE_ID_AMD_15H_NB_F4 0x1604 +#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703 +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 +#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 +#define PCI_DEVICE_ID_AMD_SCSI 0x2020 +#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0 +#define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006 +#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007 +#define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C +#define PCI_DEVICE_ID_AMD_FE_GATE_700E 0x700E +#define PCI_DEVICE_ID_AMD_COBRA_7401 0x7401 +#define PCI_DEVICE_ID_AMD_VIPER_7409 0x7409 +#define PCI_DEVICE_ID_AMD_VIPER_740B 0x740B +#define PCI_DEVICE_ID_AMD_VIPER_7410 0x7410 +#define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411 +#define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413 +#define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440 +#define PCI_DEVICE_ID_AMD_OPUS_7441 0x7441 +#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443 +#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443 +#define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445 +#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460 +#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468 +#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469 +#define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a +#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b +#define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d +#define PCI_DEVICE_ID_AMD_8151_0 0x7454 +#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 +#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 +#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458 +#define PCI_DEVICE_ID_AMD_HUDSON2_SMBUS 0x780b +#define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F +#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 +#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 +#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 +#define PCI_DEVICE_ID_AMD_CS5536_OHC 0x2094 +#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095 +#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096 +#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097 +#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A +#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081 +#define PCI_DEVICE_ID_AMD_LX_AES 0x2082 +#define PCI_DEVICE_ID_AMD_HUDSON2_IDE 0x780c +#define PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE 0x7800 + +#define PCI_VENDOR_ID_TRIDENT 0x1023 +#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 +#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 +#define PCI_DEVICE_ID_TRIDENT_9320 0x9320 +#define PCI_DEVICE_ID_TRIDENT_9388 0x9388 +#define PCI_DEVICE_ID_TRIDENT_9397 0x9397 +#define PCI_DEVICE_ID_TRIDENT_939A 0x939A +#define PCI_DEVICE_ID_TRIDENT_9520 0x9520 +#define PCI_DEVICE_ID_TRIDENT_9525 0x9525 +#define PCI_DEVICE_ID_TRIDENT_9420 0x9420 +#define PCI_DEVICE_ID_TRIDENT_9440 0x9440 +#define PCI_DEVICE_ID_TRIDENT_9660 0x9660 +#define PCI_DEVICE_ID_TRIDENT_9750 0x9750 +#define PCI_DEVICE_ID_TRIDENT_9850 0x9850 +#define PCI_DEVICE_ID_TRIDENT_9880 0x9880 +#define PCI_DEVICE_ID_TRIDENT_8400 0x8400 +#define PCI_DEVICE_ID_TRIDENT_8420 0x8420 +#define PCI_DEVICE_ID_TRIDENT_8500 0x8500 + +#define PCI_VENDOR_ID_AI 0x1025 +#define PCI_DEVICE_ID_AI_M1435 0x1435 + +#define PCI_VENDOR_ID_DELL 0x1028 +#define PCI_DEVICE_ID_DELL_RACIII 0x0008 +#define PCI_DEVICE_ID_DELL_RAC4 0x0012 +#define PCI_DEVICE_ID_DELL_PERC5 0x0015 + +#define PCI_VENDOR_ID_MATROX 0x102B +#define PCI_DEVICE_ID_MATROX_MGA_2 0x0518 +#define PCI_DEVICE_ID_MATROX_MIL 0x0519 +#define PCI_DEVICE_ID_MATROX_MYS 0x051A +#define PCI_DEVICE_ID_MATROX_MIL_2 0x051b +#define PCI_DEVICE_ID_MATROX_MYS_AGP 0x051e +#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f +#define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10 +#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000 +#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 +#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 +#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 +#define PCI_DEVICE_ID_MATROX_G400 0x0525 +#define PCI_DEVICE_ID_MATROX_G200EV_PCI 0x0530 +#define PCI_DEVICE_ID_MATROX_G550 0x2527 +#define PCI_DEVICE_ID_MATROX_VIA 0x4536 + +#define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2 + +#define PCI_VENDOR_ID_CT 0x102c +#define PCI_DEVICE_ID_CT_69000 0x00c0 +#define PCI_DEVICE_ID_CT_65545 0x00d8 +#define PCI_DEVICE_ID_CT_65548 0x00dc +#define PCI_DEVICE_ID_CT_65550 0x00e0 +#define PCI_DEVICE_ID_CT_65554 0x00e4 +#define PCI_DEVICE_ID_CT_65555 0x00e5 + +#define PCI_VENDOR_ID_MIRO 0x1031 +#define PCI_DEVICE_ID_MIRO_36050 0x5601 +#define PCI_DEVICE_ID_MIRO_DC10PLUS 0x7efe +#define PCI_DEVICE_ID_MIRO_DC30PLUS 0xd801 + +#define PCI_VENDOR_ID_NEC 0x1033 +#define PCI_DEVICE_ID_NEC_CBUS_1 0x0001 /* PCI-Cbus Bridge */ +#define PCI_DEVICE_ID_NEC_LOCAL 0x0002 /* Local Bridge */ +#define PCI_DEVICE_ID_NEC_ATM 0x0003 /* ATM LAN Controller */ +#define PCI_DEVICE_ID_NEC_R4000 0x0004 /* R4000 Bridge */ +#define PCI_DEVICE_ID_NEC_486 0x0005 /* 486 Like Peripheral Bus Bridge */ +#define PCI_DEVICE_ID_NEC_ACCEL_1 0x0006 /* Graphic Accelerator */ +#define PCI_DEVICE_ID_NEC_UXBUS 0x0007 /* UX-Bus Bridge */ +#define PCI_DEVICE_ID_NEC_ACCEL_2 0x0008 /* Graphic Accelerator */ +#define PCI_DEVICE_ID_NEC_GRAPH 0x0009 /* PCI-CoreGraph Bridge */ +#define PCI_DEVICE_ID_NEC_VL 0x0016 /* PCI-VL Bridge */ +#define PCI_DEVICE_ID_NEC_STARALPHA2 0x002c /* STAR ALPHA2 */ +#define PCI_DEVICE_ID_NEC_CBUS_2 0x002d /* PCI-Cbus Bridge */ +#define PCI_DEVICE_ID_NEC_USB 0x0035 /* PCI-USB Host */ +#define PCI_DEVICE_ID_NEC_CBUS_3 0x003b +#define PCI_DEVICE_ID_NEC_NAPCCARD 0x003e +#define PCI_DEVICE_ID_NEC_PCX2 0x0046 /* PowerVR */ +#define PCI_DEVICE_ID_NEC_VRC5476 0x009b +#define PCI_DEVICE_ID_NEC_VRC4173 0x00a5 +#define PCI_DEVICE_ID_NEC_VRC5477_AC97 0x00a6 +#define PCI_DEVICE_ID_NEC_PC9821CS01 0x800c /* PC-9821-CS01 */ +#define PCI_DEVICE_ID_NEC_PC9821NRB06 0x800d /* PC-9821NR-B06 */ + +#define PCI_VENDOR_ID_FD 0x1036 +#define PCI_DEVICE_ID_FD_36C70 0x0000 + +#define PCI_VENDOR_ID_SI 0x1039 +#define PCI_DEVICE_ID_SI_5591_AGP 0x0001 +#define PCI_DEVICE_ID_SI_6202 0x0002 +#define PCI_DEVICE_ID_SI_503 0x0008 +#define PCI_DEVICE_ID_SI_ACPI 0x0009 +#define PCI_DEVICE_ID_SI_SMBUS 0x0016 +#define PCI_DEVICE_ID_SI_LPC 0x0018 +#define PCI_DEVICE_ID_SI_5597_VGA 0x0200 +#define PCI_DEVICE_ID_SI_6205 0x0205 +#define PCI_DEVICE_ID_SI_501 0x0406 +#define PCI_DEVICE_ID_SI_496 0x0496 +#define PCI_DEVICE_ID_SI_300 0x0300 +#define PCI_DEVICE_ID_SI_315H 0x0310 +#define PCI_DEVICE_ID_SI_315 0x0315 +#define PCI_DEVICE_ID_SI_315PRO 0x0325 +#define PCI_DEVICE_ID_SI_530 0x0530 +#define PCI_DEVICE_ID_SI_540 0x0540 +#define PCI_DEVICE_ID_SI_550 0x0550 +#define PCI_DEVICE_ID_SI_540_VGA 0x5300 +#define PCI_DEVICE_ID_SI_550_VGA 0x5315 +#define PCI_DEVICE_ID_SI_620 0x0620 +#define PCI_DEVICE_ID_SI_630 0x0630 +#define PCI_DEVICE_ID_SI_633 0x0633 +#define PCI_DEVICE_ID_SI_635 0x0635 +#define PCI_DEVICE_ID_SI_640 0x0640 +#define PCI_DEVICE_ID_SI_645 0x0645 +#define PCI_DEVICE_ID_SI_646 0x0646 +#define PCI_DEVICE_ID_SI_648 0x0648 +#define PCI_DEVICE_ID_SI_650 0x0650 +#define PCI_DEVICE_ID_SI_651 0x0651 +#define PCI_DEVICE_ID_SI_655 0x0655 +#define PCI_DEVICE_ID_SI_661 0x0661 +#define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_733 0x0733 +#define PCI_DEVICE_ID_SI_630_VGA 0x6300 +#define PCI_DEVICE_ID_SI_735 0x0735 +#define PCI_DEVICE_ID_SI_740 0x0740 +#define PCI_DEVICE_ID_SI_741 0x0741 +#define PCI_DEVICE_ID_SI_745 0x0745 +#define PCI_DEVICE_ID_SI_746 0x0746 +#define PCI_DEVICE_ID_SI_755 0x0755 +#define PCI_DEVICE_ID_SI_760 0x0760 +#define PCI_DEVICE_ID_SI_900 0x0900 +#define PCI_DEVICE_ID_SI_961 0x0961 +#define PCI_DEVICE_ID_SI_962 0x0962 +#define PCI_DEVICE_ID_SI_963 0x0963 +#define PCI_DEVICE_ID_SI_965 0x0965 +#define PCI_DEVICE_ID_SI_966 0x0966 +#define PCI_DEVICE_ID_SI_968 0x0968 +#define PCI_DEVICE_ID_SI_1180 0x1180 +#define PCI_DEVICE_ID_SI_5511 0x5511 +#define PCI_DEVICE_ID_SI_5513 0x5513 +#define PCI_DEVICE_ID_SI_5517 0x5517 +#define PCI_DEVICE_ID_SI_5518 0x5518 +#define PCI_DEVICE_ID_SI_5571 0x5571 +#define PCI_DEVICE_ID_SI_5581 0x5581 +#define PCI_DEVICE_ID_SI_5582 0x5582 +#define PCI_DEVICE_ID_SI_5591 0x5591 +#define PCI_DEVICE_ID_SI_5596 0x5596 +#define PCI_DEVICE_ID_SI_5597 0x5597 +#define PCI_DEVICE_ID_SI_5598 0x5598 +#define PCI_DEVICE_ID_SI_5600 0x5600 +#define PCI_DEVICE_ID_SI_7012 0x7012 +#define PCI_DEVICE_ID_SI_7013 0x7013 +#define PCI_DEVICE_ID_SI_7016 0x7016 +#define PCI_DEVICE_ID_SI_7018 0x7018 + +#define PCI_VENDOR_ID_HP 0x103c +#define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005 +#define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006 +#define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008 +#define PCI_DEVICE_ID_HP_VISUALIZE_FX2 0x100a +#define PCI_DEVICE_ID_HP_TACHYON 0x1028 +#define PCI_DEVICE_ID_HP_TACHLITE 0x1029 +#define PCI_DEVICE_ID_HP_J2585A 0x1030 +#define PCI_DEVICE_ID_HP_J2585B 0x1031 +#define PCI_DEVICE_ID_HP_J2973A 0x1040 +#define PCI_DEVICE_ID_HP_J2970A 0x1042 +#define PCI_DEVICE_ID_HP_DIVA 0x1048 +#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 +#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A +#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B +#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 +#define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b +#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 +#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 +#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227 +#define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a +#define PCI_DEVICE_ID_HP_PCIX_LBA 0x122e +#define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c +#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 +#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 +#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 +#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a +#define PCI_DEVICE_ID_HP_CISSA 0x3220 +#define PCI_DEVICE_ID_HP_CISSC 0x3230 +#define PCI_DEVICE_ID_HP_CISSD 0x3238 +#define PCI_DEVICE_ID_HP_CISSE 0x323a +#define PCI_DEVICE_ID_HP_CISSF 0x323b +#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 + +#define PCI_VENDOR_ID_PCTECH 0x1042 +#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 +#define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001 +#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020 + +#define PCI_VENDOR_ID_ASUSTEK 0x1043 +#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675 + +#define PCI_VENDOR_ID_DPT 0x1044 +#define PCI_DEVICE_ID_DPT 0xa400 + +#define PCI_VENDOR_ID_OPTI 0x1045 +#define PCI_DEVICE_ID_OPTI_82C558 0xc558 +#define PCI_DEVICE_ID_OPTI_82C621 0xc621 +#define PCI_DEVICE_ID_OPTI_82C700 0xc700 +#define PCI_DEVICE_ID_OPTI_82C825 0xd568 + +#define PCI_VENDOR_ID_ELSA 0x1048 +#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 +#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 + +#define PCI_VENDOR_ID_STMICRO 0x104A + +#define PCI_VENDOR_ID_BUSLOGIC 0x104B +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040 +#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130 + +#define PCI_VENDOR_ID_TI 0x104c +#define PCI_DEVICE_ID_TI_TVP4020 0x3d07 +#define PCI_DEVICE_ID_TI_4450 0x8011 +#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 +#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033 +#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034 +#define PCI_DEVICE_ID_TI_X515 0x8036 +#define PCI_DEVICE_ID_TI_XX12 0x8039 +#define PCI_DEVICE_ID_TI_XX12_FM 0x803b +#define PCI_DEVICE_ID_TI_XIO2000A 0x8231 +#define PCI_DEVICE_ID_TI_1130 0xac12 +#define PCI_DEVICE_ID_TI_1031 0xac13 +#define PCI_DEVICE_ID_TI_1131 0xac15 +#define PCI_DEVICE_ID_TI_1250 0xac16 +#define PCI_DEVICE_ID_TI_1220 0xac17 +#define PCI_DEVICE_ID_TI_1221 0xac19 +#define PCI_DEVICE_ID_TI_1210 0xac1a +#define PCI_DEVICE_ID_TI_1450 0xac1b +#define PCI_DEVICE_ID_TI_1225 0xac1c +#define PCI_DEVICE_ID_TI_1251A 0xac1d +#define PCI_DEVICE_ID_TI_1211 0xac1e +#define PCI_DEVICE_ID_TI_1251B 0xac1f +#define PCI_DEVICE_ID_TI_4410 0xac41 +#define PCI_DEVICE_ID_TI_4451 0xac42 +#define PCI_DEVICE_ID_TI_4510 0xac44 +#define PCI_DEVICE_ID_TI_4520 0xac46 +#define PCI_DEVICE_ID_TI_7510 0xac47 +#define PCI_DEVICE_ID_TI_7610 0xac48 +#define PCI_DEVICE_ID_TI_7410 0xac49 +#define PCI_DEVICE_ID_TI_1410 0xac50 +#define PCI_DEVICE_ID_TI_1420 0xac51 +#define PCI_DEVICE_ID_TI_1451A 0xac52 +#define PCI_DEVICE_ID_TI_1620 0xac54 +#define PCI_DEVICE_ID_TI_1520 0xac55 +#define PCI_DEVICE_ID_TI_1510 0xac56 +#define PCI_DEVICE_ID_TI_X620 0xac8d +#define PCI_DEVICE_ID_TI_X420 0xac8e +#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f + +#define PCI_VENDOR_ID_SONY 0x104d + +/* Winbond have two vendor IDs! See 0x10ad as well */ +#define PCI_VENDOR_ID_WINBOND2 0x1050 +#define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a +#define PCI_DEVICE_ID_WINBOND2_6692 0x6692 + +#define PCI_VENDOR_ID_ANIGMA 0x1051 +#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100 + +#define PCI_VENDOR_ID_EFAR 0x1055 +#define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130 +#define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463 + +#define PCI_VENDOR_ID_MOTOROLA 0x1057 +#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001 +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 +#define PCI_DEVICE_ID_MOTOROLA_MPC107 0x0004 +#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 +#define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802 +#define PCI_DEVICE_ID_MOTOROLA_HAWK 0x4803 +#define PCI_DEVICE_ID_MOTOROLA_HARRIER 0x480b +#define PCI_DEVICE_ID_MOTOROLA_MPC5200 0x5803 +#define PCI_DEVICE_ID_MOTOROLA_MPC5200B 0x5809 + +#define PCI_VENDOR_ID_PROMISE 0x105a +#define PCI_DEVICE_ID_PROMISE_20265 0x0d30 +#define PCI_DEVICE_ID_PROMISE_20267 0x4d30 +#define PCI_DEVICE_ID_PROMISE_20246 0x4d33 +#define PCI_DEVICE_ID_PROMISE_20262 0x4d38 +#define PCI_DEVICE_ID_PROMISE_20263 0x0D38 +#define PCI_DEVICE_ID_PROMISE_20268 0x4d68 +#define PCI_DEVICE_ID_PROMISE_20269 0x4d69 +#define PCI_DEVICE_ID_PROMISE_20270 0x6268 +#define PCI_DEVICE_ID_PROMISE_20271 0x6269 +#define PCI_DEVICE_ID_PROMISE_20275 0x1275 +#define PCI_DEVICE_ID_PROMISE_20276 0x5275 +#define PCI_DEVICE_ID_PROMISE_20277 0x7275 + +#define PCI_VENDOR_ID_FOXCONN 0x105b + +#define PCI_VENDOR_ID_UMC 0x1060 +#define PCI_DEVICE_ID_UMC_UM8673F 0x0101 +#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a +#define PCI_DEVICE_ID_UMC_UM8886A 0x886a + +#define PCI_VENDOR_ID_PICOPOWER 0x1066 +#define PCI_DEVICE_ID_PICOPOWER_PT86C523 0x0002 +#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP 0x8002 + +#define PCI_VENDOR_ID_MYLEX 0x1069 +#define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001 +#define PCI_DEVICE_ID_MYLEX_DAC960_PD 0x0002 +#define PCI_DEVICE_ID_MYLEX_DAC960_PG 0x0010 +#define PCI_DEVICE_ID_MYLEX_DAC960_LA 0x0020 +#define PCI_DEVICE_ID_MYLEX_DAC960_LP 0x0050 +#define PCI_DEVICE_ID_MYLEX_DAC960_BA 0xBA56 +#define PCI_DEVICE_ID_MYLEX_DAC960_GEM 0xB166 + +#define PCI_VENDOR_ID_APPLE 0x106b +#define PCI_DEVICE_ID_APPLE_BANDIT 0x0001 +#define PCI_DEVICE_ID_APPLE_HYDRA 0x000e +#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 +#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021 +#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d +#define PCI_DEVICE_ID_APPLE_UNI_N_PCI15 0x002e +#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032 +#define PCI_DEVICE_ID_APPLE_UNI_N_ATA 0x0033 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034 +#define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b +#define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043 +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b +#define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c +#define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050 +#define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051 +#define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058 +#define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059 +#define PCI_DEVICE_ID_APPLE_U4_PCIE 0x005b +#define PCI_DEVICE_ID_APPLE_IPID2_AGP 0x0066 +#define PCI_DEVICE_ID_APPLE_IPID2_ATA 0x0069 +#define PCI_DEVICE_ID_APPLE_IPID2_FW 0x006a +#define PCI_DEVICE_ID_APPLE_IPID2_GMAC 0x006b +#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 + +#define PCI_VENDOR_ID_YAMAHA 0x1073 +#define PCI_DEVICE_ID_YAMAHA_724 0x0004 +#define PCI_DEVICE_ID_YAMAHA_724F 0x000d +#define PCI_DEVICE_ID_YAMAHA_740 0x000a +#define PCI_DEVICE_ID_YAMAHA_740C 0x000c +#define PCI_DEVICE_ID_YAMAHA_744 0x0010 +#define PCI_DEVICE_ID_YAMAHA_754 0x0012 + +#define PCI_VENDOR_ID_QLOGIC 0x1077 +#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 +#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 +#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 +#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 +#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 +#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 +#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 +#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 +#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 +#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312 +#define PCI_DEVICE_ID_QLOGIC_ISP2322 0x2322 +#define PCI_DEVICE_ID_QLOGIC_ISP6312 0x6312 +#define PCI_DEVICE_ID_QLOGIC_ISP6322 0x6322 +#define PCI_DEVICE_ID_QLOGIC_ISP2422 0x2422 +#define PCI_DEVICE_ID_QLOGIC_ISP2432 0x2432 +#define PCI_DEVICE_ID_QLOGIC_ISP2512 0x2512 +#define PCI_DEVICE_ID_QLOGIC_ISP2522 0x2522 +#define PCI_DEVICE_ID_QLOGIC_ISP5422 0x5422 +#define PCI_DEVICE_ID_QLOGIC_ISP5432 0x5432 + +#define PCI_VENDOR_ID_CYRIX 0x1078 +#define PCI_DEVICE_ID_CYRIX_5510 0x0000 +#define PCI_DEVICE_ID_CYRIX_PCI_MASTER 0x0001 +#define PCI_DEVICE_ID_CYRIX_5520 0x0002 +#define PCI_DEVICE_ID_CYRIX_5530_LEGACY 0x0100 +#define PCI_DEVICE_ID_CYRIX_5530_IDE 0x0102 +#define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103 +#define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104 + +#define PCI_VENDOR_ID_CONTAQ 0x1080 +#define PCI_DEVICE_ID_CONTAQ_82C693 0xc693 + +#define PCI_VENDOR_ID_OLICOM 0x108d +#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012 +#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013 +#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014 + +#define PCI_VENDOR_ID_SUN 0x108e +#define PCI_DEVICE_ID_SUN_EBUS 0x1000 +#define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001 +#define PCI_DEVICE_ID_SUN_RIO_EBUS 0x1100 +#define PCI_DEVICE_ID_SUN_RIO_GEM 0x1101 +#define PCI_DEVICE_ID_SUN_RIO_1394 0x1102 +#define PCI_DEVICE_ID_SUN_RIO_USB 0x1103 +#define PCI_DEVICE_ID_SUN_GEM 0x2bad +#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 +#define PCI_DEVICE_ID_SUN_PBM 0x8000 +#define PCI_DEVICE_ID_SUN_SCHIZO 0x8001 +#define PCI_DEVICE_ID_SUN_SABRE 0xa000 +#define PCI_DEVICE_ID_SUN_HUMMINGBIRD 0xa001 +#define PCI_DEVICE_ID_SUN_TOMATILLO 0xa801 +#define PCI_DEVICE_ID_SUN_CASSINI 0xabba + +#define PCI_VENDOR_ID_NI 0x1093 +#define PCI_DEVICE_ID_NI_PCI2322 0xd130 +#define PCI_DEVICE_ID_NI_PCI2324 0xd140 +#define PCI_DEVICE_ID_NI_PCI2328 0xd150 +#define PCI_DEVICE_ID_NI_PXI8422_2322 0xd190 +#define PCI_DEVICE_ID_NI_PXI8422_2324 0xd1a0 +#define PCI_DEVICE_ID_NI_PXI8420_2322 0xd1d0 +#define PCI_DEVICE_ID_NI_PXI8420_2324 0xd1e0 +#define PCI_DEVICE_ID_NI_PXI8420_2328 0xd1f0 +#define PCI_DEVICE_ID_NI_PXI8420_23216 0xd1f1 +#define PCI_DEVICE_ID_NI_PCI2322I 0xd250 +#define PCI_DEVICE_ID_NI_PCI2324I 0xd270 +#define PCI_DEVICE_ID_NI_PCI23216 0xd2b0 +#define PCI_DEVICE_ID_NI_PXI8430_2322 0x7080 +#define PCI_DEVICE_ID_NI_PCI8430_2322 0x70db +#define PCI_DEVICE_ID_NI_PXI8430_2324 0x70dd +#define PCI_DEVICE_ID_NI_PCI8430_2324 0x70df +#define PCI_DEVICE_ID_NI_PXI8430_2328 0x70e2 +#define PCI_DEVICE_ID_NI_PCI8430_2328 0x70e4 +#define PCI_DEVICE_ID_NI_PXI8430_23216 0x70e6 +#define PCI_DEVICE_ID_NI_PCI8430_23216 0x70e7 +#define PCI_DEVICE_ID_NI_PXI8432_2322 0x70e8 +#define PCI_DEVICE_ID_NI_PCI8432_2322 0x70ea +#define PCI_DEVICE_ID_NI_PXI8432_2324 0x70ec +#define PCI_DEVICE_ID_NI_PCI8432_2324 0x70ee + +#define PCI_VENDOR_ID_CMD 0x1095 +#define PCI_DEVICE_ID_CMD_643 0x0643 +#define PCI_DEVICE_ID_CMD_646 0x0646 +#define PCI_DEVICE_ID_CMD_648 0x0648 +#define PCI_DEVICE_ID_CMD_649 0x0649 + +#define PCI_DEVICE_ID_SII_680 0x0680 +#define PCI_DEVICE_ID_SII_3112 0x3112 +#define PCI_DEVICE_ID_SII_1210SA 0x0240 + +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#define PCI_DEVICE_ID_BROOKTREE_878 0x0878 +#define PCI_DEVICE_ID_BROOKTREE_879 0x0879 + +#define PCI_VENDOR_ID_SGI 0x10a9 +#define PCI_DEVICE_ID_SGI_IOC3 0x0003 +#define PCI_DEVICE_ID_SGI_LITHIUM 0x1002 +#define PCI_DEVICE_ID_SGI_IOC4 0x100a + +#define PCI_VENDOR_ID_WINBOND 0x10ad +#define PCI_DEVICE_ID_WINBOND_82C105 0x0105 +#define PCI_DEVICE_ID_WINBOND_83C553 0x0565 + +#define PCI_VENDOR_ID_PLX 0x10b5 +#define PCI_DEVICE_ID_PLX_R685 0x1030 +#define PCI_DEVICE_ID_PLX_ROMULUS 0x106a +#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076 +#define PCI_DEVICE_ID_PLX_1077 0x1077 +#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103 +#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 +#define PCI_DEVICE_ID_PLX_R753 0x1152 +#define PCI_DEVICE_ID_PLX_OLITEC 0x1187 +#define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196 +#define PCI_DEVICE_ID_PLX_9030 0x9030 +#define PCI_DEVICE_ID_PLX_9050 0x9050 +#define PCI_DEVICE_ID_PLX_9056 0x9056 +#define PCI_DEVICE_ID_PLX_9080 0x9080 +#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001 + +#define PCI_VENDOR_ID_MADGE 0x10b6 +#define PCI_DEVICE_ID_MADGE_MK2 0x0002 + +#define PCI_VENDOR_ID_3COM 0x10b7 +#define PCI_DEVICE_ID_3COM_3C985 0x0001 +#define PCI_DEVICE_ID_3COM_3C940 0x1700 +#define PCI_DEVICE_ID_3COM_3C339 0x3390 +#define PCI_DEVICE_ID_3COM_3C359 0x3590 +#define PCI_DEVICE_ID_3COM_3C940B 0x80eb +#define PCI_DEVICE_ID_3COM_3CR990 0x9900 +#define PCI_DEVICE_ID_3COM_3CR990_TX_95 0x9902 +#define PCI_DEVICE_ID_3COM_3CR990_TX_97 0x9903 +#define PCI_DEVICE_ID_3COM_3CR990B 0x9904 +#define PCI_DEVICE_ID_3COM_3CR990_FX 0x9905 +#define PCI_DEVICE_ID_3COM_3CR990SVR95 0x9908 +#define PCI_DEVICE_ID_3COM_3CR990SVR97 0x9909 +#define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a + +#define PCI_VENDOR_ID_AL 0x10b9 +#define PCI_DEVICE_ID_AL_M1533 0x1533 +#define PCI_DEVICE_ID_AL_M1535 0x1535 +#define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1563 0x1563 +#define PCI_DEVICE_ID_AL_M1621 0x1621 +#define PCI_DEVICE_ID_AL_M1631 0x1631 +#define PCI_DEVICE_ID_AL_M1632 0x1632 +#define PCI_DEVICE_ID_AL_M1641 0x1641 +#define PCI_DEVICE_ID_AL_M1644 0x1644 +#define PCI_DEVICE_ID_AL_M1647 0x1647 +#define PCI_DEVICE_ID_AL_M1651 0x1651 +#define PCI_DEVICE_ID_AL_M1671 0x1671 +#define PCI_DEVICE_ID_AL_M1681 0x1681 +#define PCI_DEVICE_ID_AL_M1683 0x1683 +#define PCI_DEVICE_ID_AL_M1689 0x1689 +#define PCI_DEVICE_ID_AL_M5219 0x5219 +#define PCI_DEVICE_ID_AL_M5228 0x5228 +#define PCI_DEVICE_ID_AL_M5229 0x5229 +#define PCI_DEVICE_ID_AL_M5451 0x5451 +#define PCI_DEVICE_ID_AL_M7101 0x7101 + +#define PCI_VENDOR_ID_NEOMAGIC 0x10c8 +#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 +#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 +#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016 + +#define PCI_VENDOR_ID_TCONRAD 0x10da +#define PCI_DEVICE_ID_TCONRAD_TOKENRING 0x0508 + +#define PCI_VENDOR_ID_NVIDIA 0x10de +#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020 +#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028 +#define PCI_DEVICE_ID_NVIDIA_UTNT2 0x0029 +#define PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN 0x002a +#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C +#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800 0x0041 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE 0x0042 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x0045 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000 0x004E +#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 +#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 +#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d +#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 +#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069 +#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 +#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089 +#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT 0x0090 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX 0x0091 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800 0x0098 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX 0x0099 +#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 +#define PCI_DEVICE_ID_GEFORCE_6800A 0x00c1 +#define PCI_DEVICE_ID_GEFORCE_6800A_LE 0x00c2 +#define PCI_DEVICE_ID_GEFORCE_GO_6800 0x00c8 +#define PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA 0x00c9 +#define PCI_DEVICE_ID_QUADRO_FX_GO1400 0x00cc +#define PCI_DEVICE_ID_QUADRO_FX_1400 0x00ce +#define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 +#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9 +#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 +#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1 0x00f1 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3 +#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x00f9 +#define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280 0x00fd +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 +#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112 +#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT 0x0140 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600 0x0141 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL 0x0145 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540 0x014E +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200 0x014F +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152 +#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE 0x0161 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200 0x0164 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250 0x0166 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1 0x0167 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1 0x0168 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460 0x0170 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440 0x0171 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420 0x0172 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE 0x0173 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO 0x0174 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO 0x0175 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO 0x0177 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL 0x0178 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_200 0x017A +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16 0x017D +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X 0x0181 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X 0x0182 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X 0x0183 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000 0x0185 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO 0x0186 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO 0x0187 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL 0x0188 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC 0x0189 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS 0x018A +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL 0x018B +#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 +#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 +#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc +#define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B 0x0211 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE 0x0212 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT 0x0215 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600 0x0250 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400 0x0251 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200 0x0253 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO 0x0286 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL 0x0288 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL 0x0289 +#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL 0x028C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA 0x0301 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800 0x0302 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000 0x0308 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000 0x0309 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA 0x0311 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600 0x0312 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE 0x0314 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600 0x031A +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650 0x031B +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700 0x031C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200 0x0320 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA 0x0321 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1 0x0322 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE 0x0323 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200 0x0324 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250 0x0325 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500 0x0326 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100 0x0327 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32 0x0328 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200 0x0329 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI 0x032A +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500 0x032B +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300 0x032C +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100 0x032D +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA 0x0330 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900 0x0331 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT 0x0332 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA 0x0333 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT 0x0334 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000 0x0338 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700 0x033F +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA 0x0341 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700 0x0342 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE 0x0343 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE 0x0344 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1 0x0347 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C +#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E +#define PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V0 0x0360 +#define PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V4 0x0364 +#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS 0x0542 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE 0x056C +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS 0x0752 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE 0x0759 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS 0x07D8 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS 0x0AA2 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA 0x0D85 + +#define PCI_VENDOR_ID_IMS 0x10e0 +#define PCI_DEVICE_ID_IMS_TT128 0x9128 +#define PCI_DEVICE_ID_IMS_TT3D 0x9135 + +#define PCI_VENDOR_ID_INTERG 0x10ea +#define PCI_DEVICE_ID_INTERG_1682 0x1682 +#define PCI_DEVICE_ID_INTERG_2000 0x2000 +#define PCI_DEVICE_ID_INTERG_2010 0x2010 +#define PCI_DEVICE_ID_INTERG_5000 0x5000 +#define PCI_DEVICE_ID_INTERG_5050 0x5050 + +#define PCI_VENDOR_ID_REALTEK 0x10ec +#define PCI_DEVICE_ID_REALTEK_8139 0x8139 + +#define PCI_VENDOR_ID_XILINX 0x10ee +#define PCI_DEVICE_ID_RME_DIGI96 0x3fc0 +#define PCI_DEVICE_ID_RME_DIGI96_8 0x3fc1 +#define PCI_DEVICE_ID_RME_DIGI96_8_PRO 0x3fc2 +#define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3 +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 + +#define PCI_VENDOR_ID_INIT 0x1101 + +#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */ +#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 +#define PCI_DEVICE_ID_CREATIVE_20K1 0x0005 +#define PCI_DEVICE_ID_CREATIVE_20K2 0x000b +#define PCI_SUBDEVICE_ID_CREATIVE_SB0760 0x0024 +#define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 +#define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 +#define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 +#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062 +#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 + +#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ +#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 + +#define PCI_VENDOR_ID_TTI 0x1103 +#define PCI_DEVICE_ID_TTI_HPT343 0x0003 +#define PCI_DEVICE_ID_TTI_HPT366 0x0004 +#define PCI_DEVICE_ID_TTI_HPT372 0x0005 +#define PCI_DEVICE_ID_TTI_HPT302 0x0006 +#define PCI_DEVICE_ID_TTI_HPT371 0x0007 +#define PCI_DEVICE_ID_TTI_HPT374 0x0008 +#define PCI_DEVICE_ID_TTI_HPT372N 0x0009 /* apparently a 372N variant? */ + +#define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_DEVICE_ID_VIA_8763_0 0x0198 +#define PCI_DEVICE_ID_VIA_8380_0 0x0204 +#define PCI_DEVICE_ID_VIA_3238_0 0x0238 +#define PCI_DEVICE_ID_VIA_PT880 0x0258 +#define PCI_DEVICE_ID_VIA_PT880ULTRA 0x0308 +#define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259 +#define PCI_DEVICE_ID_VIA_3269_0 0x0269 +#define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282 +#define PCI_DEVICE_ID_VIA_3296_0 0x0296 +#define PCI_DEVICE_ID_VIA_8363_0 0x0305 +#define PCI_DEVICE_ID_VIA_P4M800CE 0x0314 +#define PCI_DEVICE_ID_VIA_P4M890 0x0327 +#define PCI_DEVICE_ID_VIA_VT3324 0x0324 +#define PCI_DEVICE_ID_VIA_VT3336 0x0336 +#define PCI_DEVICE_ID_VIA_VT3351 0x0351 +#define PCI_DEVICE_ID_VIA_VT3364 0x0364 +#define PCI_DEVICE_ID_VIA_8371_0 0x0391 +#define PCI_DEVICE_ID_VIA_6415 0x0415 +#define PCI_DEVICE_ID_VIA_8501_0 0x0501 +#define PCI_DEVICE_ID_VIA_82C561 0x0561 +#define PCI_DEVICE_ID_VIA_82C586_1 0x0571 +#define PCI_DEVICE_ID_VIA_82C576 0x0576 +#define PCI_DEVICE_ID_VIA_82C586_0 0x0586 +#define PCI_DEVICE_ID_VIA_82C596 0x0596 +#define PCI_DEVICE_ID_VIA_82C597_0 0x0597 +#define PCI_DEVICE_ID_VIA_82C598_0 0x0598 +#define PCI_DEVICE_ID_VIA_8601_0 0x0601 +#define PCI_DEVICE_ID_VIA_8605_0 0x0605 +#define PCI_DEVICE_ID_VIA_82C686 0x0686 +#define PCI_DEVICE_ID_VIA_82C691_0 0x0691 +#define PCI_DEVICE_ID_VIA_82C576_1 0x1571 +#define PCI_DEVICE_ID_VIA_82C586_2 0x3038 +#define PCI_DEVICE_ID_VIA_82C586_3 0x3040 +#define PCI_DEVICE_ID_VIA_82C596_3 0x3050 +#define PCI_DEVICE_ID_VIA_82C596B_3 0x3051 +#define PCI_DEVICE_ID_VIA_82C686_4 0x3057 +#define PCI_DEVICE_ID_VIA_82C686_5 0x3058 +#define PCI_DEVICE_ID_VIA_8233_5 0x3059 +#define PCI_DEVICE_ID_VIA_8233_0 0x3074 +#define PCI_DEVICE_ID_VIA_8633_0 0x3091 +#define PCI_DEVICE_ID_VIA_8367_0 0x3099 +#define PCI_DEVICE_ID_VIA_8653_0 0x3101 +#define PCI_DEVICE_ID_VIA_8622 0x3102 +#define PCI_DEVICE_ID_VIA_8235_USB_2 0x3104 +#define PCI_DEVICE_ID_VIA_8233C_0 0x3109 +#define PCI_DEVICE_ID_VIA_8361 0x3112 +#define PCI_DEVICE_ID_VIA_XM266 0x3116 +#define PCI_DEVICE_ID_VIA_612X 0x3119 +#define PCI_DEVICE_ID_VIA_862X_0 0x3123 +#define PCI_DEVICE_ID_VIA_8753_0 0x3128 +#define PCI_DEVICE_ID_VIA_8233A 0x3147 +#define PCI_DEVICE_ID_VIA_8703_51_0 0x3148 +#define PCI_DEVICE_ID_VIA_8237_SATA 0x3149 +#define PCI_DEVICE_ID_VIA_XN266 0x3156 +#define PCI_DEVICE_ID_VIA_6410 0x3164 +#define PCI_DEVICE_ID_VIA_8754C_0 0x3168 +#define PCI_DEVICE_ID_VIA_8235 0x3177 +#define PCI_DEVICE_ID_VIA_8385_0 0x3188 +#define PCI_DEVICE_ID_VIA_8377_0 0x3189 +#define PCI_DEVICE_ID_VIA_8378_0 0x3205 +#define PCI_DEVICE_ID_VIA_8783_0 0x3208 +#define PCI_DEVICE_ID_VIA_8237 0x3227 +#define PCI_DEVICE_ID_VIA_8251 0x3287 +#define PCI_DEVICE_ID_VIA_8261 0x3402 +#define PCI_DEVICE_ID_VIA_8237A 0x3337 +#define PCI_DEVICE_ID_VIA_8237S 0x3372 +#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x5324 +#define PCI_DEVICE_ID_VIA_8231 0x8231 +#define PCI_DEVICE_ID_VIA_8231_4 0x8235 +#define PCI_DEVICE_ID_VIA_8365_1 0x8305 +#define PCI_DEVICE_ID_VIA_CX700 0x8324 +#define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581 +#define PCI_DEVICE_ID_VIA_VX800 0x8353 +#define PCI_DEVICE_ID_VIA_VX855 0x8409 +#define PCI_DEVICE_ID_VIA_8371_1 0x8391 +#define PCI_DEVICE_ID_VIA_82C598_1 0x8598 +#define PCI_DEVICE_ID_VIA_838X_1 0xB188 +#define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198 +#define PCI_DEVICE_ID_VIA_VX855_IDE 0xC409 +#define PCI_DEVICE_ID_VIA_ANON 0xFFFF + +#define PCI_VENDOR_ID_SIEMENS 0x110A +#define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 + +#define PCI_VENDOR_ID_VORTEX 0x1119 +#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000 +#define PCI_DEVICE_ID_VORTEX_GDT6000B 0x0001 +#define PCI_DEVICE_ID_VORTEX_GDT6x10 0x0002 +#define PCI_DEVICE_ID_VORTEX_GDT6x20 0x0003 +#define PCI_DEVICE_ID_VORTEX_GDT6530 0x0004 +#define PCI_DEVICE_ID_VORTEX_GDT6550 0x0005 +#define PCI_DEVICE_ID_VORTEX_GDT6x17 0x0006 +#define PCI_DEVICE_ID_VORTEX_GDT6x27 0x0007 +#define PCI_DEVICE_ID_VORTEX_GDT6537 0x0008 +#define PCI_DEVICE_ID_VORTEX_GDT6557 0x0009 +#define PCI_DEVICE_ID_VORTEX_GDT6x15 0x000a +#define PCI_DEVICE_ID_VORTEX_GDT6x25 0x000b +#define PCI_DEVICE_ID_VORTEX_GDT6535 0x000c +#define PCI_DEVICE_ID_VORTEX_GDT6555 0x000d +#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x0100 +#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x0101 +#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x0102 +#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x0103 +#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x0104 +#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x0105 + +#define PCI_VENDOR_ID_EF 0x111a +#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000 +#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002 +#define PCI_DEVICE_ID_EF_ATM_LANAI2 0x0003 +#define PCI_DEVICE_ID_EF_ATM_LANAIHB 0x0005 + +#define PCI_VENDOR_ID_IDT 0x111d +#define PCI_DEVICE_ID_IDT_IDT77201 0x0001 + +#define PCI_VENDOR_ID_FORE 0x1127 +#define PCI_DEVICE_ID_FORE_PCA200E 0x0300 + +#define PCI_VENDOR_ID_PHILIPS 0x1131 +#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146 +#define PCI_DEVICE_ID_PHILIPS_SAA9730 0x9730 + +#define PCI_VENDOR_ID_EICON 0x1133 +#define PCI_DEVICE_ID_EICON_DIVA20 0xe002 +#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 +#define PCI_DEVICE_ID_EICON_DIVA201 0xe005 +#define PCI_DEVICE_ID_EICON_DIVA202 0xe00b +#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010 +#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012 +#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013 +#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014 + +#define PCI_VENDOR_ID_CISCO 0x1137 + +#define PCI_VENDOR_ID_ZIATECH 0x1138 +#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550 + + +#define PCI_VENDOR_ID_SYSKONNECT 0x1148 +#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200 +#define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300 +#define PCI_DEVICE_ID_SYSKONNECT_YU 0x4320 +#define PCI_DEVICE_ID_SYSKONNECT_9DXX 0x4400 +#define PCI_DEVICE_ID_SYSKONNECT_9MXX 0x4500 + +#define PCI_VENDOR_ID_DIGI 0x114f +#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070 +#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071 +#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072 +#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073 +#define PCI_DEVICE_ID_DIGI_NEO_8 0x00B1 +#define PCI_DEVICE_ID_NEO_2DB9 0x00C8 +#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9 +#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA +#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB +#define PCIE_DEVICE_ID_NEO_4_IBM 0x00F4 + +#define PCI_VENDOR_ID_XIRCOM 0x115d +#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101 +#define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103 + +#define PCI_VENDOR_ID_SERVERWORKS 0x1166 +#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008 +#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 +#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017 +#define PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB 0x0036 +#define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103 +#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 +#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203 +#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211 +#define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213 +#define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227 +#define PCI_DEVICE_ID_SERVERWORKS_HT1100LD 0x0408 + +#define PCI_VENDOR_ID_SBE 0x1176 +#define PCI_DEVICE_ID_SBE_WANXL100 0x0301 +#define PCI_DEVICE_ID_SBE_WANXL200 0x0302 +#define PCI_DEVICE_ID_SBE_WANXL400 0x0104 +#define PCI_SUBDEVICE_ID_SBE_T3E3 0x0009 +#define PCI_SUBDEVICE_ID_SBE_2T3E3_P0 0x0901 +#define PCI_SUBDEVICE_ID_SBE_2T3E3_P1 0x0902 + +#define PCI_VENDOR_ID_TOSHIBA 0x1179 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0101 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0102 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_3 0x0103 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_5 0x0105 +#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a +#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f +#define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617 + +#define PCI_VENDOR_ID_TOSHIBA_2 0x102f +#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030 +#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031 +#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032 +#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105 +#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108 +#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3 + +#define PCI_VENDOR_ID_ATTO 0x117c + +#define PCI_VENDOR_ID_RICOH 0x1180 +#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465 +#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466 +#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475 +#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 +#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 +#define PCI_DEVICE_ID_RICOH_R5C822 0x0822 +#define PCI_DEVICE_ID_RICOH_R5CE823 0xe823 +#define PCI_DEVICE_ID_RICOH_R5C832 0x0832 +#define PCI_DEVICE_ID_RICOH_R5C843 0x0843 + +#define PCI_VENDOR_ID_DLINK 0x1186 +#define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00 + +#define PCI_VENDOR_ID_ARTOP 0x1191 +#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005 +#define PCI_DEVICE_ID_ARTOP_ATP860 0x0006 +#define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007 +#define PCI_DEVICE_ID_ARTOP_ATP865 0x0008 +#define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009 +#define PCI_DEVICE_ID_ARTOP_ATP867A 0x000A +#define PCI_DEVICE_ID_ARTOP_ATP867B 0x000B +#define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002 +#define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010 +#define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020 +#define PCI_DEVICE_ID_ARTOP_AEC7612S 0x8030 +#define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040 +#define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050 +#define PCI_DEVICE_ID_ARTOP_8060 0x8060 + +#define PCI_VENDOR_ID_ZEITNET 0x1193 +#define PCI_DEVICE_ID_ZEITNET_1221 0x0001 +#define PCI_DEVICE_ID_ZEITNET_1225 0x0002 + +#define PCI_VENDOR_ID_FUJITSU_ME 0x119e +#define PCI_DEVICE_ID_FUJITSU_FS155 0x0001 +#define PCI_DEVICE_ID_FUJITSU_FS50 0x0003 + +#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9 +#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334 + +#define PCI_VENDOR_ID_MARVELL 0x11ab +#define PCI_DEVICE_ID_MARVELL_GT64111 0x4146 +#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 +#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 +#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480 +#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND 0x4100 +#define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101 +#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102 + +#define PCI_VENDOR_ID_V3 0x11b0 +#define PCI_DEVICE_ID_V3_V960 0x0001 +#define PCI_DEVICE_ID_V3_V351 0x0002 + +#define PCI_VENDOR_ID_ATT 0x11c1 +#define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480 + +#define PCI_VENDOR_ID_SPECIALIX 0x11cb +#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000 +#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 +#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004 + +#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4 +#define PCI_DEVICE_ID_AD1889JS 0x1889 + +#define PCI_DEVICE_ID_SEGA_BBA 0x1234 + +#define PCI_VENDOR_ID_ZORAN 0x11de +#define PCI_DEVICE_ID_ZORAN_36057 0x6057 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 + +#define PCI_VENDOR_ID_COMPEX 0x11f6 +#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 + +#define PCI_VENDOR_ID_PMC_Sierra 0x11f8 + +#define PCI_VENDOR_ID_RP 0x11fe +#define PCI_DEVICE_ID_RP32INTF 0x0001 +#define PCI_DEVICE_ID_RP8INTF 0x0002 +#define PCI_DEVICE_ID_RP16INTF 0x0003 +#define PCI_DEVICE_ID_RP4QUAD 0x0004 +#define PCI_DEVICE_ID_RP8OCTA 0x0005 +#define PCI_DEVICE_ID_RP8J 0x0006 +#define PCI_DEVICE_ID_RP4J 0x0007 +#define PCI_DEVICE_ID_RP8SNI 0x0008 +#define PCI_DEVICE_ID_RP16SNI 0x0009 +#define PCI_DEVICE_ID_RPP4 0x000A +#define PCI_DEVICE_ID_RPP8 0x000B +#define PCI_DEVICE_ID_RP4M 0x000D +#define PCI_DEVICE_ID_RP2_232 0x000E +#define PCI_DEVICE_ID_RP2_422 0x000F +#define PCI_DEVICE_ID_URP32INTF 0x0801 +#define PCI_DEVICE_ID_URP8INTF 0x0802 +#define PCI_DEVICE_ID_URP16INTF 0x0803 +#define PCI_DEVICE_ID_URP8OCTA 0x0805 +#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C +#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D +#define PCI_DEVICE_ID_CRP16INTF 0x0903 + +#define PCI_VENDOR_ID_CYCLADES 0x120e +#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100 +#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101 +#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102 +#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103 +#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104 +#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105 +#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 +#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 +#define PCI_DEVICE_ID_PC300_RX_2 0x0300 +#define PCI_DEVICE_ID_PC300_RX_1 0x0301 +#define PCI_DEVICE_ID_PC300_TE_2 0x0310 +#define PCI_DEVICE_ID_PC300_TE_1 0x0311 +#define PCI_DEVICE_ID_PC300_TE_M_2 0x0320 +#define PCI_DEVICE_ID_PC300_TE_M_1 0x0321 + +#define PCI_VENDOR_ID_ESSENTIAL 0x120f +#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001 + +#define PCI_VENDOR_ID_O2 0x1217 +#define PCI_DEVICE_ID_O2_6729 0x6729 +#define PCI_DEVICE_ID_O2_6730 0x673a +#define PCI_DEVICE_ID_O2_6832 0x6832 +#define PCI_DEVICE_ID_O2_6836 0x6836 +#define PCI_DEVICE_ID_O2_6812 0x6872 +#define PCI_DEVICE_ID_O2_6933 0x6933 +#define PCI_DEVICE_ID_O2_8120 0x8120 +#define PCI_DEVICE_ID_O2_8220 0x8220 +#define PCI_DEVICE_ID_O2_8221 0x8221 +#define PCI_DEVICE_ID_O2_8320 0x8320 +#define PCI_DEVICE_ID_O2_8321 0x8321 + +#define PCI_VENDOR_ID_3DFX 0x121a +#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 +#define PCI_DEVICE_ID_3DFX_VOODOO2 0x0002 +#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003 +#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005 +#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009 + +#define PCI_VENDOR_ID_AVM 0x1244 +#define PCI_DEVICE_ID_AVM_B1 0x0700 +#define PCI_DEVICE_ID_AVM_C4 0x0800 +#define PCI_DEVICE_ID_AVM_A1 0x0a00 +#define PCI_DEVICE_ID_AVM_A1_V2 0x0e00 +#define PCI_DEVICE_ID_AVM_C2 0x1100 +#define PCI_DEVICE_ID_AVM_T1 0x1200 + +#define PCI_VENDOR_ID_STALLION 0x124d + +/* Allied Telesyn */ +#define PCI_VENDOR_ID_AT 0x1259 +#define PCI_SUBDEVICE_ID_AT_2700FX 0x2701 +#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703 + +#define PCI_VENDOR_ID_ESS 0x125d +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 +#define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988 +#define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989 +#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990 +#define PCI_DEVICE_ID_ESS_CANYON3D_2 0x1992 +#define PCI_DEVICE_ID_ESS_MAESTRO3 0x1998 +#define PCI_DEVICE_ID_ESS_MAESTRO3_1 0x1999 +#define PCI_DEVICE_ID_ESS_MAESTRO3_HW 0x199a +#define PCI_DEVICE_ID_ESS_MAESTRO3_2 0x199b + +#define PCI_VENDOR_ID_SATSAGEM 0x1267 +#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 + +#define PCI_VENDOR_ID_ENSONIQ 0x1274 +#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 +#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 +#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 + +#define PCI_VENDOR_ID_TRANSMETA 0x1279 +#define PCI_DEVICE_ID_EFFICEON 0x0060 + +#define PCI_VENDOR_ID_ROCKWELL 0x127A + +#define PCI_VENDOR_ID_ITE 0x1283 +#define PCI_DEVICE_ID_ITE_8172 0x8172 +#define PCI_DEVICE_ID_ITE_8211 0x8211 +#define PCI_DEVICE_ID_ITE_8212 0x8212 +#define PCI_DEVICE_ID_ITE_8213 0x8213 +#define PCI_DEVICE_ID_ITE_8152 0x8152 +#define PCI_DEVICE_ID_ITE_8872 0x8872 +#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 + +/* formerly Platform Tech */ +#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 + +#define PCI_VENDOR_ID_ALTEON 0x12ae + +#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232 0x0002 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232 0x0003 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485 0x0004 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4 0x0005 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485 0x0006 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2 0x0007 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485 0x0008 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6 0x0009 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ 0x000C +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_PTM 0x000D +#define PCI_SUBDEVICE_ID_CONNECT_TECH_NT960PCI 0x0100 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2 0x0201 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4 0x0202 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232 0x0300 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232 0x0301 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232 0x0302 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1 0x0310 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2 0x0311 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4 0x0312 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2 0x0320 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4 0x0321 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8 0x0322 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485 0x0330 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485 0x0331 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485 0x0332 + +#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2 +#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018 + +#define PCI_SUBVENDOR_ID_CHASE_PCIFAST 0x12E0 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4 0x0031 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8 0x0021 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16 0x0011 +#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC 0x0041 +#define PCI_SUBVENDOR_ID_CHASE_PCIRAS 0x124D +#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4 0xF001 +#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8 0xF010 + +#define PCI_VENDOR_ID_AUREAL 0x12eb +#define PCI_DEVICE_ID_AUREAL_VORTEX_1 0x0001 +#define PCI_DEVICE_ID_AUREAL_VORTEX_2 0x0002 +#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003 + +#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8 +#define PCI_DEVICE_ID_LML_33R10 0x8a02 + +#define PCI_VENDOR_ID_ESDGMBH 0x12fe +#define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111 + +#define PCI_VENDOR_ID_SIIG 0x131f +#define PCI_SUBVENDOR_ID_SIIG 0x131f +#define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000 +#define PCI_DEVICE_ID_SIIG_1S_10x_650 0x1001 +#define PCI_DEVICE_ID_SIIG_1S_10x_850 0x1002 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011 +#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012 +#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020 +#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021 +#define PCI_DEVICE_ID_SIIG_2S_10x_550 0x1030 +#define PCI_DEVICE_ID_SIIG_2S_10x_650 0x1031 +#define PCI_DEVICE_ID_SIIG_2S_10x_850 0x1032 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035 +#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036 +#define PCI_DEVICE_ID_SIIG_4S_10x_550 0x1050 +#define PCI_DEVICE_ID_SIIG_4S_10x_650 0x1051 +#define PCI_DEVICE_ID_SIIG_4S_10x_850 0x1052 +#define PCI_DEVICE_ID_SIIG_1S_20x_550 0x2000 +#define PCI_DEVICE_ID_SIIG_1S_20x_650 0x2001 +#define PCI_DEVICE_ID_SIIG_1S_20x_850 0x2002 +#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020 +#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021 +#define PCI_DEVICE_ID_SIIG_2S_20x_550 0x2030 +#define PCI_DEVICE_ID_SIIG_2S_20x_650 0x2031 +#define PCI_DEVICE_ID_SIIG_2S_20x_850 0x2032 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041 +#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011 +#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012 +#define PCI_DEVICE_ID_SIIG_4S_20x_550 0x2050 +#define PCI_DEVICE_ID_SIIG_4S_20x_650 0x2051 +#define PCI_DEVICE_ID_SIIG_4S_20x_850 0x2052 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061 +#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 +#define PCI_DEVICE_ID_SIIG_8S_20x_550 0x2080 +#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081 +#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082 +#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 +#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL 0x2530 + +#define PCI_VENDOR_ID_RADISYS 0x1331 + +#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 +#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415 +#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425 +#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155 + +#define PCI_VENDOR_ID_DOMEX 0x134a +#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001 + +#define PCI_VENDOR_ID_INTASHIELD 0x135a +#define PCI_DEVICE_ID_INTASHIELD_IS200 0x0d80 +#define PCI_DEVICE_ID_INTASHIELD_IS400 0x0dc0 + +#define PCI_VENDOR_ID_QUATECH 0x135C +#define PCI_DEVICE_ID_QUATECH_QSC100 0x0010 +#define PCI_DEVICE_ID_QUATECH_DSC100 0x0020 +#define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050 +#define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060 +#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278 + +#define PCI_VENDOR_ID_SEALEVEL 0x135e +#define PCI_DEVICE_ID_SEALEVEL_U530 0x7101 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM2 0x7201 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM422 0x7402 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202 +#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401 +#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801 +#define PCI_DEVICE_ID_SEALEVEL_7803 0x7803 +#define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804 + +#define PCI_VENDOR_ID_HYPERCOPE 0x1365 +#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050 +#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104 +#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106 +#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107 +#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108 + +#define PCI_VENDOR_ID_DIGIGRAM 0x1369 +#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM 0xc001 +#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM 0xc002 + +#define PCI_VENDOR_ID_KAWASAKI 0x136b +#define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01 + +#define PCI_VENDOR_ID_CNET 0x1371 +#define PCI_DEVICE_ID_CNET_GIGACARD 0x434e + +#define PCI_VENDOR_ID_LMC 0x1376 +#define PCI_DEVICE_ID_LMC_HSSI 0x0003 +#define PCI_DEVICE_ID_LMC_DS3 0x0004 +#define PCI_DEVICE_ID_LMC_SSI 0x0005 +#define PCI_DEVICE_ID_LMC_T1 0x0006 + +#define PCI_VENDOR_ID_NETGEAR 0x1385 +#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a + +#define PCI_VENDOR_ID_APPLICOM 0x1389 +#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 +#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 +#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 + +#define PCI_VENDOR_ID_MOXA 0x1393 +#define PCI_DEVICE_ID_MOXA_RC7000 0x0001 +#define PCI_DEVICE_ID_MOXA_CP102 0x1020 +#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021 +#define PCI_DEVICE_ID_MOXA_CP102U 0x1022 +#define PCI_DEVICE_ID_MOXA_C104 0x1040 +#define PCI_DEVICE_ID_MOXA_CP104U 0x1041 +#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042 +#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043 +#define PCI_DEVICE_ID_MOXA_CT114 0x1140 +#define PCI_DEVICE_ID_MOXA_CP114 0x1141 +#define PCI_DEVICE_ID_MOXA_CP118U 0x1180 +#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181 +#define PCI_DEVICE_ID_MOXA_CP132 0x1320 +#define PCI_DEVICE_ID_MOXA_CP132U 0x1321 +#define PCI_DEVICE_ID_MOXA_CP134U 0x1340 +#define PCI_DEVICE_ID_MOXA_C168 0x1680 +#define PCI_DEVICE_ID_MOXA_CP168U 0x1681 +#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 +#define PCI_DEVICE_ID_MOXA_CP204J 0x2040 +#define PCI_DEVICE_ID_MOXA_C218 0x2180 +#define PCI_DEVICE_ID_MOXA_C320 0x3200 + +#define PCI_VENDOR_ID_CCD 0x1397 +#define PCI_DEVICE_ID_CCD_HFC4S 0x08B4 +#define PCI_SUBDEVICE_ID_CCD_PMX2S 0x1234 +#define PCI_DEVICE_ID_CCD_HFC8S 0x16B8 +#define PCI_DEVICE_ID_CCD_2BD0 0x2bd0 +#define PCI_DEVICE_ID_CCD_HFCE1 0x30B1 +#define PCI_SUBDEVICE_ID_CCD_SPD4S 0x3136 +#define PCI_SUBDEVICE_ID_CCD_SPDE1 0x3137 +#define PCI_DEVICE_ID_CCD_B000 0xb000 +#define PCI_DEVICE_ID_CCD_B006 0xb006 +#define PCI_DEVICE_ID_CCD_B007 0xb007 +#define PCI_DEVICE_ID_CCD_B008 0xb008 +#define PCI_DEVICE_ID_CCD_B009 0xb009 +#define PCI_DEVICE_ID_CCD_B00A 0xb00a +#define PCI_DEVICE_ID_CCD_B00B 0xb00b +#define PCI_DEVICE_ID_CCD_B00C 0xb00c +#define PCI_DEVICE_ID_CCD_B100 0xb100 +#define PCI_SUBDEVICE_ID_CCD_IOB4ST 0xB520 +#define PCI_SUBDEVICE_ID_CCD_IOB8STR 0xB521 +#define PCI_SUBDEVICE_ID_CCD_IOB8ST 0xB522 +#define PCI_SUBDEVICE_ID_CCD_IOB1E1 0xB523 +#define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540 +#define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550 +#define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552 +#define PCI_SUBDEVICE_ID_CCD_JHSE1 0xB553 +#define PCI_SUBDEVICE_ID_CCD_JH8S 0xB55B +#define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560 +#define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562 +#define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563 +#define PCI_SUBDEVICE_ID_CCD_BNE1D 0xB564 +#define PCI_SUBDEVICE_ID_CCD_BNE1DP 0xB565 +#define PCI_SUBDEVICE_ID_CCD_BN2S 0xB566 +#define PCI_SUBDEVICE_ID_CCD_BN1SM 0xB567 +#define PCI_SUBDEVICE_ID_CCD_BN4SM 0xB568 +#define PCI_SUBDEVICE_ID_CCD_BN2SM 0xB569 +#define PCI_SUBDEVICE_ID_CCD_BNE1M 0xB56A +#define PCI_SUBDEVICE_ID_CCD_BN8SP 0xB56B +#define PCI_SUBDEVICE_ID_CCD_HFC4S 0xB620 +#define PCI_SUBDEVICE_ID_CCD_HFC8S 0xB622 +#define PCI_DEVICE_ID_CCD_B700 0xb700 +#define PCI_DEVICE_ID_CCD_B701 0xb701 +#define PCI_SUBDEVICE_ID_CCD_HFCE1 0xC523 +#define PCI_SUBDEVICE_ID_CCD_OV2S 0xE884 +#define PCI_SUBDEVICE_ID_CCD_OV4S 0xE888 +#define PCI_SUBDEVICE_ID_CCD_OV8S 0xE998 + +#define PCI_VENDOR_ID_EXAR 0x13a8 +#define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 +#define PCI_DEVICE_ID_EXAR_XR17C154 0x0154 +#define PCI_DEVICE_ID_EXAR_XR17C158 0x0158 + +#define PCI_VENDOR_ID_MICROGATE 0x13c0 +#define PCI_DEVICE_ID_MICROGATE_USC 0x0010 +#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030 + +#define PCI_VENDOR_ID_3WARE 0x13C1 +#define PCI_DEVICE_ID_3WARE_1000 0x1000 +#define PCI_DEVICE_ID_3WARE_7000 0x1001 +#define PCI_DEVICE_ID_3WARE_9000 0x1002 + +#define PCI_VENDOR_ID_IOMEGA 0x13ca +#define PCI_DEVICE_ID_IOMEGA_BUZ 0x4231 + +#define PCI_VENDOR_ID_ABOCOM 0x13D1 +#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1 + +#define PCI_VENDOR_ID_SUNDANCE 0x13f0 + +#define PCI_VENDOR_ID_CMEDIA 0x13f6 +#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100 +#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101 +#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 +#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112 + +#define PCI_VENDOR_ID_LAVA 0x1407 +#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */ +#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_QUATRO_B 0x0102 /* 2x 16550, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_QUATTRO_A 0x0120 /* 2x 16550A, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_QUATTRO_B 0x0121 /* 2x 16550A, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_OCTO_A 0x0180 /* 4x 16550A, half of 8 port */ +#define PCI_DEVICE_ID_LAVA_OCTO_B 0x0181 /* 4x 16550A, half of 8 port */ +#define PCI_DEVICE_ID_LAVA_PORT_PLUS 0x0200 /* 2x 16650 */ +#define PCI_DEVICE_ID_LAVA_QUAD_A 0x0201 /* 2x 16650, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_QUAD_B 0x0202 /* 2x 16650, half of 4 port */ +#define PCI_DEVICE_ID_LAVA_SSERIAL 0x0500 /* 1x 16550 */ +#define PCI_DEVICE_ID_LAVA_PORT_650 0x0600 /* 1x 16650 */ +#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 +#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */ +#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */ +#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR 0x8800 + +#define PCI_VENDOR_ID_TIMEDIA 0x1409 +#define PCI_DEVICE_ID_TIMEDIA_1889 0x7168 + +#define PCI_VENDOR_ID_ICE 0x1412 +#define PCI_DEVICE_ID_ICE_1712 0x1712 +#define PCI_DEVICE_ID_VT1724 0x1724 + +#define PCI_VENDOR_ID_OXSEMI 0x1415 +#define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403 +#define PCI_DEVICE_ID_OXSEMI_PCIe840 0xC000 +#define PCI_DEVICE_ID_OXSEMI_PCIe840_G 0xC004 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_0 0xC100 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_0_G 0xC104 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1 0xC110 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_G 0xC114 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U 0xC118 +#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU 0xC11C +#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501 +#define PCI_DEVICE_ID_OXSEMI_C950 0x950B +#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511 +#define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513 +#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521 +#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523 +#define PCI_SUBDEVICE_ID_OXSEMI_C950 0x0001 + +#define PCI_VENDOR_ID_CHELSIO 0x1425 + +#define PCI_VENDOR_ID_SAMSUNG 0x144d + +#define PCI_VENDOR_ID_GIGABYTE 0x1458 + +#define PCI_VENDOR_ID_AMBIT 0x1468 + +#define PCI_VENDOR_ID_MYRICOM 0x14c1 + +#define PCI_VENDOR_ID_TITAN 0x14D2 +#define PCI_DEVICE_ID_TITAN_010L 0x8001 +#define PCI_DEVICE_ID_TITAN_100L 0x8010 +#define PCI_DEVICE_ID_TITAN_110L 0x8011 +#define PCI_DEVICE_ID_TITAN_200L 0x8020 +#define PCI_DEVICE_ID_TITAN_210L 0x8021 +#define PCI_DEVICE_ID_TITAN_400L 0x8040 +#define PCI_DEVICE_ID_TITAN_800L 0x8080 +#define PCI_DEVICE_ID_TITAN_100 0xA001 +#define PCI_DEVICE_ID_TITAN_200 0xA005 +#define PCI_DEVICE_ID_TITAN_400 0xA003 +#define PCI_DEVICE_ID_TITAN_800B 0xA004 + +#define PCI_VENDOR_ID_PANACOM 0x14d4 +#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400 +#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402 + +#define PCI_VENDOR_ID_SIPACKETS 0x14d9 +#define PCI_DEVICE_ID_SP1011 0x0010 + +#define PCI_VENDOR_ID_AFAVLAB 0x14db +#define PCI_DEVICE_ID_AFAVLAB_P028 0x2180 +#define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 +#define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150 + +#define PCI_VENDOR_ID_BCM_GVC 0x14a4 +#define PCI_VENDOR_ID_BROADCOM 0x14e4 +#define PCI_DEVICE_ID_TIGON3_5752 0x1600 +#define PCI_DEVICE_ID_TIGON3_5752M 0x1601 +#define PCI_DEVICE_ID_NX2_5709 0x1639 +#define PCI_DEVICE_ID_NX2_5709S 0x163a +#define PCI_DEVICE_ID_TIGON3_5700 0x1644 +#define PCI_DEVICE_ID_TIGON3_5701 0x1645 +#define PCI_DEVICE_ID_TIGON3_5702 0x1646 +#define PCI_DEVICE_ID_TIGON3_5703 0x1647 +#define PCI_DEVICE_ID_TIGON3_5704 0x1648 +#define PCI_DEVICE_ID_TIGON3_5704S_2 0x1649 +#define PCI_DEVICE_ID_NX2_5706 0x164a +#define PCI_DEVICE_ID_NX2_5708 0x164c +#define PCI_DEVICE_ID_TIGON3_5702FE 0x164d +#define PCI_DEVICE_ID_NX2_57710 0x164e +#define PCI_DEVICE_ID_NX2_57711 0x164f +#define PCI_DEVICE_ID_NX2_57711E 0x1650 +#define PCI_DEVICE_ID_TIGON3_5705 0x1653 +#define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 +#define PCI_DEVICE_ID_TIGON3_5721 0x1659 +#define PCI_DEVICE_ID_TIGON3_5722 0x165a +#define PCI_DEVICE_ID_TIGON3_5723 0x165b +#define PCI_DEVICE_ID_TIGON3_5705M 0x165d +#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e +#define PCI_DEVICE_ID_NX2_57712 0x1662 +#define PCI_DEVICE_ID_NX2_57712E 0x1663 +#define PCI_DEVICE_ID_TIGON3_5714 0x1668 +#define PCI_DEVICE_ID_TIGON3_5714S 0x1669 +#define PCI_DEVICE_ID_TIGON3_5780 0x166a +#define PCI_DEVICE_ID_TIGON3_5780S 0x166b +#define PCI_DEVICE_ID_TIGON3_5705F 0x166e +#define PCI_DEVICE_ID_TIGON3_5754M 0x1672 +#define PCI_DEVICE_ID_TIGON3_5755M 0x1673 +#define PCI_DEVICE_ID_TIGON3_5756 0x1674 +#define PCI_DEVICE_ID_TIGON3_5751 0x1677 +#define PCI_DEVICE_ID_TIGON3_5715 0x1678 +#define PCI_DEVICE_ID_TIGON3_5715S 0x1679 +#define PCI_DEVICE_ID_TIGON3_5754 0x167a +#define PCI_DEVICE_ID_TIGON3_5755 0x167b +#define PCI_DEVICE_ID_TIGON3_5751M 0x167d +#define PCI_DEVICE_ID_TIGON3_5751F 0x167e +#define PCI_DEVICE_ID_TIGON3_5787F 0x167f +#define PCI_DEVICE_ID_TIGON3_5761E 0x1680 +#define PCI_DEVICE_ID_TIGON3_5761 0x1681 +#define PCI_DEVICE_ID_TIGON3_5764 0x1684 +#define PCI_DEVICE_ID_NX2_57800 0x168a +#define PCI_DEVICE_ID_NX2_57840 0x168d +#define PCI_DEVICE_ID_NX2_57810 0x168e +#define PCI_DEVICE_ID_TIGON3_5787M 0x1693 +#define PCI_DEVICE_ID_TIGON3_5782 0x1696 +#define PCI_DEVICE_ID_TIGON3_5784 0x1698 +#define PCI_DEVICE_ID_TIGON3_5786 0x169a +#define PCI_DEVICE_ID_TIGON3_5787 0x169b +#define PCI_DEVICE_ID_TIGON3_5788 0x169c +#define PCI_DEVICE_ID_TIGON3_5789 0x169d +#define PCI_DEVICE_ID_NX2_57800_MF 0x16a5 +#define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 +#define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 +#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 +#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9 +#define PCI_DEVICE_ID_NX2_5706S 0x16aa +#define PCI_DEVICE_ID_NX2_57840_MF 0x16ab +#define PCI_DEVICE_ID_NX2_5708S 0x16ac +#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad +#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae +#define PCI_DEVICE_ID_NX2_57810_VF 0x16af +#define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6 +#define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7 +#define PCI_DEVICE_ID_TIGON3_5781 0x16dd +#define PCI_DEVICE_ID_TIGON3_5753 0x16f7 +#define PCI_DEVICE_ID_TIGON3_5753M 0x16fd +#define PCI_DEVICE_ID_TIGON3_5753F 0x16fe +#define PCI_DEVICE_ID_TIGON3_5901 0x170d +#define PCI_DEVICE_ID_BCM4401B1 0x170c +#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e +#define PCI_DEVICE_ID_TIGON3_5906 0x1712 +#define PCI_DEVICE_ID_TIGON3_5906M 0x1713 +#define PCI_DEVICE_ID_BCM4401 0x4401 +#define PCI_DEVICE_ID_BCM4401B0 0x4402 + +#define PCI_VENDOR_ID_TOPIC 0x151f +#define PCI_DEVICE_ID_TOPIC_TP560 0x0000 + +#define PCI_VENDOR_ID_MAINPINE 0x1522 +#define PCI_DEVICE_ID_MAINPINE_PBRIDGE 0x0100 +#define PCI_VENDOR_ID_ENE 0x1524 +#define PCI_DEVICE_ID_ENE_CB710_FLASH 0x0510 +#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550 +#define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551 +#define PCI_DEVICE_ID_ENE_CB714_SD 0x0750 +#define PCI_DEVICE_ID_ENE_CB714_SD_2 0x0751 +#define PCI_DEVICE_ID_ENE_1211 0x1211 +#define PCI_DEVICE_ID_ENE_1225 0x1225 +#define PCI_DEVICE_ID_ENE_1410 0x1410 +#define PCI_DEVICE_ID_ENE_710 0x1411 +#define PCI_DEVICE_ID_ENE_712 0x1412 +#define PCI_DEVICE_ID_ENE_1420 0x1420 +#define PCI_DEVICE_ID_ENE_720 0x1421 +#define PCI_DEVICE_ID_ENE_722 0x1422 + +#define PCI_SUBVENDOR_ID_PERLE 0x155f +#define PCI_SUBDEVICE_ID_PCI_RAS4 0xf001 +#define PCI_SUBDEVICE_ID_PCI_RAS8 0xf010 + +#define PCI_VENDOR_ID_SYBA 0x1592 +#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 +#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783 + +#define PCI_VENDOR_ID_MORETON 0x15aa +#define PCI_DEVICE_ID_RASTEL_2PORT 0x2000 + +#define PCI_VENDOR_ID_ZOLTRIX 0x15b0 +#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0 + +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 +#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46 +#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 +#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 +#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c +#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 + +#define PCI_VENDOR_ID_DFI 0x15bd + +#define PCI_VENDOR_ID_QUICKNET 0x15e2 +#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500 + +/* + * ADDI-DATA GmbH communication cards + */ +#define PCI_VENDOR_ID_ADDIDATA_OLD 0x10E8 +#define PCI_VENDOR_ID_ADDIDATA 0x15B8 +#define PCI_DEVICE_ID_ADDIDATA_APCI7500 0x7000 +#define PCI_DEVICE_ID_ADDIDATA_APCI7420 0x7001 +#define PCI_DEVICE_ID_ADDIDATA_APCI7300 0x7002 +#define PCI_DEVICE_ID_ADDIDATA_APCI7800 0x818E +#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2 0x7009 +#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2 0x700A +#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2 0x700B +#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3 0x700C +#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3 0x700D +#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3 0x700E +#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3 0x700F +#define PCI_DEVICE_ID_ADDIDATA_APCIe7300 0x7010 +#define PCI_DEVICE_ID_ADDIDATA_APCIe7420 0x7011 +#define PCI_DEVICE_ID_ADDIDATA_APCIe7500 0x7012 +#define PCI_DEVICE_ID_ADDIDATA_APCIe7800 0x7013 + +#define PCI_VENDOR_ID_PDC 0x15e9 + +#define PCI_VENDOR_ID_FARSITE 0x1619 +#define PCI_DEVICE_ID_FARSITE_T2P 0x0400 +#define PCI_DEVICE_ID_FARSITE_T4P 0x0440 +#define PCI_DEVICE_ID_FARSITE_T1U 0x0610 +#define PCI_DEVICE_ID_FARSITE_T2U 0x0620 +#define PCI_DEVICE_ID_FARSITE_T4U 0x0640 +#define PCI_DEVICE_ID_FARSITE_TE1 0x1610 +#define PCI_DEVICE_ID_FARSITE_TE1C 0x1612 + +#define PCI_VENDOR_ID_ARIMA 0x161f + +#define PCI_VENDOR_ID_BROCADE 0x1657 +#define PCI_DEVICE_ID_BROCADE_CT 0x0014 +#define PCI_DEVICE_ID_BROCADE_FC_8G1P 0x0017 +#define PCI_DEVICE_ID_BROCADE_CT_FC 0x0021 + +#define PCI_VENDOR_ID_SIBYTE 0x166d +#define PCI_DEVICE_ID_BCM1250_PCI 0x0001 +#define PCI_DEVICE_ID_BCM1250_HT 0x0002 + +#define PCI_VENDOR_ID_ATHEROS 0x168c + +#define PCI_VENDOR_ID_NETCELL 0x169c +#define PCI_DEVICE_ID_REVOLUTION 0x0044 + +#define PCI_VENDOR_ID_CENATEK 0x16CA +#define PCI_DEVICE_ID_CENATEK_IDE 0x0001 + +#define PCI_VENDOR_ID_VITESSE 0x1725 +#define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174 + +#define PCI_VENDOR_ID_LINKSYS 0x1737 +#define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 + +#define PCI_VENDOR_ID_ALTIMA 0x173b +#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8 +#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9 +#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea +#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb + +#define PCI_VENDOR_ID_BELKIN 0x1799 +#define PCI_DEVICE_ID_BELKIN_F5D7010V7 0x701f + +#define PCI_VENDOR_ID_RDC 0x17f3 +#define PCI_DEVICE_ID_RDC_R6020 0x6020 +#define PCI_DEVICE_ID_RDC_R6030 0x6030 +#define PCI_DEVICE_ID_RDC_R6040 0x6040 +#define PCI_DEVICE_ID_RDC_R6060 0x6060 +#define PCI_DEVICE_ID_RDC_R6061 0x6061 +#define PCI_DEVICE_ID_RDC_D1010 0x1010 + +#define PCI_VENDOR_ID_LENOVO 0x17aa + +#define PCI_VENDOR_ID_ARECA 0x17d3 +#define PCI_DEVICE_ID_ARECA_1110 0x1110 +#define PCI_DEVICE_ID_ARECA_1120 0x1120 +#define PCI_DEVICE_ID_ARECA_1130 0x1130 +#define PCI_DEVICE_ID_ARECA_1160 0x1160 +#define PCI_DEVICE_ID_ARECA_1170 0x1170 +#define PCI_DEVICE_ID_ARECA_1200 0x1200 +#define PCI_DEVICE_ID_ARECA_1201 0x1201 +#define PCI_DEVICE_ID_ARECA_1202 0x1202 +#define PCI_DEVICE_ID_ARECA_1210 0x1210 +#define PCI_DEVICE_ID_ARECA_1220 0x1220 +#define PCI_DEVICE_ID_ARECA_1230 0x1230 +#define PCI_DEVICE_ID_ARECA_1260 0x1260 +#define PCI_DEVICE_ID_ARECA_1270 0x1270 +#define PCI_DEVICE_ID_ARECA_1280 0x1280 +#define PCI_DEVICE_ID_ARECA_1380 0x1380 +#define PCI_DEVICE_ID_ARECA_1381 0x1381 +#define PCI_DEVICE_ID_ARECA_1680 0x1680 +#define PCI_DEVICE_ID_ARECA_1681 0x1681 + +#define PCI_VENDOR_ID_S2IO 0x17d5 +#define PCI_DEVICE_ID_S2IO_WIN 0x5731 +#define PCI_DEVICE_ID_S2IO_UNI 0x5831 +#define PCI_DEVICE_ID_HERC_WIN 0x5732 +#define PCI_DEVICE_ID_HERC_UNI 0x5832 + +#define PCI_VENDOR_ID_SITECOM 0x182d +#define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069 + +#define PCI_VENDOR_ID_TOPSPIN 0x1867 + +#define PCI_VENDOR_ID_SILAN 0x1904 + +#define PCI_VENDOR_ID_RENESAS 0x1912 +#define PCI_DEVICE_ID_RENESAS_SH7781 0x0001 +#define PCI_DEVICE_ID_RENESAS_SH7780 0x0002 +#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004 +#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007 +#define PCI_DEVICE_ID_RENESAS_SH7786 0x0010 + +#define PCI_VENDOR_ID_SOLARFLARE 0x1924 +#define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0 0x0703 +#define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1 0x6703 +#define PCI_DEVICE_ID_SOLARFLARE_SFC4000B 0x0710 + +#define PCI_VENDOR_ID_TDI 0x192E +#define PCI_DEVICE_ID_TDI_EHCI 0x0101 + +#define PCI_VENDOR_ID_FREESCALE 0x1957 +#define PCI_DEVICE_ID_MPC8308 0xc006 +#define PCI_DEVICE_ID_MPC8315E 0x00b4 +#define PCI_DEVICE_ID_MPC8315 0x00b5 +#define PCI_DEVICE_ID_MPC8314E 0x00b6 +#define PCI_DEVICE_ID_MPC8314 0x00b7 +#define PCI_DEVICE_ID_MPC8378E 0x00c4 +#define PCI_DEVICE_ID_MPC8378 0x00c5 +#define PCI_DEVICE_ID_MPC8377E 0x00c6 +#define PCI_DEVICE_ID_MPC8377 0x00c7 +#define PCI_DEVICE_ID_MPC8548E 0x0012 +#define PCI_DEVICE_ID_MPC8548 0x0013 +#define PCI_DEVICE_ID_MPC8543E 0x0014 +#define PCI_DEVICE_ID_MPC8543 0x0015 +#define PCI_DEVICE_ID_MPC8547E 0x0018 +#define PCI_DEVICE_ID_MPC8545E 0x0019 +#define PCI_DEVICE_ID_MPC8545 0x001a +#define PCI_DEVICE_ID_MPC8569E 0x0061 +#define PCI_DEVICE_ID_MPC8569 0x0060 +#define PCI_DEVICE_ID_MPC8568E 0x0020 +#define PCI_DEVICE_ID_MPC8568 0x0021 +#define PCI_DEVICE_ID_MPC8567E 0x0022 +#define PCI_DEVICE_ID_MPC8567 0x0023 +#define PCI_DEVICE_ID_MPC8533E 0x0030 +#define PCI_DEVICE_ID_MPC8533 0x0031 +#define PCI_DEVICE_ID_MPC8544E 0x0032 +#define PCI_DEVICE_ID_MPC8544 0x0033 +#define PCI_DEVICE_ID_MPC8572E 0x0040 +#define PCI_DEVICE_ID_MPC8572 0x0041 +#define PCI_DEVICE_ID_MPC8536E 0x0050 +#define PCI_DEVICE_ID_MPC8536 0x0051 +#define PCI_DEVICE_ID_P2020E 0x0070 +#define PCI_DEVICE_ID_P2020 0x0071 +#define PCI_DEVICE_ID_P2010E 0x0078 +#define PCI_DEVICE_ID_P2010 0x0079 +#define PCI_DEVICE_ID_P1020E 0x0100 +#define PCI_DEVICE_ID_P1020 0x0101 +#define PCI_DEVICE_ID_P1021E 0x0102 +#define PCI_DEVICE_ID_P1021 0x0103 +#define PCI_DEVICE_ID_P1011E 0x0108 +#define PCI_DEVICE_ID_P1011 0x0109 +#define PCI_DEVICE_ID_P1022E 0x0110 +#define PCI_DEVICE_ID_P1022 0x0111 +#define PCI_DEVICE_ID_P1013E 0x0118 +#define PCI_DEVICE_ID_P1013 0x0119 +#define PCI_DEVICE_ID_P4080E 0x0400 +#define PCI_DEVICE_ID_P4080 0x0401 +#define PCI_DEVICE_ID_P4040E 0x0408 +#define PCI_DEVICE_ID_P4040 0x0409 +#define PCI_DEVICE_ID_P2040E 0x0410 +#define PCI_DEVICE_ID_P2040 0x0411 +#define PCI_DEVICE_ID_P3041E 0x041E +#define PCI_DEVICE_ID_P3041 0x041F +#define PCI_DEVICE_ID_P5020E 0x0420 +#define PCI_DEVICE_ID_P5020 0x0421 +#define PCI_DEVICE_ID_P5010E 0x0428 +#define PCI_DEVICE_ID_P5010 0x0429 +#define PCI_DEVICE_ID_MPC8641 0x7010 +#define PCI_DEVICE_ID_MPC8641D 0x7011 +#define PCI_DEVICE_ID_MPC8610 0x7018 + +#define PCI_VENDOR_ID_PASEMI 0x1959 + +#define PCI_VENDOR_ID_ATTANSIC 0x1969 +#define PCI_DEVICE_ID_ATTANSIC_L1 0x1048 +#define PCI_DEVICE_ID_ATTANSIC_L2 0x2048 + +#define PCI_VENDOR_ID_JMICRON 0x197B +#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 +#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361 +#define PCI_DEVICE_ID_JMICRON_JMB362 0x2362 +#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363 +#define PCI_DEVICE_ID_JMICRON_JMB364 0x2364 +#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365 +#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366 +#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368 +#define PCI_DEVICE_ID_JMICRON_JMB369 0x2369 +#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 +#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382 +#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 +#define PCI_DEVICE_ID_JMICRON_JMB385_MS 0x2388 +#define PCI_DEVICE_ID_JMICRON_JMB388_SD 0x2391 +#define PCI_DEVICE_ID_JMICRON_JMB388_ESD 0x2392 +#define PCI_DEVICE_ID_JMICRON_JMB390_MS 0x2393 + +#define PCI_VENDOR_ID_KORENIX 0x1982 +#define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 +#define PCI_DEVICE_ID_KORENIX_JETCARDF1 0x16ff +#define PCI_DEVICE_ID_KORENIX_JETCARDF2 0x1700 +#define PCI_DEVICE_ID_KORENIX_JETCARDF3 0x17ff + +#define PCI_VENDOR_ID_QMI 0x1a32 + +#define PCI_VENDOR_ID_AZWAVE 0x1a3b + +#define PCI_VENDOR_ID_ASMEDIA 0x1b21 + +#define PCI_VENDOR_ID_TEKRAM 0x1de1 +#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 + +#define PCI_VENDOR_ID_TEHUTI 0x1fc9 +#define PCI_DEVICE_ID_TEHUTI_3009 0x3009 +#define PCI_DEVICE_ID_TEHUTI_3010 0x3010 +#define PCI_DEVICE_ID_TEHUTI_3014 0x3014 + +#define PCI_VENDOR_ID_HINT 0x3388 +#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013 + +#define PCI_VENDOR_ID_3DLABS 0x3d3d +#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007 +#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009 + +#define PCI_VENDOR_ID_NETXEN 0x4040 +#define PCI_DEVICE_ID_NX2031_10GXSR 0x0001 +#define PCI_DEVICE_ID_NX2031_10GCX4 0x0002 +#define PCI_DEVICE_ID_NX2031_4GCU 0x0003 +#define PCI_DEVICE_ID_NX2031_IMEZ 0x0004 +#define PCI_DEVICE_ID_NX2031_HMEZ 0x0005 +#define PCI_DEVICE_ID_NX2031_XG_MGMT 0x0024 +#define PCI_DEVICE_ID_NX2031_XG_MGMT2 0x0025 +#define PCI_DEVICE_ID_NX3031 0x0100 + +#define PCI_VENDOR_ID_AKS 0x416c +#define PCI_DEVICE_ID_AKS_ALADDINCARD 0x0100 + +#define PCI_VENDOR_ID_ACCESSIO 0x494f +#define PCI_DEVICE_ID_ACCESSIO_WDG_CSM 0x22c0 + +#define PCI_VENDOR_ID_S3 0x5333 +#define PCI_DEVICE_ID_S3_TRIO 0x8811 +#define PCI_DEVICE_ID_S3_868 0x8880 +#define PCI_DEVICE_ID_S3_968 0x88f0 +#define PCI_DEVICE_ID_S3_SAVAGE4 0x8a25 +#define PCI_DEVICE_ID_S3_PROSAVAGE8 0x8d04 +#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00 + +#define PCI_VENDOR_ID_DUNORD 0x5544 +#define PCI_DEVICE_ID_DUNORD_I3000 0x0001 + +#define PCI_VENDOR_ID_DCI 0x6666 +#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001 +#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002 +#define PCI_DEVICE_ID_DCI_PCCOM2 0x0004 + +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_EESSC 0x0008 +#define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 +#define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 +#define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 +#define PCI_DEVICE_ID_INTEL_PXH_1 0x032A +#define PCI_DEVICE_ID_INTEL_PXHV 0x032C +#define PCI_DEVICE_ID_INTEL_80332_0 0x0330 +#define PCI_DEVICE_ID_INTEL_80332_1 0x0332 +#define PCI_DEVICE_ID_INTEL_80333_0 0x0370 +#define PCI_DEVICE_ID_INTEL_80333_1 0x0372 +#define PCI_DEVICE_ID_INTEL_82375 0x0482 +#define PCI_DEVICE_ID_INTEL_82424 0x0483 +#define PCI_DEVICE_ID_INTEL_82378 0x0484 +#define PCI_DEVICE_ID_INTEL_MRST_SD0 0x0807 +#define PCI_DEVICE_ID_INTEL_MRST_SD1 0x0808 +#define PCI_DEVICE_ID_INTEL_MFD_SD 0x0820 +#define PCI_DEVICE_ID_INTEL_MFD_SDIO1 0x0821 +#define PCI_DEVICE_ID_INTEL_MFD_SDIO2 0x0822 +#define PCI_DEVICE_ID_INTEL_MFD_EMMC0 0x0823 +#define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824 +#define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F +#define PCI_DEVICE_ID_INTEL_I960 0x0960 +#define PCI_DEVICE_ID_INTEL_I960RM 0x0962 +#define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062 +#define PCI_DEVICE_ID_INTEL_82573E_SOL 0x1085 +#define PCI_DEVICE_ID_INTEL_82573L_SOL 0x108F +#define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 +#define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 +#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 +#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 +#define PCI_DEVICE_ID_INTEL_7205_0 0x255d +#define PCI_DEVICE_ID_INTEL_82437 0x122d +#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e +#define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230 +#define PCI_DEVICE_ID_INTEL_82371MX 0x1234 +#define PCI_DEVICE_ID_INTEL_82441 0x1237 +#define PCI_DEVICE_ID_INTEL_82380FB 0x124b +#define PCI_DEVICE_ID_INTEL_82439 0x1250 +#define PCI_DEVICE_ID_INTEL_80960_RP 0x1960 +#define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21 +#define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 +#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40 +#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI 0x1e31 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e40 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f +#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX 0x231f +#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 +#define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411 +#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 +#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 +#define PCI_DEVICE_ID_INTEL_82801AA_6 0x2416 +#define PCI_DEVICE_ID_INTEL_82801AA_8 0x2418 +#define PCI_DEVICE_ID_INTEL_82801AB_0 0x2420 +#define PCI_DEVICE_ID_INTEL_82801AB_1 0x2421 +#define PCI_DEVICE_ID_INTEL_82801AB_3 0x2423 +#define PCI_DEVICE_ID_INTEL_82801AB_5 0x2425 +#define PCI_DEVICE_ID_INTEL_82801AB_6 0x2426 +#define PCI_DEVICE_ID_INTEL_82801AB_8 0x2428 +#define PCI_DEVICE_ID_INTEL_82801BA_0 0x2440 +#define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443 +#define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445 +#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448 +#define PCI_DEVICE_ID_INTEL_82801BA_8 0x244a +#define PCI_DEVICE_ID_INTEL_82801BA_9 0x244b +#define PCI_DEVICE_ID_INTEL_82801BA_10 0x244c +#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e +#define PCI_DEVICE_ID_INTEL_82801E_0 0x2450 +#define PCI_DEVICE_ID_INTEL_82801E_11 0x245b +#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480 +#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483 +#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485 +#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486 +#define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a +#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b +#define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c +#define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0 +#define PCI_DEVICE_ID_INTEL_82801DB_1 0x24c1 +#define PCI_DEVICE_ID_INTEL_82801DB_2 0x24c2 +#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3 +#define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5 +#define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6 +#define PCI_DEVICE_ID_INTEL_82801DB_9 0x24c9 +#define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca +#define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb +#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc +#define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0 +#define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1 +#define PCI_DEVICE_ID_INTEL_82801EB_3 0x24d3 +#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 +#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 +#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db +#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc +#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd +#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 +#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 +#define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4 +#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 +#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab +#define PCI_DEVICE_ID_INTEL_ESB_10 0x25ac +#define PCI_DEVICE_ID_INTEL_82820_HB 0x2500 +#define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501 +#define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 +#define PCI_DEVICE_ID_INTEL_82860_HB 0x2531 +#define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c +#define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560 +#define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 +#define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 +#define PCI_DEVICE_ID_INTEL_82865_IG 0x2572 +#define PCI_DEVICE_ID_INTEL_82875_HB 0x2578 +#define PCI_DEVICE_ID_INTEL_82915G_HB 0x2580 +#define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582 +#define PCI_DEVICE_ID_INTEL_82915GM_HB 0x2590 +#define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592 +#define PCI_DEVICE_ID_INTEL_5000_ERR 0x25F0 +#define PCI_DEVICE_ID_INTEL_5000_FBD0 0x25F5 +#define PCI_DEVICE_ID_INTEL_5000_FBD1 0x25F6 +#define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770 +#define PCI_DEVICE_ID_INTEL_82945G_IG 0x2772 +#define PCI_DEVICE_ID_INTEL_3000_HB 0x2778 +#define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0 +#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2 +#define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 +#define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 +#define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642 +#define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a +#define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d +#define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e +#define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f +#define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670 +#define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698 +#define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b +#define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e +#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 +#define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 +#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc +#define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd +#define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da +#define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd +#define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de +#define PCI_DEVICE_ID_INTEL_ICH7_21 0x27df +#define PCI_DEVICE_ID_INTEL_ICH8_0 0x2810 +#define PCI_DEVICE_ID_INTEL_ICH8_1 0x2811 +#define PCI_DEVICE_ID_INTEL_ICH8_2 0x2812 +#define PCI_DEVICE_ID_INTEL_ICH8_3 0x2814 +#define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 +#define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e +#define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 +#define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18 +#define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19 +#define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a +#define PCI_DEVICE_ID_INTEL_I7_MC_TEST 0x2c1c +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL 0x2c20 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR 0x2c21 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK 0x2c22 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC 0x2c23 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL 0x2c28 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR 0x2c29 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK 0x2c2a +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC 0x2c2b +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL 0x2c30 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 +#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 +#define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2 0x2c70 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_SAD 0x2c81 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0 0x2c90 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_PHY0 0x2c91 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR 0x2c98 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD 0x2c99 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST 0x2c9C +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL 0x2ca0 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR 0x2ca1 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK 0x2ca2 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC 0x2ca3 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL 0x2ca8 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR 0x2ca9 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK 0x2caa +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC 0x2cab +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2 0x2d98 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2 0x2d99 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2 0x2d9a +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2 0x2d9c +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2 0x2da0 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2 0x2da1 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2 0x2da2 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2 0x2da3 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2 0x2da8 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2 0x2da9 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2 0x2daa +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2 0x2dab +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2 0x2db0 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2 0x2db1 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2 0x2db2 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2 0x2db3 +#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a +#define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b +#define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c +#define PCI_DEVICE_ID_INTEL_X58_HUB_MGMT 0x342e +#define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432 +#define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433 +#define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 +#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 +#define PCI_DEVICE_ID_INTEL_82854_HB 0x358c +#define PCI_DEVICE_ID_INTEL_82854_IG 0x358e +#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 +#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 +#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590 +#define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592 +#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595 +#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596 +#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597 +#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598 +#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599 +#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a +#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e +#define PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 0x360c +#define PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 0x360f +#define PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 0x3610 +#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b +#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c +#define PCI_DEVICE_ID_INTEL_IOAT_JSF0 0x3710 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF1 0x3711 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF2 0x3712 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF3 0x3713 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF4 0x3714 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF5 0x3715 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF6 0x3716 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF7 0x3717 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF8 0x3718 +#define PCI_DEVICE_ID_INTEL_IOAT_JSF9 0x3719 +#define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14 +#define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16 +#define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18 +#define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a +#define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30 +#define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN 0x3b00 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX 0x3b1f +#define PCI_DEVICE_ID_INTEL_IOAT_SNB0 0x3c20 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB1 0x3c21 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB2 0x3c22 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB3 0x3c23 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB4 0x3c24 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB5 0x3c25 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB6 0x3c26 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 +#define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e +#define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f +#define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f +#define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 +#define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 +#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6 +#define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030 +#define PCI_DEVICE_ID_INTEL_5400_FBD0 0x4035 +#define PCI_DEVICE_ID_INTEL_5400_FBD1 0x4036 +#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff +#define PCI_DEVICE_ID_INTEL_EP80579_0 0x5031 +#define PCI_DEVICE_ID_INTEL_EP80579_1 0x5032 +#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 +#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 +#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 +#define PCI_DEVICE_ID_INTEL_82437VX 0x7030 +#define PCI_DEVICE_ID_INTEL_82439TX 0x7100 +#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 +#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 +#define PCI_DEVICE_ID_INTEL_82810_MC1 0x7120 +#define PCI_DEVICE_ID_INTEL_82810_IG1 0x7121 +#define PCI_DEVICE_ID_INTEL_82810_MC3 0x7122 +#define PCI_DEVICE_ID_INTEL_82810_IG3 0x7123 +#define PCI_DEVICE_ID_INTEL_82810E_MC 0x7124 +#define PCI_DEVICE_ID_INTEL_82810E_IG 0x7125 +#define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180 +#define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181 +#define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190 +#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 +#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 +#define PCI_DEVICE_ID_INTEL_440MX 0x7195 +#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196 +#define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198 +#define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199 +#define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b +#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 +#define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 +#define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 +#define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119 +#define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a +#define PCI_DEVICE_ID_INTEL_ITC_LPC 0x8186 +#define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 +#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 +#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca +#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb +#define PCI_DEVICE_ID_INTEL_84460GX 0x84ea +#define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500 +#define PCI_DEVICE_ID_INTEL_IXP2800 0x9004 +#define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 + +#define PCI_VENDOR_ID_SCALEMP 0x8686 +#define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010 + +#define PCI_VENDOR_ID_COMPUTONE 0x8e0e +#define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291 +#define PCI_DEVICE_ID_COMPUTONE_PG 0x0302 +#define PCI_SUBVENDOR_ID_COMPUTONE 0x8e0e +#define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001 +#define PCI_SUBDEVICE_ID_COMPUTONE_PG8 0x0002 +#define PCI_SUBDEVICE_ID_COMPUTONE_PG6 0x0003 + +#define PCI_VENDOR_ID_KTI 0x8e2e + +#define PCI_VENDOR_ID_ADAPTEC 0x9004 +#define PCI_DEVICE_ID_ADAPTEC_7810 0x1078 +#define PCI_DEVICE_ID_ADAPTEC_7821 0x2178 +#define PCI_DEVICE_ID_ADAPTEC_38602 0x3860 +#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078 +#define PCI_DEVICE_ID_ADAPTEC_7855 0x5578 +#define PCI_DEVICE_ID_ADAPTEC_3860 0x6038 +#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075 +#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078 +#define PCI_DEVICE_ID_ADAPTEC_7861 0x6178 +#define PCI_DEVICE_ID_ADAPTEC_7870 0x7078 +#define PCI_DEVICE_ID_ADAPTEC_7871 0x7178 +#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278 +#define PCI_DEVICE_ID_ADAPTEC_7873 0x7378 +#define PCI_DEVICE_ID_ADAPTEC_7874 0x7478 +#define PCI_DEVICE_ID_ADAPTEC_7895 0x7895 +#define PCI_DEVICE_ID_ADAPTEC_7880 0x8078 +#define PCI_DEVICE_ID_ADAPTEC_7881 0x8178 +#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278 +#define PCI_DEVICE_ID_ADAPTEC_7883 0x8378 +#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478 +#define PCI_DEVICE_ID_ADAPTEC_7885 0x8578 +#define PCI_DEVICE_ID_ADAPTEC_7886 0x8678 +#define PCI_DEVICE_ID_ADAPTEC_7887 0x8778 +#define PCI_DEVICE_ID_ADAPTEC_7888 0x8878 + +#define PCI_VENDOR_ID_ADAPTEC2 0x9005 +#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010 +#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011 +#define PCI_DEVICE_ID_ADAPTEC2_7890B 0x0013 +#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f +#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050 +#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051 +#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f +#define PCI_DEVICE_ID_ADAPTEC2_7892A 0x0080 +#define PCI_DEVICE_ID_ADAPTEC2_7892B 0x0081 +#define PCI_DEVICE_ID_ADAPTEC2_7892D 0x0083 +#define PCI_DEVICE_ID_ADAPTEC2_7892P 0x008f +#define PCI_DEVICE_ID_ADAPTEC2_7899A 0x00c0 +#define PCI_DEVICE_ID_ADAPTEC2_7899B 0x00c1 +#define PCI_DEVICE_ID_ADAPTEC2_7899D 0x00c3 +#define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf +#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN 0x0500 +#define PCI_DEVICE_ID_ADAPTEC2_SCAMP 0x0503 + +#define PCI_VENDOR_ID_HOLTEK 0x9412 +#define PCI_DEVICE_ID_HOLTEK_6565 0x6565 + +#define PCI_VENDOR_ID_NETMOS 0x9710 +#define PCI_DEVICE_ID_NETMOS_9705 0x9705 +#define PCI_DEVICE_ID_NETMOS_9715 0x9715 +#define PCI_DEVICE_ID_NETMOS_9735 0x9735 +#define PCI_DEVICE_ID_NETMOS_9745 0x9745 +#define PCI_DEVICE_ID_NETMOS_9755 0x9755 +#define PCI_DEVICE_ID_NETMOS_9805 0x9805 +#define PCI_DEVICE_ID_NETMOS_9815 0x9815 +#define PCI_DEVICE_ID_NETMOS_9835 0x9835 +#define PCI_DEVICE_ID_NETMOS_9845 0x9845 +#define PCI_DEVICE_ID_NETMOS_9855 0x9855 +#define PCI_DEVICE_ID_NETMOS_9865 0x9865 +#define PCI_DEVICE_ID_NETMOS_9900 0x9900 +#define PCI_DEVICE_ID_NETMOS_9901 0x9901 +#define PCI_DEVICE_ID_NETMOS_9904 0x9904 +#define PCI_DEVICE_ID_NETMOS_9912 0x9912 +#define PCI_DEVICE_ID_NETMOS_9922 0x9922 + +#define PCI_VENDOR_ID_3COM_2 0xa727 + +#define PCI_VENDOR_ID_DIGIUM 0xd161 +#define PCI_DEVICE_ID_DIGIUM_HFC4S 0xb410 + +#define PCI_SUBVENDOR_ID_EXSYS 0xd84d +#define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014 +#define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055 + +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#define PCI_DEVICE_ID_TIGERJET_300 0x0001 +#define PCI_DEVICE_ID_TIGERJET_100 0x0002 + +#define PCI_VENDOR_ID_XILINX_RME 0xea60 +#define PCI_DEVICE_ID_RME_DIGI32 0x9896 +#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 +#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 + +#define PCI_VENDOR_ID_XEN 0x5853 +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 + +#define PCI_VENDOR_ID_OCZ 0x1b85 diff --git a/include/compat/linux/pm_qos.h b/include/compat/linux/pm_qos.h new file mode 100644 index 00000000..c58c1c1f --- /dev/null +++ b/include/compat/linux/pm_qos.h @@ -0,0 +1,12 @@ +#ifndef _COMPAT_LINUX_PM_QOS_H +#define _COMPAT_LINUX_PM_QOS_H 1 + +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) +#include_next +#else +#include +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) */ + +#endif /* _COMPAT_LINUX_PM_QOS_H */ diff --git a/include/compat/linux/pm_qos_params.h b/include/compat/linux/pm_qos_params.h new file mode 100644 index 00000000..d0e3ad86 --- /dev/null +++ b/include/compat/linux/pm_qos_params.h @@ -0,0 +1,36 @@ +#include + +#ifndef __COMPAT_LINUX_PM_QOS_PARAMS_H +#define __COMPAT_LINUX_PM_QOS_PARAMS_H + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) +#include_next +#else +/* interface for the pm_qos_power infrastructure of the linux kernel. + * + * Mark Gross + */ +#include +#include +#include + +#define PM_QOS_RESERVED 0 +#define PM_QOS_CPU_DMA_LATENCY 1 +#define PM_QOS_NETWORK_LATENCY 2 +#define PM_QOS_NETWORK_THROUGHPUT 3 +#define PM_QOS_SYSTEM_BUS_FREQ 4 + +#define PM_QOS_NUM_CLASSES 5 +#define PM_QOS_DEFAULT_VALUE -1 + +int pm_qos_add_requirement(int qos, char *name, s32 value); +int pm_qos_update_requirement(int qos, char *name, s32 new_value); +void pm_qos_remove_requirement(int qos, char *name); + +int pm_qos_requirement(int qos); + +int pm_qos_add_notifier(int qos, struct notifier_block *notifier); +int pm_qos_remove_notifier(int qos, struct notifier_block *notifier); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) */ + +#endif diff --git a/include/compat/linux/pm_runtime.h b/include/compat/linux/pm_runtime.h new file mode 100644 index 00000000..eec965ba --- /dev/null +++ b/include/compat/linux/pm_runtime.h @@ -0,0 +1,14 @@ +#include + +#ifndef __COMPAT_LINUX_PM_RUNTIME_H +#define __COMPAT_LINUX_PM_RUNTIME_H + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) +#include_next +#else + +static inline void pm_runtime_enable(struct device *dev) {} + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) */ + +#endif diff --git a/include/compat/linux/printk.h b/include/compat/linux/printk.h new file mode 100644 index 00000000..c0822ac4 --- /dev/null +++ b/include/compat/linux/printk.h @@ -0,0 +1,12 @@ +#ifndef _COMPAT_LINUX_PRINTK_H +#define _COMPAT_LINUX_PRINTK_H 1 + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)) +#include_next +#else +#include +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) */ + +#endif /* _COMPAT_LINUX_PRINTK_H */ diff --git a/include/compat/linux/rfkill.h b/include/compat/linux/rfkill.h new file mode 100644 index 00000000..d615ac9f --- /dev/null +++ b/include/compat/linux/rfkill.h @@ -0,0 +1,32 @@ +#ifndef __COMPAT_RFKILL_H +#define __COMPAT_RFKILL_H + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)) + +#include_next + +#else + +#include + +#undef CONFIG_RFKILL +#undef CONFIG_RFKILL_INPUT +#undef CONFIG_RFKILL_LEDS + +#ifdef CONFIG_RFKILL_BACKPORT +#define CONFIG_RFKILL 1 +#endif + +#ifdef CONFIG_RFKILL_BACKPORT_INPUT +#define CONFIG_RFKILL_INPUT +#endif + +#ifdef CONFIG_RFKILL_BACKPORT_LEDS +#define CONFIG_RFKILL_LEDS +#endif + +#include + +#endif + +#endif diff --git a/include/compat/linux/rfkill_backport.h b/include/compat/linux/rfkill_backport.h new file mode 100644 index 00000000..c6c60848 --- /dev/null +++ b/include/compat/linux/rfkill_backport.h @@ -0,0 +1,359 @@ +#ifndef __RFKILL_H +#define __RFKILL_H + +/* + * Copyright (C) 2006 - 2007 Ivo van Doorn + * Copyright (C) 2007 Dmitry Torokhov + * Copyright 2009 Johannes Berg + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include + +/* define userspace visible states */ +#define RFKILL_STATE_SOFT_BLOCKED 0 +#define RFKILL_STATE_UNBLOCKED 1 +#define RFKILL_STATE_HARD_BLOCKED 2 + +/** + * enum rfkill_type - type of rfkill switch. + * + * @RFKILL_TYPE_ALL: toggles all switches (requests only - not a switch type) + * @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device. + * @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device. + * @RFKILL_TYPE_UWB: switch is on a ultra wideband device. + * @RFKILL_TYPE_WIMAX: switch is on a WiMAX device. + * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device. + * @RFKILL_TYPE_GPS: switch is on a GPS device. + * @RFKILL_TYPE_FM: switch is on a FM radio device. + * @NUM_RFKILL_TYPES: number of defined rfkill types + */ +enum rfkill_type { + RFKILL_TYPE_ALL = 0, + RFKILL_TYPE_WLAN, + RFKILL_TYPE_BLUETOOTH, + RFKILL_TYPE_UWB, + RFKILL_TYPE_WIMAX, + RFKILL_TYPE_WWAN, + RFKILL_TYPE_GPS, + RFKILL_TYPE_FM, + NUM_RFKILL_TYPES, +}; + +/** + * enum rfkill_operation - operation types + * @RFKILL_OP_ADD: a device was added + * @RFKILL_OP_DEL: a device was removed + * @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device + * @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all) + */ +enum rfkill_operation { + RFKILL_OP_ADD = 0, + RFKILL_OP_DEL, + RFKILL_OP_CHANGE, + RFKILL_OP_CHANGE_ALL, +}; + +/** + * struct rfkill_event - events for userspace on /dev/rfkill + * @idx: index of dev rfkill + * @type: type of the rfkill struct + * @op: operation code + * @hard: hard state (0/1) + * @soft: soft state (0/1) + * + * Structure used for userspace communication on /dev/rfkill, + * used for events from the kernel and control to the kernel. + */ +struct rfkill_event { + __u32 idx; + __u8 type; + __u8 op; + __u8 soft, hard; +} __attribute__((packed)); + +/* + * We are planning to be backward and forward compatible with changes + * to the event struct, by adding new, optional, members at the end. + * When reading an event (whether the kernel from userspace or vice + * versa) we need to accept anything that's at least as large as the + * version 1 event size, but might be able to accept other sizes in + * the future. + * + * One exception is the kernel -- we already have two event sizes in + * that we've made the 'hard' member optional since our only option + * is to ignore it anyway. + */ +#define RFKILL_EVENT_SIZE_V1 8 + +/* ioctl for turning off rfkill-input (if present) */ +#define RFKILL_IOC_MAGIC 'R' +#define RFKILL_IOC_NOINPUT 1 +#define RFKILL_IOCTL_NOINPUT _IO(RFKILL_IOC_MAGIC, RFKILL_IOC_NOINPUT) + +/* and that's all userspace gets */ +#ifdef __KERNEL__ +/* don't allow anyone to use these in the kernel */ +enum rfkill_user_states { + RFKILL_USER_STATE_SOFT_BLOCKED = RFKILL_STATE_SOFT_BLOCKED, + RFKILL_USER_STATE_UNBLOCKED = RFKILL_STATE_UNBLOCKED, + RFKILL_USER_STATE_HARD_BLOCKED = RFKILL_STATE_HARD_BLOCKED, +}; +#undef RFKILL_STATE_SOFT_BLOCKED +#undef RFKILL_STATE_UNBLOCKED +#undef RFKILL_STATE_HARD_BLOCKED + +#include +#include +#include +#include +#include +#include + +/* this is opaque */ +struct rfkill; + +/** + * struct rfkill_ops - rfkill driver methods + * + * @poll: poll the rfkill block state(s) -- only assign this method + * when you need polling. When called, simply call one of the + * rfkill_set{,_hw,_sw}_state family of functions. If the hw + * is getting unblocked you need to take into account the return + * value of those functions to make sure the software block is + * properly used. + * @query: query the rfkill block state(s) and call exactly one of the + * rfkill_set{,_hw,_sw}_state family of functions. Assign this + * method if input events can cause hardware state changes to make + * the rfkill core query your driver before setting a requested + * block. + * @set_block: turn the transmitter on (blocked == false) or off + * (blocked == true) -- ignore and return 0 when hard blocked. + * This callback must be assigned. + */ +struct rfkill_ops { + void (*poll)(struct rfkill *rfkill, void *data); + void (*query)(struct rfkill *rfkill, void *data); + int (*set_block)(void *data, bool blocked); +}; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +/** + * rfkill_alloc - allocate rfkill structure + * @name: name of the struct -- the string is not copied internally + * @parent: device that has rf switch on it + * @type: type of the switch (RFKILL_TYPE_*) + * @ops: rfkill methods + * @ops_data: data passed to each method + * + * This function should be called by the transmitter driver to allocate an + * rfkill structure. Returns %NULL on failure. + */ +struct rfkill * __must_check rfkill_alloc(const char *name, + struct device *parent, + const enum rfkill_type type, + const struct rfkill_ops *ops, + void *ops_data); + +/** + * rfkill_register - Register a rfkill structure. + * @rfkill: rfkill structure to be registered + * + * This function should be called by the transmitter driver to register + * the rfkill structure. Before calling this function the driver needs + * to be ready to service method calls from rfkill. + * + * If rfkill_init_sw_state() is not called before registration, + * set_block() will be called to initialize the software blocked state + * to a default value. + * + * If the hardware blocked state is not set before registration, + * it is assumed to be unblocked. + */ +int __must_check rfkill_register(struct rfkill *rfkill); + +/** + * rfkill_pause_polling(struct rfkill *rfkill) + * + * Pause polling -- say transmitter is off for other reasons. + * NOTE: not necessary for suspend/resume -- in that case the + * core stops polling anyway + */ +void rfkill_pause_polling(struct rfkill *rfkill); + +/** + * rfkill_resume_polling(struct rfkill *rfkill) + * + * Pause polling -- say transmitter is off for other reasons. + * NOTE: not necessary for suspend/resume -- in that case the + * core stops polling anyway + */ +void rfkill_resume_polling(struct rfkill *rfkill); + + +/** + * rfkill_unregister - Unregister a rfkill structure. + * @rfkill: rfkill structure to be unregistered + * + * This function should be called by the network driver during device + * teardown to destroy rfkill structure. Until it returns, the driver + * needs to be able to service method calls. + */ +void rfkill_unregister(struct rfkill *rfkill); + +/** + * rfkill_destroy - free rfkill structure + * @rfkill: rfkill structure to be destroyed + * + * Destroys the rfkill structure. + */ +void rfkill_destroy(struct rfkill *rfkill); + +/** + * rfkill_set_hw_state - Set the internal rfkill hardware block state + * @rfkill: pointer to the rfkill class to modify. + * @state: the current hardware block state to set + * + * rfkill drivers that get events when the hard-blocked state changes + * use this function to notify the rfkill core (and through that also + * userspace) of the current state. They should also use this after + * resume if the state could have changed. + * + * You need not (but may) call this function if poll_state is assigned. + * + * This function can be called in any context, even from within rfkill + * callbacks. + * + * The function returns the combined block state (true if transmitter + * should be blocked) so that drivers need not keep track of the soft + * block state -- which they might not be able to. + */ +bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked); + +/** + * rfkill_set_sw_state - Set the internal rfkill software block state + * @rfkill: pointer to the rfkill class to modify. + * @state: the current software block state to set + * + * rfkill drivers that get events when the soft-blocked state changes + * (yes, some platforms directly act on input but allow changing again) + * use this function to notify the rfkill core (and through that also + * userspace) of the current state. + * + * Drivers should also call this function after resume if the state has + * been changed by the user. This only makes sense for "persistent" + * devices (see rfkill_init_sw_state()). + * + * This function can be called in any context, even from within rfkill + * callbacks. + * + * The function returns the combined block state (true if transmitter + * should be blocked). + */ +bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked); + +/** + * rfkill_init_sw_state - Initialize persistent software block state + * @rfkill: pointer to the rfkill class to modify. + * @state: the current software block state to set + * + * rfkill drivers that preserve their software block state over power off + * use this function to notify the rfkill core (and through that also + * userspace) of their initial state. It should only be used before + * registration. + * + * In addition, it marks the device as "persistent", an attribute which + * can be read by userspace. Persistent devices are expected to preserve + * their own state when suspended. + */ +void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked); + +/** + * rfkill_set_states - Set the internal rfkill block states + * @rfkill: pointer to the rfkill class to modify. + * @sw: the current software block state to set + * @hw: the current hardware block state to set + * + * This function can be called in any context, even from within rfkill + * callbacks. + */ +void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw); + +/** + * rfkill_blocked - query rfkill block + * + * @rfkill: rfkill struct to query + */ +bool rfkill_blocked(struct rfkill *rfkill); +#else /* !RFKILL */ +static inline struct rfkill * __must_check +rfkill_alloc(const char *name, + struct device *parent, + const enum rfkill_type type, + const struct rfkill_ops *ops, + void *ops_data) +{ + return ERR_PTR(-ENODEV); +} + +static inline int __must_check rfkill_register(struct rfkill *rfkill) +{ + if (rfkill == ERR_PTR(-ENODEV)) + return 0; + return -EINVAL; +} + +static inline void rfkill_pause_polling(struct rfkill *rfkill) +{ +} + +static inline void rfkill_resume_polling(struct rfkill *rfkill) +{ +} + +static inline void rfkill_unregister(struct rfkill *rfkill) +{ +} + +static inline void rfkill_destroy(struct rfkill *rfkill) +{ +} + +static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) +{ + return blocked; +} + +static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) +{ + return blocked; +} + +static inline void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked) +{ +} + +static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) +{ +} + +static inline bool rfkill_blocked(struct rfkill *rfkill) +{ + return false; +} +#endif /* RFKILL || RFKILL_MODULE */ + +#endif /* __KERNEL__ */ + +#endif /* RFKILL_H */ diff --git a/include/compat/linux/semaphore.h b/include/compat/linux/semaphore.h new file mode 100644 index 00000000..78af4db3 --- /dev/null +++ b/include/compat/linux/semaphore.h @@ -0,0 +1,12 @@ +#ifndef _COMPAT_LINUX_SEMAPHORE_H +#define _COMPAT_LINUX_SEMAPHORE_H 1 + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)) +#include_next +#else +#include +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)) */ + +#endif /* _COMPAT_LINUX_SEMAPHORE_H */ diff --git a/include/compat/linux/spi/libertas_spi.h b/include/compat/linux/spi/libertas_spi.h new file mode 100644 index 00000000..1b5d5384 --- /dev/null +++ b/include/compat/linux/spi/libertas_spi.h @@ -0,0 +1,29 @@ +/* + * board-specific data for the libertas_spi driver. + * + * Copyright 2008 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ +#ifndef _LIBERTAS_SPI_H_ +#define _LIBERTAS_SPI_H_ + +struct spi_device; + +struct libertas_spi_platform_data { + /* There are two ways to read data from the WLAN module's SPI + * interface. Setting 0 or 1 here controls which one is used. + * + * Usually you want to set use_dummy_writes = 1. + * However, if that doesn't work or if you are using a slow SPI clock + * speed, you may want to use 0 here. */ + u16 use_dummy_writes; + + /* Board specific setup/teardown */ + int (*setup)(struct spi_device *spi); + int (*teardown)(struct spi_device *spi); +}; +#endif diff --git a/include/compat/linux/ssb/ssb.h b/include/compat/linux/ssb/ssb.h new file mode 100644 index 00000000..061e5602 --- /dev/null +++ b/include/compat/linux/ssb/ssb.h @@ -0,0 +1,538 @@ +#ifndef LINUX_SSB_H_ +#define LINUX_SSB_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + + +struct pcmcia_device; +struct ssb_bus; +struct ssb_driver; + +struct ssb_sprom { + u8 revision; + u8 il0mac[6]; /* MAC address for 802.11b/g */ + u8 et0mac[6]; /* MAC address for Ethernet */ + u8 et1mac[6]; /* MAC address for 802.11a */ + u8 et0phyaddr; /* MII address for enet0 */ + u8 et1phyaddr; /* MII address for enet1 */ + u8 et0mdcport; /* MDIO for enet0 */ + u8 et1mdcport; /* MDIO for enet1 */ + u16 board_rev; /* Board revision number from SPROM. */ + u8 country_code; /* Country Code */ + u16 leddc_on_time; /* LED Powersave Duty Cycle On Count */ + u16 leddc_off_time; /* LED Powersave Duty Cycle Off Count */ + u8 ant_available_a; /* 2GHz antenna available bits (up to 4) */ + u8 ant_available_bg; /* 5GHz antenna available bits (up to 4) */ + u16 pa0b0; + u16 pa0b1; + u16 pa0b2; + u16 pa1b0; + u16 pa1b1; + u16 pa1b2; + u16 pa1lob0; + u16 pa1lob1; + u16 pa1lob2; + u16 pa1hib0; + u16 pa1hib1; + u16 pa1hib2; + u8 gpio0; /* GPIO pin 0 */ + u8 gpio1; /* GPIO pin 1 */ + u8 gpio2; /* GPIO pin 2 */ + u8 gpio3; /* GPIO pin 3 */ + u16 maxpwr_bg; /* 2.4GHz Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_al; /* 5.2GHz Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_a; /* 5.3GHz Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_ah; /* 5.8GHz Amplifier Max Power (in dBm Q5.2) */ + u8 itssi_a; /* Idle TSSI Target for A-PHY */ + u8 itssi_bg; /* Idle TSSI Target for B/G-PHY */ + u8 tri2g; /* 2.4GHz TX isolation */ + u8 tri5gl; /* 5.2GHz TX isolation */ + u8 tri5g; /* 5.3GHz TX isolation */ + u8 tri5gh; /* 5.8GHz TX isolation */ + u8 txpid2g[4]; /* 2GHz TX power index */ + u8 txpid5gl[4]; /* 4.9 - 5.1GHz TX power index */ + u8 txpid5g[4]; /* 5.1 - 5.5GHz TX power index */ + u8 txpid5gh[4]; /* 5.5 - ...GHz TX power index */ + u8 rxpo2g; /* 2GHz RX power offset */ + u8 rxpo5g; /* 5GHz RX power offset */ + u8 rssisav2g; /* 2GHz RSSI params */ + u8 rssismc2g; + u8 rssismf2g; + u8 bxa2g; /* 2GHz BX arch */ + u8 rssisav5g; /* 5GHz RSSI params */ + u8 rssismc5g; + u8 rssismf5g; + u8 bxa5g; /* 5GHz BX arch */ + u16 cck2gpo; /* CCK power offset */ + u32 ofdm2gpo; /* 2.4GHz OFDM power offset */ + u32 ofdm5glpo; /* 5.2GHz OFDM power offset */ + u32 ofdm5gpo; /* 5.3GHz OFDM power offset */ + u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */ + u16 boardflags_lo; /* Board flags (bits 0-15) */ + u16 boardflags_hi; /* Board flags (bits 16-31) */ + u16 boardflags2_lo; /* Board flags (bits 32-47) */ + u16 boardflags2_hi; /* Board flags (bits 48-63) */ + /* TODO store board flags in a single u64 */ + + /* Antenna gain values for up to 4 antennas + * on each band. Values in dBm/4 (Q5.2). Negative gain means the + * loss in the connectors is bigger than the gain. */ + struct { + struct { + s8 a0, a1, a2, a3; + } ghz24; /* 2.4GHz band */ + struct { + s8 a0, a1, a2, a3; + } ghz5; /* 5GHz band */ + } antenna_gain; + + /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */ +}; + +/* Information about the PCB the circuitry is soldered on. */ +struct ssb_boardinfo { + u16 vendor; + u16 type; + u8 rev; +}; + + +struct ssb_device; +/* Lowlevel read/write operations on the device MMIO. + * Internal, don't use that outside of ssb. */ +struct ssb_bus_ops { + u8 (*read8)(struct ssb_device *dev, u16 offset); + u16 (*read16)(struct ssb_device *dev, u16 offset); + u32 (*read32)(struct ssb_device *dev, u16 offset); + void (*write8)(struct ssb_device *dev, u16 offset, u8 value); + void (*write16)(struct ssb_device *dev, u16 offset, u16 value); + void (*write32)(struct ssb_device *dev, u16 offset, u32 value); +#ifdef CONFIG_SSB_BLOCKIO + void (*block_read)(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width); + void (*block_write)(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width); +#endif +}; + + +/* Core-ID values. */ +#define SSB_DEV_CHIPCOMMON 0x800 +#define SSB_DEV_ILINE20 0x801 +#define SSB_DEV_SDRAM 0x803 +#define SSB_DEV_PCI 0x804 +#define SSB_DEV_MIPS 0x805 +#define SSB_DEV_ETHERNET 0x806 +#define SSB_DEV_V90 0x807 +#define SSB_DEV_USB11_HOSTDEV 0x808 +#define SSB_DEV_ADSL 0x809 +#define SSB_DEV_ILINE100 0x80A +#define SSB_DEV_IPSEC 0x80B +#define SSB_DEV_PCMCIA 0x80D +#define SSB_DEV_INTERNAL_MEM 0x80E +#define SSB_DEV_MEMC_SDRAM 0x80F +#define SSB_DEV_EXTIF 0x811 +#define SSB_DEV_80211 0x812 +#define SSB_DEV_MIPS_3302 0x816 +#define SSB_DEV_USB11_HOST 0x817 +#define SSB_DEV_USB11_DEV 0x818 +#define SSB_DEV_USB20_HOST 0x819 +#define SSB_DEV_USB20_DEV 0x81A +#define SSB_DEV_SDIO_HOST 0x81B +#define SSB_DEV_ROBOSWITCH 0x81C +#define SSB_DEV_PARA_ATA 0x81D +#define SSB_DEV_SATA_XORDMA 0x81E +#define SSB_DEV_ETHERNET_GBIT 0x81F +#define SSB_DEV_PCIE 0x820 +#define SSB_DEV_MIMO_PHY 0x821 +#define SSB_DEV_SRAM_CTRLR 0x822 +#define SSB_DEV_MINI_MACPHY 0x823 +#define SSB_DEV_ARM_1176 0x824 +#define SSB_DEV_ARM_7TDMI 0x825 + +/* Vendor-ID values */ +#define SSB_VENDOR_BROADCOM 0x4243 + +/* Some kernel subsystems poke with dev->drvdata, so we must use the + * following ugly workaround to get from struct device to struct ssb_device */ +struct __ssb_dev_wrapper { + struct device dev; + struct ssb_device *sdev; +}; + +struct ssb_device { + /* Having a copy of the ops pointer in each dev struct + * is an optimization. */ + const struct ssb_bus_ops *ops; + + struct device *dev, *dma_dev; + + struct ssb_bus *bus; + struct ssb_device_id id; + + u8 core_index; + unsigned int irq; + + /* Internal-only stuff follows. */ + void *drvdata; /* Per-device data */ + void *devtypedata; /* Per-devicetype (eg 802.11) data */ +}; + +/* Go from struct device to struct ssb_device. */ +static inline +struct ssb_device * dev_to_ssb_dev(struct device *dev) +{ + struct __ssb_dev_wrapper *wrap; + wrap = container_of(dev, struct __ssb_dev_wrapper, dev); + return wrap->sdev; +} + +/* Device specific user data */ +static inline +void ssb_set_drvdata(struct ssb_device *dev, void *data) +{ + dev->drvdata = data; +} +static inline +void * ssb_get_drvdata(struct ssb_device *dev) +{ + return dev->drvdata; +} + +/* Devicetype specific user data. This is per device-type (not per device) */ +void ssb_set_devtypedata(struct ssb_device *dev, void *data); +static inline +void * ssb_get_devtypedata(struct ssb_device *dev) +{ + return dev->devtypedata; +} + + +struct ssb_driver { + const char *name; + const struct ssb_device_id *id_table; + + int (*probe)(struct ssb_device *dev, const struct ssb_device_id *id); + void (*remove)(struct ssb_device *dev); + int (*suspend)(struct ssb_device *dev, pm_message_t state); + int (*resume)(struct ssb_device *dev); + void (*shutdown)(struct ssb_device *dev); + + struct device_driver drv; +}; +#define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv) + +extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner); +#define ssb_driver_register(drv) \ + __ssb_driver_register(drv, THIS_MODULE) + +extern void ssb_driver_unregister(struct ssb_driver *drv); + + + + +enum ssb_bustype { + SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */ + SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */ + SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */ + SSB_BUSTYPE_SDIO, /* SSB is connected to SDIO bus */ +}; + +/* board_vendor */ +#define SSB_BOARDVENDOR_BCM 0x14E4 /* Broadcom */ +#define SSB_BOARDVENDOR_DELL 0x1028 /* Dell */ +#define SSB_BOARDVENDOR_HP 0x0E11 /* HP */ +/* board_type */ +#define SSB_BOARD_BCM94306MP 0x0418 +#define SSB_BOARD_BCM4309G 0x0421 +#define SSB_BOARD_BCM4306CB 0x0417 +#define SSB_BOARD_BCM4309MP 0x040C +#define SSB_BOARD_MP4318 0x044A +#define SSB_BOARD_BU4306 0x0416 +#define SSB_BOARD_BU4309 0x040A +/* chip_package */ +#define SSB_CHIPPACK_BCM4712S 1 /* Small 200pin 4712 */ +#define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */ +#define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */ + +#include +#include +#include +#include + +struct ssb_bus { + /* The MMIO area. */ + void __iomem *mmio; + + const struct ssb_bus_ops *ops; + + /* The core currently mapped into the MMIO window. + * Not valid on all host-buses. So don't use outside of SSB. */ + struct ssb_device *mapped_device; + union { + /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */ + u8 mapped_pcmcia_seg; + /* Current SSB base address window for SDIO. */ + u32 sdio_sbaddr; + }; + /* Lock for core and segment switching. + * On PCMCIA-host busses this is used to protect the whole MMIO access. */ + spinlock_t bar_lock; + + /* The host-bus this backplane is running on. */ + enum ssb_bustype bustype; + /* Pointers to the host-bus. Check bustype before using any of these pointers. */ + union { + /* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */ + struct pci_dev *host_pci; + /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ + struct pcmcia_device *host_pcmcia; + /* Pointer to the SDIO device (only if bustype == SSB_BUSTYPE_SDIO). */ + struct sdio_func *host_sdio; + }; + + /* See enum ssb_quirks */ + unsigned int quirks; + +#ifdef CONFIG_SSB_SPROM + /* Mutex to protect the SPROM writing. */ + struct mutex sprom_mutex; +#endif + + /* ID information about the Chip. */ + u16 chip_id; + u8 chip_rev; + u16 sprom_offset; + u16 sprom_size; /* number of words in sprom */ + u8 chip_package; + + /* List of devices (cores) on the backplane. */ + struct ssb_device devices[SSB_MAX_NR_CORES]; + u8 nr_devices; + + /* Software ID number for this bus. */ + unsigned int busnumber; + + /* The ChipCommon device (if available). */ + struct ssb_chipcommon chipco; + /* The PCI-core device (if available). */ + struct ssb_pcicore pcicore; + /* The MIPS-core device (if available). */ + struct ssb_mipscore mipscore; + /* The EXTif-core device (if available). */ + struct ssb_extif extif; + + /* The following structure elements are not available in early + * SSB initialization. Though, they are available for regular + * registered drivers at any stage. So be careful when + * using them in the ssb core code. */ + + /* ID information about the PCB. */ + struct ssb_boardinfo boardinfo; + /* Contents of the SPROM. */ + struct ssb_sprom sprom; + /* If the board has a cardbus slot, this is set to true. */ + bool has_cardbus_slot; + +#ifdef CONFIG_SSB_EMBEDDED + /* Lock for GPIO register access. */ + spinlock_t gpio_lock; +#endif /* EMBEDDED */ + + /* Internal-only stuff follows. Do not touch. */ + struct list_head list; +#ifdef CONFIG_SSB_DEBUG + /* Is the bus already powered up? */ + bool powered_up; + int power_warn_count; +#endif /* DEBUG */ +}; + +enum ssb_quirks { + /* SDIO connected card requires performing a read after writing a 32-bit value */ + SSB_QUIRK_SDIO_READ_AFTER_WRITE32 = (1 << 0), +}; + +/* The initialization-invariants. */ +struct ssb_init_invariants { + /* Versioning information about the PCB. */ + struct ssb_boardinfo boardinfo; + /* The SPROM information. That's either stored in an + * EEPROM or NVRAM on the board. */ + struct ssb_sprom sprom; + /* If the board has a cardbus slot, this is set to true. */ + bool has_cardbus_slot; +}; +/* Type of function to fetch the invariants. */ +typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus, + struct ssb_init_invariants *iv); + +/* Register a SSB system bus. get_invariants() is called after the + * basic system devices are initialized. + * The invariants are usually fetched from some NVRAM. + * Put the invariants into the struct pointed to by iv. */ +extern int ssb_bus_ssbbus_register(struct ssb_bus *bus, + unsigned long baseaddr, + ssb_invariants_func_t get_invariants); +#ifdef CONFIG_SSB_PCIHOST +extern int ssb_bus_pcibus_register(struct ssb_bus *bus, + struct pci_dev *host_pci); +#endif /* CONFIG_SSB_PCIHOST */ +#ifdef CONFIG_SSB_PCMCIAHOST +extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, + struct pcmcia_device *pcmcia_dev, + unsigned long baseaddr); +#endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +extern int ssb_bus_sdiobus_register(struct ssb_bus *bus, + struct sdio_func *sdio_func, + unsigned int quirks); +#endif /* CONFIG_SSB_SDIOHOST */ + + +extern void ssb_bus_unregister(struct ssb_bus *bus); + +/* Does the device have an SPROM? */ +extern bool ssb_is_sprom_available(struct ssb_bus *bus); + +/* Set a fallback SPROM. + * See kdoc at the function definition for complete documentation. */ +extern int ssb_arch_register_fallback_sprom( + int (*sprom_callback)(struct ssb_bus *bus, + struct ssb_sprom *out)); + +/* Suspend a SSB bus. + * Call this from the parent bus suspend routine. */ +extern int ssb_bus_suspend(struct ssb_bus *bus); +/* Resume a SSB bus. + * Call this from the parent bus resume routine. */ +extern int ssb_bus_resume(struct ssb_bus *bus); + +extern u32 ssb_clockspeed(struct ssb_bus *bus); + +/* Is the device enabled in hardware? */ +int ssb_device_is_enabled(struct ssb_device *dev); +/* Enable a device and pass device-specific SSB_TMSLOW flags. + * If no device-specific flags are available, use 0. */ +void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags); +/* Disable a device in hardware and pass SSB_TMSLOW flags (if any). */ +void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags); + + +/* Device MMIO register read/write functions. */ +static inline u8 ssb_read8(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read8(dev, offset); +} +static inline u16 ssb_read16(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read16(dev, offset); +} +static inline u32 ssb_read32(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read32(dev, offset); +} +static inline void ssb_write8(struct ssb_device *dev, u16 offset, u8 value) +{ + dev->ops->write8(dev, offset, value); +} +static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + dev->ops->write16(dev, offset, value); +} +static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + dev->ops->write32(dev, offset, value); +} +#ifdef CONFIG_SSB_BLOCKIO +static inline void ssb_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + dev->ops->block_read(dev, buffer, count, offset, reg_width); +} + +static inline void ssb_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + dev->ops->block_write(dev, buffer, count, offset, reg_width); +} +#endif /* CONFIG_SSB_BLOCKIO */ + + +/* The SSB DMA API. Use this API for any DMA operation on the device. + * This API basically is a wrapper that calls the correct DMA API for + * the host device type the SSB device is attached to. */ + +/* Translation (routing) bits that need to be ORed to DMA + * addresses before they are given to a device. */ +extern u32 ssb_dma_translation(struct ssb_device *dev); +#define SSB_DMA_TRANSLATION_MASK 0xC0000000 +#define SSB_DMA_TRANSLATION_SHIFT 30 + +static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev) +{ +#ifdef CONFIG_SSB_DEBUG + printk(KERN_ERR "SSB: BUG! Calling DMA API for " + "unsupported bustype %d\n", dev->bus->bustype); +#endif /* DEBUG */ +} + +#ifdef CONFIG_SSB_PCIHOST +/* PCI-host wrapper driver */ +extern int ssb_pcihost_register(struct pci_driver *driver); +static inline void ssb_pcihost_unregister(struct pci_driver *driver) +{ + pci_unregister_driver(driver); +} + +static inline +void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state) +{ + if (sdev->bus->bustype == SSB_BUSTYPE_PCI) + pci_set_power_state(sdev->bus->host_pci, state); +} +#else +static inline void ssb_pcihost_unregister(struct pci_driver *driver) +{ +} + +static inline +void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state) +{ +} +#endif /* CONFIG_SSB_PCIHOST */ + + +/* If a driver is shutdown or suspended, call this to signal + * that the bus may be completely powered down. SSB will decide, + * if it's really time to power down the bus, based on if there + * are other devices that want to run. */ +extern int ssb_bus_may_powerdown(struct ssb_bus *bus); +/* Before initializing and enabling a device, call this to power-up the bus. + * If you want to allow use of dynamic-power-control, pass the flag. + * Otherwise static always-on powercontrol will be used. */ +extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl); + +extern void ssb_commit_settings(struct ssb_bus *bus); + +/* Various helper functions */ +extern u32 ssb_admatch_base(u32 adm); +extern u32 ssb_admatch_size(u32 adm); + +/* PCI device mapping and fixup routines. + * Called from the architecture pcibios init code. + * These are only available on SSB_EMBEDDED configurations. */ +#ifdef CONFIG_SSB_EMBEDDED +int ssb_pcibios_plat_dev_init(struct pci_dev *dev); +int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); +#endif /* CONFIG_SSB_EMBEDDED */ + +#endif /* LINUX_SSB_H_ */ diff --git a/include/compat/linux/ssb/ssb_driver_chipcommon.h b/include/compat/linux/ssb/ssb_driver_chipcommon.h new file mode 100644 index 00000000..1a6b0045 --- /dev/null +++ b/include/compat/linux/ssb/ssb_driver_chipcommon.h @@ -0,0 +1,665 @@ +#ifndef LINUX_SSB_CHIPCO_H_ +#define LINUX_SSB_CHIPCO_H_ + +/* SonicsSiliconBackplane CHIPCOMMON core hardware definitions + * + * The chipcommon core provides chip identification, SB control, + * jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer, + * gpio interface, extbus, and support for serial and parallel flashes. + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, Michael Buesch + * + * Licensed under the GPL version 2. See COPYING for details. + */ + +/** ChipCommon core registers. **/ + +#define SSB_CHIPCO_CHIPID 0x0000 +#define SSB_CHIPCO_IDMASK 0x0000FFFF +#define SSB_CHIPCO_REVMASK 0x000F0000 +#define SSB_CHIPCO_REVSHIFT 16 +#define SSB_CHIPCO_PACKMASK 0x00F00000 +#define SSB_CHIPCO_PACKSHIFT 20 +#define SSB_CHIPCO_NRCORESMASK 0x0F000000 +#define SSB_CHIPCO_NRCORESSHIFT 24 +#define SSB_CHIPCO_CAP 0x0004 /* Capabilities */ +#define SSB_CHIPCO_CAP_NRUART 0x00000003 /* # of UARTs */ +#define SSB_CHIPCO_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */ +#define SSB_CHIPCO_CAP_UARTCLK 0x00000018 /* UART clock select */ +#define SSB_CHIPCO_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */ +#define SSB_CHIPCO_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */ +#define SSB_CHIPCO_CAP_EXTBUS 0x000000C0 /* External buses present */ +#define SSB_CHIPCO_CAP_FLASHT 0x00000700 /* Flash Type */ +#define SSB_CHIPCO_FLASHT_NONE 0x00000000 /* No flash */ +#define SSB_CHIPCO_FLASHT_STSER 0x00000100 /* ST serial flash */ +#define SSB_CHIPCO_FLASHT_ATSER 0x00000200 /* Atmel serial flash */ +#define SSB_CHIPCO_FLASHT_PARA 0x00000700 /* Parallel flash */ +#define SSB_CHIPCO_CAP_PLLT 0x00038000 /* PLL Type */ +#define SSB_PLLTYPE_NONE 0x00000000 +#define SSB_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */ +#define SSB_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */ +#define SSB_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */ +#define SSB_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */ +#define SSB_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */ +#define SSB_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */ +#define SSB_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */ +#define SSB_CHIPCO_CAP_PCTL 0x00040000 /* Power Control */ +#define SSB_CHIPCO_CAP_OTPS 0x00380000 /* OTP size */ +#define SSB_CHIPCO_CAP_OTPS_SHIFT 19 +#define SSB_CHIPCO_CAP_OTPS_BASE 5 +#define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */ +#define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */ +#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */ +#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ +#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ +#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */ +#define SSB_CHIPCO_CORECTL 0x0008 +#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ +#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define SSB_CHIPCO_CORECTL_UARTCLKEN 0x00000008 /* UART clock enable (rev >= 21) */ +#define SSB_CHIPCO_BIST 0x000C +#define SSB_CHIPCO_OTPS 0x0010 /* OTP status */ +#define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000 +#define SSB_CHIPCO_OTPS_PROTECT 0x00000007 +#define SSB_CHIPCO_OTPS_HW_PROTECT 0x00000001 +#define SSB_CHIPCO_OTPS_SW_PROTECT 0x00000002 +#define SSB_CHIPCO_OTPS_CID_PROTECT 0x00000004 +#define SSB_CHIPCO_OTPC 0x0014 /* OTP control */ +#define SSB_CHIPCO_OTPC_RECWAIT 0xFF000000 +#define SSB_CHIPCO_OTPC_PROGWAIT 0x00FFFF00 +#define SSB_CHIPCO_OTPC_PRW_SHIFT 8 +#define SSB_CHIPCO_OTPC_MAXFAIL 0x00000038 +#define SSB_CHIPCO_OTPC_VSEL 0x00000006 +#define SSB_CHIPCO_OTPC_SELVL 0x00000001 +#define SSB_CHIPCO_OTPP 0x0018 /* OTP prog */ +#define SSB_CHIPCO_OTPP_COL 0x000000FF +#define SSB_CHIPCO_OTPP_ROW 0x0000FF00 +#define SSB_CHIPCO_OTPP_ROW_SHIFT 8 +#define SSB_CHIPCO_OTPP_READERR 0x10000000 +#define SSB_CHIPCO_OTPP_VALUE 0x20000000 +#define SSB_CHIPCO_OTPP_READ 0x40000000 +#define SSB_CHIPCO_OTPP_START 0x80000000 +#define SSB_CHIPCO_OTPP_BUSY 0x80000000 +#define SSB_CHIPCO_IRQSTAT 0x0020 +#define SSB_CHIPCO_IRQMASK 0x0024 +#define SSB_CHIPCO_IRQ_GPIO 0x00000001 /* gpio intr */ +#define SSB_CHIPCO_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */ +#define SSB_CHIPCO_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */ +#define SSB_CHIPCO_CHIPCTL 0x0028 /* Rev >= 11 only */ +#define SSB_CHIPCO_CHIPSTAT 0x002C /* Rev >= 11 only */ +#define SSB_CHIPCO_JCMD 0x0030 /* Rev >= 10 only */ +#define SSB_CHIPCO_JCMD_START 0x80000000 +#define SSB_CHIPCO_JCMD_BUSY 0x80000000 +#define SSB_CHIPCO_JCMD_PAUSE 0x40000000 +#define SSB_CHIPCO_JCMD0_ACC_MASK 0x0000F000 +#define SSB_CHIPCO_JCMD0_ACC_IRDR 0x00000000 +#define SSB_CHIPCO_JCMD0_ACC_DR 0x00001000 +#define SSB_CHIPCO_JCMD0_ACC_IR 0x00002000 +#define SSB_CHIPCO_JCMD0_ACC_RESET 0x00003000 +#define SSB_CHIPCO_JCMD0_ACC_IRPDR 0x00004000 +#define SSB_CHIPCO_JCMD0_ACC_PDR 0x00005000 +#define SSB_CHIPCO_JCMD0_IRW_MASK 0x00000F00 +#define SSB_CHIPCO_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */ +#define SSB_CHIPCO_JCMD_ACC_IRDR 0x00000000 +#define SSB_CHIPCO_JCMD_ACC_DR 0x00010000 +#define SSB_CHIPCO_JCMD_ACC_IR 0x00020000 +#define SSB_CHIPCO_JCMD_ACC_RESET 0x00030000 +#define SSB_CHIPCO_JCMD_ACC_IRPDR 0x00040000 +#define SSB_CHIPCO_JCMD_ACC_PDR 0x00050000 +#define SSB_CHIPCO_JCMD_IRW_MASK 0x00001F00 +#define SSB_CHIPCO_JCMD_IRW_SHIFT 8 +#define SSB_CHIPCO_JCMD_DRW_MASK 0x0000003F +#define SSB_CHIPCO_JIR 0x0034 /* Rev >= 10 only */ +#define SSB_CHIPCO_JDR 0x0038 /* Rev >= 10 only */ +#define SSB_CHIPCO_JCTL 0x003C /* Rev >= 10 only */ +#define SSB_CHIPCO_JCTL_FORCE_CLK 4 /* Force clock */ +#define SSB_CHIPCO_JCTL_EXT_EN 2 /* Enable external targets */ +#define SSB_CHIPCO_JCTL_EN 1 /* Enable Jtag master */ +#define SSB_CHIPCO_FLASHCTL 0x0040 +#define SSB_CHIPCO_FLASHCTL_START 0x80000000 +#define SSB_CHIPCO_FLASHCTL_BUSY SSB_CHIPCO_FLASHCTL_START +#define SSB_CHIPCO_FLASHADDR 0x0044 +#define SSB_CHIPCO_FLASHDATA 0x0048 +#define SSB_CHIPCO_BCAST_ADDR 0x0050 +#define SSB_CHIPCO_BCAST_DATA 0x0054 +#define SSB_CHIPCO_GPIOPULLUP 0x0058 /* Rev >= 20 only */ +#define SSB_CHIPCO_GPIOPULLDOWN 0x005C /* Rev >= 20 only */ +#define SSB_CHIPCO_GPIOIN 0x0060 +#define SSB_CHIPCO_GPIOOUT 0x0064 +#define SSB_CHIPCO_GPIOOUTEN 0x0068 +#define SSB_CHIPCO_GPIOCTL 0x006C +#define SSB_CHIPCO_GPIOPOL 0x0070 +#define SSB_CHIPCO_GPIOIRQ 0x0074 +#define SSB_CHIPCO_WATCHDOG 0x0080 +#define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_GPIOTIMER_OFFTIME 0x0000FFFF +#define SSB_CHIPCO_GPIOTIMER_OFFTIME_SHIFT 0 +#define SSB_CHIPCO_GPIOTIMER_ONTIME 0xFFFF0000 +#define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16 +#define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_CLOCK_N 0x0090 +#define SSB_CHIPCO_CLOCK_SB 0x0094 +#define SSB_CHIPCO_CLOCK_PCI 0x0098 +#define SSB_CHIPCO_CLOCK_M2 0x009C +#define SSB_CHIPCO_CLOCK_MIPS 0x00A0 +#define SSB_CHIPCO_CLKDIV 0x00A4 /* Rev >= 3 only */ +#define SSB_CHIPCO_CLKDIV_SFLASH 0x0F000000 +#define SSB_CHIPCO_CLKDIV_SFLASH_SHIFT 24 +#define SSB_CHIPCO_CLKDIV_OTP 0x000F0000 +#define SSB_CHIPCO_CLKDIV_OTP_SHIFT 16 +#define SSB_CHIPCO_CLKDIV_JTAG 0x00000F00 +#define SSB_CHIPCO_CLKDIV_JTAG_SHIFT 8 +#define SSB_CHIPCO_CLKDIV_UART 0x000000FF +#define SSB_CHIPCO_PLLONDELAY 0x00B0 /* Rev >= 4 only */ +#define SSB_CHIPCO_FREFSELDELAY 0x00B4 /* Rev >= 4 only */ +#define SSB_CHIPCO_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */ +#define SSB_CHIPCO_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */ +#define SSB_CHIPCO_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define SSB_CHIPCO_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ +#define SSB_CHIPCO_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ +#define SSB_CHIPCO_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */ +#define SSB_CHIPCO_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */ +#define SSB_CHIPCO_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV_SHIFT 16 +#define SSB_CHIPCO_SYSCLKCTL 0x00C0 /* Rev >= 3 only */ +#define SSB_CHIPCO_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */ +#define SSB_CHIPCO_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */ +#define SSB_CHIPCO_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */ +#define SSB_CHIPCO_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define SSB_CHIPCO_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */ +#define SSB_CHIPCO_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */ +#define SSB_CHIPCO_SYSCLKCTL_CLKDIV_SHIFT 16 +#define SSB_CHIPCO_CLKSTSTR 0x00C4 /* Rev >= 3 only */ +#define SSB_CHIPCO_PCMCIA_CFG 0x0100 +#define SSB_CHIPCO_PCMCIA_MEMWAIT 0x0104 +#define SSB_CHIPCO_PCMCIA_ATTRWAIT 0x0108 +#define SSB_CHIPCO_PCMCIA_IOWAIT 0x010C +#define SSB_CHIPCO_IDE_CFG 0x0110 +#define SSB_CHIPCO_IDE_MEMWAIT 0x0114 +#define SSB_CHIPCO_IDE_ATTRWAIT 0x0118 +#define SSB_CHIPCO_IDE_IOWAIT 0x011C +#define SSB_CHIPCO_PROG_CFG 0x0120 +#define SSB_CHIPCO_PROG_WAITCNT 0x0124 +#define SSB_CHIPCO_FLASH_CFG 0x0128 +#define SSB_CHIPCO_FLASH_WAITCNT 0x012C +#define SSB_CHIPCO_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */ +#define SSB_CHIPCO_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */ +#define SSB_CHIPCO_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */ +#define SSB_CHIPCO_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */ +#define SSB_CHIPCO_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ +#define SSB_CHIPCO_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ +#define SSB_CHIPCO_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ +#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00010000 /* ALP available */ +#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00020000 /* HT available */ +#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */ +#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */ +#define SSB_CHIPCO_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ +#define SSB_CHIPCO_UART0_DATA 0x0300 +#define SSB_CHIPCO_UART0_IMR 0x0304 +#define SSB_CHIPCO_UART0_FCR 0x0308 +#define SSB_CHIPCO_UART0_LCR 0x030C +#define SSB_CHIPCO_UART0_MCR 0x0310 +#define SSB_CHIPCO_UART0_LSR 0x0314 +#define SSB_CHIPCO_UART0_MSR 0x0318 +#define SSB_CHIPCO_UART0_SCRATCH 0x031C +#define SSB_CHIPCO_UART1_DATA 0x0400 +#define SSB_CHIPCO_UART1_IMR 0x0404 +#define SSB_CHIPCO_UART1_FCR 0x0408 +#define SSB_CHIPCO_UART1_LCR 0x040C +#define SSB_CHIPCO_UART1_MCR 0x0410 +#define SSB_CHIPCO_UART1_LSR 0x0414 +#define SSB_CHIPCO_UART1_MSR 0x0418 +#define SSB_CHIPCO_UART1_SCRATCH 0x041C +/* PMU registers (rev >= 20) */ +#define SSB_CHIPCO_PMU_CTL 0x0600 /* PMU control */ +#define SSB_CHIPCO_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */ +#define SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT 16 +#define SSB_CHIPCO_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */ +#define SSB_CHIPCO_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */ +#define SSB_CHIPCO_PMU_CTL_ALPREQEN 0x00000080 /* ALP req enable */ +#define SSB_CHIPCO_PMU_CTL_XTALFREQ 0x0000007C /* Crystal freq */ +#define SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT 2 +#define SSB_CHIPCO_PMU_CTL_ILPDIVEN 0x00000002 /* ILP div enable */ +#define SSB_CHIPCO_PMU_CTL_LPOSEL 0x00000001 /* LPO sel */ +#define SSB_CHIPCO_PMU_CAP 0x0604 /* PMU capabilities */ +#define SSB_CHIPCO_PMU_CAP_REVISION 0x000000FF /* Revision mask */ +#define SSB_CHIPCO_PMU_STAT 0x0608 /* PMU status */ +#define SSB_CHIPCO_PMU_STAT_INTPEND 0x00000040 /* Interrupt pending */ +#define SSB_CHIPCO_PMU_STAT_SBCLKST 0x00000030 /* Backplane clock status? */ +#define SSB_CHIPCO_PMU_STAT_HAVEALP 0x00000008 /* ALP available */ +#define SSB_CHIPCO_PMU_STAT_HAVEHT 0x00000004 /* HT available */ +#define SSB_CHIPCO_PMU_STAT_RESINIT 0x00000003 /* Res init */ +#define SSB_CHIPCO_PMU_RES_STAT 0x060C /* PMU res status */ +#define SSB_CHIPCO_PMU_RES_PEND 0x0610 /* PMU res pending */ +#define SSB_CHIPCO_PMU_TIMER 0x0614 /* PMU timer */ +#define SSB_CHIPCO_PMU_MINRES_MSK 0x0618 /* PMU min res mask */ +#define SSB_CHIPCO_PMU_MAXRES_MSK 0x061C /* PMU max res mask */ +#define SSB_CHIPCO_PMU_RES_TABSEL 0x0620 /* PMU res table sel */ +#define SSB_CHIPCO_PMU_RES_DEPMSK 0x0624 /* PMU res dep mask */ +#define SSB_CHIPCO_PMU_RES_UPDNTM 0x0628 /* PMU res updown timer */ +#define SSB_CHIPCO_PMU_RES_TIMER 0x062C /* PMU res timer */ +#define SSB_CHIPCO_PMU_CLKSTRETCH 0x0630 /* PMU clockstretch */ +#define SSB_CHIPCO_PMU_WATCHDOG 0x0634 /* PMU watchdog */ +#define SSB_CHIPCO_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */ +#define SSB_CHIPCO_PMU_RES_REQT 0x0644 /* PMU res req timer */ +#define SSB_CHIPCO_PMU_RES_REQM 0x0648 /* PMU res req mask */ +#define SSB_CHIPCO_CHIPCTL_ADDR 0x0650 +#define SSB_CHIPCO_CHIPCTL_DATA 0x0654 +#define SSB_CHIPCO_REGCTL_ADDR 0x0658 +#define SSB_CHIPCO_REGCTL_DATA 0x065C +#define SSB_CHIPCO_PLLCTL_ADDR 0x0660 +#define SSB_CHIPCO_PLLCTL_DATA 0x0664 + + + +/** PMU PLL registers */ + +/* PMU rev 0 PLL registers */ +#define SSB_PMU0_PLLCTL0 0 +#define SSB_PMU0_PLLCTL0_PDIV_MSK 0x00000001 +#define SSB_PMU0_PLLCTL0_PDIV_FREQ 25000 /* kHz */ +#define SSB_PMU0_PLLCTL1 1 +#define SSB_PMU0_PLLCTL1_WILD_IMSK 0xF0000000 /* Wild int mask (low nibble) */ +#define SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT 28 +#define SSB_PMU0_PLLCTL1_WILD_FMSK 0x0FFFFF00 /* Wild frac mask */ +#define SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT 8 +#define SSB_PMU0_PLLCTL1_STOPMOD 0x00000040 /* Stop mod */ +#define SSB_PMU0_PLLCTL2 2 +#define SSB_PMU0_PLLCTL2_WILD_IMSKHI 0x0000000F /* Wild int mask (high nibble) */ +#define SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT 0 + +/* PMU rev 1 PLL registers */ +#define SSB_PMU1_PLLCTL0 0 +#define SSB_PMU1_PLLCTL0_P1DIV 0x00F00000 /* P1 div */ +#define SSB_PMU1_PLLCTL0_P1DIV_SHIFT 20 +#define SSB_PMU1_PLLCTL0_P2DIV 0x0F000000 /* P2 div */ +#define SSB_PMU1_PLLCTL0_P2DIV_SHIFT 24 +#define SSB_PMU1_PLLCTL1 1 +#define SSB_PMU1_PLLCTL1_M1DIV 0x000000FF /* M1 div */ +#define SSB_PMU1_PLLCTL1_M1DIV_SHIFT 0 +#define SSB_PMU1_PLLCTL1_M2DIV 0x0000FF00 /* M2 div */ +#define SSB_PMU1_PLLCTL1_M2DIV_SHIFT 8 +#define SSB_PMU1_PLLCTL1_M3DIV 0x00FF0000 /* M3 div */ +#define SSB_PMU1_PLLCTL1_M3DIV_SHIFT 16 +#define SSB_PMU1_PLLCTL1_M4DIV 0xFF000000 /* M4 div */ +#define SSB_PMU1_PLLCTL1_M4DIV_SHIFT 24 +#define SSB_PMU1_PLLCTL2 2 +#define SSB_PMU1_PLLCTL2_M5DIV 0x000000FF /* M5 div */ +#define SSB_PMU1_PLLCTL2_M5DIV_SHIFT 0 +#define SSB_PMU1_PLLCTL2_M6DIV 0x0000FF00 /* M6 div */ +#define SSB_PMU1_PLLCTL2_M6DIV_SHIFT 8 +#define SSB_PMU1_PLLCTL2_NDIVMODE 0x000E0000 /* NDIV mode */ +#define SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT 17 +#define SSB_PMU1_PLLCTL2_NDIVINT 0x1FF00000 /* NDIV int */ +#define SSB_PMU1_PLLCTL2_NDIVINT_SHIFT 20 +#define SSB_PMU1_PLLCTL3 3 +#define SSB_PMU1_PLLCTL3_NDIVFRAC 0x00FFFFFF /* NDIV frac */ +#define SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT 0 +#define SSB_PMU1_PLLCTL4 4 +#define SSB_PMU1_PLLCTL5 5 +#define SSB_PMU1_PLLCTL5_CLKDRV 0xFFFFFF00 /* clk drv */ +#define SSB_PMU1_PLLCTL5_CLKDRV_SHIFT 8 + +/* BCM4312 PLL resource numbers. */ +#define SSB_PMURES_4312_SWITCHER_BURST 0 +#define SSB_PMURES_4312_SWITCHER_PWM 1 +#define SSB_PMURES_4312_PA_REF_LDO 2 +#define SSB_PMURES_4312_CORE_LDO_BURST 3 +#define SSB_PMURES_4312_CORE_LDO_PWM 4 +#define SSB_PMURES_4312_RADIO_LDO 5 +#define SSB_PMURES_4312_ILP_REQUEST 6 +#define SSB_PMURES_4312_BG_FILTBYP 7 +#define SSB_PMURES_4312_TX_FILTBYP 8 +#define SSB_PMURES_4312_RX_FILTBYP 9 +#define SSB_PMURES_4312_XTAL_PU 10 +#define SSB_PMURES_4312_ALP_AVAIL 11 +#define SSB_PMURES_4312_BB_PLL_FILTBYP 12 +#define SSB_PMURES_4312_RF_PLL_FILTBYP 13 +#define SSB_PMURES_4312_HT_AVAIL 14 + +/* BCM4325 PLL resource numbers. */ +#define SSB_PMURES_4325_BUCK_BOOST_BURST 0 +#define SSB_PMURES_4325_CBUCK_BURST 1 +#define SSB_PMURES_4325_CBUCK_PWM 2 +#define SSB_PMURES_4325_CLDO_CBUCK_BURST 3 +#define SSB_PMURES_4325_CLDO_CBUCK_PWM 4 +#define SSB_PMURES_4325_BUCK_BOOST_PWM 5 +#define SSB_PMURES_4325_ILP_REQUEST 6 +#define SSB_PMURES_4325_ABUCK_BURST 7 +#define SSB_PMURES_4325_ABUCK_PWM 8 +#define SSB_PMURES_4325_LNLDO1_PU 9 +#define SSB_PMURES_4325_LNLDO2_PU 10 +#define SSB_PMURES_4325_LNLDO3_PU 11 +#define SSB_PMURES_4325_LNLDO4_PU 12 +#define SSB_PMURES_4325_XTAL_PU 13 +#define SSB_PMURES_4325_ALP_AVAIL 14 +#define SSB_PMURES_4325_RX_PWRSW_PU 15 +#define SSB_PMURES_4325_TX_PWRSW_PU 16 +#define SSB_PMURES_4325_RFPLL_PWRSW_PU 17 +#define SSB_PMURES_4325_LOGEN_PWRSW_PU 18 +#define SSB_PMURES_4325_AFE_PWRSW_PU 19 +#define SSB_PMURES_4325_BBPLL_PWRSW_PU 20 +#define SSB_PMURES_4325_HT_AVAIL 21 + +/* BCM4328 PLL resource numbers. */ +#define SSB_PMURES_4328_EXT_SWITCHER_PWM 0 +#define SSB_PMURES_4328_BB_SWITCHER_PWM 1 +#define SSB_PMURES_4328_BB_SWITCHER_BURST 2 +#define SSB_PMURES_4328_BB_EXT_SWITCHER_BURST 3 +#define SSB_PMURES_4328_ILP_REQUEST 4 +#define SSB_PMURES_4328_RADIO_SWITCHER_PWM 5 +#define SSB_PMURES_4328_RADIO_SWITCHER_BURST 6 +#define SSB_PMURES_4328_ROM_SWITCH 7 +#define SSB_PMURES_4328_PA_REF_LDO 8 +#define SSB_PMURES_4328_RADIO_LDO 9 +#define SSB_PMURES_4328_AFE_LDO 10 +#define SSB_PMURES_4328_PLL_LDO 11 +#define SSB_PMURES_4328_BG_FILTBYP 12 +#define SSB_PMURES_4328_TX_FILTBYP 13 +#define SSB_PMURES_4328_RX_FILTBYP 14 +#define SSB_PMURES_4328_XTAL_PU 15 +#define SSB_PMURES_4328_XTAL_EN 16 +#define SSB_PMURES_4328_BB_PLL_FILTBYP 17 +#define SSB_PMURES_4328_RF_PLL_FILTBYP 18 +#define SSB_PMURES_4328_BB_PLL_PU 19 + +/* BCM5354 PLL resource numbers. */ +#define SSB_PMURES_5354_EXT_SWITCHER_PWM 0 +#define SSB_PMURES_5354_BB_SWITCHER_PWM 1 +#define SSB_PMURES_5354_BB_SWITCHER_BURST 2 +#define SSB_PMURES_5354_BB_EXT_SWITCHER_BURST 3 +#define SSB_PMURES_5354_ILP_REQUEST 4 +#define SSB_PMURES_5354_RADIO_SWITCHER_PWM 5 +#define SSB_PMURES_5354_RADIO_SWITCHER_BURST 6 +#define SSB_PMURES_5354_ROM_SWITCH 7 +#define SSB_PMURES_5354_PA_REF_LDO 8 +#define SSB_PMURES_5354_RADIO_LDO 9 +#define SSB_PMURES_5354_AFE_LDO 10 +#define SSB_PMURES_5354_PLL_LDO 11 +#define SSB_PMURES_5354_BG_FILTBYP 12 +#define SSB_PMURES_5354_TX_FILTBYP 13 +#define SSB_PMURES_5354_RX_FILTBYP 14 +#define SSB_PMURES_5354_XTAL_PU 15 +#define SSB_PMURES_5354_XTAL_EN 16 +#define SSB_PMURES_5354_BB_PLL_FILTBYP 17 +#define SSB_PMURES_5354_RF_PLL_FILTBYP 18 +#define SSB_PMURES_5354_BB_PLL_PU 19 + + + +/** Chip specific Chip-Status register contents. */ +#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS 0x00000040 /* SPROM present */ +#define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003 +#define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ +#define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ +#define SSB_CHIPCO_CHST_4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ +#define SSB_CHIPCO_CHST_4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ +#define SSB_CHIPCO_CHST_4325_SDIO_USB_MODE 0x00000004 +#define SSB_CHIPCO_CHST_4325_SDIO_USB_MODE_SHIFT 2 +#define SSB_CHIPCO_CHST_4325_RCAL_VALID 0x00000008 +#define SSB_CHIPCO_CHST_4325_RCAL_VALID_SHIFT 3 +#define SSB_CHIPCO_CHST_4325_RCAL_VALUE 0x000001F0 +#define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4 +#define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */ + +/** Macros to determine SPROM presence based on Chip-Status register. */ +#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \ + ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ + SSB_CHIPCO_CHST_4325_OTP_SEL) +#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \ + (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS) +#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \ + (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ + SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \ + ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ + SSB_CHIPCO_CHST_4325_OTP_SEL)) + + + +/** Clockcontrol masks and values **/ + +/* SSB_CHIPCO_CLOCK_N */ +#define SSB_CHIPCO_CLK_N1 0x0000003F /* n1 control */ +#define SSB_CHIPCO_CLK_N2 0x00003F00 /* n2 control */ +#define SSB_CHIPCO_CLK_N2_SHIFT 8 +#define SSB_CHIPCO_CLK_PLLC 0x000F0000 /* pll control */ +#define SSB_CHIPCO_CLK_PLLC_SHIFT 16 + +/* SSB_CHIPCO_CLOCK_SB/PCI/UART */ +#define SSB_CHIPCO_CLK_M1 0x0000003F /* m1 control */ +#define SSB_CHIPCO_CLK_M2 0x00003F00 /* m2 control */ +#define SSB_CHIPCO_CLK_M2_SHIFT 8 +#define SSB_CHIPCO_CLK_M3 0x003F0000 /* m3 control */ +#define SSB_CHIPCO_CLK_M3_SHIFT 16 +#define SSB_CHIPCO_CLK_MC 0x1F000000 /* mux control */ +#define SSB_CHIPCO_CLK_MC_SHIFT 24 + +/* N3M Clock control magic field values */ +#define SSB_CHIPCO_CLK_F6_2 0x02 /* A factor of 2 in */ +#define SSB_CHIPCO_CLK_F6_3 0x03 /* 6-bit fields like */ +#define SSB_CHIPCO_CLK_F6_4 0x05 /* N1, M1 or M3 */ +#define SSB_CHIPCO_CLK_F6_5 0x09 +#define SSB_CHIPCO_CLK_F6_6 0x11 +#define SSB_CHIPCO_CLK_F6_7 0x21 + +#define SSB_CHIPCO_CLK_F5_BIAS 5 /* 5-bit fields get this added */ + +#define SSB_CHIPCO_CLK_MC_BYPASS 0x08 +#define SSB_CHIPCO_CLK_MC_M1 0x04 +#define SSB_CHIPCO_CLK_MC_M1M2 0x02 +#define SSB_CHIPCO_CLK_MC_M1M2M3 0x01 +#define SSB_CHIPCO_CLK_MC_M1M3 0x11 + +/* Type 2 Clock control magic field values */ +#define SSB_CHIPCO_CLK_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ +#define SSB_CHIPCO_CLK_T2M2_BIAS 3 /* m2 bias */ + +#define SSB_CHIPCO_CLK_T2MC_M1BYP 1 +#define SSB_CHIPCO_CLK_T2MC_M2BYP 2 +#define SSB_CHIPCO_CLK_T2MC_M3BYP 4 + +/* Type 6 Clock control magic field values */ +#define SSB_CHIPCO_CLK_T6_MMASK 1 /* bits of interest in m */ +#define SSB_CHIPCO_CLK_T6_M0 120000000 /* sb clock for m = 0 */ +#define SSB_CHIPCO_CLK_T6_M1 100000000 /* sb clock for m = 1 */ +#define SSB_CHIPCO_CLK_SB2MIPS_T6(sb) (2 * (sb)) + +/* Common clock base */ +#define SSB_CHIPCO_CLK_BASE1 24000000 /* Half the clock freq */ +#define SSB_CHIPCO_CLK_BASE2 12500000 /* Alternate crystal on some PLL's */ + +/* Clock control values for 200Mhz in 5350 */ +#define SSB_CHIPCO_CLK_5350_N 0x0311 +#define SSB_CHIPCO_CLK_5350_M 0x04020009 + + +/** Bits in the config registers **/ + +#define SSB_CHIPCO_CFG_EN 0x0001 /* Enable */ +#define SSB_CHIPCO_CFG_EXTM 0x000E /* Extif Mode */ +#define SSB_CHIPCO_CFG_EXTM_ASYNC 0x0002 /* Async/Parallel flash */ +#define SSB_CHIPCO_CFG_EXTM_SYNC 0x0004 /* Synchronous */ +#define SSB_CHIPCO_CFG_EXTM_PCMCIA 0x0008 /* PCMCIA */ +#define SSB_CHIPCO_CFG_EXTM_IDE 0x000A /* IDE */ +#define SSB_CHIPCO_CFG_DS16 0x0010 /* Data size, 0=8bit, 1=16bit */ +#define SSB_CHIPCO_CFG_CLKDIV 0x0060 /* Sync: Clock divisor */ +#define SSB_CHIPCO_CFG_CLKEN 0x0080 /* Sync: Clock enable */ +#define SSB_CHIPCO_CFG_BSTRO 0x0100 /* Sync: Size/Bytestrobe */ + + +/** Flash-specific control/status values */ + +/* flashcontrol opcodes for ST flashes */ +#define SSB_CHIPCO_FLASHCTL_ST_WREN 0x0006 /* Write Enable */ +#define SSB_CHIPCO_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */ +#define SSB_CHIPCO_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */ +#define SSB_CHIPCO_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */ +#define SSB_CHIPCO_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */ +#define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */ +#define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */ +#define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */ +#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */ +#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */ + +/* Status register bits for ST flashes */ +#define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */ +#define SSB_CHIPCO_FLASHSTA_ST_WEL 0x02 /* Write Enable Latch */ +#define SSB_CHIPCO_FLASHSTA_ST_BP 0x1C /* Block Protect */ +#define SSB_CHIPCO_FLASHSTA_ST_BP_SHIFT 2 +#define SSB_CHIPCO_FLASHSTA_ST_SRWD 0x80 /* Status Register Write Disable */ + +/* flashcontrol opcodes for Atmel flashes */ +#define SSB_CHIPCO_FLASHCTL_AT_READ 0x07E8 +#define SSB_CHIPCO_FLASHCTL_AT_PAGE_READ 0x07D2 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_READ /* FIXME */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_READ /* FIXME */ +#define SSB_CHIPCO_FLASHCTL_AT_STATUS 0x01D7 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE 0x0384 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRITE 0x0387 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_ERASE_PRGM 0x0283 /* Erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_ERASE_PRGM 0x0286 /* Erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM 0x0288 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_PROGRAM 0x0289 +#define SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE 0x0281 +#define SSB_CHIPCO_FLASHCTL_AT_BLOCK_ERASE 0x0250 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRER_PRGM 0x0382 /* Write erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRER_PRGM 0x0385 /* Write erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD 0x0253 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_LOAD 0x0255 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_COMPARE 0x0260 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_COMPARE 0x0261 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_REPROGRAM 0x0258 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_REPROGRAM 0x0259 + +/* Status register bits for Atmel flashes */ +#define SSB_CHIPCO_FLASHSTA_AT_READY 0x80 +#define SSB_CHIPCO_FLASHSTA_AT_MISMATCH 0x40 +#define SSB_CHIPCO_FLASHSTA_AT_ID 0x38 +#define SSB_CHIPCO_FLASHSTA_AT_ID_SHIFT 3 + + +/** OTP **/ + +/* OTP regions */ +#define SSB_CHIPCO_OTP_HW_REGION SSB_CHIPCO_OTPS_HW_PROTECT +#define SSB_CHIPCO_OTP_SW_REGION SSB_CHIPCO_OTPS_SW_PROTECT +#define SSB_CHIPCO_OTP_CID_REGION SSB_CHIPCO_OTPS_CID_PROTECT + +/* OTP regions (Byte offsets from otp size) */ +#define SSB_CHIPCO_OTP_SWLIM_OFF (-8) +#define SSB_CHIPCO_OTP_CIDBASE_OFF 0 +#define SSB_CHIPCO_OTP_CIDLIM_OFF 8 + +/* Predefined OTP words (Word offset from otp size) */ +#define SSB_CHIPCO_OTP_BOUNDARY_OFF (-4) +#define SSB_CHIPCO_OTP_HWSIGN_OFF (-3) +#define SSB_CHIPCO_OTP_SWSIGN_OFF (-2) +#define SSB_CHIPCO_OTP_CIDSIGN_OFF (-1) + +#define SSB_CHIPCO_OTP_CID_OFF 0 +#define SSB_CHIPCO_OTP_PKG_OFF 1 +#define SSB_CHIPCO_OTP_FID_OFF 2 +#define SSB_CHIPCO_OTP_RSV_OFF 3 +#define SSB_CHIPCO_OTP_LIM_OFF 4 + +#define SSB_CHIPCO_OTP_SIGNATURE 0x578A +#define SSB_CHIPCO_OTP_MAGIC 0x4E56 + + +struct ssb_device; +struct ssb_serial_port; + +/* Data for the PMU, if available. + * Check availability with ((struct ssb_chipcommon)->capabilities & SSB_CHIPCO_CAP_PMU) + */ +struct ssb_chipcommon_pmu { + u8 rev; /* PMU revision */ + u32 crystalfreq; /* The active crystal frequency (in kHz) */ +}; + +struct ssb_chipcommon { + struct ssb_device *dev; + u32 capabilities; + u32 status; + /* Fast Powerup Delay constant */ + u16 fast_pwrup_delay; + struct ssb_chipcommon_pmu pmu; +}; + +static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) +{ + return (cc->dev != NULL); +} + +/* Register access */ +#define chipco_read32(cc, offset) ssb_read32((cc)->dev, offset) +#define chipco_write32(cc, offset, val) ssb_write32((cc)->dev, offset, val) + +#define chipco_mask32(cc, offset, mask) \ + chipco_write32(cc, offset, chipco_read32(cc, offset) & (mask)) +#define chipco_set32(cc, offset, set) \ + chipco_write32(cc, offset, chipco_read32(cc, offset) | (set)) +#define chipco_maskset32(cc, offset, mask, set) \ + chipco_write32(cc, offset, (chipco_read32(cc, offset) & (mask)) | (set)) + +extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); + +extern void ssb_chipco_suspend(struct ssb_chipcommon *cc); +extern void ssb_chipco_resume(struct ssb_chipcommon *cc); + +extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); +extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); +extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc, + unsigned long ns_per_cycle); + +enum ssb_clkmode { + SSB_CLKMODE_SLOW, + SSB_CLKMODE_FAST, + SSB_CLKMODE_DYNAMIC, +}; + +extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode); + +extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, + u32 ticks); + +void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value); + +u32 ssb_chipco_irq_status(struct ssb_chipcommon *cc, u32 mask); + +/* Chipcommon GPIO pin access. */ +u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask); +u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value); + +#ifdef CONFIG_SSB_SERIAL +extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports); +#endif /* CONFIG_SSB_SERIAL */ + +/* PMU support */ +extern void ssb_pmu_init(struct ssb_chipcommon *cc); + +enum ssb_pmu_ldo_volt_id { + LDO_PAREF = 0, + LDO_VOLT1, + LDO_VOLT2, + LDO_VOLT3, +}; + +void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc, + enum ssb_pmu_ldo_volt_id id, u32 voltage); +void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on); + +#endif /* LINUX_SSB_CHIPCO_H_ */ diff --git a/include/compat/linux/ssb/ssb_driver_extif.h b/include/compat/linux/ssb/ssb_driver_extif.h new file mode 100644 index 00000000..91161f0a --- /dev/null +++ b/include/compat/linux/ssb/ssb_driver_extif.h @@ -0,0 +1,214 @@ +/* + * Hardware-specific External Interface I/O core definitions + * for the BCM47xx family of SiliconBackplane-based chips. + * + * The External Interface core supports a total of three external chip selects + * supporting external interfaces. One of the external chip selects is + * used for Flash, one is used for PCMCIA, and the other may be + * programmed to support either a synchronous interface or an + * asynchronous interface. The asynchronous interface can be used to + * support external devices such as UARTs and the BCM2019 Bluetooth + * baseband processor. + * The external interface core also contains 2 on-chip 16550 UARTs, clock + * frequency control, a watchdog interrupt timer, and a GPIO interface. + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, Michael Buesch + * + * Licensed under the GPL version 2. See COPYING for details. + */ +#ifndef LINUX_SSB_EXTIFCORE_H_ +#define LINUX_SSB_EXTIFCORE_H_ + +/* external interface address space */ +#define SSB_EXTIF_PCMCIA_MEMBASE(x) (x) +#define SSB_EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000) +#define SSB_EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000) +#define SSB_EXTIF_CFGIF_BASE(x) ((x) + 0x800000) +#define SSB_EXTIF_FLASH_BASE(x) ((x) + 0xc00000) + +#define SSB_EXTIF_NR_GPIOOUT 5 +/* GPIO NOTE: + * The multiple instances of output and output enable registers + * are present to allow driver software for multiple cores to control + * gpio outputs without needing to share a single register pair. + * Use the following helper macro to get a register offset value. + */ +#define SSB_EXTIF_GPIO_OUT(index) ({ \ + BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \ + SSB_EXTIF_GPIO_OUT_BASE + ((index) * 8); \ + }) +#define SSB_EXTIF_GPIO_OUTEN(index) ({ \ + BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \ + SSB_EXTIF_GPIO_OUTEN_BASE + ((index) * 8); \ + }) + +/** EXTIF core registers **/ + +#define SSB_EXTIF_CTL 0x0000 +#define SSB_EXTIF_CTL_UARTEN (1 << 0) /* UART enable */ +#define SSB_EXTIF_EXTSTAT 0x0004 +#define SSB_EXTIF_EXTSTAT_EMODE (1 << 0) /* Endian mode (ro) */ +#define SSB_EXTIF_EXTSTAT_EIRQPIN (1 << 1) /* External interrupt pin (ro) */ +#define SSB_EXTIF_EXTSTAT_GPIOIRQPIN (1 << 2) /* GPIO interrupt pin (ro) */ +#define SSB_EXTIF_PCMCIA_CFG 0x0010 +#define SSB_EXTIF_PCMCIA_MEMWAIT 0x0014 +#define SSB_EXTIF_PCMCIA_ATTRWAIT 0x0018 +#define SSB_EXTIF_PCMCIA_IOWAIT 0x001C +#define SSB_EXTIF_PROG_CFG 0x0020 +#define SSB_EXTIF_PROG_WAITCNT 0x0024 +#define SSB_EXTIF_FLASH_CFG 0x0028 +#define SSB_EXTIF_FLASH_WAITCNT 0x002C +#define SSB_EXTIF_WATCHDOG 0x0040 +#define SSB_EXTIF_CLOCK_N 0x0044 +#define SSB_EXTIF_CLOCK_SB 0x0048 +#define SSB_EXTIF_CLOCK_PCI 0x004C +#define SSB_EXTIF_CLOCK_MII 0x0050 +#define SSB_EXTIF_GPIO_IN 0x0060 +#define SSB_EXTIF_GPIO_OUT_BASE 0x0064 +#define SSB_EXTIF_GPIO_OUTEN_BASE 0x0068 +#define SSB_EXTIF_EJTAG_OUTEN 0x0090 +#define SSB_EXTIF_GPIO_INTPOL 0x0094 +#define SSB_EXTIF_GPIO_INTMASK 0x0098 +#define SSB_EXTIF_UART_DATA 0x0300 +#define SSB_EXTIF_UART_TIMER 0x0310 +#define SSB_EXTIF_UART_FCR 0x0320 +#define SSB_EXTIF_UART_LCR 0x0330 +#define SSB_EXTIF_UART_MCR 0x0340 +#define SSB_EXTIF_UART_LSR 0x0350 +#define SSB_EXTIF_UART_MSR 0x0360 +#define SSB_EXTIF_UART_SCRATCH 0x0370 + + + + +/* pcmcia/prog/flash_config */ +#define SSB_EXTCFG_EN (1 << 0) /* enable */ +#define SSB_EXTCFG_MODE 0xE /* mode */ +#define SSB_EXTCFG_MODE_SHIFT 1 +#define SSB_EXTCFG_MODE_FLASH 0x0 /* flash/asynchronous mode */ +#define SSB_EXTCFG_MODE_SYNC 0x2 /* synchronous mode */ +#define SSB_EXTCFG_MODE_PCMCIA 0x4 /* pcmcia mode */ +#define SSB_EXTCFG_DS16 (1 << 4) /* destsize: 0=8bit, 1=16bit */ +#define SSB_EXTCFG_BSWAP (1 << 5) /* byteswap */ +#define SSB_EXTCFG_CLKDIV 0xC0 /* clock divider */ +#define SSB_EXTCFG_CLKDIV_SHIFT 6 +#define SSB_EXTCFG_CLKDIV_2 0x0 /* backplane/2 */ +#define SSB_EXTCFG_CLKDIV_3 0x40 /* backplane/3 */ +#define SSB_EXTCFG_CLKDIV_4 0x80 /* backplane/4 */ +#define SSB_EXTCFG_CLKEN (1 << 8) /* clock enable */ +#define SSB_EXTCFG_STROBE (1 << 9) /* size/bytestrobe (synch only) */ + +/* pcmcia_memwait */ +#define SSB_PCMCIA_MEMW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_MEMW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_MEMW_1_SHIFT 8 +#define SSB_PCMCIA_MEMW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_MEMW_2_SHIFT 16 +#define SSB_PCMCIA_MEMW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_MEMW_3_SHIFT 24 + +/* pcmcia_attrwait */ +#define SSB_PCMCIA_ATTW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_ATTW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_ATTW_1_SHIFT 8 +#define SSB_PCMCIA_ATTW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_ATTW_2_SHIFT 16 +#define SSB_PCMCIA_ATTW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_ATTW_3_SHIFT 24 + +/* pcmcia_iowait */ +#define SSB_PCMCIA_IOW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_IOW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_IOW_1_SHIFT 8 +#define SSB_PCMCIA_IOW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_IOW_2_SHIFT 16 +#define SSB_PCMCIA_IOW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_IOW_3_SHIFT 24 + +/* prog_waitcount */ +#define SSB_PROG_WCNT_0 0x0000001F /* waitcount0 */ +#define SSB_PROG_WCNT_1 0x00001F00 /* waitcount1 */ +#define SSB_PROG_WCNT_1_SHIFT 8 +#define SSB_PROG_WCNT_2 0x001F0000 /* waitcount2 */ +#define SSB_PROG_WCNT_2_SHIFT 16 +#define SSB_PROG_WCNT_3 0x1F000000 /* waitcount3 */ +#define SSB_PROG_WCNT_3_SHIFT 24 + +#define SSB_PROG_W0 0x0000000C +#define SSB_PROG_W1 0x00000A00 +#define SSB_PROG_W2 0x00020000 +#define SSB_PROG_W3 0x01000000 + +/* flash_waitcount */ +#define SSB_FLASH_WCNT_0 0x0000001F /* waitcount0 */ +#define SSB_FLASH_WCNT_1 0x00001F00 /* waitcount1 */ +#define SSB_FLASH_WCNT_1_SHIFT 8 +#define SSB_FLASH_WCNT_2 0x001F0000 /* waitcount2 */ +#define SSB_FLASH_WCNT_2_SHIFT 16 +#define SSB_FLASH_WCNT_3 0x1F000000 /* waitcount3 */ +#define SSB_FLASH_WCNT_3_SHIFT 24 + +/* watchdog */ +#define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ + + + +#ifdef CONFIG_SSB_DRIVER_EXTIF + +struct ssb_extif { + struct ssb_device *dev; +}; + +static inline bool ssb_extif_available(struct ssb_extif *extif) +{ + return (extif->dev != NULL); +} + +extern void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *plltype, u32 *n, u32 *m); + +extern void ssb_extif_timing_init(struct ssb_extif *extif, + unsigned long ns); + +extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, + u32 ticks); + +/* Extif GPIO pin access */ +u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask); +u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); +u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value); +u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value); +u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value); + +#ifdef CONFIG_SSB_SERIAL +extern int ssb_extif_serial_init(struct ssb_extif *extif, + struct ssb_serial_port *ports); +#endif /* CONFIG_SSB_SERIAL */ + + +#else /* CONFIG_SSB_DRIVER_EXTIF */ +/* extif disabled */ + +struct ssb_extif { +}; + +static inline bool ssb_extif_available(struct ssb_extif *extif) +{ + return 0; +} + +static inline +void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *plltype, u32 *n, u32 *m) +{ +} + +static inline +void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, + u32 ticks) +{ +} + +#endif /* CONFIG_SSB_DRIVER_EXTIF */ +#endif /* LINUX_SSB_EXTIFCORE_H_ */ diff --git a/include/compat/linux/ssb/ssb_driver_gige.h b/include/compat/linux/ssb/ssb_driver_gige.h new file mode 100644 index 00000000..eba52a10 --- /dev/null +++ b/include/compat/linux/ssb/ssb_driver_gige.h @@ -0,0 +1,179 @@ +#ifndef LINUX_SSB_DRIVER_GIGE_H_ +#define LINUX_SSB_DRIVER_GIGE_H_ + +#include +#include +#include + + +#ifdef CONFIG_SSB_DRIVER_GIGE + + +#define SSB_GIGE_PCIIO 0x0000 /* PCI I/O Registers (1024 bytes) */ +#define SSB_GIGE_RESERVED 0x0400 /* Reserved (1024 bytes) */ +#define SSB_GIGE_PCICFG 0x0800 /* PCI config space (256 bytes) */ +#define SSB_GIGE_SHIM_FLUSHSTAT 0x0C00 /* PCI to OCP: Flush status control (32bit) */ +#define SSB_GIGE_SHIM_FLUSHRDA 0x0C04 /* PCI to OCP: Flush read address (32bit) */ +#define SSB_GIGE_SHIM_FLUSHTO 0x0C08 /* PCI to OCP: Flush timeout counter (32bit) */ +#define SSB_GIGE_SHIM_BARRIER 0x0C0C /* PCI to OCP: Barrier register (32bit) */ +#define SSB_GIGE_SHIM_MAOCPSI 0x0C10 /* PCI to OCP: MaocpSI Control (32bit) */ +#define SSB_GIGE_SHIM_SIOCPMA 0x0C14 /* PCI to OCP: SiocpMa Control (32bit) */ + +/* TM Status High flags */ +#define SSB_GIGE_TMSHIGH_RGMII 0x00010000 /* Have an RGMII PHY-bus */ +/* TM Status Low flags */ +#define SSB_GIGE_TMSLOW_TXBYPASS 0x00080000 /* TX bypass (no delay) */ +#define SSB_GIGE_TMSLOW_RXBYPASS 0x00100000 /* RX bypass (no delay) */ +#define SSB_GIGE_TMSLOW_DLLEN 0x01000000 /* Enable DLL controls */ + +/* Boardflags (low) */ +#define SSB_GIGE_BFL_ROBOSWITCH 0x0010 + + +#define SSB_GIGE_MEM_RES_NAME "SSB Broadcom 47xx GigE memory" +#define SSB_GIGE_IO_RES_NAME "SSB Broadcom 47xx GigE I/O" + +struct ssb_gige { + struct ssb_device *dev; + + spinlock_t lock; + + /* True, if the device has an RGMII bus. + * False, if the device has a GMII bus. */ + bool has_rgmii; + + /* The PCI controller device. */ + struct pci_controller pci_controller; + struct pci_ops pci_ops; + struct resource mem_resource; + struct resource io_resource; +}; + +/* Check whether a PCI device is a SSB Gigabit Ethernet core. */ +extern bool pdev_is_ssb_gige_core(struct pci_dev *pdev); + +/* Convert a pci_dev pointer to a ssb_gige pointer. */ +static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) +{ + if (!pdev_is_ssb_gige_core(pdev)) + return NULL; + return container_of(pdev->bus->ops, struct ssb_gige, pci_ops); +} + +/* Returns whether the PHY is connected by an RGMII bus. */ +static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + return (dev ? dev->has_rgmii : 0); +} + +/* Returns whether we have a Roboswitch. */ +static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + if (dev) + return !!(dev->dev->bus->sprom.boardflags_lo & + SSB_GIGE_BFL_ROBOSWITCH); + return 0; +} + +/* Returns whether we can only do one DMA at once. */ +static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + if (dev) + return ((dev->dev->bus->chip_id == 0x4785) && + (dev->dev->bus->chip_rev < 2)); + return 0; +} + +/* Returns whether we must flush posted writes. */ +static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) +{ + struct ssb_gige *dev = pdev_to_ssb_gige(pdev); + if (dev) + return (dev->dev->bus->chip_id == 0x4785); + return 0; +} + +#ifdef CONFIG_BCM47XX +#include +/* Get the device MAC address */ +static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) +{ + char buf[20]; + if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0) + return; + nvram_parse_macaddr(buf, macaddr); +} +#else +static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) +{ +} +#endif + +extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev); +extern int ssb_gige_map_irq(struct ssb_device *sdev, + const struct pci_dev *pdev); + +/* The GigE driver is not a standalone module, because we don't have support + * for unregistering the driver. So we could not unload the module anyway. */ +extern int ssb_gige_init(void); +static inline void ssb_gige_exit(void) +{ + /* Currently we can not unregister the GigE driver, + * because we can not unregister the PCI bridge. */ + BUG(); +} + + +#else /* CONFIG_SSB_DRIVER_GIGE */ +/* Gigabit Ethernet driver disabled */ + + +static inline int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, + struct pci_dev *pdev) +{ + return -ENOSYS; +} +static inline int ssb_gige_map_irq(struct ssb_device *sdev, + const struct pci_dev *pdev) +{ + return -ENOSYS; +} +static inline int ssb_gige_init(void) +{ + return 0; +} +static inline void ssb_gige_exit(void) +{ +} + +static inline bool pdev_is_ssb_gige_core(struct pci_dev *pdev) +{ + return 0; +} +static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) +{ + return NULL; +} +static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) +{ + return 0; +} +static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) +{ + return 0; +} +static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) +{ + return 0; +} +static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) +{ + return 0; +} + +#endif /* CONFIG_SSB_DRIVER_GIGE */ +#endif /* LINUX_SSB_DRIVER_GIGE_H_ */ diff --git a/include/compat/linux/ssb/ssb_driver_mips.h b/include/compat/linux/ssb/ssb_driver_mips.h new file mode 100644 index 00000000..5f44e974 --- /dev/null +++ b/include/compat/linux/ssb/ssb_driver_mips.h @@ -0,0 +1,46 @@ +#ifndef LINUX_SSB_MIPSCORE_H_ +#define LINUX_SSB_MIPSCORE_H_ + +#ifdef CONFIG_SSB_DRIVER_MIPS + +struct ssb_device; + +struct ssb_serial_port { + void *regs; + unsigned long clockspeed; + unsigned int irq; + unsigned int baud_base; + unsigned int reg_shift; +}; + + +struct ssb_mipscore { + struct ssb_device *dev; + + int nr_serial_ports; + struct ssb_serial_port serial_ports[4]; + + u8 flash_buswidth; + u32 flash_window; + u32 flash_window_size; +}; + +extern void ssb_mipscore_init(struct ssb_mipscore *mcore); +extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore); + +extern unsigned int ssb_mips_irq(struct ssb_device *dev); + + +#else /* CONFIG_SSB_DRIVER_MIPS */ + +struct ssb_mipscore { +}; + +static inline +void ssb_mipscore_init(struct ssb_mipscore *mcore) +{ +} + +#endif /* CONFIG_SSB_DRIVER_MIPS */ + +#endif /* LINUX_SSB_MIPSCORE_H_ */ diff --git a/include/compat/linux/ssb/ssb_driver_pci.h b/include/compat/linux/ssb/ssb_driver_pci.h new file mode 100644 index 00000000..41e330e5 --- /dev/null +++ b/include/compat/linux/ssb/ssb_driver_pci.h @@ -0,0 +1,130 @@ +#ifndef LINUX_SSB_PCICORE_H_ +#define LINUX_SSB_PCICORE_H_ + +#include + +struct pci_dev; + + +#ifdef CONFIG_SSB_DRIVER_PCICORE + +/* PCI core registers. */ +#define SSB_PCICORE_CTL 0x0000 /* PCI Control */ +#define SSB_PCICORE_CTL_RST_OE 0x00000001 /* PCI_RESET Output Enable */ +#define SSB_PCICORE_CTL_RST 0x00000002 /* PCI_RESET driven out to pin */ +#define SSB_PCICORE_CTL_CLK_OE 0x00000004 /* Clock gate Output Enable */ +#define SSB_PCICORE_CTL_CLK 0x00000008 /* Gate for clock driven out to pin */ +#define SSB_PCICORE_ARBCTL 0x0010 /* PCI Arbiter Control */ +#define SSB_PCICORE_ARBCTL_INTERN 0x00000001 /* Use internal arbiter */ +#define SSB_PCICORE_ARBCTL_EXTERN 0x00000002 /* Use external arbiter */ +#define SSB_PCICORE_ARBCTL_PARKID 0x00000006 /* Mask, selects which agent is parked on an idle bus */ +#define SSB_PCICORE_ARBCTL_PARKID_LAST 0x00000000 /* Last requestor */ +#define SSB_PCICORE_ARBCTL_PARKID_4710 0x00000002 /* 4710 */ +#define SSB_PCICORE_ARBCTL_PARKID_EXT0 0x00000004 /* External requestor 0 */ +#define SSB_PCICORE_ARBCTL_PARKID_EXT1 0x00000006 /* External requestor 1 */ +#define SSB_PCICORE_ISTAT 0x0020 /* Interrupt status */ +#define SSB_PCICORE_ISTAT_INTA 0x00000001 /* PCI INTA# */ +#define SSB_PCICORE_ISTAT_INTB 0x00000002 /* PCI INTB# */ +#define SSB_PCICORE_ISTAT_SERR 0x00000004 /* PCI SERR# (write to clear) */ +#define SSB_PCICORE_ISTAT_PERR 0x00000008 /* PCI PERR# (write to clear) */ +#define SSB_PCICORE_ISTAT_PME 0x00000010 /* PCI PME# */ +#define SSB_PCICORE_IMASK 0x0024 /* Interrupt mask */ +#define SSB_PCICORE_IMASK_INTA 0x00000001 /* PCI INTA# */ +#define SSB_PCICORE_IMASK_INTB 0x00000002 /* PCI INTB# */ +#define SSB_PCICORE_IMASK_SERR 0x00000004 /* PCI SERR# */ +#define SSB_PCICORE_IMASK_PERR 0x00000008 /* PCI PERR# */ +#define SSB_PCICORE_IMASK_PME 0x00000010 /* PCI PME# */ +#define SSB_PCICORE_MBOX 0x0028 /* Backplane to PCI Mailbox */ +#define SSB_PCICORE_MBOX_F0_0 0x00000100 /* PCI function 0, INT 0 */ +#define SSB_PCICORE_MBOX_F0_1 0x00000200 /* PCI function 0, INT 1 */ +#define SSB_PCICORE_MBOX_F1_0 0x00000400 /* PCI function 1, INT 0 */ +#define SSB_PCICORE_MBOX_F1_1 0x00000800 /* PCI function 1, INT 1 */ +#define SSB_PCICORE_MBOX_F2_0 0x00001000 /* PCI function 2, INT 0 */ +#define SSB_PCICORE_MBOX_F2_1 0x00002000 /* PCI function 2, INT 1 */ +#define SSB_PCICORE_MBOX_F3_0 0x00004000 /* PCI function 3, INT 0 */ +#define SSB_PCICORE_MBOX_F3_1 0x00008000 /* PCI function 3, INT 1 */ +#define SSB_PCICORE_BCAST_ADDR 0x0050 /* Backplane Broadcast Address */ +#define SSB_PCICORE_BCAST_ADDR_MASK 0x000000FF +#define SSB_PCICORE_BCAST_DATA 0x0054 /* Backplane Broadcast Data */ +#define SSB_PCICORE_GPIO_IN 0x0060 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_OUT 0x0064 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_ENABLE 0x0068 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_CTL 0x006C /* rev >= 2 only */ +#define SSB_PCICORE_SBTOPCI0 0x0100 /* Backplane to PCI translation 0 (sbtopci0) */ +#define SSB_PCICORE_SBTOPCI0_MASK 0xFC000000 +#define SSB_PCICORE_SBTOPCI1 0x0104 /* Backplane to PCI translation 1 (sbtopci1) */ +#define SSB_PCICORE_SBTOPCI1_MASK 0xFC000000 +#define SSB_PCICORE_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */ +#define SSB_PCICORE_SBTOPCI2_MASK 0xC0000000 +#define SSB_PCICORE_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */ +#define SSB_PCICORE_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */ +#define SSB_PCICORE_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ +#define SSB_PCICORE_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ +#define SSB_PCICORE_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ + +/* SBtoPCIx */ +#define SSB_PCICORE_SBTOPCI_MEM 0x00000000 +#define SSB_PCICORE_SBTOPCI_IO 0x00000001 +#define SSB_PCICORE_SBTOPCI_CFG0 0x00000002 +#define SSB_PCICORE_SBTOPCI_CFG1 0x00000003 +#define SSB_PCICORE_SBTOPCI_PREF 0x00000004 /* Prefetch enable */ +#define SSB_PCICORE_SBTOPCI_BURST 0x00000008 /* Burst enable */ +#define SSB_PCICORE_SBTOPCI_MRM 0x00000020 /* Memory Read Multiple */ +#define SSB_PCICORE_SBTOPCI_RC 0x00000030 /* Read Command mask (rev >= 11) */ +#define SSB_PCICORE_SBTOPCI_RC_READ 0x00000000 /* Memory read */ +#define SSB_PCICORE_SBTOPCI_RC_READL 0x00000010 /* Memory read line */ +#define SSB_PCICORE_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */ + + +/* PCIcore specific boardflags */ +#define SSB_PCICORE_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ + + +struct ssb_pcicore { + struct ssb_device *dev; + u8 setup_done:1; + u8 hostmode:1; + u8 cardbusmode:1; +}; + +extern void ssb_pcicore_init(struct ssb_pcicore *pc); + +/* Enable IRQ routing for a specific device */ +extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev); + +int ssb_pcicore_plat_dev_init(struct pci_dev *d); +int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); + + +#else /* CONFIG_SSB_DRIVER_PCICORE */ + + +struct ssb_pcicore { +}; + +static inline +void ssb_pcicore_init(struct ssb_pcicore *pc) +{ +} + +static inline +int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev) +{ + return 0; +} + +static inline +int ssb_pcicore_plat_dev_init(struct pci_dev *d) +{ + return -ENODEV; +} +static inline +int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return -ENODEV; +} + +#endif /* CONFIG_SSB_DRIVER_PCICORE */ +#endif /* LINUX_SSB_PCICORE_H_ */ diff --git a/include/compat/linux/ssb/ssb_embedded.h b/include/compat/linux/ssb/ssb_embedded.h new file mode 100644 index 00000000..8d8dedff --- /dev/null +++ b/include/compat/linux/ssb/ssb_embedded.h @@ -0,0 +1,18 @@ +#ifndef LINUX_SSB_EMBEDDED_H_ +#define LINUX_SSB_EMBEDDED_H_ + +#include +#include + + +extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks); + +/* Generic GPIO API */ +u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask); +u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value); + +#endif /* LINUX_SSB_EMBEDDED_H_ */ diff --git a/include/compat/linux/ssb/ssb_regs.h b/include/compat/linux/ssb/ssb_regs.h new file mode 100644 index 00000000..98941203 --- /dev/null +++ b/include/compat/linux/ssb/ssb_regs.h @@ -0,0 +1,543 @@ +#ifndef LINUX_SSB_REGS_H_ +#define LINUX_SSB_REGS_H_ + + +/* SiliconBackplane Address Map. + * All regions may not exist on all chips. + */ +#define SSB_SDRAM_BASE 0x00000000U /* Physical SDRAM */ +#define SSB_PCI_MEM 0x08000000U /* Host Mode sb2pcitranslation0 (64 MB) */ +#define SSB_PCI_CFG 0x0c000000U /* Host Mode sb2pcitranslation1 (64 MB) */ +#define SSB_SDRAM_SWAPPED 0x10000000U /* Byteswapped Physical SDRAM */ +#define SSB_ENUM_BASE 0x18000000U /* Enumeration space base */ +#define SSB_ENUM_LIMIT 0x18010000U /* Enumeration space limit */ + +#define SSB_FLASH2 0x1c000000U /* Flash Region 2 (region 1 shadowed here) */ +#define SSB_FLASH2_SZ 0x02000000U /* Size of Flash Region 2 */ + +#define SSB_EXTIF_BASE 0x1f000000U /* External Interface region base address */ +#define SSB_FLASH1 0x1fc00000U /* Flash Region 1 */ +#define SSB_FLASH1_SZ 0x00400000U /* Size of Flash Region 1 */ + +#define SSB_PCI_DMA 0x40000000U /* Client Mode sb2pcitranslation2 (1 GB) */ +#define SSB_PCI_DMA_SZ 0x40000000U /* Client Mode sb2pcitranslation2 size in bytes */ +#define SSB_PCIE_DMA_L32 0x00000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), low 32 bits */ +#define SSB_PCIE_DMA_H32 0x80000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */ +#define SSB_EUART (SSB_EXTIF_BASE + 0x00800000) +#define SSB_LED (SSB_EXTIF_BASE + 0x00900000) + + +/* Enumeration space constants */ +#define SSB_CORE_SIZE 0x1000 /* Size of a core MMIO area */ +#define SSB_MAX_NR_CORES ((SSB_ENUM_LIMIT - SSB_ENUM_BASE) / SSB_CORE_SIZE) + + +/* mips address */ +#define SSB_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */ + + +/* SSB PCI config space registers. */ +#define SSB_PMCSR 0x44 +#define SSB_PE 0x100 +#define SSB_BAR0_WIN 0x80 /* Backplane address space 0 */ +#define SSB_BAR1_WIN 0x84 /* Backplane address space 1 */ +#define SSB_SPROMCTL 0x88 /* SPROM control */ +#define SSB_SPROMCTL_WE 0x10 /* SPROM write enable */ +#define SSB_BAR1_CONTROL 0x8c /* Address space 1 burst control */ +#define SSB_PCI_IRQS 0x90 /* PCI interrupts */ +#define SSB_PCI_IRQMASK 0x94 /* PCI IRQ control and mask (pcirev >= 6 only) */ +#define SSB_BACKPLANE_IRQS 0x98 /* Backplane Interrupts */ +#define SSB_GPIO_IN 0xB0 /* GPIO Input (pcirev >= 3 only) */ +#define SSB_GPIO_OUT 0xB4 /* GPIO Output (pcirev >= 3 only) */ +#define SSB_GPIO_OUT_ENABLE 0xB8 /* GPIO Output Enable/Disable (pcirev >= 3 only) */ +#define SSB_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define SSB_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define SSB_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */ +#define SSB_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */ + + +#define SSB_BAR0_MAX_RETRIES 50 + +/* Silicon backplane configuration register definitions */ +#define SSB_IPSFLAG 0x0F08 +#define SSB_IPSFLAG_IRQ1 0x0000003F /* which sbflags get routed to mips interrupt 1 */ +#define SSB_IPSFLAG_IRQ1_SHIFT 0 +#define SSB_IPSFLAG_IRQ2 0x00003F00 /* which sbflags get routed to mips interrupt 2 */ +#define SSB_IPSFLAG_IRQ2_SHIFT 8 +#define SSB_IPSFLAG_IRQ3 0x003F0000 /* which sbflags get routed to mips interrupt 3 */ +#define SSB_IPSFLAG_IRQ3_SHIFT 16 +#define SSB_IPSFLAG_IRQ4 0x3F000000 /* which sbflags get routed to mips interrupt 4 */ +#define SSB_IPSFLAG_IRQ4_SHIFT 24 +#define SSB_TPSFLAG 0x0F18 +#define SSB_TPSFLAG_BPFLAG 0x0000003F /* Backplane flag # */ +#define SSB_TPSFLAG_ALWAYSIRQ 0x00000040 /* IRQ is always sent on the Backplane */ +#define SSB_TMERRLOGA 0x0F48 +#define SSB_TMERRLOG 0x0F50 +#define SSB_ADMATCH3 0x0F60 +#define SSB_ADMATCH2 0x0F68 +#define SSB_ADMATCH1 0x0F70 +#define SSB_IMSTATE 0x0F90 /* SB Initiator Agent State */ +#define SSB_IMSTATE_PC 0x0000000f /* Pipe Count */ +#define SSB_IMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ +#define SSB_IMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */ +#define SSB_IMSTATE_AP_TS 0x00000010 /* Use timeslices only */ +#define SSB_IMSTATE_AP_TK 0x00000020 /* Use token only */ +#define SSB_IMSTATE_AP_RSV 0x00000030 /* Reserved */ +#define SSB_IMSTATE_IBE 0x00020000 /* In Band Error */ +#define SSB_IMSTATE_TO 0x00040000 /* Timeout */ +#define SSB_IMSTATE_BUSY 0x01800000 /* Busy (Backplane rev >= 2.3 only) */ +#define SSB_IMSTATE_REJECT 0x02000000 /* Reject (Backplane rev >= 2.3 only) */ +#define SSB_INTVEC 0x0F94 /* SB Interrupt Mask */ +#define SSB_INTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ +#define SSB_INTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */ +#define SSB_INTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */ +#define SSB_INTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */ +#define SSB_INTVEC_USB 0x00000010 /* Enable interrupts for usb */ +#define SSB_INTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */ +#define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ +#define SSB_TMSLOW 0x0F98 /* SB Target State Low */ +#define SSB_TMSLOW_RESET 0x00000001 /* Reset */ +#define SSB_TMSLOW_REJECT 0x00000002 /* Reject (Standard Backplane) */ +#define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */ +#define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */ +#define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ +#define SSB_TMSLOW_PE 0x40000000 /* Power Management Enable */ +#define SSB_TMSLOW_BE 0x80000000 /* BIST Enable */ +#define SSB_TMSHIGH 0x0F9C /* SB Target State High */ +#define SSB_TMSHIGH_SERR 0x00000001 /* S-error */ +#define SSB_TMSHIGH_INT 0x00000002 /* Interrupt */ +#define SSB_TMSHIGH_BUSY 0x00000004 /* Busy */ +#define SSB_TMSHIGH_TO 0x00000020 /* Timeout. Backplane rev >= 2.3 only */ +#define SSB_TMSHIGH_COREFL 0x1FFF0000 /* Core specific flags */ +#define SSB_TMSHIGH_COREFL_SHIFT 16 +#define SSB_TMSHIGH_DMA64 0x10000000 /* 64bit DMA supported */ +#define SSB_TMSHIGH_GCR 0x20000000 /* Gated Clock Request */ +#define SSB_TMSHIGH_BISTF 0x40000000 /* BIST Failed */ +#define SSB_TMSHIGH_BISTD 0x80000000 /* BIST Done */ +#define SSB_BWA0 0x0FA0 +#define SSB_IMCFGLO 0x0FA8 +#define SSB_IMCFGLO_SERTO 0x00000007 /* Service timeout */ +#define SSB_IMCFGLO_REQTO 0x00000070 /* Request timeout */ +#define SSB_IMCFGLO_REQTO_SHIFT 4 +#define SSB_IMCFGLO_CONNID 0x00FF0000 /* Connection ID */ +#define SSB_IMCFGLO_CONNID_SHIFT 16 +#define SSB_IMCFGHI 0x0FAC +#define SSB_ADMATCH0 0x0FB0 +#define SSB_TMCFGLO 0x0FB8 +#define SSB_TMCFGHI 0x0FBC +#define SSB_BCONFIG 0x0FC0 +#define SSB_BSTATE 0x0FC8 +#define SSB_ACTCFG 0x0FD8 +#define SSB_FLAGST 0x0FE8 +#define SSB_IDLOW 0x0FF8 +#define SSB_IDLOW_CFGSP 0x00000003 /* Config Space */ +#define SSB_IDLOW_ADDRNGE 0x00000038 /* Address Ranges supported */ +#define SSB_IDLOW_ADDRNGE_SHIFT 3 +#define SSB_IDLOW_SYNC 0x00000040 +#define SSB_IDLOW_INITIATOR 0x00000080 +#define SSB_IDLOW_MIBL 0x00000F00 /* Minimum Backplane latency */ +#define SSB_IDLOW_MIBL_SHIFT 8 +#define SSB_IDLOW_MABL 0x0000F000 /* Maximum Backplane latency */ +#define SSB_IDLOW_MABL_SHIFT 12 +#define SSB_IDLOW_TIF 0x00010000 /* This Initiator is first */ +#define SSB_IDLOW_CCW 0x000C0000 /* Cycle counter width */ +#define SSB_IDLOW_CCW_SHIFT 18 +#define SSB_IDLOW_TPT 0x00F00000 /* Target ports */ +#define SSB_IDLOW_TPT_SHIFT 20 +#define SSB_IDLOW_INITP 0x0F000000 /* Initiator ports */ +#define SSB_IDLOW_INITP_SHIFT 24 +#define SSB_IDLOW_SSBREV 0xF0000000 /* Sonics Backplane Revision code */ +#define SSB_IDLOW_SSBREV_22 0x00000000 /* <= 2.2 */ +#define SSB_IDLOW_SSBREV_23 0x10000000 /* 2.3 */ +#define SSB_IDLOW_SSBREV_24 0x40000000 /* ?? Found in BCM4328 */ +#define SSB_IDLOW_SSBREV_25 0x50000000 /* ?? Not Found yet */ +#define SSB_IDLOW_SSBREV_26 0x60000000 /* ?? Found in some BCM4311/2 */ +#define SSB_IDLOW_SSBREV_27 0x70000000 /* ?? Found in some BCM4311/2 */ +#define SSB_IDHIGH 0x0FFC /* SB Identification High */ +#define SSB_IDHIGH_RCLO 0x0000000F /* Revision Code (low part) */ +#define SSB_IDHIGH_CC 0x00008FF0 /* Core Code */ +#define SSB_IDHIGH_CC_SHIFT 4 +#define SSB_IDHIGH_RCHI 0x00007000 /* Revision Code (high part) */ +#define SSB_IDHIGH_RCHI_SHIFT 8 /* yes, shift 8 is right */ +#define SSB_IDHIGH_VC 0xFFFF0000 /* Vendor Code */ +#define SSB_IDHIGH_VC_SHIFT 16 + +/* SPROM shadow area. If not otherwise noted, fields are + * two bytes wide. Note that the SPROM can _only_ be read + * in two-byte quantities. + */ +#define SSB_SPROMSIZE_WORDS 64 +#define SSB_SPROMSIZE_BYTES (SSB_SPROMSIZE_WORDS * sizeof(u16)) +#define SSB_SPROMSIZE_WORDS_R123 64 +#define SSB_SPROMSIZE_WORDS_R4 220 +#define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16)) +#define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16)) +#define SSB_SPROM_BASE1 0x1000 +#define SSB_SPROM_BASE31 0x0800 +#define SSB_SPROM_REVISION 0x007E +#define SSB_SPROM_REVISION_REV 0x00FF /* SPROM Revision number */ +#define SSB_SPROM_REVISION_CRC 0xFF00 /* SPROM CRC8 value */ +#define SSB_SPROM_REVISION_CRC_SHIFT 8 + +/* SPROM Revision 1 */ +#define SSB_SPROM1_SPID 0x0004 /* Subsystem Product ID for PCI */ +#define SSB_SPROM1_SVID 0x0006 /* Subsystem Vendor ID for PCI */ +#define SSB_SPROM1_PID 0x0008 /* Product ID for PCI */ +#define SSB_SPROM1_IL0MAC 0x0048 /* 6 bytes MAC address for 802.11b/g */ +#define SSB_SPROM1_ET0MAC 0x004E /* 6 bytes MAC address for Ethernet */ +#define SSB_SPROM1_ET1MAC 0x0054 /* 6 bytes MAC address for 802.11a */ +#define SSB_SPROM1_ETHPHY 0x005A /* Ethernet PHY settings */ +#define SSB_SPROM1_ETHPHY_ET0A 0x001F /* MII Address for enet0 */ +#define SSB_SPROM1_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */ +#define SSB_SPROM1_ETHPHY_ET1A_SHIFT 5 +#define SSB_SPROM1_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */ +#define SSB_SPROM1_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */ +#define SSB_SPROM1_BINF 0x005C /* Board info */ +#define SSB_SPROM1_BINF_BREV 0x00FF /* Board Revision */ +#define SSB_SPROM1_BINF_CCODE 0x0F00 /* Country Code */ +#define SSB_SPROM1_BINF_CCODE_SHIFT 8 +#define SSB_SPROM1_BINF_ANTBG 0x3000 /* Available B-PHY and G-PHY antennas */ +#define SSB_SPROM1_BINF_ANTBG_SHIFT 12 +#define SSB_SPROM1_BINF_ANTA 0xC000 /* Available A-PHY antennas */ +#define SSB_SPROM1_BINF_ANTA_SHIFT 14 +#define SSB_SPROM1_PA0B0 0x005E +#define SSB_SPROM1_PA0B1 0x0060 +#define SSB_SPROM1_PA0B2 0x0062 +#define SSB_SPROM1_GPIOA 0x0064 /* General Purpose IO pins 0 and 1 */ +#define SSB_SPROM1_GPIOA_P0 0x00FF /* Pin 0 */ +#define SSB_SPROM1_GPIOA_P1 0xFF00 /* Pin 1 */ +#define SSB_SPROM1_GPIOA_P1_SHIFT 8 +#define SSB_SPROM1_GPIOB 0x0066 /* General Purpuse IO pins 2 and 3 */ +#define SSB_SPROM1_GPIOB_P2 0x00FF /* Pin 2 */ +#define SSB_SPROM1_GPIOB_P3 0xFF00 /* Pin 3 */ +#define SSB_SPROM1_GPIOB_P3_SHIFT 8 +#define SSB_SPROM1_MAXPWR 0x0068 /* Power Amplifier Max Power */ +#define SSB_SPROM1_MAXPWR_BG 0x00FF /* B-PHY and G-PHY (in dBm Q5.2) */ +#define SSB_SPROM1_MAXPWR_A 0xFF00 /* A-PHY (in dBm Q5.2) */ +#define SSB_SPROM1_MAXPWR_A_SHIFT 8 +#define SSB_SPROM1_PA1B0 0x006A +#define SSB_SPROM1_PA1B1 0x006C +#define SSB_SPROM1_PA1B2 0x006E +#define SSB_SPROM1_ITSSI 0x0070 /* Idle TSSI Target */ +#define SSB_SPROM1_ITSSI_BG 0x00FF /* B-PHY and G-PHY*/ +#define SSB_SPROM1_ITSSI_A 0xFF00 /* A-PHY */ +#define SSB_SPROM1_ITSSI_A_SHIFT 8 +#define SSB_SPROM1_BFLLO 0x0072 /* Boardflags (low 16 bits) */ +#define SSB_SPROM1_AGAIN 0x0074 /* Antenna Gain (in dBm Q5.2) */ +#define SSB_SPROM1_AGAIN_BG 0x00FF /* B-PHY and G-PHY */ +#define SSB_SPROM1_AGAIN_BG_SHIFT 0 +#define SSB_SPROM1_AGAIN_A 0xFF00 /* A-PHY */ +#define SSB_SPROM1_AGAIN_A_SHIFT 8 + +/* SPROM Revision 2 (inherits from rev 1) */ +#define SSB_SPROM2_BFLHI 0x0038 /* Boardflags (high 16 bits) */ +#define SSB_SPROM2_MAXP_A 0x003A /* A-PHY Max Power */ +#define SSB_SPROM2_MAXP_A_HI 0x00FF /* Max Power High */ +#define SSB_SPROM2_MAXP_A_LO 0xFF00 /* Max Power Low */ +#define SSB_SPROM2_MAXP_A_LO_SHIFT 8 +#define SSB_SPROM2_PA1LOB0 0x003C /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1LOB1 0x003E /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1LOB2 0x0040 /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1HIB0 0x0042 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_PA1HIB1 0x0044 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_PA1HIB2 0x0046 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_OPO 0x0078 /* OFDM Power Offset from CCK Level */ +#define SSB_SPROM2_OPO_VALUE 0x00FF +#define SSB_SPROM2_OPO_UNUSED 0xFF00 +#define SSB_SPROM2_CCODE 0x007C /* Two char Country Code */ + +/* SPROM Revision 3 (inherits most data from rev 2) */ +#define SSB_SPROM3_OFDMAPO 0x002C /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_OFDMALPO 0x0030 /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_OFDMAHPO 0x0034 /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_GPIOLDC 0x0042 /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */ +#define SSB_SPROM3_GPIOLDC_OFF 0x0000FF00 /* Off Count */ +#define SSB_SPROM3_GPIOLDC_OFF_SHIFT 8 +#define SSB_SPROM3_GPIOLDC_ON 0x00FF0000 /* On Count */ +#define SSB_SPROM3_GPIOLDC_ON_SHIFT 16 +#define SSB_SPROM3_IL0MAC 0x004A /* 6 bytes MAC address for 802.11b/g */ +#define SSB_SPROM3_CCKPO 0x0078 /* CCK Power Offset */ +#define SSB_SPROM3_CCKPO_1M 0x000F /* 1M Rate PO */ +#define SSB_SPROM3_CCKPO_2M 0x00F0 /* 2M Rate PO */ +#define SSB_SPROM3_CCKPO_2M_SHIFT 4 +#define SSB_SPROM3_CCKPO_55M 0x0F00 /* 5.5M Rate PO */ +#define SSB_SPROM3_CCKPO_55M_SHIFT 8 +#define SSB_SPROM3_CCKPO_11M 0xF000 /* 11M Rate PO */ +#define SSB_SPROM3_CCKPO_11M_SHIFT 12 +#define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */ + +/* SPROM Revision 4 */ +#define SSB_SPROM4_BFLLO 0x0044 /* Boardflags (low 16 bits) */ +#define SSB_SPROM4_BFLHI 0x0046 /* Board Flags Hi */ +#define SSB_SPROM4_BFL2LO 0x0048 /* Board flags 2 (low 16 bits) */ +#define SSB_SPROM4_BFL2HI 0x004A /* Board flags 2 Hi */ +#define SSB_SPROM4_IL0MAC 0x004C /* 6 byte MAC address for a/b/g/n */ +#define SSB_SPROM4_CCODE 0x0052 /* Country Code (2 bytes) */ +#define SSB_SPROM4_GPIOA 0x0056 /* Gen. Purpose IO # 0 and 1 */ +#define SSB_SPROM4_GPIOA_P0 0x00FF /* Pin 0 */ +#define SSB_SPROM4_GPIOA_P1 0xFF00 /* Pin 1 */ +#define SSB_SPROM4_GPIOA_P1_SHIFT 8 +#define SSB_SPROM4_GPIOB 0x0058 /* Gen. Purpose IO # 2 and 3 */ +#define SSB_SPROM4_GPIOB_P2 0x00FF /* Pin 2 */ +#define SSB_SPROM4_GPIOB_P3 0xFF00 /* Pin 3 */ +#define SSB_SPROM4_GPIOB_P3_SHIFT 8 +#define SSB_SPROM4_ETHPHY 0x005A /* Ethernet PHY settings ?? */ +#define SSB_SPROM4_ETHPHY_ET0A 0x001F /* MII Address for enet0 */ +#define SSB_SPROM4_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */ +#define SSB_SPROM4_ETHPHY_ET1A_SHIFT 5 +#define SSB_SPROM4_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */ +#define SSB_SPROM4_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */ +#define SSB_SPROM4_ANTAVAIL 0x005D /* Antenna available bitfields */ +#define SSB_SPROM4_ANTAVAIL_A 0x00FF /* A-PHY bitfield */ +#define SSB_SPROM4_ANTAVAIL_A_SHIFT 0 +#define SSB_SPROM4_ANTAVAIL_BG 0xFF00 /* B-PHY and G-PHY bitfield */ +#define SSB_SPROM4_ANTAVAIL_BG_SHIFT 8 +#define SSB_SPROM4_AGAIN01 0x005E /* Antenna Gain (in dBm Q5.2) */ +#define SSB_SPROM4_AGAIN0 0x00FF /* Antenna 0 */ +#define SSB_SPROM4_AGAIN0_SHIFT 0 +#define SSB_SPROM4_AGAIN1 0xFF00 /* Antenna 1 */ +#define SSB_SPROM4_AGAIN1_SHIFT 8 +#define SSB_SPROM4_AGAIN23 0x0060 +#define SSB_SPROM4_AGAIN2 0x00FF /* Antenna 2 */ +#define SSB_SPROM4_AGAIN2_SHIFT 0 +#define SSB_SPROM4_AGAIN3 0xFF00 /* Antenna 3 */ +#define SSB_SPROM4_AGAIN3_SHIFT 8 +#define SSB_SPROM4_TXPID2G01 0x0062 /* TX Power Index 2GHz */ +#define SSB_SPROM4_TXPID2G0 0x00FF +#define SSB_SPROM4_TXPID2G0_SHIFT 0 +#define SSB_SPROM4_TXPID2G1 0xFF00 +#define SSB_SPROM4_TXPID2G1_SHIFT 8 +#define SSB_SPROM4_TXPID2G23 0x0064 /* TX Power Index 2GHz */ +#define SSB_SPROM4_TXPID2G2 0x00FF +#define SSB_SPROM4_TXPID2G2_SHIFT 0 +#define SSB_SPROM4_TXPID2G3 0xFF00 +#define SSB_SPROM4_TXPID2G3_SHIFT 8 +#define SSB_SPROM4_TXPID5G01 0x0066 /* TX Power Index 5GHz middle subband */ +#define SSB_SPROM4_TXPID5G0 0x00FF +#define SSB_SPROM4_TXPID5G0_SHIFT 0 +#define SSB_SPROM4_TXPID5G1 0xFF00 +#define SSB_SPROM4_TXPID5G1_SHIFT 8 +#define SSB_SPROM4_TXPID5G23 0x0068 /* TX Power Index 5GHz middle subband */ +#define SSB_SPROM4_TXPID5G2 0x00FF +#define SSB_SPROM4_TXPID5G2_SHIFT 0 +#define SSB_SPROM4_TXPID5G3 0xFF00 +#define SSB_SPROM4_TXPID5G3_SHIFT 8 +#define SSB_SPROM4_TXPID5GL01 0x006A /* TX Power Index 5GHz low subband */ +#define SSB_SPROM4_TXPID5GL0 0x00FF +#define SSB_SPROM4_TXPID5GL0_SHIFT 0 +#define SSB_SPROM4_TXPID5GL1 0xFF00 +#define SSB_SPROM4_TXPID5GL1_SHIFT 8 +#define SSB_SPROM4_TXPID5GL23 0x006C /* TX Power Index 5GHz low subband */ +#define SSB_SPROM4_TXPID5GL2 0x00FF +#define SSB_SPROM4_TXPID5GL2_SHIFT 0 +#define SSB_SPROM4_TXPID5GL3 0xFF00 +#define SSB_SPROM4_TXPID5GL3_SHIFT 8 +#define SSB_SPROM4_TXPID5GH01 0x006E /* TX Power Index 5GHz high subband */ +#define SSB_SPROM4_TXPID5GH0 0x00FF +#define SSB_SPROM4_TXPID5GH0_SHIFT 0 +#define SSB_SPROM4_TXPID5GH1 0xFF00 +#define SSB_SPROM4_TXPID5GH1_SHIFT 8 +#define SSB_SPROM4_TXPID5GH23 0x0070 /* TX Power Index 5GHz high subband */ +#define SSB_SPROM4_TXPID5GH2 0x00FF +#define SSB_SPROM4_TXPID5GH2_SHIFT 0 +#define SSB_SPROM4_TXPID5GH3 0xFF00 +#define SSB_SPROM4_TXPID5GH3_SHIFT 8 +#define SSB_SPROM4_MAXP_BG 0x0080 /* Max Power BG in path 1 */ +#define SSB_SPROM4_MAXP_BG_MASK 0x00FF /* Mask for Max Power BG */ +#define SSB_SPROM4_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */ +#define SSB_SPROM4_ITSSI_BG_SHIFT 8 +#define SSB_SPROM4_MAXP_A 0x008A /* Max Power A in path 1 */ +#define SSB_SPROM4_MAXP_A_MASK 0x00FF /* Mask for Max Power A */ +#define SSB_SPROM4_ITSSI_A 0xFF00 /* Mask for path 1 itssi_a */ +#define SSB_SPROM4_ITSSI_A_SHIFT 8 +#define SSB_SPROM4_PA0B0 0x0082 /* The paXbY locations are */ +#define SSB_SPROM4_PA0B1 0x0084 /* only guesses */ +#define SSB_SPROM4_PA0B2 0x0086 +#define SSB_SPROM4_PA1B0 0x008E +#define SSB_SPROM4_PA1B1 0x0090 +#define SSB_SPROM4_PA1B2 0x0092 + +/* SPROM Revision 5 (inherits most data from rev 4) */ +#define SSB_SPROM5_CCODE 0x0044 /* Country Code (2 bytes) */ +#define SSB_SPROM5_BFLLO 0x004A /* Boardflags (low 16 bits) */ +#define SSB_SPROM5_BFLHI 0x004C /* Board Flags Hi */ +#define SSB_SPROM5_BFL2LO 0x004E /* Board flags 2 (low 16 bits) */ +#define SSB_SPROM5_BFL2HI 0x0050 /* Board flags 2 Hi */ +#define SSB_SPROM5_IL0MAC 0x0052 /* 6 byte MAC address for a/b/g/n */ +#define SSB_SPROM5_GPIOA 0x0076 /* Gen. Purpose IO # 0 and 1 */ +#define SSB_SPROM5_GPIOA_P0 0x00FF /* Pin 0 */ +#define SSB_SPROM5_GPIOA_P1 0xFF00 /* Pin 1 */ +#define SSB_SPROM5_GPIOA_P1_SHIFT 8 +#define SSB_SPROM5_GPIOB 0x0078 /* Gen. Purpose IO # 2 and 3 */ +#define SSB_SPROM5_GPIOB_P2 0x00FF /* Pin 2 */ +#define SSB_SPROM5_GPIOB_P3 0xFF00 /* Pin 3 */ +#define SSB_SPROM5_GPIOB_P3_SHIFT 8 + +/* SPROM Revision 8 */ +#define SSB_SPROM8_BOARDREV 0x0082 /* Board revision */ +#define SSB_SPROM8_BFLLO 0x0084 /* Board flags (bits 0-15) */ +#define SSB_SPROM8_BFLHI 0x0086 /* Board flags (bits 16-31) */ +#define SSB_SPROM8_BFL2LO 0x0088 /* Board flags (bits 32-47) */ +#define SSB_SPROM8_BFL2HI 0x008A /* Board flags (bits 48-63) */ +#define SSB_SPROM8_IL0MAC 0x008C /* 6 byte MAC address */ +#define SSB_SPROM8_CCODE 0x0092 /* 2 byte country code */ +#define SSB_SPROM8_GPIOA 0x0096 /*Gen. Purpose IO # 0 and 1 */ +#define SSB_SPROM8_GPIOA_P0 0x00FF /* Pin 0 */ +#define SSB_SPROM8_GPIOA_P1 0xFF00 /* Pin 1 */ +#define SSB_SPROM8_GPIOA_P1_SHIFT 8 +#define SSB_SPROM8_GPIOB 0x0098 /* Gen. Purpose IO # 2 and 3 */ +#define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */ +#define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */ +#define SSB_SPROM8_GPIOB_P3_SHIFT 8 +#define SSB_SPROM8_ANTAVAIL 0x009C /* Antenna available bitfields*/ +#define SSB_SPROM8_ANTAVAIL_A 0xFF00 /* A-PHY bitfield */ +#define SSB_SPROM8_ANTAVAIL_A_SHIFT 8 +#define SSB_SPROM8_ANTAVAIL_BG 0x00FF /* B-PHY and G-PHY bitfield */ +#define SSB_SPROM8_ANTAVAIL_BG_SHIFT 0 +#define SSB_SPROM8_AGAIN01 0x009E /* Antenna Gain (in dBm Q5.2) */ +#define SSB_SPROM8_AGAIN0 0x00FF /* Antenna 0 */ +#define SSB_SPROM8_AGAIN0_SHIFT 0 +#define SSB_SPROM8_AGAIN1 0xFF00 /* Antenna 1 */ +#define SSB_SPROM8_AGAIN1_SHIFT 8 +#define SSB_SPROM8_AGAIN23 0x00A0 +#define SSB_SPROM8_AGAIN2 0x00FF /* Antenna 2 */ +#define SSB_SPROM8_AGAIN2_SHIFT 0 +#define SSB_SPROM8_AGAIN3 0xFF00 /* Antenna 3 */ +#define SSB_SPROM8_AGAIN3_SHIFT 8 +#define SSB_SPROM8_RSSIPARM2G 0x00A4 /* RSSI params for 2GHz */ +#define SSB_SPROM8_RSSISMF2G 0x000F +#define SSB_SPROM8_RSSISMC2G 0x00F0 +#define SSB_SPROM8_RSSISMC2G_SHIFT 4 +#define SSB_SPROM8_RSSISAV2G 0x0700 +#define SSB_SPROM8_RSSISAV2G_SHIFT 8 +#define SSB_SPROM8_BXA2G 0x1800 +#define SSB_SPROM8_BXA2G_SHIFT 11 +#define SSB_SPROM8_RSSIPARM5G 0x00A6 /* RSSI params for 5GHz */ +#define SSB_SPROM8_RSSISMF5G 0x000F +#define SSB_SPROM8_RSSISMC5G 0x00F0 +#define SSB_SPROM8_RSSISMC5G_SHIFT 4 +#define SSB_SPROM8_RSSISAV5G 0x0700 +#define SSB_SPROM8_RSSISAV5G_SHIFT 8 +#define SSB_SPROM8_BXA5G 0x1800 +#define SSB_SPROM8_BXA5G_SHIFT 11 +#define SSB_SPROM8_TRI25G 0x00A8 /* TX isolation 2.4&5.3GHz */ +#define SSB_SPROM8_TRI2G 0x00FF /* TX isolation 2.4GHz */ +#define SSB_SPROM8_TRI5G 0xFF00 /* TX isolation 5.3GHz */ +#define SSB_SPROM8_TRI5G_SHIFT 8 +#define SSB_SPROM8_TRI5GHL 0x00AA /* TX isolation 5.2/5.8GHz */ +#define SSB_SPROM8_TRI5GL 0x00FF /* TX isolation 5.2GHz */ +#define SSB_SPROM8_TRI5GH 0xFF00 /* TX isolation 5.8GHz */ +#define SSB_SPROM8_TRI5GH_SHIFT 8 +#define SSB_SPROM8_RXPO 0x00AC /* RX power offsets */ +#define SSB_SPROM8_RXPO2G 0x00FF /* 2GHz RX power offset */ +#define SSB_SPROM8_RXPO5G 0xFF00 /* 5GHz RX power offset */ +#define SSB_SPROM8_RXPO5G_SHIFT 8 +#define SSB_SPROM8_MAXP_BG 0x00C0 /* Max Power 2GHz in path 1 */ +#define SSB_SPROM8_MAXP_BG_MASK 0x00FF /* Mask for Max Power 2GHz */ +#define SSB_SPROM8_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */ +#define SSB_SPROM8_ITSSI_BG_SHIFT 8 +#define SSB_SPROM8_PA0B0 0x00C2 /* 2GHz power amp settings */ +#define SSB_SPROM8_PA0B1 0x00C4 +#define SSB_SPROM8_PA0B2 0x00C6 +#define SSB_SPROM8_MAXP_A 0x00C8 /* Max Power 5.3GHz */ +#define SSB_SPROM8_MAXP_A_MASK 0x00FF /* Mask for Max Power 5.3GHz */ +#define SSB_SPROM8_ITSSI_A 0xFF00 /* Mask for path 1 itssi_a */ +#define SSB_SPROM8_ITSSI_A_SHIFT 8 +#define SSB_SPROM8_MAXP_AHL 0x00CA /* Max Power 5.2/5.8GHz */ +#define SSB_SPROM8_MAXP_AH_MASK 0x00FF /* Mask for Max Power 5.8GHz */ +#define SSB_SPROM8_MAXP_AL_MASK 0xFF00 /* Mask for Max Power 5.2GHz */ +#define SSB_SPROM8_MAXP_AL_SHIFT 8 +#define SSB_SPROM8_PA1B0 0x00CC /* 5.3GHz power amp settings */ +#define SSB_SPROM8_PA1B1 0x00CE +#define SSB_SPROM8_PA1B2 0x00D0 +#define SSB_SPROM8_PA1LOB0 0x00D2 /* 5.2GHz power amp settings */ +#define SSB_SPROM8_PA1LOB1 0x00D4 +#define SSB_SPROM8_PA1LOB2 0x00D6 +#define SSB_SPROM8_PA1HIB0 0x00D8 /* 5.8GHz power amp settings */ +#define SSB_SPROM8_PA1HIB1 0x00DA +#define SSB_SPROM8_PA1HIB2 0x00DC +#define SSB_SPROM8_CCK2GPO 0x0140 /* CCK power offset */ +#define SSB_SPROM8_OFDM2GPO 0x0142 /* 2.4GHz OFDM power offset */ +#define SSB_SPROM8_OFDM5GPO 0x0146 /* 5.3GHz OFDM power offset */ +#define SSB_SPROM8_OFDM5GLPO 0x014A /* 5.2GHz OFDM power offset */ +#define SSB_SPROM8_OFDM5GHPO 0x014E /* 5.8GHz OFDM power offset */ + +/* Values for boardflags_lo read from SPROM */ +#define SSB_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ +#define SSB_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ +#define SSB_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ +#define SSB_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ +#define SSB_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ +#define SSB_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ +#define SSB_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ +#define SSB_BFL_ENETADM 0x0080 /* has ADMtek switch */ +#define SSB_BFL_ENETVLAN 0x0100 /* can do vlan */ +#define SSB_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ +#define SSB_BFL_NOPCI 0x0400 /* board leaves PCI floating */ +#define SSB_BFL_FEM 0x0800 /* supports the Front End Module */ +#define SSB_BFL_EXTLNA 0x1000 /* has an external LNA */ +#define SSB_BFL_HGPA 0x2000 /* had high gain PA */ +#define SSB_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ +#define SSB_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ + +/* Values for boardflags_hi read from SPROM */ +#define SSB_BFH_NOPA 0x0001 /* has no PA */ +#define SSB_BFH_RSSIINV 0x0002 /* RSSI uses positive slope (not TSSI) */ +#define SSB_BFH_PAREF 0x0004 /* uses the PARef LDO */ +#define SSB_BFH_3TSWITCH 0x0008 /* uses a triple throw switch shared with bluetooth */ +#define SSB_BFH_PHASESHIFT 0x0010 /* can support phase shifter */ +#define SSB_BFH_BUCKBOOST 0x0020 /* has buck/booster */ +#define SSB_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna with bluetooth */ + +/* Values for boardflags2_lo read from SPROM */ +#define SSB_BFL2_RXBB_INT_REG_DIS 0x0001 /* external RX BB regulator present */ +#define SSB_BFL2_APLL_WAR 0x0002 /* alternative A-band PLL settings implemented */ +#define SSB_BFL2_TXPWRCTRL_EN 0x0004 /* permits enabling TX Power Control */ +#define SSB_BFL2_2X4_DIV 0x0008 /* 2x4 diversity switch */ +#define SSB_BFL2_5G_PWRGAIN 0x0010 /* supports 5G band power gain */ +#define SSB_BFL2_PCIEWAR_OVR 0x0020 /* overrides ASPM and Clkreq settings */ +#define SSB_BFL2_CAESERS_BRD 0x0040 /* is Caesers board (unused) */ +#define SSB_BFL2_BTC3WIRE 0x0080 /* used 3-wire bluetooth coexist */ +#define SSB_BFL2_SKWRKFEM_BRD 0x0100 /* 4321mcm93 uses Skyworks FEM */ +#define SSB_BFL2_SPUR_WAR 0x0200 /* has a workaround for clock-harmonic spurs */ +#define SSB_BFL2_GPLL_WAR 0x0400 /* altenative G-band PLL settings implemented */ + +/* Values for SSB_SPROM1_BINF_CCODE */ +enum { + SSB_SPROM1CCODE_WORLD = 0, + SSB_SPROM1CCODE_THAILAND, + SSB_SPROM1CCODE_ISRAEL, + SSB_SPROM1CCODE_JORDAN, + SSB_SPROM1CCODE_CHINA, + SSB_SPROM1CCODE_JAPAN, + SSB_SPROM1CCODE_USA_CANADA_ANZ, + SSB_SPROM1CCODE_EUROPE, + SSB_SPROM1CCODE_USA_LOW, + SSB_SPROM1CCODE_JAPAN_HIGH, + SSB_SPROM1CCODE_ALL, + SSB_SPROM1CCODE_NONE, +}; + +/* Address-Match values and masks (SSB_ADMATCHxxx) */ +#define SSB_ADM_TYPE 0x00000003 /* Address type */ +#define SSB_ADM_TYPE0 0 +#define SSB_ADM_TYPE1 1 +#define SSB_ADM_TYPE2 2 +#define SSB_ADM_AD64 0x00000004 +#define SSB_ADM_SZ0 0x000000F8 /* Type0 size */ +#define SSB_ADM_SZ0_SHIFT 3 +#define SSB_ADM_SZ1 0x000001F8 /* Type1 size */ +#define SSB_ADM_SZ1_SHIFT 3 +#define SSB_ADM_SZ2 0x000001F8 /* Type2 size */ +#define SSB_ADM_SZ2_SHIFT 3 +#define SSB_ADM_EN 0x00000400 /* Enable */ +#define SSB_ADM_NEG 0x00000800 /* Negative decode */ +#define SSB_ADM_BASE0 0xFFFFFF00 /* Type0 base address */ +#define SSB_ADM_BASE0_SHIFT 8 +#define SSB_ADM_BASE1 0xFFFFF000 /* Type1 base address for the core */ +#define SSB_ADM_BASE1_SHIFT 12 +#define SSB_ADM_BASE2 0xFFFF0000 /* Type2 base address for the core */ +#define SSB_ADM_BASE2_SHIFT 16 + + +#endif /* LINUX_SSB_REGS_H_ */ diff --git a/include/compat/linux/tracepoint.h b/include/compat/linux/tracepoint.h new file mode 100644 index 00000000..9f5add1c --- /dev/null +++ b/include/compat/linux/tracepoint.h @@ -0,0 +1,10 @@ +#ifndef _COMPAT_LINUX_TRACEPOINT_H +#define _COMPAT_LINUX_TRACEPOINT_H 1 + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)) +#include_next +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)) */ + +#endif /* _COMPAT_LINUX_TRACEPOINT_H */ diff --git a/include/compat/linux/unaligned/access_ok.h b/include/compat/linux/unaligned/access_ok.h new file mode 100644 index 00000000..99c1b4d2 --- /dev/null +++ b/include/compat/linux/unaligned/access_ok.h @@ -0,0 +1,67 @@ +#ifndef _LINUX_UNALIGNED_ACCESS_OK_H +#define _LINUX_UNALIGNED_ACCESS_OK_H + +#include +#include + +static inline u16 get_unaligned_le16(const void *p) +{ + return le16_to_cpup((__le16 *)p); +} + +static inline u32 get_unaligned_le32(const void *p) +{ + return le32_to_cpup((__le32 *)p); +} + +static inline u64 get_unaligned_le64(const void *p) +{ + return le64_to_cpup((__le64 *)p); +} + +static inline u16 get_unaligned_be16(const void *p) +{ + return be16_to_cpup((__be16 *)p); +} + +static inline u32 get_unaligned_be32(const void *p) +{ + return be32_to_cpup((__be32 *)p); +} + +static inline u64 get_unaligned_be64(const void *p) +{ + return be64_to_cpup((__be64 *)p); +} + +static inline void put_unaligned_le16(u16 val, void *p) +{ + *((__le16 *)p) = cpu_to_le16(val); +} + +static inline void put_unaligned_le32(u32 val, void *p) +{ + *((__le32 *)p) = cpu_to_le32(val); +} + +static inline void put_unaligned_le64(u64 val, void *p) +{ + *((__le64 *)p) = cpu_to_le64(val); +} + +static inline void put_unaligned_be16(u16 val, void *p) +{ + *((__be16 *)p) = cpu_to_be16(val); +} + +static inline void put_unaligned_be32(u32 val, void *p) +{ + *((__be32 *)p) = cpu_to_be32(val); +} + +static inline void put_unaligned_be64(u64 val, void *p) +{ + *((__be64 *)p) = cpu_to_be64(val); +} + +#endif /* _LINUX_UNALIGNED_ACCESS_OK_H */ diff --git a/include/compat/linux/unaligned/be_byteshift.h b/include/compat/linux/unaligned/be_byteshift.h new file mode 100644 index 00000000..9356b242 --- /dev/null +++ b/include/compat/linux/unaligned/be_byteshift.h @@ -0,0 +1,70 @@ +#ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H +#define _LINUX_UNALIGNED_BE_BYTESHIFT_H + +#include + +static inline u16 __get_unaligned_be16(const u8 *p) +{ + return p[0] << 8 | p[1]; +} + +static inline u32 __get_unaligned_be32(const u8 *p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +static inline u64 __get_unaligned_be64(const u8 *p) +{ + return (u64)__get_unaligned_be32(p) << 32 | + __get_unaligned_be32(p + 4); +} + +static inline void __put_unaligned_be16(u16 val, u8 *p) +{ + *p++ = val >> 8; + *p++ = val; +} + +static inline void __put_unaligned_be32(u32 val, u8 *p) +{ + __put_unaligned_be16(val >> 16, p); + __put_unaligned_be16(val, p + 2); +} + +static inline void __put_unaligned_be64(u64 val, u8 *p) +{ + __put_unaligned_be32(val >> 32, p); + __put_unaligned_be32(val, p + 4); +} + +static inline u16 get_unaligned_be16(const void *p) +{ + return __get_unaligned_be16((const u8 *)p); +} + +static inline u32 get_unaligned_be32(const void *p) +{ + return __get_unaligned_be32((const u8 *)p); +} + +static inline u64 get_unaligned_be64(const void *p) +{ + return __get_unaligned_be64((const u8 *)p); +} + +static inline void put_unaligned_be16(u16 val, void *p) +{ + __put_unaligned_be16(val, p); +} + +static inline void put_unaligned_be32(u32 val, void *p) +{ + __put_unaligned_be32(val, p); +} + +static inline void put_unaligned_be64(u64 val, void *p) +{ + __put_unaligned_be64(val, p); +} + +#endif /* _LINUX_UNALIGNED_BE_BYTESHIFT_H */ diff --git a/include/compat/linux/unaligned/be_memmove.h b/include/compat/linux/unaligned/be_memmove.h new file mode 100644 index 00000000..c2a76c5c --- /dev/null +++ b/include/compat/linux/unaligned/be_memmove.h @@ -0,0 +1,36 @@ +#ifndef _LINUX_UNALIGNED_BE_MEMMOVE_H +#define _LINUX_UNALIGNED_BE_MEMMOVE_H + +#include + +static inline u16 get_unaligned_be16(const void *p) +{ + return __get_unaligned_memmove16((const u8 *)p); +} + +static inline u32 get_unaligned_be32(const void *p) +{ + return __get_unaligned_memmove32((const u8 *)p); +} + +static inline u64 get_unaligned_be64(const void *p) +{ + return __get_unaligned_memmove64((const u8 *)p); +} + +static inline void put_unaligned_be16(u16 val, void *p) +{ + __put_unaligned_memmove16(val, p); +} + +static inline void put_unaligned_be32(u32 val, void *p) +{ + __put_unaligned_memmove32(val, p); +} + +static inline void put_unaligned_be64(u64 val, void *p) +{ + __put_unaligned_memmove64(val, p); +} + +#endif /* _LINUX_UNALIGNED_LE_MEMMOVE_H */ diff --git a/include/compat/linux/unaligned/be_struct.h b/include/compat/linux/unaligned/be_struct.h new file mode 100644 index 00000000..13241583 --- /dev/null +++ b/include/compat/linux/unaligned/be_struct.h @@ -0,0 +1,36 @@ +#ifndef _LINUX_UNALIGNED_BE_STRUCT_H +#define _LINUX_UNALIGNED_BE_STRUCT_H + +#include + +static inline u16 get_unaligned_be16(const void *p) +{ + return __get_unaligned_cpu16((const u8 *)p); +} + +static inline u32 get_unaligned_be32(const void *p) +{ + return __get_unaligned_cpu32((const u8 *)p); +} + +static inline u64 get_unaligned_be64(const void *p) +{ + return __get_unaligned_cpu64((const u8 *)p); +} + +static inline void put_unaligned_be16(u16 val, void *p) +{ + __put_unaligned_cpu16(val, p); +} + +static inline void put_unaligned_be32(u32 val, void *p) +{ + __put_unaligned_cpu32(val, p); +} + +static inline void put_unaligned_be64(u64 val, void *p) +{ + __put_unaligned_cpu64(val, p); +} + +#endif /* _LINUX_UNALIGNED_BE_STRUCT_H */ diff --git a/include/compat/linux/unaligned/generic.h b/include/compat/linux/unaligned/generic.h new file mode 100644 index 00000000..02d97ff3 --- /dev/null +++ b/include/compat/linux/unaligned/generic.h @@ -0,0 +1,68 @@ +#ifndef _LINUX_UNALIGNED_GENERIC_H +#define _LINUX_UNALIGNED_GENERIC_H + +/* + * Cause a link-time error if we try an unaligned access other than + * 1,2,4 or 8 bytes long + */ +extern void __bad_unaligned_access_size(void); + +#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \ + __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ + __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \ + __bad_unaligned_access_size())))); \ + })) + +#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \ + __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ + __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \ + __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \ + __bad_unaligned_access_size())))); \ + })) + +#define __put_unaligned_le(val, ptr) ({ \ + void *__gu_p = (ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(u8 *)__gu_p = (__force u8)(val); \ + break; \ + case 2: \ + put_unaligned_le16((__force u16)(val), __gu_p); \ + break; \ + case 4: \ + put_unaligned_le32((__force u32)(val), __gu_p); \ + break; \ + case 8: \ + put_unaligned_le64((__force u64)(val), __gu_p); \ + break; \ + default: \ + __bad_unaligned_access_size(); \ + break; \ + } \ + (void)0; }) + +#define __put_unaligned_be(val, ptr) ({ \ + void *__gu_p = (ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(u8 *)__gu_p = (__force u8)(val); \ + break; \ + case 2: \ + put_unaligned_be16((__force u16)(val), __gu_p); \ + break; \ + case 4: \ + put_unaligned_be32((__force u32)(val), __gu_p); \ + break; \ + case 8: \ + put_unaligned_be64((__force u64)(val), __gu_p); \ + break; \ + default: \ + __bad_unaligned_access_size(); \ + break; \ + } \ + (void)0; }) + +#endif /* _LINUX_UNALIGNED_GENERIC_H */ diff --git a/include/compat/linux/unaligned/le_byteshift.h b/include/compat/linux/unaligned/le_byteshift.h new file mode 100644 index 00000000..be376fb7 --- /dev/null +++ b/include/compat/linux/unaligned/le_byteshift.h @@ -0,0 +1,70 @@ +#ifndef _LINUX_UNALIGNED_LE_BYTESHIFT_H +#define _LINUX_UNALIGNED_LE_BYTESHIFT_H + +#include + +static inline u16 __get_unaligned_le16(const u8 *p) +{ + return p[0] | p[1] << 8; +} + +static inline u32 __get_unaligned_le32(const u8 *p) +{ + return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; +} + +static inline u64 __get_unaligned_le64(const u8 *p) +{ + return (u64)__get_unaligned_le32(p + 4) << 32 | + __get_unaligned_le32(p); +} + +static inline void __put_unaligned_le16(u16 val, u8 *p) +{ + *p++ = val; + *p++ = val >> 8; +} + +static inline void __put_unaligned_le32(u32 val, u8 *p) +{ + __put_unaligned_le16(val >> 16, p + 2); + __put_unaligned_le16(val, p); +} + +static inline void __put_unaligned_le64(u64 val, u8 *p) +{ + __put_unaligned_le32(val >> 32, p + 4); + __put_unaligned_le32(val, p); +} + +static inline u16 get_unaligned_le16(const void *p) +{ + return __get_unaligned_le16((const u8 *)p); +} + +static inline u32 get_unaligned_le32(const void *p) +{ + return __get_unaligned_le32((const u8 *)p); +} + +static inline u64 get_unaligned_le64(const void *p) +{ + return __get_unaligned_le64((const u8 *)p); +} + +static inline void put_unaligned_le16(u16 val, void *p) +{ + __put_unaligned_le16(val, p); +} + +static inline void put_unaligned_le32(u32 val, void *p) +{ + __put_unaligned_le32(val, p); +} + +static inline void put_unaligned_le64(u64 val, void *p) +{ + __put_unaligned_le64(val, p); +} + +#endif /* _LINUX_UNALIGNED_LE_BYTESHIFT_H */ diff --git a/include/compat/linux/unaligned/le_memmove.h b/include/compat/linux/unaligned/le_memmove.h new file mode 100644 index 00000000..269849be --- /dev/null +++ b/include/compat/linux/unaligned/le_memmove.h @@ -0,0 +1,36 @@ +#ifndef _LINUX_UNALIGNED_LE_MEMMOVE_H +#define _LINUX_UNALIGNED_LE_MEMMOVE_H + +#include + +static inline u16 get_unaligned_le16(const void *p) +{ + return __get_unaligned_memmove16((const u8 *)p); +} + +static inline u32 get_unaligned_le32(const void *p) +{ + return __get_unaligned_memmove32((const u8 *)p); +} + +static inline u64 get_unaligned_le64(const void *p) +{ + return __get_unaligned_memmove64((const u8 *)p); +} + +static inline void put_unaligned_le16(u16 val, void *p) +{ + __put_unaligned_memmove16(val, p); +} + +static inline void put_unaligned_le32(u32 val, void *p) +{ + __put_unaligned_memmove32(val, p); +} + +static inline void put_unaligned_le64(u64 val, void *p) +{ + __put_unaligned_memmove64(val, p); +} + +#endif /* _LINUX_UNALIGNED_LE_MEMMOVE_H */ diff --git a/include/compat/linux/unaligned/le_struct.h b/include/compat/linux/unaligned/le_struct.h new file mode 100644 index 00000000..088c4572 --- /dev/null +++ b/include/compat/linux/unaligned/le_struct.h @@ -0,0 +1,36 @@ +#ifndef _LINUX_UNALIGNED_LE_STRUCT_H +#define _LINUX_UNALIGNED_LE_STRUCT_H + +#include + +static inline u16 get_unaligned_le16(const void *p) +{ + return __get_unaligned_cpu16((const u8 *)p); +} + +static inline u32 get_unaligned_le32(const void *p) +{ + return __get_unaligned_cpu32((const u8 *)p); +} + +static inline u64 get_unaligned_le64(const void *p) +{ + return __get_unaligned_cpu64((const u8 *)p); +} + +static inline void put_unaligned_le16(u16 val, void *p) +{ + __put_unaligned_cpu16(val, p); +} + +static inline void put_unaligned_le32(u32 val, void *p) +{ + __put_unaligned_cpu32(val, p); +} + +static inline void put_unaligned_le64(u64 val, void *p) +{ + __put_unaligned_cpu64(val, p); +} + +#endif /* _LINUX_UNALIGNED_LE_STRUCT_H */ diff --git a/include/compat/linux/unaligned/memmove.h b/include/compat/linux/unaligned/memmove.h new file mode 100644 index 00000000..eeb5a779 --- /dev/null +++ b/include/compat/linux/unaligned/memmove.h @@ -0,0 +1,45 @@ +#ifndef _LINUX_UNALIGNED_MEMMOVE_H +#define _LINUX_UNALIGNED_MEMMOVE_H + +#include +#include + +/* Use memmove here, so gcc does not insert a __builtin_memcpy. */ + +static inline u16 __get_unaligned_memmove16(const void *p) +{ + u16 tmp; + memmove(&tmp, p, 2); + return tmp; +} + +static inline u32 __get_unaligned_memmove32(const void *p) +{ + u32 tmp; + memmove(&tmp, p, 4); + return tmp; +} + +static inline u64 __get_unaligned_memmove64(const void *p) +{ + u64 tmp; + memmove(&tmp, p, 8); + return tmp; +} + +static inline void __put_unaligned_memmove16(u16 val, void *p) +{ + memmove(p, &val, 2); +} + +static inline void __put_unaligned_memmove32(u32 val, void *p) +{ + memmove(p, &val, 4); +} + +static inline void __put_unaligned_memmove64(u64 val, void *p) +{ + memmove(p, &val, 8); +} + +#endif /* _LINUX_UNALIGNED_MEMMOVE_H */ diff --git a/include/compat/linux/unaligned/packed_struct.h b/include/compat/linux/unaligned/packed_struct.h new file mode 100644 index 00000000..2498bb9f --- /dev/null +++ b/include/compat/linux/unaligned/packed_struct.h @@ -0,0 +1,46 @@ +#ifndef _LINUX_UNALIGNED_PACKED_STRUCT_H +#define _LINUX_UNALIGNED_PACKED_STRUCT_H + +#include + +struct __una_u16 { u16 x __attribute__((packed)); }; +struct __una_u32 { u32 x __attribute__((packed)); }; +struct __una_u64 { u64 x __attribute__((packed)); }; + +static inline u16 __get_unaligned_cpu16(const void *p) +{ + const struct __una_u16 *ptr = (const struct __una_u16 *)p; + return ptr->x; +} + +static inline u32 __get_unaligned_cpu32(const void *p) +{ + const struct __una_u32 *ptr = (const struct __una_u32 *)p; + return ptr->x; +} + +static inline u64 __get_unaligned_cpu64(const void *p) +{ + const struct __una_u64 *ptr = (const struct __una_u64 *)p; + return ptr->x; +} + +static inline void __put_unaligned_cpu16(u16 val, void *p) +{ + struct __una_u16 *ptr = (struct __una_u16 *)p; + ptr->x = val; +} + +static inline void __put_unaligned_cpu32(u32 val, void *p) +{ + struct __una_u32 *ptr = (struct __una_u32 *)p; + ptr->x = val; +} + +static inline void __put_unaligned_cpu64(u64 val, void *p) +{ + struct __una_u64 *ptr = (struct __una_u64 *)p; + ptr->x = val; +} + +#endif /* _LINUX_UNALIGNED_PACKED_STRUCT_H */ diff --git a/include/compat/linux/usb/rndis_host.h b/include/compat/linux/usb/rndis_host.h new file mode 100644 index 00000000..88fceb71 --- /dev/null +++ b/include/compat/linux/usb/rndis_host.h @@ -0,0 +1,272 @@ +/* + * Host Side support for RNDIS Networking Links + * Copyright (C) 2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_USB_RNDIS_HOST_H +#define __LINUX_USB_RNDIS_HOST_H + +/* + * CONTROL uses CDC "encapsulated commands" with funky notifications. + * - control-out: SEND_ENCAPSULATED + * - interrupt-in: RESPONSE_AVAILABLE + * - control-in: GET_ENCAPSULATED + * + * We'll try to ignore the RESPONSE_AVAILABLE notifications. + * + * REVISIT some RNDIS implementations seem to have curious issues still + * to be resolved. + */ +struct rndis_msg_hdr { + __le32 msg_type; /* RNDIS_MSG_* */ + __le32 msg_len; + /* followed by data that varies between messages */ + __le32 request_id; + __le32 status; + /* ... and more */ +} __attribute__ ((packed)); + +/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */ +#define CONTROL_BUFFER_SIZE 1025 + +/* RNDIS defines an (absurdly huge) 10 second control timeout, + * but ActiveSync seems to use a more usual 5 second timeout + * (which matches the USB 2.0 spec). + */ +#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000) + +#define RNDIS_MSG_COMPLETION cpu_to_le32(0x80000000) + +/* codes for "msg_type" field of rndis messages; + * only the data channel uses packet messages (maybe batched); + * everything else goes on the control channel. + */ +#define RNDIS_MSG_PACKET cpu_to_le32(0x00000001) /* 1-N packets */ +#define RNDIS_MSG_INIT cpu_to_le32(0x00000002) +#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_HALT cpu_to_le32(0x00000003) +#define RNDIS_MSG_QUERY cpu_to_le32(0x00000004) +#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_SET cpu_to_le32(0x00000005) +#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_RESET cpu_to_le32(0x00000006) +#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_INDICATE cpu_to_le32(0x00000007) +#define RNDIS_MSG_KEEPALIVE cpu_to_le32(0x00000008) +#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) + +/* codes for "status" field of completion messages */ +#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000) +#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001) +#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015) +#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb) +#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b) +#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c) +#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION cpu_to_le32(0x40010012) + +/* codes for OID_GEN_PHYSICAL_MEDIUM */ +#define RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED cpu_to_le32(0x00000000) +#define RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN cpu_to_le32(0x00000001) +#define RNDIS_PHYSICAL_MEDIUM_CABLE_MODEM cpu_to_le32(0x00000002) +#define RNDIS_PHYSICAL_MEDIUM_PHONE_LINE cpu_to_le32(0x00000003) +#define RNDIS_PHYSICAL_MEDIUM_POWER_LINE cpu_to_le32(0x00000004) +#define RNDIS_PHYSICAL_MEDIUM_DSL cpu_to_le32(0x00000005) +#define RNDIS_PHYSICAL_MEDIUM_FIBRE_CHANNEL cpu_to_le32(0x00000006) +#define RNDIS_PHYSICAL_MEDIUM_1394 cpu_to_le32(0x00000007) +#define RNDIS_PHYSICAL_MEDIUM_WIRELESS_WAN cpu_to_le32(0x00000008) +#define RNDIS_PHYSICAL_MEDIUM_MAX cpu_to_le32(0x00000009) + +struct rndis_data_hdr { + __le32 msg_type; /* RNDIS_MSG_PACKET */ + __le32 msg_len; /* rndis_data_hdr + data_len + pad */ + __le32 data_offset; /* 36 -- right after header */ + __le32 data_len; /* ... real packet size */ + + __le32 oob_data_offset; /* zero */ + __le32 oob_data_len; /* zero */ + __le32 num_oob; /* zero */ + __le32 packet_data_offset; /* zero */ + + __le32 packet_data_len; /* zero */ + __le32 vc_handle; /* zero */ + __le32 reserved; /* zero */ +} __attribute__ ((packed)); + +struct rndis_init { /* OUT */ + /* header and: */ + __le32 msg_type; /* RNDIS_MSG_INIT */ + __le32 msg_len; /* 24 */ + __le32 request_id; + __le32 major_version; /* of rndis (1.0) */ + __le32 minor_version; + __le32 max_transfer_size; +} __attribute__ ((packed)); + +struct rndis_init_c { /* IN */ + /* header and: */ + __le32 msg_type; /* RNDIS_MSG_INIT_C */ + __le32 msg_len; + __le32 request_id; + __le32 status; + __le32 major_version; /* of rndis (1.0) */ + __le32 minor_version; + __le32 device_flags; + __le32 medium; /* zero == 802.3 */ + __le32 max_packets_per_message; + __le32 max_transfer_size; + __le32 packet_alignment; /* max 7; (1< + * Copyright (C) 2003-2005 David Hollis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_USB_USBNET_H +#define __LINUX_USB_USBNET_H + +/* interface from usbnet core to each USB networking link we handle */ +struct usbnet { + /* housekeeping */ + struct usb_device *udev; + struct usb_interface *intf; + struct driver_info *driver_info; + const char *driver_name; + void *driver_priv; + wait_queue_head_t *wait; + struct mutex phy_mutex; + unsigned char suspend_count; + + /* i/o info: pipes etc */ + unsigned in, out; + struct usb_host_endpoint *status; + unsigned maxpacket; + struct timer_list delay; + + /* protocol/interface state */ + struct net_device *net; + int msg_enable; + unsigned long data[5]; + u32 xid; + u32 hard_mtu; /* count any extra framing */ + size_t rx_urb_size; /* size for rx urbs */ + struct mii_if_info mii; + + /* various kinds of pending driver work */ + struct sk_buff_head rxq; + struct sk_buff_head txq; + struct sk_buff_head done; + struct sk_buff_head rxq_pause; + struct urb *interrupt; + struct usb_anchor deferred; + struct tasklet_struct bh; + + struct work_struct kevent; + unsigned long flags; +# define EVENT_TX_HALT 0 +# define EVENT_RX_HALT 1 +# define EVENT_RX_MEMORY 2 +# define EVENT_STS_SPLIT 3 +# define EVENT_LINK_RESET 4 +# define EVENT_RX_PAUSED 5 +# define EVENT_DEV_WAKING 6 +# define EVENT_DEV_ASLEEP 7 +# define EVENT_DEV_OPEN 8 +}; + +static inline struct usb_driver *driver_of(struct usb_interface *intf) +{ + return to_usb_driver(intf->dev.driver); +} + +/* interface from the device/framing level "minidriver" to core */ +struct driver_info { + char *description; + + int flags; +/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ +#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ +#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ +#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ +#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ + +#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ +#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ + +#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ +#define FLAG_WLAN 0x0080 /* use "wlan%d" names */ +#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ +#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */ +#define FLAG_WWAN 0x0400 /* use "wwan%d" names */ + +#define FLAG_LINK_INTR 0x0800 /* updates link (carrier) status */ + +#define FLAG_POINTTOPOINT 0x1000 /* possibly use "usb%d" names */ + +/* + * Indicates to usbnet, that USB driver accumulates multiple IP packets. + * Affects statistic (counters) and short packet handling. + */ +#define FLAG_MULTI_PACKET 0x2000 +#define FLAG_RX_ASSEMBLE 0x4000 /* rx packets may span >1 frames */ + + /* init device ... can sleep, or cause probe() failure */ + int (*bind)(struct usbnet *, struct usb_interface *); + + /* cleanup device ... can sleep, but can't fail */ + void (*unbind)(struct usbnet *, struct usb_interface *); + + /* reset device ... can sleep */ + int (*reset)(struct usbnet *); + + /* stop device ... can sleep */ + int (*stop)(struct usbnet *); + + /* see if peer is connected ... can sleep */ + int (*check_connect)(struct usbnet *); + + /* (dis)activate runtime power management */ + int (*manage_power)(struct usbnet *, int); + + /* for status polling */ + void (*status)(struct usbnet *, struct urb *); + + /* link reset handling, called from defer_kevent */ + int (*link_reset)(struct usbnet *); + + /* fixup rx packet (strip framing) */ + int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); + + /* fixup tx packet (add framing) */ + struct sk_buff *(*tx_fixup)(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags); + + /* early initialization code, can sleep. This is for minidrivers + * having 'subminidrivers' that need to do extra initialization + * right after minidriver have initialized hardware. */ + int (*early_init)(struct usbnet *dev); + + /* called by minidriver when receiving indication */ + void (*indication)(struct usbnet *dev, void *ind, int indlen); + + /* for new devices, use the descriptor-reading code instead */ + int in; /* rx endpoint */ + int out; /* tx endpoint */ + + unsigned long data; /* Misc driver specific data */ +}; + +/* Minidrivers are just drivers using the "usbnet" core as a powerful + * network-specific subroutine library ... that happens to do pretty + * much everything except custom framing and chip-specific stuff. + */ +extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *); +extern int usbnet_suspend(struct usb_interface *, pm_message_t); +extern int usbnet_resume(struct usb_interface *); +extern void usbnet_disconnect(struct usb_interface *); + + +/* Drivers that reuse some of the standard USB CDC infrastructure + * (notably, using multiple interfaces according to the CDC + * union descriptor) get some helper code. + */ +struct cdc_state { + struct usb_cdc_header_desc *header; + struct usb_cdc_union_desc *u; + struct usb_cdc_ether_desc *ether; + struct usb_interface *control; + struct usb_interface *data; +}; + +extern int usbnet_generic_cdc_bind(struct usbnet *, struct usb_interface *); +extern int usbnet_cdc_bind(struct usbnet *, struct usb_interface *); +extern void usbnet_cdc_unbind(struct usbnet *, struct usb_interface *); +extern void usbnet_cdc_status(struct usbnet *, struct urb *); + +/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ +#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ + |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ + |USB_CDC_PACKET_TYPE_PROMISCUOUS \ + |USB_CDC_PACKET_TYPE_DIRECTED) + + +/* we record the state for each of our queued skbs */ +enum skb_state { + illegal = 0, + tx_start, tx_done, + rx_start, rx_done, rx_cleanup +}; + +struct skb_data { /* skb->cb is one of these */ + struct urb *urb; + struct usbnet *dev; + enum skb_state state; + size_t length; +}; + +extern int usbnet_open(struct net_device *net); +extern int usbnet_stop(struct net_device *net); +extern netdev_tx_t usbnet_start_xmit(struct sk_buff *skb, + struct net_device *net); +extern void usbnet_tx_timeout(struct net_device *net); +extern int usbnet_change_mtu(struct net_device *net, int new_mtu); + +extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *); +extern int usbnet_get_ethernet_addr(struct usbnet *, int); +extern void usbnet_defer_kevent(struct usbnet *, int); +extern void usbnet_skb_return(struct usbnet *, struct sk_buff *); +extern void usbnet_unlink_rx_urbs(struct usbnet *); + +extern void usbnet_pause_rx(struct usbnet *); +extern void usbnet_resume_rx(struct usbnet *); +extern void usbnet_purge_paused_rxq(struct usbnet *); + +extern int usbnet_get_settings(struct net_device *net, + struct ethtool_cmd *cmd); +extern int usbnet_set_settings(struct net_device *net, + struct ethtool_cmd *cmd); +extern u32 usbnet_get_link(struct net_device *net); +extern u32 usbnet_get_msglevel(struct net_device *); +extern void usbnet_set_msglevel(struct net_device *, u32); +extern void usbnet_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); +extern int usbnet_nway_reset(struct net_device *net); + +#endif /* __LINUX_USB_USBNET_H */ diff --git a/include/compat/linux/wireless.h b/include/compat/linux/wireless.h new file mode 100644 index 00000000..4395b28b --- /dev/null +++ b/include/compat/linux/wireless.h @@ -0,0 +1,1162 @@ +/* + * This file define a set of standard wireless extensions + * + * Version : 22 16.3.07 + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + */ + +#ifndef _LINUX_WIRELESS_H +#define _LINUX_WIRELESS_H + +/************************** DOCUMENTATION **************************/ +/* + * Initial APIs (1996 -> onward) : + * ----------------------------- + * Basically, the wireless extensions are for now a set of standard ioctl + * call + /proc/net/wireless + * + * The entry /proc/net/wireless give statistics and information on the + * driver. + * This is better than having each driver having its entry because + * its centralised and we may remove the driver module safely. + * + * Ioctl are used to configure the driver and issue commands. This is + * better than command line options of insmod because we may want to + * change dynamically (while the driver is running) some parameters. + * + * The ioctl mechanimsm are copied from standard devices ioctl. + * We have the list of command plus a structure descibing the + * data exchanged... + * Note that to add these ioctl, I was obliged to modify : + * # net/core/dev.c (two place + add include) + * # net/ipv4/af_inet.c (one place + add include) + * + * /proc/net/wireless is a copy of /proc/net/dev. + * We have a structure for data passed from the driver to /proc/net/wireless + * Too add this, I've modified : + * # net/core/dev.c (two other places) + * # include/linux/netdevice.h (one place) + * # include/linux/proc_fs.h (one place) + * + * New driver API (2002 -> onward) : + * ------------------------------- + * This file is only concerned with the user space API and common definitions. + * The new driver API is defined and documented in : + * # include/net/iw_handler.h + * + * Note as well that /proc/net/wireless implementation has now moved in : + * # net/core/wireless.c + * + * Wireless Events (2002 -> onward) : + * -------------------------------- + * Events are defined at the end of this file, and implemented in : + * # net/core/wireless.c + * + * Other comments : + * -------------- + * Do not add here things that are redundant with other mechanisms + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not + * wireless specific. + * + * These wireless extensions are not magic : each driver has to provide + * support for them... + * + * IMPORTANT NOTE : As everything in the kernel, this is very much a + * work in progress. Contact me if you have ideas of improvements... + */ + +/***************************** INCLUDES *****************************/ + +#include /* for __u* and __s* typedefs */ +#include /* for "struct sockaddr" et al */ +#include /* for IFNAMSIZ and co... */ + +/***************************** VERSION *****************************/ +/* + * This constant is used to know the availability of the wireless + * extensions and to know which version of wireless extensions it is + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +#define WIRELESS_EXT 22 + +/* + * Changes : + * + * V2 to V3 + * -------- + * Alan Cox start some incompatibles changes. I've integrated a bit more. + * - Encryption renamed to Encode to avoid US regulation problems + * - Frequency changed from float to struct to avoid problems on old 386 + * + * V3 to V4 + * -------- + * - Add sensitivity + * + * V4 to V5 + * -------- + * - Missing encoding definitions in range + * - Access points stuff + * + * V5 to V6 + * -------- + * - 802.11 support (ESSID ioctls) + * + * V6 to V7 + * -------- + * - define IW_ESSID_MAX_SIZE and IW_MAX_AP + * + * V7 to V8 + * -------- + * - Changed my e-mail address + * - More 802.11 support (nickname, rate, rts, frag) + * - List index in frequencies + * + * V8 to V9 + * -------- + * - Support for 'mode of operation' (ad-hoc, managed...) + * - Support for unicast and multicast power saving + * - Change encoding to support larger tokens (>64 bits) + * - Updated iw_params (disable, flags) and use it for NWID + * - Extracted iw_point from iwreq for clarity + * + * V9 to V10 + * --------- + * - Add PM capability to range structure + * - Add PM modifier : MAX/MIN/RELATIVE + * - Add encoding option : IW_ENCODE_NOKEY + * - Add TxPower ioctls (work like TxRate) + * + * V10 to V11 + * ---------- + * - Add WE version in range (help backward/forward compatibility) + * - Add retry ioctls (work like PM) + * + * V11 to V12 + * ---------- + * - Add SIOCSIWSTATS to get /proc/net/wireless programatically + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space + * - Add new statistics (frag, retry, beacon) + * - Add average quality (for user space calibration) + * + * V12 to V13 + * ---------- + * - Document creation of new driver API. + * - Extract union iwreq_data from struct iwreq (for new driver API). + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT + * + * V13 to V14 + * ---------- + * - Wireless Events support : define struct iw_event + * - Define additional specific event numbers + * - Add "addr" and "param" fields in union iwreq_data + * - AP scanning stuff (SIOCSIWSCAN and friends) + * + * V14 to V15 + * ---------- + * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg + * - Make struct iw_freq signed (both m & e), add explicit padding + * - Add IWEVCUSTOM for driver specific event/scanning token + * - Add IW_MAX_GET_SPY for driver returning a lot of addresses + * - Add IW_TXPOW_RANGE for range of Tx Powers + * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points + * - Add IW_MODE_MONITOR for passive monitor + * + * V15 to V16 + * ---------- + * - Increase the number of bitrates in iw_range to 32 (for 802.11g) + * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) + * - Reshuffle struct iw_range for increases, add filler + * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses + * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support + * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" + * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index + * + * V16 to V17 + * ---------- + * - Add flags to frequency -> auto/fixed + * - Document (struct iw_quality *)->updated, add new flags (INVALID) + * - Wireless Event capability in struct iw_range + * - Add support for relative TxPower (yick !) + * + * V17 to V18 (From Jouni Malinen ) + * ---------- + * - Add support for WPA/WPA2 + * - Add extended encoding configuration (SIOCSIWENCODEEXT and + * SIOCGIWENCODEEXT) + * - Add SIOCSIWGENIE/SIOCGIWGENIE + * - Add SIOCSIWMLME + * - Add SIOCSIWPMKSA + * - Add struct iw_range bit field for supported encoding capabilities + * - Add optional scan request parameters for SIOCSIWSCAN + * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA + * related parameters (extensible up to 4096 parameter values) + * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, + * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND + * + * V18 to V19 + * ---------- + * - Remove (struct iw_point *)->pointer from events and streams + * - Remove header includes to help user space + * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 + * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros + * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM + * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros + * + * V19 to V20 + * ---------- + * - RtNetlink requests support (SET/GET) + * + * V20 to V21 + * ---------- + * - Remove (struct net_device *)->get_wireless_stats() + * - Change length in ESSID and NICK to strlen() instead of strlen()+1 + * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers + * - Power/Retry relative values no longer * 100000 + * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI + * + * V21 to V22 + * ---------- + * - Prevent leaking of kernel space in stream on 64 bits. + */ + +/**************************** CONSTANTS ****************************/ + +/* -------------------------- IOCTL LIST -------------------------- */ + +/* Wireless Identification */ +#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ +#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. + * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... + * Don't put the name of your driver there, it's useless. */ + +/* Basic operations */ +#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ +#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ +#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ +#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ +#define SIOCSIWMODE 0x8B06 /* set operation mode */ +#define SIOCGIWMODE 0x8B07 /* get operation mode */ +#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ +#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ + +/* Informative stuff */ +#define SIOCSIWRANGE 0x8B0A /* Unused */ +#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ +#define SIOCSIWPRIV 0x8B0C /* Unused */ +#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ +#define SIOCSIWSTATS 0x8B0E /* Unused */ +#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ +/* SIOCGIWSTATS is strictly used between user space and the kernel, and + * is never passed to the driver (i.e. the driver will never see it). */ + +/* Spy support (statistics per MAC address - used for Mobile IP support) */ +#define SIOCSIWSPY 0x8B10 /* set spy addresses */ +#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ +#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ +#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ + +/* Access Point manipulation */ +#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ +#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ +#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ +#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ +#define SIOCGIWSCAN 0x8B19 /* get scanning results */ + +/* 802.11 specific support */ +#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ +#define SIOCGIWESSID 0x8B1B /* get ESSID */ +#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ +#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ +/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit + * within the 'iwreq' structure, so we need to use the 'data' member to + * point to a string in user space, like it is done for RANGE... */ + +/* Other parameters useful in 802.11 and some other devices */ +#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ +#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ +#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ +#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ +#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ +#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ +#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ +#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ +#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ +#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ + +/* Encoding stuff (scrambling, hardware security, WEP...) */ +#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ +#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ +/* Power saving stuff (power management, unicast and multicast) */ +#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ +#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ + +/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). + * This ioctl uses struct iw_point and data buffer that includes IE id and len + * fields. More than one IE may be included in the request. Setting the generic + * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers + * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers + * are required to report the used IE as a wireless event, e.g., when + * associating with an AP. */ +#define SIOCSIWGENIE 0x8B30 /* set generic IE */ +#define SIOCGIWGENIE 0x8B31 /* get generic IE */ + +/* WPA : IEEE 802.11 MLME requests */ +#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses + * struct iw_mlme */ +/* WPA : Authentication mode parameters */ +#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ +#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ + +/* WPA : Extended version of encoding configuration */ +#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ +#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ + +/* WPA2 : PMKSA cache management */ +#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ + +/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ + +/* These 32 ioctl are wireless device private, for 16 commands. + * Each driver is free to use them for whatever purpose it chooses, + * however the driver *must* export the description of those ioctls + * with SIOCGIWPRIV and *must* use arguments as defined below. + * If you don't follow those rules, DaveM is going to hate you (reason : + * it make mixed 32/64bit operation impossible). + */ +#define SIOCIWFIRSTPRIV 0x8BE0 +#define SIOCIWLASTPRIV 0x8BFF +/* Previously, we were using SIOCDEVPRIVATE, but we now have our + * separate range because of collisions with other tools such as + * 'mii-tool'. + * We now have 32 commands, so a bit more space ;-). + * Also, all 'even' commands are only usable by root and don't return the + * content of ifr/iwr to user (but you are not obliged to use the set/get + * convention, just use every other two command). More details in iwpriv.c. + * And I repeat : you are not forced to use them with iwpriv, but you + * must be compliant with it. + */ + +/* ------------------------- IOCTL STUFF ------------------------- */ + +/* The first and the last (range) */ +#define SIOCIWFIRST 0x8B00 +#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ +#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) +#define IW_HANDLER(id, func) \ + [IW_IOCTL_IDX(id)] = func + +/* Odd : get (world access), even : set (root access) */ +#define IW_IS_SET(cmd) (!((cmd) & 0x1)) +#define IW_IS_GET(cmd) ((cmd) & 0x1) + +/* ----------------------- WIRELESS EVENTS ----------------------- */ +/* Those are *NOT* ioctls, do not issue request on them !!! */ +/* Most events use the same identifier as ioctl requests */ + +#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ +#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ +#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ +#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ +#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ +#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) + * (scan results); This includes id and + * length fields. One IWEVGENIE may + * contain more than one IE. Scan + * results may contain one or more + * IWEVGENIE events. */ +#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure + * (struct iw_michaelmicfailure) + */ +#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. + * The data includes id and length + * fields and may contain more than one + * IE. This event is required in + * Managed mode if the driver + * generates its own WPA/RSN IE. This + * should be sent just before + * IWEVREGISTERED event for the + * association. */ +#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association + * Response. The data includes id and + * length fields and may contain more + * than one IE. This may be sent + * between IWEVASSOCREQIE and + * IWEVREGISTERED events for the + * association. */ +#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN + * pre-authentication + * (struct iw_pmkid_cand) */ + +#define IWEVFIRST 0x8C00 +#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) + +/* ------------------------- PRIVATE INFO ------------------------- */ +/* + * The following is used with SIOCGIWPRIV. It allow a driver to define + * the interface (name, type of data) for its private ioctl. + * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV + */ + +#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ +#define IW_PRIV_TYPE_NONE 0x0000 +#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ +#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ +#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ +#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ +#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ + +#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ + +#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ + +/* + * Note : if the number of args is fixed and the size < 16 octets, + * instead of passing a pointer we will put args in the iwreq struct... + */ + +/* ----------------------- OTHER CONSTANTS ----------------------- */ + +/* Maximum frequencies in the range struct */ +#define IW_MAX_FREQUENCIES 32 +/* Note : if you have something like 80 frequencies, + * don't increase this constant and don't fill the frequency list. + * The user will be able to set by channel anyway... */ + +/* Maximum bit rates in the range struct */ +#define IW_MAX_BITRATES 32 + +/* Maximum tx powers in the range struct */ +#define IW_MAX_TXPOWER 8 +/* Note : if you more than 8 TXPowers, just set the max and min or + * a few of them in the struct iw_range. */ + +/* Maximum of address that you may set with SPY */ +#define IW_MAX_SPY 8 + +/* Maximum of address that you may get in the + list of access points in range */ +#define IW_MAX_AP 64 + +/* Maximum size of the ESSID and NICKN strings */ +#define IW_ESSID_MAX_SIZE 32 + +/* Modes of operation */ +#define IW_MODE_AUTO 0 /* Let the driver decides */ +#define IW_MODE_ADHOC 1 /* Single cell network */ +#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ +#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ +#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ +#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ +#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ +#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */ + +/* Statistics flags (bitmask in updated) */ +#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ +#define IW_QUAL_LEVEL_UPDATED 0x02 +#define IW_QUAL_NOISE_UPDATED 0x04 +#define IW_QUAL_ALL_UPDATED 0x07 +#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ +#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ +#define IW_QUAL_ALL_INVALID 0x70 + +/* Frequency flags */ +#define IW_FREQ_AUTO 0x00 /* Let the driver decides */ +#define IW_FREQ_FIXED 0x01 /* Force a specific value */ + +/* Maximum number of size of encoding token available + * they are listed in the range structure */ +#define IW_MAX_ENCODING_SIZES 8 + +/* Maximum size of the encoding token in bytes */ +#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ + +/* Flags for encoding (along with the token) */ +#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ +#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ +#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ +#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ +#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ +#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ +#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ + +/* Power management flags available (along with the value, if any) */ +#define IW_POWER_ON 0x0000 /* No details... */ +#define IW_POWER_TYPE 0xF000 /* Type of parameter */ +#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ +#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ +#define IW_POWER_MODE 0x0F00 /* Power Management mode */ +#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ +#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ +#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ +#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ +#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ +#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ +#define IW_POWER_MIN 0x0001 /* Value is a minimum */ +#define IW_POWER_MAX 0x0002 /* Value is a maximum */ +#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + +/* Transmit Power flags available */ +#define IW_TXPOW_TYPE 0x00FF /* Type of value */ +#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ +#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ +#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ +#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ + +/* Retry limits and lifetime flags available */ +#define IW_RETRY_ON 0x0000 /* No details... */ +#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ +#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ +#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ +#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ +#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ +#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ +#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ +#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ +#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ + +/* Scanning request flags */ +#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ +#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ +#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ +#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ +#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ +#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ +#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ +#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ +#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ +/* struct iw_scan_req scan_type */ +#define IW_SCAN_TYPE_ACTIVE 0 +#define IW_SCAN_TYPE_PASSIVE 1 +/* Maximum size of returned data */ +#define IW_SCAN_MAX_DATA 4096 /* In bytes */ + +/* Scan capability flags - in (struct iw_range *)->scan_capa */ +#define IW_SCAN_CAPA_NONE 0x00 +#define IW_SCAN_CAPA_ESSID 0x01 +#define IW_SCAN_CAPA_BSSID 0x02 +#define IW_SCAN_CAPA_CHANNEL 0x04 +#define IW_SCAN_CAPA_MODE 0x08 +#define IW_SCAN_CAPA_RATE 0x10 +#define IW_SCAN_CAPA_TYPE 0x20 +#define IW_SCAN_CAPA_TIME 0x40 + +/* Max number of char in custom event - use multiple of them if needed */ +#define IW_CUSTOM_MAX 256 /* In bytes */ + +/* Generic information element */ +#define IW_GENERIC_IE_MAX 1024 + +/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ +#define IW_MLME_DEAUTH 0 +#define IW_MLME_DISASSOC 1 +#define IW_MLME_AUTH 2 +#define IW_MLME_ASSOC 3 + +/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ +#define IW_AUTH_INDEX 0x0FFF +#define IW_AUTH_FLAGS 0xF000 +/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) + * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the + * parameter that is being set/get to; value will be read/written to + * struct iw_param value field) */ +#define IW_AUTH_WPA_VERSION 0 +#define IW_AUTH_CIPHER_PAIRWISE 1 +#define IW_AUTH_CIPHER_GROUP 2 +#define IW_AUTH_KEY_MGMT 3 +#define IW_AUTH_TKIP_COUNTERMEASURES 4 +#define IW_AUTH_DROP_UNENCRYPTED 5 +#define IW_AUTH_80211_AUTH_ALG 6 +#define IW_AUTH_WPA_ENABLED 7 +#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 +#define IW_AUTH_ROAMING_CONTROL 9 +#define IW_AUTH_PRIVACY_INVOKED 10 +#define IW_AUTH_CIPHER_GROUP_MGMT 11 +#define IW_AUTH_MFP 12 + +/* IW_AUTH_WPA_VERSION values (bit field) */ +#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 +#define IW_AUTH_WPA_VERSION_WPA 0x00000002 +#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 + +/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT + * values (bit field) */ +#define IW_AUTH_CIPHER_NONE 0x00000001 +#define IW_AUTH_CIPHER_WEP40 0x00000002 +#define IW_AUTH_CIPHER_TKIP 0x00000004 +#define IW_AUTH_CIPHER_CCMP 0x00000008 +#define IW_AUTH_CIPHER_WEP104 0x00000010 +#define IW_AUTH_CIPHER_AES_CMAC 0x00000020 + +/* IW_AUTH_KEY_MGMT values (bit field) */ +#define IW_AUTH_KEY_MGMT_802_1X 1 +#define IW_AUTH_KEY_MGMT_PSK 2 + +/* IW_AUTH_80211_AUTH_ALG values (bit field) */ +#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 +#define IW_AUTH_ALG_SHARED_KEY 0x00000002 +#define IW_AUTH_ALG_LEAP 0x00000004 + +/* IW_AUTH_ROAMING_CONTROL values */ +#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ +#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming + * control */ + +/* IW_AUTH_MFP (management frame protection) values */ +#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ +#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ +#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ + +/* SIOCSIWENCODEEXT definitions */ +#define IW_ENCODE_SEQ_MAX_SIZE 8 +/* struct iw_encode_ext ->alg */ +#define IW_ENCODE_ALG_NONE 0 +#define IW_ENCODE_ALG_WEP 1 +#define IW_ENCODE_ALG_TKIP 2 +#define IW_ENCODE_ALG_CCMP 3 +#define IW_ENCODE_ALG_PMK 4 +#define IW_ENCODE_ALG_AES_CMAC 5 +/* struct iw_encode_ext ->ext_flags */ +#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 +#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 +#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 +#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 + +/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ +#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ +#define IW_MICFAILURE_GROUP 0x00000004 +#define IW_MICFAILURE_PAIRWISE 0x00000008 +#define IW_MICFAILURE_STAKEY 0x00000010 +#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) + */ + +/* Bit field values for enc_capa in struct iw_range */ +#define IW_ENC_CAPA_WPA 0x00000001 +#define IW_ENC_CAPA_WPA2 0x00000002 +#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 +#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 +#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 + +/* Event capability macros - in (struct iw_range *)->event_capa + * Because we have more than 32 possible events, we use an array of + * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ +#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ + (cmd - SIOCIWFIRSTPRIV + 0x60) : \ + (cmd - SIOCIWFIRST)) +#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) +#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) +/* Event capability constants - event autogenerated by the kernel + * This list is valid for most 802.11 devices, customise as needed... */ +#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ + IW_EVENT_CAPA_MASK(0x8B06) | \ + IW_EVENT_CAPA_MASK(0x8B1A)) +#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) +/* "Easy" macro to set events in iw_range (less efficient) */ +#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) +#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } + + +/****************************** TYPES ******************************/ + +/* --------------------------- SUBTYPES --------------------------- */ +/* + * Generic format for most parameters that fit in an int + */ +struct iw_param +{ + __s32 value; /* The value of the parameter itself */ + __u8 fixed; /* Hardware should not use auto select */ + __u8 disabled; /* Disable the feature */ + __u16 flags; /* Various specifc flags (if any) */ +}; + +/* + * For all data larger than 16 octets, we need to use a + * pointer to memory allocated in user space. + */ +struct iw_point +{ + void __user *pointer; /* Pointer to the data (in user space) */ + __u16 length; /* number of fields or size in bytes */ + __u16 flags; /* Optional params */ +}; + +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT + +#include + +struct compat_iw_point { + compat_caddr_t pointer; + __u16 length; + __u16 flags; +}; +#endif +#endif + +/* + * A frequency + * For numbers lower than 10^9, we encode the number in 'm' and + * set 'e' to 0 + * For number greater than 10^9, we divide it by the lowest power + * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... + * The power of 10 is in 'e', the result of the division is in 'm'. + */ +struct iw_freq +{ + __s32 m; /* Mantissa */ + __s16 e; /* Exponent */ + __u8 i; /* List index (when in range struct) */ + __u8 flags; /* Flags (fixed/auto) */ +}; + +/* + * Quality of the link + */ +struct iw_quality +{ + __u8 qual; /* link quality (%retries, SNR, + %missed beacons or better...) */ + __u8 level; /* signal level (dBm) */ + __u8 noise; /* noise level (dBm) */ + __u8 updated; /* Flags to know if updated */ +}; + +/* + * Packet discarded in the wireless adapter due to + * "wireless" specific problems... + * Note : the list of counter and statistics in net_device_stats + * is already pretty exhaustive, and you should use that first. + * This is only additional stats... + */ +struct iw_discarded +{ + __u32 nwid; /* Rx : Wrong nwid/essid */ + __u32 code; /* Rx : Unable to code/decode (WEP) */ + __u32 fragment; /* Rx : Can't perform MAC reassembly */ + __u32 retries; /* Tx : Max MAC retries num reached */ + __u32 misc; /* Others cases */ +}; + +/* + * Packet/Time period missed in the wireless adapter due to + * "wireless" specific problems... + */ +struct iw_missed +{ + __u32 beacon; /* Missed beacons/superframe */ +}; + +/* + * Quality range (for spy threshold) + */ +struct iw_thrspy +{ + struct sockaddr addr; /* Source address (hw/mac) */ + struct iw_quality qual; /* Quality of the link */ + struct iw_quality low; /* Low threshold */ + struct iw_quality high; /* High threshold */ +}; + +/* + * Optional data for scan request + * + * Note: these optional parameters are controlling parameters for the + * scanning behavior, these do not apply to getting scan results + * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and + * provide a merged results with all BSSes even if the previous scan + * request limited scanning to a subset, e.g., by specifying an SSID. + * Especially, scan results are required to include an entry for the + * current BSS if the driver is in Managed mode and associated with an AP. + */ +struct iw_scan_req +{ + __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ + __u8 essid_len; + __u8 num_channels; /* num entries in channel_list; + * 0 = scan all allowed channels */ + __u8 flags; /* reserved as padding; use zero, this may + * be used in the future for adding flags + * to request different scan behavior */ + struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or + * individual address of a specific BSS */ + + /* + * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using + * the current ESSID. This allows scan requests for specific ESSID + * without having to change the current ESSID and potentially breaking + * the current association. + */ + __u8 essid[IW_ESSID_MAX_SIZE]; + + /* + * Optional parameters for changing the default scanning behavior. + * These are based on the MLME-SCAN.request from IEEE Std 802.11. + * TU is 1.024 ms. If these are set to 0, driver is expected to use + * reasonable default values. min_channel_time defines the time that + * will be used to wait for the first reply on each channel. If no + * replies are received, next channel will be scanned after this. If + * replies are received, total time waited on the channel is defined by + * max_channel_time. + */ + __u32 min_channel_time; /* in TU */ + __u32 max_channel_time; /* in TU */ + + struct iw_freq channel_list[IW_MAX_FREQUENCIES]; +}; + +/* ------------------------- WPA SUPPORT ------------------------- */ + +/* + * Extended data structure for get/set encoding (this is used with + * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* + * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and + * only the data contents changes (key data -> this structure, including + * key data). + * + * If the new key is the first group key, it will be set as the default + * TX key. Otherwise, default TX key index is only changed if + * IW_ENCODE_EXT_SET_TX_KEY flag is set. + * + * Key will be changed with SIOCSIWENCODEEXT in all cases except for + * special "change TX key index" operation which is indicated by setting + * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. + * + * tx_seq/rx_seq are only used when respective + * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal + * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start + * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally + * used only by an Authenticator (AP or an IBSS station) to get the + * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and + * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for + * debugging/testing. + */ +struct iw_encode_ext +{ + __u32 ext_flags; /* IW_ENCODE_EXT_* */ + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ + struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys */ + __u16 alg; /* IW_ENCODE_ALG_* */ + __u16 key_len; + __u8 key[0]; +}; + +/* SIOCSIWMLME data */ +struct iw_mlme +{ + __u16 cmd; /* IW_MLME_* */ + __u16 reason_code; + struct sockaddr addr; +}; + +/* SIOCSIWPMKSA data */ +#define IW_PMKSA_ADD 1 +#define IW_PMKSA_REMOVE 2 +#define IW_PMKSA_FLUSH 3 + +#define IW_PMKID_LEN 16 + +struct iw_pmksa +{ + __u32 cmd; /* IW_PMKSA_* */ + struct sockaddr bssid; + __u8 pmkid[IW_PMKID_LEN]; +}; + +/* IWEVMICHAELMICFAILURE data */ +struct iw_michaelmicfailure +{ + __u32 flags; + struct sockaddr src_addr; + __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ +}; + +/* IWEVPMKIDCAND data */ +#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ +struct iw_pmkid_cand +{ + __u32 flags; /* IW_PMKID_CAND_* */ + __u32 index; /* the smaller the index, the higher the + * priority */ + struct sockaddr bssid; +}; + +/* ------------------------ WIRELESS STATS ------------------------ */ +/* + * Wireless statistics (used for /proc/net/wireless) + */ +struct iw_statistics +{ + __u16 status; /* Status + * - device dependent for now */ + + struct iw_quality qual; /* Quality of the link + * (instant/mean/max) */ + struct iw_discarded discard; /* Packet discarded counts */ + struct iw_missed miss; /* Packet missed counts */ +}; + +/* ------------------------ IOCTL REQUEST ------------------------ */ +/* + * This structure defines the payload of an ioctl, and is used + * below. + * + * Note that this structure should fit on the memory footprint + * of iwreq (which is the same as ifreq), which mean a max size of + * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... + * You should check this when increasing the structures defined + * above in this file... + */ +union iwreq_data +{ + /* Config - generic */ + char name[IFNAMSIZ]; + /* Name : used to verify the presence of wireless extensions. + * Name of the protocol/provider... */ + + struct iw_point essid; /* Extended network name */ + struct iw_param nwid; /* network id (or domain - the cell) */ + struct iw_freq freq; /* frequency or channel : + * 0-1000 = channel + * > 1000 = frequency in Hz */ + + struct iw_param sens; /* signal level threshold */ + struct iw_param bitrate; /* default bit rate */ + struct iw_param txpower; /* default transmit power */ + struct iw_param rts; /* RTS threshold threshold */ + struct iw_param frag; /* Fragmentation threshold */ + __u32 mode; /* Operation mode */ + struct iw_param retry; /* Retry limits & lifetime */ + + struct iw_point encoding; /* Encoding stuff : tokens */ + struct iw_param power; /* PM duration/timeout */ + struct iw_quality qual; /* Quality part of statistics */ + + struct sockaddr ap_addr; /* Access point address */ + struct sockaddr addr; /* Destination address (hw/mac) */ + + struct iw_param param; /* Other small parameters */ + struct iw_point data; /* Other large parameters */ +}; + +/* + * The structure to exchange data for ioctl. + * This structure is the same as 'struct ifreq', but (re)defined for + * convenience... + * Do I need to remind you about structure size (32 octets) ? + */ +struct iwreq +{ + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ + } ifr_ifrn; + + /* Data part (defined just above) */ + union iwreq_data u; +}; + +/* -------------------------- IOCTL DATA -------------------------- */ +/* + * For those ioctl which want to exchange mode data that what could + * fit in the above structure... + */ + +/* + * Range of parameters + */ + +struct iw_range +{ + /* Informative stuff (to choose between different interface) */ + __u32 throughput; /* To give an idea... */ + /* In theory this value should be the maximum benchmarked + * TCP/IP throughput, because with most of these devices the + * bit rate is meaningless (overhead an co) to estimate how + * fast the connection will go and pick the fastest one. + * I suggest people to play with Netperf or any benchmark... + */ + + /* NWID (or domain id) */ + __u32 min_nwid; /* Minimal NWID we are able to set */ + __u32 max_nwid; /* Maximal NWID we are able to set */ + + /* Old Frequency (backward compat - moved lower ) */ + __u16 old_num_channels; + __u8 old_num_frequency; + + /* Scan capabilities */ + __u8 scan_capa; /* IW_SCAN_CAPA_* bit field */ + + /* Wireless event capability bitmasks */ + __u32 event_capa[6]; + + /* signal level threshold range */ + __s32 sensitivity; + + /* Quality of link & SNR stuff */ + /* Quality range (link, level, noise) + * If the quality is absolute, it will be in the range [0 ; max_qual], + * if the quality is dBm, it will be in the range [max_qual ; 0]. + * Don't forget that we use 8 bit arithmetics... */ + struct iw_quality max_qual; /* Quality of the link */ + /* This should contain the average/typical values of the quality + * indicator. This should be the threshold between a "good" and + * a "bad" link (example : monitor going from green to orange). + * Currently, user space apps like quality monitors don't have any + * way to calibrate the measurement. With this, they can split + * the range between 0 and max_qual in different quality level + * (using a geometric subdivision centered on the average). + * I expect that people doing the user space apps will feedback + * us on which value we need to put in each driver... */ + struct iw_quality avg_qual; /* Quality of the link */ + + /* Rates */ + __u8 num_bitrates; /* Number of entries in the list */ + __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ + + /* RTS threshold */ + __s32 min_rts; /* Minimal RTS threshold */ + __s32 max_rts; /* Maximal RTS threshold */ + + /* Frag threshold */ + __s32 min_frag; /* Minimal frag threshold */ + __s32 max_frag; /* Maximal frag threshold */ + + /* Power Management duration & timeout */ + __s32 min_pmp; /* Minimal PM period */ + __s32 max_pmp; /* Maximal PM period */ + __s32 min_pmt; /* Minimal PM timeout */ + __s32 max_pmt; /* Maximal PM timeout */ + __u16 pmp_flags; /* How to decode max/min PM period */ + __u16 pmt_flags; /* How to decode max/min PM timeout */ + __u16 pm_capa; /* What PM options are supported */ + + /* Encoder stuff */ + __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ + __u8 num_encoding_sizes; /* Number of entry in the list */ + __u8 max_encoding_tokens; /* Max number of tokens */ + /* For drivers that need a "login/passwd" form */ + __u8 encoding_login_index; /* token index for login token */ + + /* Transmit power */ + __u16 txpower_capa; /* What options are supported */ + __u8 num_txpower; /* Number of entries in the list */ + __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ + + /* Wireless Extension version info */ + __u8 we_version_compiled; /* Must be WIRELESS_EXT */ + __u8 we_version_source; /* Last update of source */ + + /* Retry limits and lifetime */ + __u16 retry_capa; /* What retry options are supported */ + __u16 retry_flags; /* How to decode max/min retry limit */ + __u16 r_time_flags; /* How to decode max/min retry life */ + __s32 min_retry; /* Minimal number of retries */ + __s32 max_retry; /* Maximal number of retries */ + __s32 min_r_time; /* Minimal retry lifetime */ + __s32 max_r_time; /* Maximal retry lifetime */ + + /* Frequency */ + __u16 num_channels; /* Number of channels [0; num - 1] */ + __u8 num_frequency; /* Number of entry in the list */ + struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ + /* Note : this frequency list doesn't need to fit channel numbers, + * because each entry contain its channel index */ + + __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ +}; + +/* + * Private ioctl interface information + */ + +struct iw_priv_args +{ + __u32 cmd; /* Number of the ioctl to issue */ + __u16 set_args; /* Type and number of args */ + __u16 get_args; /* Type and number of args */ + char name[IFNAMSIZ]; /* Name of the extension */ +}; + +/* ----------------------- WIRELESS EVENTS ----------------------- */ +/* + * Wireless events are carried through the rtnetlink socket to user + * space. They are encapsulated in the IFLA_WIRELESS field of + * a RTM_NEWLINK message. + */ + +/* + * A Wireless Event. Contains basically the same data as the ioctl... + */ +struct iw_event +{ + __u16 len; /* Real length of this stuff */ + __u16 cmd; /* Wireless IOCTL */ + union iwreq_data u; /* IOCTL fixed payload */ +}; + +/* Size of the Event prefix (including padding and alignement junk) */ +#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) +/* Size of the various events */ +#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) +#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) +#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) +#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) +#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) +#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) + +/* iw_point events are special. First, the payload (extra data) come at + * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, + * we omit the pointer, so start at an offset. */ +#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ + (char *) NULL) +#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ + IW_EV_POINT_OFF) + +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +struct __compat_iw_event { + __u16 len; /* Real length of this stuff */ + __u16 cmd; /* Wireless IOCTL */ + compat_caddr_t pointer; +}; +#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer) +#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length) + +/* Size of the various events for compat */ +#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ) +#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32)) +#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq)) +#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param)) +#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr)) +#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality)) +#define IW_EV_COMPAT_POINT_LEN \ + (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \ + IW_EV_COMPAT_POINT_OFF) +#endif +#endif + +/* Size of the Event prefix when packed in stream */ +#define IW_EV_LCP_PK_LEN (4) +/* Size of the various events when packed in stream */ +#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ) +#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32)) +#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq)) +#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param)) +#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr)) +#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality)) +#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4) + +#endif /* _LINUX_WIRELESS_H */ diff --git a/include/compat/linux/wl12xx.h b/include/compat/linux/wl12xx.h new file mode 100644 index 00000000..4b697395 --- /dev/null +++ b/include/compat/linux/wl12xx.h @@ -0,0 +1,78 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef _LINUX_WL12XX_H +#define _LINUX_WL12XX_H + +/* Reference clock values */ +enum { + WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ + WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ + WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ + WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ + WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ + WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ +}; + +/* TCXO clock values */ +enum { + WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ + WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ + WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ + WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ + WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ + WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ + WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ + WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ +}; + +struct wl12xx_platform_data { + void (*set_power)(bool enable); + /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ + int irq; + bool use_eeprom; + int board_ref_clock; + int board_tcxo_clock; + unsigned long platform_quirks; +}; + +/* Platform does not support level trigger interrupts */ +#define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) + +#ifdef CONFIG_WL12XX_PLATFORM_DATA + +int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); + +#else + +static inline +int wl12xx_set_platform_data(const struct wl12xx_platform_data *data) +{ + return -ENOSYS; +} + +#endif + +const struct wl12xx_platform_data *wl12xx_get_platform_data(void); + +#endif diff --git a/include/compat/net/bluetooth/bluetooth.h b/include/compat/net/bluetooth/bluetooth.h new file mode 100644 index 00000000..71ab25bf --- /dev/null +++ b/include/compat/net/bluetooth/bluetooth.h @@ -0,0 +1,276 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __BLUETOOTH_H +#define __BLUETOOTH_H + +#include +#include +#include +#include +#include + +#ifndef AF_BLUETOOTH +#define AF_BLUETOOTH 31 +#define PF_BLUETOOTH AF_BLUETOOTH +#endif + +/* Reserv for core and drivers use */ +#define BT_SKB_RESERVE 8 + +#define BTPROTO_L2CAP 0 +#define BTPROTO_HCI 1 +#define BTPROTO_SCO 2 +#define BTPROTO_RFCOMM 3 +#define BTPROTO_BNEP 4 +#define BTPROTO_CMTP 5 +#define BTPROTO_HIDP 6 +#define BTPROTO_AVDTP 7 + +#define SOL_HCI 0 +#define SOL_L2CAP 6 +#define SOL_SCO 17 +#define SOL_RFCOMM 18 + +#define BT_SECURITY 4 +struct bt_security { + __u8 level; + __u8 key_size; +}; +#define BT_SECURITY_SDP 0 +#define BT_SECURITY_LOW 1 +#define BT_SECURITY_MEDIUM 2 +#define BT_SECURITY_HIGH 3 + +#define BT_DEFER_SETUP 7 + +#define BT_FLUSHABLE 8 + +#define BT_FLUSHABLE_OFF 0 +#define BT_FLUSHABLE_ON 1 + +#define BT_POWER 9 +struct bt_power { + __u8 force_active; +}; +#define BT_POWER_FORCE_ACTIVE_OFF 0 +#define BT_POWER_FORCE_ACTIVE_ON 1 + +#define BT_CHANNEL_POLICY 10 + +/* BR/EDR only (default policy) + * AMP controllers cannot be used. + * Channel move requests from the remote device are denied. + * If the L2CAP channel is currently using AMP, move the channel to BR/EDR. + */ +#define BT_CHANNEL_POLICY_BREDR_ONLY 0 + +/* BR/EDR Preferred + * Allow use of AMP controllers. + * If the L2CAP channel is currently on AMP, move it to BR/EDR. + * Channel move requests from the remote device are allowed. + */ +#define BT_CHANNEL_POLICY_BREDR_PREFERRED 1 + +/* AMP Preferred + * Allow use of AMP controllers + * If the L2CAP channel is currently on BR/EDR and AMP controller + * resources are available, initiate a channel move to AMP. + * Channel move requests from the remote device are allowed. + * If the L2CAP socket has not been connected yet, try to create + * and configure the channel directly on an AMP controller rather + * than BR/EDR. + */ +#define BT_CHANNEL_POLICY_AMP_PREFERRED 2 + +__printf(2, 3) +int bt_printk(const char *level, const char *fmt, ...); + +#define BT_INFO(fmt, arg...) bt_printk(KERN_INFO, pr_fmt(fmt), ##arg) +#define BT_ERR(fmt, arg...) bt_printk(KERN_ERR, pr_fmt(fmt), ##arg) +#define BT_DBG(fmt, arg...) pr_debug(fmt "\n", ##arg) + +/* Connection and socket states */ +enum { + BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ + BT_OPEN, + BT_BOUND, + BT_LISTEN, + BT_CONNECT, + BT_CONNECT2, + BT_CONFIG, + BT_DISCONN, + BT_CLOSED +}; + +/* BD Address */ +typedef struct { + __u8 b[6]; +} __packed bdaddr_t; + +#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) +#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) + +/* Copy, swap, convert BD Address */ +static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) +{ + return memcmp(ba1, ba2, sizeof(bdaddr_t)); +} +static inline void bacpy(bdaddr_t *dst, bdaddr_t *src) +{ + memcpy(dst, src, sizeof(bdaddr_t)); +} + +void baswap(bdaddr_t *dst, bdaddr_t *src); +char *batostr(bdaddr_t *ba); +bdaddr_t *strtoba(char *str); + +/* Common socket structures and functions */ + +#define bt_sk(__sk) ((struct bt_sock *) __sk) + +struct bt_sock { + struct sock sk; + bdaddr_t src; + bdaddr_t dst; + struct list_head accept_q; + struct sock *parent; + u32 defer_setup; +}; + +struct bt_sock_list { + struct hlist_head head; + rwlock_t lock; +}; + +int bt_sock_register(int proto, const struct net_proto_family *ops); +int bt_sock_unregister(int proto); +void bt_sock_link(struct bt_sock_list *l, struct sock *s); +void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); +int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags); +int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags); +uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait); +int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); + +void bt_accept_enqueue(struct sock *parent, struct sock *sk); +void bt_accept_unlink(struct sock *sk); +struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); + +/* Skb helpers */ +struct bt_skb_cb { + __u8 pkt_type; + __u8 incoming; + __u16 expect; + __u16 tx_seq; + __u8 retries; + __u8 sar; + unsigned short channel; + __u8 force_active; +}; +#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) + +static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how) +{ + struct sk_buff *skb; + + if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) { + skb_reserve(skb, BT_SKB_RESERVE); + bt_cb(skb)->incoming = 0; + } + return skb; +} + +static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, + unsigned long len, int nb, int *err) +{ + struct sk_buff *skb; + + release_sock(sk); + if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) { + skb_reserve(skb, BT_SKB_RESERVE); + bt_cb(skb)->incoming = 0; + } + lock_sock(sk); + + if (!skb && *err) + return NULL; + + *err = sock_error(sk); + if (*err) + goto out; + + if (sk->sk_shutdown) { + *err = -ECONNRESET; + goto out; + } + + return skb; + +out: + kfree_skb(skb); + return NULL; +} + +int bt_to_errno(__u16 code); + +extern int hci_sock_init(void); +extern void hci_sock_cleanup(void); + +extern int bt_sysfs_init(void); +extern void bt_sysfs_cleanup(void); + +extern struct dentry *bt_debugfs; + +#ifdef CONFIG_COMPAT_BT_L2CAP +int l2cap_init(void); +void l2cap_exit(void); +#else +static inline int l2cap_init(void) +{ + return 0; +} + +static inline void l2cap_exit(void) +{ +} +#endif + +#ifdef CONFIG_COMPAT_BT_SCO +int sco_init(void); +void sco_exit(void); +#else +static inline int sco_init(void) +{ + return 0; +} + +static inline void sco_exit(void) +{ +} +#endif + +#endif /* __BLUETOOTH_H */ diff --git a/include/compat/net/bluetooth/hci.h b/include/compat/net/bluetooth/hci.h new file mode 100644 index 00000000..139ce2aa --- /dev/null +++ b/include/compat/net/bluetooth/hci.h @@ -0,0 +1,1334 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_H +#define __HCI_H + +#define HCI_MAX_ACL_SIZE 1024 +#define HCI_MAX_SCO_SIZE 255 +#define HCI_MAX_EVENT_SIZE 260 +#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) + +/* HCI dev events */ +#define HCI_DEV_REG 1 +#define HCI_DEV_UNREG 2 +#define HCI_DEV_UP 3 +#define HCI_DEV_DOWN 4 +#define HCI_DEV_SUSPEND 5 +#define HCI_DEV_RESUME 6 + +/* HCI notify events */ +#define HCI_NOTIFY_CONN_ADD 1 +#define HCI_NOTIFY_CONN_DEL 2 +#define HCI_NOTIFY_VOICE_SETTING 3 + +/* HCI bus types */ +#define HCI_VIRTUAL 0 +#define HCI_USB 1 +#define HCI_PCCARD 2 +#define HCI_UART 3 +#define HCI_RS232 4 +#define HCI_PCI 5 +#define HCI_SDIO 6 + +/* HCI controller types */ +#define HCI_BREDR 0x00 +#define HCI_AMP 0x01 + +/* HCI device quirks */ +enum { + HCI_QUIRK_NO_RESET, + HCI_QUIRK_RAW_DEVICE, + HCI_QUIRK_FIXUP_BUFFER_SIZE +}; + +/* HCI device flags */ +enum { + HCI_UP, + HCI_INIT, + HCI_RUNNING, + + HCI_PSCAN, + HCI_ISCAN, + HCI_AUTH, + HCI_ENCRYPT, + HCI_INQUIRY, + + HCI_RAW, + + HCI_SETUP, + HCI_AUTO_OFF, + HCI_MGMT, + HCI_PAIRABLE, + HCI_SERVICE_CACHE, + HCI_LINK_KEYS, + HCI_DEBUG_KEYS, + + HCI_RESET, +}; + +/* HCI ioctl defines */ +#define HCIDEVUP _IOW('H', 201, int) +#define HCIDEVDOWN _IOW('H', 202, int) +#define HCIDEVRESET _IOW('H', 203, int) +#define HCIDEVRESTAT _IOW('H', 204, int) + +#define HCIGETDEVLIST _IOR('H', 210, int) +#define HCIGETDEVINFO _IOR('H', 211, int) +#define HCIGETCONNLIST _IOR('H', 212, int) +#define HCIGETCONNINFO _IOR('H', 213, int) +#define HCIGETAUTHINFO _IOR('H', 215, int) + +#define HCISETRAW _IOW('H', 220, int) +#define HCISETSCAN _IOW('H', 221, int) +#define HCISETAUTH _IOW('H', 222, int) +#define HCISETENCRYPT _IOW('H', 223, int) +#define HCISETPTYPE _IOW('H', 224, int) +#define HCISETLINKPOL _IOW('H', 225, int) +#define HCISETLINKMODE _IOW('H', 226, int) +#define HCISETACLMTU _IOW('H', 227, int) +#define HCISETSCOMTU _IOW('H', 228, int) + +#define HCIBLOCKADDR _IOW('H', 230, int) +#define HCIUNBLOCKADDR _IOW('H', 231, int) + +#define HCIINQUIRY _IOR('H', 240, int) + +/* HCI timeouts */ +#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */ +#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */ +#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ +#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ +#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ +#define HCI_CMD_TIMEOUT (1000) /* 1 seconds */ + +/* HCI data types */ +#define HCI_COMMAND_PKT 0x01 +#define HCI_ACLDATA_PKT 0x02 +#define HCI_SCODATA_PKT 0x03 +#define HCI_EVENT_PKT 0x04 +#define HCI_VENDOR_PKT 0xff + +/* HCI packet types */ +#define HCI_DM1 0x0008 +#define HCI_DM3 0x0400 +#define HCI_DM5 0x4000 +#define HCI_DH1 0x0010 +#define HCI_DH3 0x0800 +#define HCI_DH5 0x8000 + +#define HCI_HV1 0x0020 +#define HCI_HV2 0x0040 +#define HCI_HV3 0x0080 + +#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) +#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) + +/* eSCO packet types */ +#define ESCO_HV1 0x0001 +#define ESCO_HV2 0x0002 +#define ESCO_HV3 0x0004 +#define ESCO_EV3 0x0008 +#define ESCO_EV4 0x0010 +#define ESCO_EV5 0x0020 +#define ESCO_2EV3 0x0040 +#define ESCO_3EV3 0x0080 +#define ESCO_2EV5 0x0100 +#define ESCO_3EV5 0x0200 + +#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) +#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) + +/* ACL flags */ +#define ACL_START_NO_FLUSH 0x00 +#define ACL_CONT 0x01 +#define ACL_START 0x02 +#define ACL_ACTIVE_BCAST 0x04 +#define ACL_PICO_BCAST 0x08 + +/* Baseband links */ +#define SCO_LINK 0x00 +#define ACL_LINK 0x01 +#define ESCO_LINK 0x02 +/* Low Energy links do not have defined link type. Use invented one */ +#define LE_LINK 0x80 + +/* LMP features */ +#define LMP_3SLOT 0x01 +#define LMP_5SLOT 0x02 +#define LMP_ENCRYPT 0x04 +#define LMP_SOFFSET 0x08 +#define LMP_TACCURACY 0x10 +#define LMP_RSWITCH 0x20 +#define LMP_HOLD 0x40 +#define LMP_SNIFF 0x80 + +#define LMP_PARK 0x01 +#define LMP_RSSI 0x02 +#define LMP_QUALITY 0x04 +#define LMP_SCO 0x08 +#define LMP_HV2 0x10 +#define LMP_HV3 0x20 +#define LMP_ULAW 0x40 +#define LMP_ALAW 0x80 + +#define LMP_CVSD 0x01 +#define LMP_PSCHEME 0x02 +#define LMP_PCONTROL 0x04 + +#define LMP_RSSI_INQ 0x40 +#define LMP_ESCO 0x80 + +#define LMP_EV4 0x01 +#define LMP_EV5 0x02 +#define LMP_LE 0x40 + +#define LMP_SNIFF_SUBR 0x02 +#define LMP_PAUSE_ENC 0x04 +#define LMP_EDR_ESCO_2M 0x20 +#define LMP_EDR_ESCO_3M 0x40 +#define LMP_EDR_3S_ESCO 0x80 + +#define LMP_EXT_INQ 0x01 +#define LMP_SIMUL_LE_BR 0x02 +#define LMP_SIMPLE_PAIR 0x08 +#define LMP_NO_FLUSH 0x40 + +#define LMP_LSTO 0x01 +#define LMP_INQ_TX_PWR 0x02 +#define LMP_EXTFEATURES 0x80 + +/* Extended LMP features */ +#define LMP_HOST_LE 0x02 + +/* Connection modes */ +#define HCI_CM_ACTIVE 0x0000 +#define HCI_CM_HOLD 0x0001 +#define HCI_CM_SNIFF 0x0002 +#define HCI_CM_PARK 0x0003 + +/* Link policies */ +#define HCI_LP_RSWITCH 0x0001 +#define HCI_LP_HOLD 0x0002 +#define HCI_LP_SNIFF 0x0004 +#define HCI_LP_PARK 0x0008 + +/* Link modes */ +#define HCI_LM_ACCEPT 0x8000 +#define HCI_LM_MASTER 0x0001 +#define HCI_LM_AUTH 0x0002 +#define HCI_LM_ENCRYPT 0x0004 +#define HCI_LM_TRUSTED 0x0008 +#define HCI_LM_RELIABLE 0x0010 +#define HCI_LM_SECURE 0x0020 + +/* Authentication types */ +#define HCI_AT_NO_BONDING 0x00 +#define HCI_AT_NO_BONDING_MITM 0x01 +#define HCI_AT_DEDICATED_BONDING 0x02 +#define HCI_AT_DEDICATED_BONDING_MITM 0x03 +#define HCI_AT_GENERAL_BONDING 0x04 +#define HCI_AT_GENERAL_BONDING_MITM 0x05 + +/* Link Key types */ +#define HCI_LK_COMBINATION 0x00 +#define HCI_LK_LOCAL_UNIT 0x01 +#define HCI_LK_REMOTE_UNIT 0x02 +#define HCI_LK_DEBUG_COMBINATION 0x03 +#define HCI_LK_UNAUTH_COMBINATION 0x04 +#define HCI_LK_AUTH_COMBINATION 0x05 +#define HCI_LK_CHANGED_COMBINATION 0x06 +/* The spec doesn't define types for SMP keys */ +#define HCI_LK_SMP_LTK 0x81 +#define HCI_LK_SMP_IRK 0x82 +#define HCI_LK_SMP_CSRK 0x83 + +/* ---- HCI Error Codes ---- */ +#define HCI_ERROR_AUTH_FAILURE 0x05 +#define HCI_ERROR_REJ_BAD_ADDR 0x0f +#define HCI_ERROR_REMOTE_USER_TERM 0x13 +#define HCI_ERROR_LOCAL_HOST_TERM 0x16 +#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 + +/* ----- HCI Commands ---- */ +#define HCI_OP_NOP 0x0000 + +#define HCI_OP_INQUIRY 0x0401 +struct hci_cp_inquiry { + __u8 lap[3]; + __u8 length; + __u8 num_rsp; +} __packed; + +#define HCI_OP_INQUIRY_CANCEL 0x0402 + +#define HCI_OP_EXIT_PERIODIC_INQ 0x0404 + +#define HCI_OP_CREATE_CONN 0x0405 +struct hci_cp_create_conn { + bdaddr_t bdaddr; + __le16 pkt_type; + __u8 pscan_rep_mode; + __u8 pscan_mode; + __le16 clock_offset; + __u8 role_switch; +} __packed; + +#define HCI_OP_DISCONNECT 0x0406 +struct hci_cp_disconnect { + __le16 handle; + __u8 reason; +} __packed; + +#define HCI_OP_ADD_SCO 0x0407 +struct hci_cp_add_sco { + __le16 handle; + __le16 pkt_type; +} __packed; + +#define HCI_OP_CREATE_CONN_CANCEL 0x0408 +struct hci_cp_create_conn_cancel { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_ACCEPT_CONN_REQ 0x0409 +struct hci_cp_accept_conn_req { + bdaddr_t bdaddr; + __u8 role; +} __packed; + +#define HCI_OP_REJECT_CONN_REQ 0x040a +struct hci_cp_reject_conn_req { + bdaddr_t bdaddr; + __u8 reason; +} __packed; + +#define HCI_OP_LINK_KEY_REPLY 0x040b +struct hci_cp_link_key_reply { + bdaddr_t bdaddr; + __u8 link_key[16]; +} __packed; + +#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c +struct hci_cp_link_key_neg_reply { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_PIN_CODE_REPLY 0x040d +struct hci_cp_pin_code_reply { + bdaddr_t bdaddr; + __u8 pin_len; + __u8 pin_code[16]; +} __packed; +struct hci_rp_pin_code_reply { + __u8 status; + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e +struct hci_cp_pin_code_neg_reply { + bdaddr_t bdaddr; +} __packed; +struct hci_rp_pin_code_neg_reply { + __u8 status; + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_CHANGE_CONN_PTYPE 0x040f +struct hci_cp_change_conn_ptype { + __le16 handle; + __le16 pkt_type; +} __packed; + +#define HCI_OP_AUTH_REQUESTED 0x0411 +struct hci_cp_auth_requested { + __le16 handle; +} __packed; + +#define HCI_OP_SET_CONN_ENCRYPT 0x0413 +struct hci_cp_set_conn_encrypt { + __le16 handle; + __u8 encrypt; +} __packed; + +#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415 +struct hci_cp_change_conn_link_key { + __le16 handle; +} __packed; + +#define HCI_OP_REMOTE_NAME_REQ 0x0419 +struct hci_cp_remote_name_req { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_mode; + __le16 clock_offset; +} __packed; + +#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a +struct hci_cp_remote_name_req_cancel { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_READ_REMOTE_FEATURES 0x041b +struct hci_cp_read_remote_features { + __le16 handle; +} __packed; + +#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c +struct hci_cp_read_remote_ext_features { + __le16 handle; + __u8 page; +} __packed; + +#define HCI_OP_READ_REMOTE_VERSION 0x041d +struct hci_cp_read_remote_version { + __le16 handle; +} __packed; + +#define HCI_OP_SETUP_SYNC_CONN 0x0428 +struct hci_cp_setup_sync_conn { + __le16 handle; + __le32 tx_bandwidth; + __le32 rx_bandwidth; + __le16 max_latency; + __le16 voice_setting; + __u8 retrans_effort; + __le16 pkt_type; +} __packed; + +#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429 +struct hci_cp_accept_sync_conn_req { + bdaddr_t bdaddr; + __le32 tx_bandwidth; + __le32 rx_bandwidth; + __le16 max_latency; + __le16 content_format; + __u8 retrans_effort; + __le16 pkt_type; +} __packed; + +#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a +struct hci_cp_reject_sync_conn_req { + bdaddr_t bdaddr; + __u8 reason; +} __packed; + +#define HCI_OP_IO_CAPABILITY_REPLY 0x042b +struct hci_cp_io_capability_reply { + bdaddr_t bdaddr; + __u8 capability; + __u8 oob_data; + __u8 authentication; +} __packed; + +#define HCI_OP_USER_CONFIRM_REPLY 0x042c +struct hci_cp_user_confirm_reply { + bdaddr_t bdaddr; +} __packed; +struct hci_rp_user_confirm_reply { + __u8 status; + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d + +#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430 +struct hci_cp_remote_oob_data_reply { + bdaddr_t bdaddr; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433 +struct hci_cp_remote_oob_data_neg_reply { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 +struct hci_cp_io_capability_neg_reply { + bdaddr_t bdaddr; + __u8 reason; +} __packed; + +#define HCI_OP_SNIFF_MODE 0x0803 +struct hci_cp_sniff_mode { + __le16 handle; + __le16 max_interval; + __le16 min_interval; + __le16 attempt; + __le16 timeout; +} __packed; + +#define HCI_OP_EXIT_SNIFF_MODE 0x0804 +struct hci_cp_exit_sniff_mode { + __le16 handle; +} __packed; + +#define HCI_OP_ROLE_DISCOVERY 0x0809 +struct hci_cp_role_discovery { + __le16 handle; +} __packed; +struct hci_rp_role_discovery { + __u8 status; + __le16 handle; + __u8 role; +} __packed; + +#define HCI_OP_SWITCH_ROLE 0x080b +struct hci_cp_switch_role { + bdaddr_t bdaddr; + __u8 role; +} __packed; + +#define HCI_OP_READ_LINK_POLICY 0x080c +struct hci_cp_read_link_policy { + __le16 handle; +} __packed; +struct hci_rp_read_link_policy { + __u8 status; + __le16 handle; + __le16 policy; +} __packed; + +#define HCI_OP_WRITE_LINK_POLICY 0x080d +struct hci_cp_write_link_policy { + __le16 handle; + __le16 policy; +} __packed; +struct hci_rp_write_link_policy { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_READ_DEF_LINK_POLICY 0x080e +struct hci_rp_read_def_link_policy { + __u8 status; + __le16 policy; +} __packed; + +#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f +struct hci_cp_write_def_link_policy { + __le16 policy; +} __packed; + +#define HCI_OP_SNIFF_SUBRATE 0x0811 +struct hci_cp_sniff_subrate { + __le16 handle; + __le16 max_latency; + __le16 min_remote_timeout; + __le16 min_local_timeout; +} __packed; + +#define HCI_OP_SET_EVENT_MASK 0x0c01 +struct hci_cp_set_event_mask { + __u8 mask[8]; +} __packed; + +#define HCI_OP_RESET 0x0c03 + +#define HCI_OP_SET_EVENT_FLT 0x0c05 +struct hci_cp_set_event_flt { + __u8 flt_type; + __u8 cond_type; + __u8 condition[0]; +} __packed; + +/* Filter types */ +#define HCI_FLT_CLEAR_ALL 0x00 +#define HCI_FLT_INQ_RESULT 0x01 +#define HCI_FLT_CONN_SETUP 0x02 + +/* CONN_SETUP Condition types */ +#define HCI_CONN_SETUP_ALLOW_ALL 0x00 +#define HCI_CONN_SETUP_ALLOW_CLASS 0x01 +#define HCI_CONN_SETUP_ALLOW_BDADDR 0x02 + +/* CONN_SETUP Conditions */ +#define HCI_CONN_SETUP_AUTO_OFF 0x01 +#define HCI_CONN_SETUP_AUTO_ON 0x02 + +#define HCI_OP_DELETE_STORED_LINK_KEY 0x0c12 +struct hci_cp_delete_stored_link_key { + bdaddr_t bdaddr; + __u8 delete_all; +} __packed; + +#define HCI_MAX_NAME_LENGTH 248 + +#define HCI_OP_WRITE_LOCAL_NAME 0x0c13 +struct hci_cp_write_local_name { + __u8 name[HCI_MAX_NAME_LENGTH]; +} __packed; + +#define HCI_OP_READ_LOCAL_NAME 0x0c14 +struct hci_rp_read_local_name { + __u8 status; + __u8 name[HCI_MAX_NAME_LENGTH]; +} __packed; + +#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 + +#define HCI_OP_WRITE_PG_TIMEOUT 0x0c18 + +#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a + #define SCAN_DISABLED 0x00 + #define SCAN_INQUIRY 0x01 + #define SCAN_PAGE 0x02 + +#define HCI_OP_READ_AUTH_ENABLE 0x0c1f + +#define HCI_OP_WRITE_AUTH_ENABLE 0x0c20 + #define AUTH_DISABLED 0x00 + #define AUTH_ENABLED 0x01 + +#define HCI_OP_READ_ENCRYPT_MODE 0x0c21 + +#define HCI_OP_WRITE_ENCRYPT_MODE 0x0c22 + #define ENCRYPT_DISABLED 0x00 + #define ENCRYPT_P2P 0x01 + #define ENCRYPT_BOTH 0x02 + +#define HCI_OP_READ_CLASS_OF_DEV 0x0c23 +struct hci_rp_read_class_of_dev { + __u8 status; + __u8 dev_class[3]; +} __packed; + +#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24 +struct hci_cp_write_class_of_dev { + __u8 dev_class[3]; +} __packed; + +#define HCI_OP_READ_VOICE_SETTING 0x0c25 +struct hci_rp_read_voice_setting { + __u8 status; + __le16 voice_setting; +} __packed; + +#define HCI_OP_WRITE_VOICE_SETTING 0x0c26 +struct hci_cp_write_voice_setting { + __le16 voice_setting; +} __packed; + +#define HCI_OP_HOST_BUFFER_SIZE 0x0c33 +struct hci_cp_host_buffer_size { + __le16 acl_mtu; + __u8 sco_mtu; + __le16 acl_max_pkt; + __le16 sco_max_pkt; +} __packed; + +#define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 + +#define HCI_MAX_EIR_LENGTH 240 + +#define HCI_OP_WRITE_EIR 0x0c52 +struct hci_cp_write_eir { + uint8_t fec; + uint8_t data[HCI_MAX_EIR_LENGTH]; +} __packed; + +#define HCI_OP_READ_SSP_MODE 0x0c55 +struct hci_rp_read_ssp_mode { + __u8 status; + __u8 mode; +} __packed; + +#define HCI_OP_WRITE_SSP_MODE 0x0c56 +struct hci_cp_write_ssp_mode { + __u8 mode; +} __packed; + +#define HCI_OP_READ_LOCAL_OOB_DATA 0x0c57 +struct hci_rp_read_local_oob_data { + __u8 status; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 + +#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d +struct hci_cp_write_le_host_supported { + __u8 le; + __u8 simul; +} __packed; + +#define HCI_OP_READ_LOCAL_VERSION 0x1001 +struct hci_rp_read_local_version { + __u8 status; + __u8 hci_ver; + __le16 hci_rev; + __u8 lmp_ver; + __le16 manufacturer; + __le16 lmp_subver; +} __packed; + +#define HCI_OP_READ_LOCAL_COMMANDS 0x1002 +struct hci_rp_read_local_commands { + __u8 status; + __u8 commands[64]; +} __packed; + +#define HCI_OP_READ_LOCAL_FEATURES 0x1003 +struct hci_rp_read_local_features { + __u8 status; + __u8 features[8]; +} __packed; + +#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004 +struct hci_cp_read_local_ext_features { + __u8 page; +} __packed; +struct hci_rp_read_local_ext_features { + __u8 status; + __u8 page; + __u8 max_page; + __u8 features[8]; +} __packed; + +#define HCI_OP_READ_BUFFER_SIZE 0x1005 +struct hci_rp_read_buffer_size { + __u8 status; + __le16 acl_mtu; + __u8 sco_mtu; + __le16 acl_max_pkt; + __le16 sco_max_pkt; +} __packed; + +#define HCI_OP_READ_BD_ADDR 0x1009 +struct hci_rp_read_bd_addr { + __u8 status; + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c +struct hci_cp_write_page_scan_activity { + __le16 interval; + __le16 window; +} __packed; + +#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47 + #define PAGE_SCAN_TYPE_STANDARD 0x00 + #define PAGE_SCAN_TYPE_INTERLACED 0x01 + +#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 +struct hci_rp_read_local_amp_info { + __u8 status; + __u8 amp_status; + __le32 total_bw; + __le32 max_bw; + __le32 min_latency; + __le32 max_pdu; + __u8 amp_type; + __le16 pal_cap; + __le16 max_assoc_size; + __le32 max_flush_to; + __le32 be_flush_to; +} __packed; + +#define HCI_OP_LE_SET_EVENT_MASK 0x2001 +struct hci_cp_le_set_event_mask { + __u8 mask[8]; +} __packed; + +#define HCI_OP_LE_READ_BUFFER_SIZE 0x2002 +struct hci_rp_le_read_buffer_size { + __u8 status; + __le16 le_mtu; + __u8 le_max_pkt; +} __packed; + +#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c +struct hci_cp_le_set_scan_enable { + __u8 enable; + __u8 filter_dup; +} __packed; + +#define HCI_OP_LE_CREATE_CONN 0x200d +struct hci_cp_le_create_conn { + __le16 scan_interval; + __le16 scan_window; + __u8 filter_policy; + __u8 peer_addr_type; + bdaddr_t peer_addr; + __u8 own_address_type; + __le16 conn_interval_min; + __le16 conn_interval_max; + __le16 conn_latency; + __le16 supervision_timeout; + __le16 min_ce_len; + __le16 max_ce_len; +} __packed; + +#define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e + +#define HCI_OP_LE_CONN_UPDATE 0x2013 +struct hci_cp_le_conn_update { + __le16 handle; + __le16 conn_interval_min; + __le16 conn_interval_max; + __le16 conn_latency; + __le16 supervision_timeout; + __le16 min_ce_len; + __le16 max_ce_len; +} __packed; + +#define HCI_OP_LE_START_ENC 0x2019 +struct hci_cp_le_start_enc { + __le16 handle; + __u8 rand[8]; + __le16 ediv; + __u8 ltk[16]; +} __packed; + +#define HCI_OP_LE_LTK_REPLY 0x201a +struct hci_cp_le_ltk_reply { + __le16 handle; + __u8 ltk[16]; +} __packed; +struct hci_rp_le_ltk_reply { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_LE_LTK_NEG_REPLY 0x201b +struct hci_cp_le_ltk_neg_reply { + __le16 handle; +} __packed; +struct hci_rp_le_ltk_neg_reply { + __u8 status; + __le16 handle; +} __packed; + +/* ---- HCI Events ---- */ +#define HCI_EV_INQUIRY_COMPLETE 0x01 + +#define HCI_EV_INQUIRY_RESULT 0x02 +struct inquiry_info { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; + __u8 dev_class[3]; + __le16 clock_offset; +} __packed; + +#define HCI_EV_CONN_COMPLETE 0x03 +struct hci_ev_conn_complete { + __u8 status; + __le16 handle; + bdaddr_t bdaddr; + __u8 link_type; + __u8 encr_mode; +} __packed; + +#define HCI_EV_CONN_REQUEST 0x04 +struct hci_ev_conn_request { + bdaddr_t bdaddr; + __u8 dev_class[3]; + __u8 link_type; +} __packed; + +#define HCI_EV_DISCONN_COMPLETE 0x05 +struct hci_ev_disconn_complete { + __u8 status; + __le16 handle; + __u8 reason; +} __packed; + +#define HCI_EV_AUTH_COMPLETE 0x06 +struct hci_ev_auth_complete { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_EV_REMOTE_NAME 0x07 +struct hci_ev_remote_name { + __u8 status; + bdaddr_t bdaddr; + __u8 name[HCI_MAX_NAME_LENGTH]; +} __packed; + +#define HCI_EV_ENCRYPT_CHANGE 0x08 +struct hci_ev_encrypt_change { + __u8 status; + __le16 handle; + __u8 encrypt; +} __packed; + +#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09 +struct hci_ev_change_link_key_complete { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_EV_REMOTE_FEATURES 0x0b +struct hci_ev_remote_features { + __u8 status; + __le16 handle; + __u8 features[8]; +} __packed; + +#define HCI_EV_REMOTE_VERSION 0x0c +struct hci_ev_remote_version { + __u8 status; + __le16 handle; + __u8 lmp_ver; + __le16 manufacturer; + __le16 lmp_subver; +} __packed; + +#define HCI_EV_QOS_SETUP_COMPLETE 0x0d +struct hci_qos { + __u8 service_type; + __u32 token_rate; + __u32 peak_bandwidth; + __u32 latency; + __u32 delay_variation; +} __packed; +struct hci_ev_qos_setup_complete { + __u8 status; + __le16 handle; + struct hci_qos qos; +} __packed; + +#define HCI_EV_CMD_COMPLETE 0x0e +struct hci_ev_cmd_complete { + __u8 ncmd; + __le16 opcode; +} __packed; + +#define HCI_EV_CMD_STATUS 0x0f +struct hci_ev_cmd_status { + __u8 status; + __u8 ncmd; + __le16 opcode; +} __packed; + +#define HCI_EV_ROLE_CHANGE 0x12 +struct hci_ev_role_change { + __u8 status; + bdaddr_t bdaddr; + __u8 role; +} __packed; + +#define HCI_EV_NUM_COMP_PKTS 0x13 +struct hci_ev_num_comp_pkts { + __u8 num_hndl; + /* variable length part */ +} __packed; + +#define HCI_EV_MODE_CHANGE 0x14 +struct hci_ev_mode_change { + __u8 status; + __le16 handle; + __u8 mode; + __le16 interval; +} __packed; + +#define HCI_EV_PIN_CODE_REQ 0x16 +struct hci_ev_pin_code_req { + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_LINK_KEY_REQ 0x17 +struct hci_ev_link_key_req { + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_LINK_KEY_NOTIFY 0x18 +struct hci_ev_link_key_notify { + bdaddr_t bdaddr; + __u8 link_key[16]; + __u8 key_type; +} __packed; + +#define HCI_EV_CLOCK_OFFSET 0x1c +struct hci_ev_clock_offset { + __u8 status; + __le16 handle; + __le16 clock_offset; +} __packed; + +#define HCI_EV_PKT_TYPE_CHANGE 0x1d +struct hci_ev_pkt_type_change { + __u8 status; + __le16 handle; + __le16 pkt_type; +} __packed; + +#define HCI_EV_PSCAN_REP_MODE 0x20 +struct hci_ev_pscan_rep_mode { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; +} __packed; + +#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 +struct inquiry_info_with_rssi { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; +} __packed; +struct inquiry_info_with_rssi_and_pscan_mode { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; +} __packed; + +#define HCI_EV_REMOTE_EXT_FEATURES 0x23 +struct hci_ev_remote_ext_features { + __u8 status; + __le16 handle; + __u8 page; + __u8 max_page; + __u8 features[8]; +} __packed; + +#define HCI_EV_SYNC_CONN_COMPLETE 0x2c +struct hci_ev_sync_conn_complete { + __u8 status; + __le16 handle; + bdaddr_t bdaddr; + __u8 link_type; + __u8 tx_interval; + __u8 retrans_window; + __le16 rx_pkt_len; + __le16 tx_pkt_len; + __u8 air_mode; +} __packed; + +#define HCI_EV_SYNC_CONN_CHANGED 0x2d +struct hci_ev_sync_conn_changed { + __u8 status; + __le16 handle; + __u8 tx_interval; + __u8 retrans_window; + __le16 rx_pkt_len; + __le16 tx_pkt_len; +} __packed; + +#define HCI_EV_SNIFF_SUBRATE 0x2e +struct hci_ev_sniff_subrate { + __u8 status; + __le16 handle; + __le16 max_tx_latency; + __le16 max_rx_latency; + __le16 max_remote_timeout; + __le16 max_local_timeout; +} __packed; + +#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f +struct extended_inquiry_info { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; + __u8 data[240]; +} __packed; + +#define HCI_EV_IO_CAPA_REQUEST 0x31 +struct hci_ev_io_capa_request { + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_IO_CAPA_REPLY 0x32 +struct hci_ev_io_capa_reply { + bdaddr_t bdaddr; + __u8 capability; + __u8 oob_data; + __u8 authentication; +} __packed; + +#define HCI_EV_USER_CONFIRM_REQUEST 0x33 +struct hci_ev_user_confirm_req { + bdaddr_t bdaddr; + __le32 passkey; +} __packed; + +#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35 +struct hci_ev_remote_oob_data_request { + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 +struct hci_ev_simple_pair_complete { + __u8 status; + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_REMOTE_HOST_FEATURES 0x3d +struct hci_ev_remote_host_features { + bdaddr_t bdaddr; + __u8 features[8]; +} __packed; + +#define HCI_EV_LE_META 0x3e +struct hci_ev_le_meta { + __u8 subevent; +} __packed; + +/* Low energy meta events */ +#define HCI_EV_LE_CONN_COMPLETE 0x01 +struct hci_ev_le_conn_complete { + __u8 status; + __le16 handle; + __u8 role; + __u8 bdaddr_type; + bdaddr_t bdaddr; + __le16 interval; + __le16 latency; + __le16 supervision_timeout; + __u8 clk_accurancy; +} __packed; + +#define HCI_EV_LE_LTK_REQ 0x05 +struct hci_ev_le_ltk_req { + __le16 handle; + __u8 random[8]; + __le16 ediv; +} __packed; + +/* Advertising report event types */ +#define ADV_IND 0x00 +#define ADV_DIRECT_IND 0x01 +#define ADV_SCAN_IND 0x02 +#define ADV_NONCONN_IND 0x03 +#define ADV_SCAN_RSP 0x04 + +#define ADDR_LE_DEV_PUBLIC 0x00 +#define ADDR_LE_DEV_RANDOM 0x01 + +#define HCI_EV_LE_ADVERTISING_REPORT 0x02 +struct hci_ev_le_advertising_info { + __u8 evt_type; + __u8 bdaddr_type; + bdaddr_t bdaddr; + __u8 length; + __u8 data[0]; +} __packed; + +/* Internal events generated by Bluetooth stack */ +#define HCI_EV_STACK_INTERNAL 0xfd +struct hci_ev_stack_internal { + __u16 type; + __u8 data[0]; +} __packed; + +#define HCI_EV_SI_DEVICE 0x01 +struct hci_ev_si_device { + __u16 event; + __u16 dev_id; +} __packed; + +#define HCI_EV_SI_SECURITY 0x02 +struct hci_ev_si_security { + __u16 event; + __u16 proto; + __u16 subproto; + __u8 incoming; +} __packed; + +/* ---- HCI Packet structures ---- */ +#define HCI_COMMAND_HDR_SIZE 3 +#define HCI_EVENT_HDR_SIZE 2 +#define HCI_ACL_HDR_SIZE 4 +#define HCI_SCO_HDR_SIZE 3 + +struct hci_command_hdr { + __le16 opcode; /* OCF & OGF */ + __u8 plen; +} __packed; + +struct hci_event_hdr { + __u8 evt; + __u8 plen; +} __packed; + +struct hci_acl_hdr { + __le16 handle; /* Handle & Flags(PB, BC) */ + __le16 dlen; +} __packed; + +struct hci_sco_hdr { + __le16 handle; + __u8 dlen; +} __packed; + +#include +static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb) +{ + return (struct hci_event_hdr *) skb->data; +} + +static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb) +{ + return (struct hci_acl_hdr *) skb->data; +} + +static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) +{ + return (struct hci_sco_hdr *) skb->data; +} + +/* Command opcode pack/unpack */ +#define hci_opcode_pack(ogf, ocf) (__u16) ((ocf & 0x03ff)|(ogf << 10)) +#define hci_opcode_ogf(op) (op >> 10) +#define hci_opcode_ocf(op) (op & 0x03ff) + +/* ACL handle and flags pack/unpack */ +#define hci_handle_pack(h, f) (__u16) ((h & 0x0fff)|(f << 12)) +#define hci_handle(h) (h & 0x0fff) +#define hci_flags(h) (h >> 12) + +/* ---- HCI Sockets ---- */ + +/* Socket options */ +#define HCI_DATA_DIR 1 +#define HCI_FILTER 2 +#define HCI_TIME_STAMP 3 + +/* CMSG flags */ +#define HCI_CMSG_DIR 0x0001 +#define HCI_CMSG_TSTAMP 0x0002 + +struct sockaddr_hci { + sa_family_t hci_family; + unsigned short hci_dev; + unsigned short hci_channel; +}; +#define HCI_DEV_NONE 0xffff + +#define HCI_CHANNEL_RAW 0 +#define HCI_CHANNEL_CONTROL 1 + +struct hci_filter { + unsigned long type_mask; + unsigned long event_mask[2]; + __le16 opcode; +}; + +struct hci_ufilter { + __u32 type_mask; + __u32 event_mask[2]; + __le16 opcode; +}; + +#define HCI_FLT_TYPE_BITS 31 +#define HCI_FLT_EVENT_BITS 63 +#define HCI_FLT_OGF_BITS 63 +#define HCI_FLT_OCF_BITS 127 + +/* ---- HCI Ioctl requests structures ---- */ +struct hci_dev_stats { + __u32 err_rx; + __u32 err_tx; + __u32 cmd_tx; + __u32 evt_rx; + __u32 acl_tx; + __u32 acl_rx; + __u32 sco_tx; + __u32 sco_rx; + __u32 byte_rx; + __u32 byte_tx; +}; + +struct hci_dev_info { + __u16 dev_id; + char name[8]; + + bdaddr_t bdaddr; + + __u32 flags; + __u8 type; + + __u8 features[8]; + + __u32 pkt_type; + __u32 link_policy; + __u32 link_mode; + + __u16 acl_mtu; + __u16 acl_pkts; + __u16 sco_mtu; + __u16 sco_pkts; + + struct hci_dev_stats stat; +}; + +struct hci_conn_info { + __u16 handle; + bdaddr_t bdaddr; + __u8 type; + __u8 out; + __u16 state; + __u32 link_mode; +}; + +struct hci_dev_req { + __u16 dev_id; + __u32 dev_opt; +}; + +struct hci_dev_list_req { + __u16 dev_num; + struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ +}; + +struct hci_conn_list_req { + __u16 dev_id; + __u16 conn_num; + struct hci_conn_info conn_info[0]; +}; + +struct hci_conn_info_req { + bdaddr_t bdaddr; + __u8 type; + struct hci_conn_info conn_info[0]; +}; + +struct hci_auth_info_req { + bdaddr_t bdaddr; + __u8 type; +}; + +struct hci_inquiry_req { + __u16 dev_id; + __u16 flags; + __u8 lap[3]; + __u8 length; + __u8 num_rsp; +}; +#define IREQ_CACHE_FLUSH 0x0001 + +#endif /* __HCI_H */ diff --git a/include/compat/net/bluetooth/hci_core.h b/include/compat/net/bluetooth/hci_core.h new file mode 100644 index 00000000..f333e768 --- /dev/null +++ b/include/compat/net/bluetooth/hci_core.h @@ -0,0 +1,988 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. + + Written 2000,2001 by Maxim Krasnyansky + + 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_CORE_H +#define __HCI_CORE_H + +#include +#include + +/* HCI upper protocols */ +#define HCI_PROTO_L2CAP 0 +#define HCI_PROTO_SCO 1 + +/* HCI priority */ +#define HCI_PRIO_MAX 7 + +/* HCI Core structures */ +struct inquiry_data { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; + __u8 ssp_mode; +}; + +struct inquiry_entry { + struct inquiry_entry *next; + __u32 timestamp; + struct inquiry_data data; +}; + +struct inquiry_cache { + spinlock_t lock; + __u32 timestamp; + struct inquiry_entry *list; +}; + +struct hci_conn_hash { + struct list_head list; + spinlock_t lock; + unsigned int acl_num; + unsigned int sco_num; + unsigned int le_num; +}; + +struct hci_chan_hash { + struct list_head list; + spinlock_t lock; + unsigned int num; +}; + +struct bdaddr_list { + struct list_head list; + bdaddr_t bdaddr; +}; + +struct bt_uuid { + struct list_head list; + u8 uuid[16]; + u8 svc_hint; +}; + +struct key_master_id { + __le16 ediv; + u8 rand[8]; +} __packed; + +struct link_key_data { + bdaddr_t bdaddr; + u8 type; + u8 val[16]; + u8 pin_len; + u8 dlen; + u8 data[0]; +} __packed; + +struct link_key { + struct list_head list; + bdaddr_t bdaddr; + u8 type; + u8 val[16]; + u8 pin_len; + u8 dlen; + u8 data[0]; +}; + +struct oob_data { + struct list_head list; + bdaddr_t bdaddr; + u8 hash[16]; + u8 randomizer[16]; +}; + +struct adv_entry { + struct list_head list; + bdaddr_t bdaddr; + u8 bdaddr_type; +}; + +#define NUM_REASSEMBLY 4 +struct hci_dev { + struct list_head list; + spinlock_t lock; + atomic_t refcnt; + + char name[8]; + unsigned long flags; + __u16 id; + __u8 bus; + __u8 dev_type; + bdaddr_t bdaddr; + __u8 dev_name[HCI_MAX_NAME_LENGTH]; + __u8 eir[HCI_MAX_EIR_LENGTH]; + __u8 dev_class[3]; + __u8 major_class; + __u8 minor_class; + __u8 features[8]; + __u8 extfeatures[8]; + __u8 commands[64]; + __u8 ssp_mode; + __u8 hci_ver; + __u16 hci_rev; + __u8 lmp_ver; + __u16 manufacturer; + __le16 lmp_subver; + __u16 voice_setting; + __u8 io_capability; + + __u16 pkt_type; + __u16 esco_type; + __u16 link_policy; + __u16 link_mode; + + __u32 idle_timeout; + __u16 sniff_min_interval; + __u16 sniff_max_interval; + + __u8 amp_status; + __u32 amp_total_bw; + __u32 amp_max_bw; + __u32 amp_min_latency; + __u32 amp_max_pdu; + __u8 amp_type; + __u16 amp_pal_cap; + __u16 amp_assoc_size; + __u32 amp_max_flush_to; + __u32 amp_be_flush_to; + + unsigned int auto_accept_delay; + + unsigned long quirks; + + atomic_t cmd_cnt; + unsigned int acl_cnt; + unsigned int sco_cnt; + unsigned int le_cnt; + + unsigned int acl_mtu; + unsigned int sco_mtu; + unsigned int le_mtu; + unsigned int acl_pkts; + unsigned int sco_pkts; + unsigned int le_pkts; + + unsigned long acl_last_tx; + unsigned long sco_last_tx; + unsigned long le_last_tx; + + struct workqueue_struct *workqueue; + + struct work_struct power_on; + struct delayed_work power_off; + + __u16 discov_timeout; + struct delayed_work discov_off; + + struct timer_list cmd_timer; + struct tasklet_struct cmd_task; + struct tasklet_struct rx_task; + struct tasklet_struct tx_task; + + struct sk_buff_head rx_q; + struct sk_buff_head raw_q; + struct sk_buff_head cmd_q; + + struct sk_buff *sent_cmd; + struct sk_buff *reassembly[NUM_REASSEMBLY]; + + struct mutex req_lock; + wait_queue_head_t req_wait_q; + __u32 req_status; + __u32 req_result; + + __u16 init_last_cmd; + + struct list_head mgmt_pending; + + struct inquiry_cache inq_cache; + struct hci_conn_hash conn_hash; + struct list_head blacklist; + + struct list_head uuids; + + struct list_head link_keys; + + struct list_head remote_oob_data; + + struct list_head adv_entries; + struct timer_list adv_timer; + + struct hci_dev_stats stat; + + struct sk_buff_head driver_init; + + void *driver_data; + void *core_data; + + atomic_t promisc; + + struct dentry *debugfs; + + struct device *parent; + struct device dev; + + struct rfkill *rfkill; + + struct module *owner; + + int (*open)(struct hci_dev *hdev); + int (*close)(struct hci_dev *hdev); + int (*flush)(struct hci_dev *hdev); + int (*send)(struct sk_buff *skb); + void (*destruct)(struct hci_dev *hdev); + void (*notify)(struct hci_dev *hdev, unsigned int evt); + int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); +}; + +struct hci_conn { + struct list_head list; + + atomic_t refcnt; + + bdaddr_t dst; + __u8 dst_type; + __u16 handle; + __u16 state; + __u8 mode; + __u8 type; + __u8 out; + __u8 attempt; + __u8 dev_class[3]; + __u8 features[8]; + __u8 ssp_mode; + __u16 interval; + __u16 pkt_type; + __u16 link_policy; + __u32 link_mode; + __u8 key_type; + __u8 auth_type; + __u8 sec_level; + __u8 pending_sec_level; + __u8 pin_length; + __u8 enc_key_size; + __u8 io_capability; + __u8 power_save; + __u16 disc_timeout; + unsigned long pend; + + __u8 remote_cap; + __u8 remote_oob; + __u8 remote_auth; + + unsigned int sent; + + struct sk_buff_head data_q; + struct hci_chan_hash chan_hash; + + struct timer_list disc_timer; + struct timer_list idle_timer; + struct timer_list auto_accept_timer; + + struct work_struct work_add; + struct work_struct work_del; + + struct device dev; + atomic_t devref; + + struct hci_dev *hdev; + void *l2cap_data; + void *sco_data; + + struct hci_conn *link; + + void (*connect_cfm_cb) (struct hci_conn *conn, u8 status); + void (*security_cfm_cb) (struct hci_conn *conn, u8 status); + void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason); +}; + +struct hci_chan { + struct list_head list; + + struct hci_conn *conn; + struct sk_buff_head data_q; + unsigned int sent; +}; + +extern struct hci_proto *hci_proto[]; +extern struct list_head hci_dev_list; +extern struct list_head hci_cb_list; +extern rwlock_t hci_dev_list_lock; +extern rwlock_t hci_cb_list_lock; + +/* ----- Inquiry cache ----- */ +#define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ +#define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */ + +#define inquiry_cache_lock(c) spin_lock(&c->lock) +#define inquiry_cache_unlock(c) spin_unlock(&c->lock) +#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock) +#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock) + +static inline void inquiry_cache_init(struct hci_dev *hdev) +{ + struct inquiry_cache *c = &hdev->inq_cache; + spin_lock_init(&c->lock); + c->list = NULL; +} + +static inline int inquiry_cache_empty(struct hci_dev *hdev) +{ + struct inquiry_cache *c = &hdev->inq_cache; + return c->list == NULL; +} + +static inline long inquiry_cache_age(struct hci_dev *hdev) +{ + struct inquiry_cache *c = &hdev->inq_cache; + return jiffies - c->timestamp; +} + +static inline long inquiry_entry_age(struct inquiry_entry *e) +{ + return jiffies - e->timestamp; +} + +struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, + bdaddr_t *bdaddr); +void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data); + +/* ----- HCI Connections ----- */ +enum { + HCI_CONN_AUTH_PEND, + HCI_CONN_REAUTH_PEND, + HCI_CONN_ENCRYPT_PEND, + HCI_CONN_RSWITCH_PEND, + HCI_CONN_MODE_CHANGE_PEND, + HCI_CONN_SCO_SETUP_PEND, + HCI_CONN_LE_SMP_PEND, +}; + +static inline void hci_conn_hash_init(struct hci_dev *hdev) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + INIT_LIST_HEAD(&h->list); + spin_lock_init(&h->lock); + h->acl_num = 0; + h->sco_num = 0; +} + +static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + list_add(&c->list, &h->list); + switch (c->type) { + case ACL_LINK: + h->acl_num++; + break; + case LE_LINK: + h->le_num++; + break; + case SCO_LINK: + case ESCO_LINK: + h->sco_num++; + break; + } +} + +static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + list_del(&c->list); + switch (c->type) { + case ACL_LINK: + h->acl_num--; + break; + case LE_LINK: + h->le_num--; + break; + case SCO_LINK: + case ESCO_LINK: + h->sco_num--; + break; + } +} + +static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + switch (type) { + case ACL_LINK: + return h->acl_num; + case LE_LINK: + return h->le_num; + case SCO_LINK: + case ESCO_LINK: + return h->sco_num; + default: + return 0; + } +} + +static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, + __u16 handle) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct list_head *p; + struct hci_conn *c; + + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->handle == handle) + return c; + } + return NULL; +} + +static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, + __u8 type, bdaddr_t *ba) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct list_head *p; + struct hci_conn *c; + + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->type == type && !bacmp(&c->dst, ba)) + return c; + } + return NULL; +} + +static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, + __u8 type, __u16 state) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct list_head *p; + struct hci_conn *c; + + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->type == type && c->state == state) + return c; + } + return NULL; +} + +static inline void hci_chan_hash_init(struct hci_conn *c) +{ + struct hci_chan_hash *h = &c->chan_hash; + INIT_LIST_HEAD(&h->list); + spin_lock_init(&h->lock); + h->num = 0; +} + +static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan) +{ + struct hci_chan_hash *h = &c->chan_hash; + list_add(&chan->list, &h->list); + h->num++; +} + +static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan) +{ + struct hci_chan_hash *h = &c->chan_hash; + list_del(&chan->list); + h->num--; +} + +void hci_acl_connect(struct hci_conn *conn); +void hci_acl_disconn(struct hci_conn *conn, __u8 reason); +void hci_add_sco(struct hci_conn *conn, __u16 handle); +void hci_setup_sync(struct hci_conn *conn, __u16 handle); +void hci_sco_setup(struct hci_conn *conn, __u8 status); + +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); +int hci_conn_del(struct hci_conn *conn); +void hci_conn_hash_flush(struct hci_dev *hdev); +void hci_conn_check_pending(struct hci_dev *hdev); + +struct hci_chan *hci_chan_create(struct hci_conn *conn); +int hci_chan_del(struct hci_chan *chan); +void hci_chan_hash_flush(struct hci_conn *conn); + +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, + __u8 sec_level, __u8 auth_type); +int hci_conn_check_link_mode(struct hci_conn *conn); +int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); +int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); +int hci_conn_change_link_key(struct hci_conn *conn); +int hci_conn_switch_role(struct hci_conn *conn, __u8 role); + +void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); +void hci_conn_enter_sniff_mode(struct hci_conn *conn); + +void hci_conn_hold_device(struct hci_conn *conn); +void hci_conn_put_device(struct hci_conn *conn); + +static inline void hci_conn_hold(struct hci_conn *conn) +{ + atomic_inc(&conn->refcnt); + del_timer(&conn->disc_timer); +} + +static inline void hci_conn_put(struct hci_conn *conn) +{ + if (atomic_dec_and_test(&conn->refcnt)) { + unsigned long timeo; + if (conn->type == ACL_LINK || conn->type == LE_LINK) { + del_timer(&conn->idle_timer); + if (conn->state == BT_CONNECTED) { + timeo = msecs_to_jiffies(conn->disc_timeout); + if (!conn->out) + timeo *= 2; + } else { + timeo = msecs_to_jiffies(10); + } + } else { + timeo = msecs_to_jiffies(10); + } + mod_timer(&conn->disc_timer, jiffies + timeo); + } +} + +/* ----- HCI Devices ----- */ +static inline void __hci_dev_put(struct hci_dev *d) +{ + if (atomic_dec_and_test(&d->refcnt)) + d->destruct(d); +} + +/* + * hci_dev_put and hci_dev_hold are macros to avoid dragging all the + * overhead of all the modular infrastructure into this header. + */ +#define hci_dev_put(d) \ +do { \ + __hci_dev_put(d); \ + module_put(d->owner); \ +} while (0) + +static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) +{ + atomic_inc(&d->refcnt); + return d; +} + +#define hci_dev_hold(d) \ +({ \ + try_module_get(d->owner) ? __hci_dev_hold(d) : NULL; \ +}) + +#define hci_dev_lock(d) spin_lock(&d->lock) +#define hci_dev_unlock(d) spin_unlock(&d->lock) +#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock) +#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock) + +struct hci_dev *hci_dev_get(int index); +struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); + +struct hci_dev *hci_alloc_dev(void); +void hci_free_dev(struct hci_dev *hdev); +int hci_register_dev(struct hci_dev *hdev); +void hci_unregister_dev(struct hci_dev *hdev); +int hci_suspend_dev(struct hci_dev *hdev); +int hci_resume_dev(struct hci_dev *hdev); +int hci_dev_open(__u16 dev); +int hci_dev_close(__u16 dev); +int hci_dev_reset(__u16 dev); +int hci_dev_reset_stat(__u16 dev); +int hci_dev_cmd(unsigned int cmd, void __user *arg); +int hci_get_dev_list(void __user *arg); +int hci_get_dev_info(void __user *arg); +int hci_get_conn_list(void __user *arg); +int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); +int hci_get_auth_info(struct hci_dev *hdev, void __user *arg); +int hci_inquiry(void __user *arg); + +struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_blacklist_clear(struct hci_dev *hdev); +int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr); + +int hci_uuids_clear(struct hci_dev *hdev); + +int hci_link_keys_clear(struct hci_dev *hdev); +struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); +struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); +struct link_key *hci_find_link_key_type(struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type); +int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, + u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]); +int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); + +int hci_remote_oob_data_clear(struct hci_dev *hdev); +struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, + bdaddr_t *bdaddr); +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, + u8 *randomizer); +int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); + +#define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */ +int hci_adv_entries_clear(struct hci_dev *hdev); +struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_add_adv_entry(struct hci_dev *hdev, + struct hci_ev_le_advertising_info *ev); + +void hci_del_off_timer(struct hci_dev *hdev); + +void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); + +int hci_recv_frame(struct sk_buff *skb); +int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count); +int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count); + +void hci_init_sysfs(struct hci_dev *hdev); +int hci_add_sysfs(struct hci_dev *hdev); +void hci_del_sysfs(struct hci_dev *hdev); +void hci_conn_init_sysfs(struct hci_conn *conn); +void hci_conn_add_sysfs(struct hci_conn *conn); +void hci_conn_del_sysfs(struct hci_conn *conn); + +#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) + +/* ----- LMP capabilities ----- */ +#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) +#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT) +#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) +#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) +#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) +#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) +#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) +#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE) + +/* ----- Extended LMP capabilities ----- */ +#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE) + +/* ----- HCI protocols ----- */ +struct hci_proto { + char *name; + unsigned int id; + unsigned long flags; + + void *priv; + + int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 type); + int (*connect_cfm) (struct hci_conn *conn, __u8 status); + int (*disconn_ind) (struct hci_conn *conn); + int (*disconn_cfm) (struct hci_conn *conn, __u8 reason); + int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, + __u16 flags); + int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); + int (*security_cfm) (struct hci_conn *conn, __u8 status, + __u8 encrypt); +}; + +static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 type) +{ + register struct hci_proto *hp; + int mask = 0; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->connect_ind) + mask |= hp->connect_ind(hdev, bdaddr, type); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->connect_ind) + mask |= hp->connect_ind(hdev, bdaddr, type); + + return mask; +} + +static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->connect_cfm) + hp->connect_cfm(conn, status); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->connect_cfm) + hp->connect_cfm(conn, status); + + if (conn->connect_cfm_cb) + conn->connect_cfm_cb(conn, status); +} + +static inline int hci_proto_disconn_ind(struct hci_conn *conn) +{ + register struct hci_proto *hp; + int reason = HCI_ERROR_REMOTE_USER_TERM; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->disconn_ind) + reason = hp->disconn_ind(conn); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->disconn_ind) + reason = hp->disconn_ind(conn); + + return reason; +} + +static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->disconn_cfm) + hp->disconn_cfm(conn, reason); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->disconn_cfm) + hp->disconn_cfm(conn, reason); + + if (conn->disconn_cfm_cb) + conn->disconn_cfm_cb(conn, reason); +} + +static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + __u8 encrypt; + + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + return; + + encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); + + if (conn->security_cfm_cb) + conn->security_cfm_cb(conn, status); +} + +static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, + __u8 encrypt) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); + + if (conn->security_cfm_cb) + conn->security_cfm_cb(conn, status); +} + +int hci_register_proto(struct hci_proto *hproto); +int hci_unregister_proto(struct hci_proto *hproto); + +/* ----- HCI callbacks ----- */ +struct hci_cb { + struct list_head list; + + char *name; + + void (*security_cfm) (struct hci_conn *conn, __u8 status, + __u8 encrypt); + void (*key_change_cfm) (struct hci_conn *conn, __u8 status); + void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role); +}; + +static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) +{ + struct list_head *p; + __u8 encrypt; + + hci_proto_auth_cfm(conn, status); + + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + return; + + encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->security_cfm) + cb->security_cfm(conn, status, encrypt); + } + read_unlock_bh(&hci_cb_list_lock); +} + +static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, + __u8 encrypt) +{ + struct list_head *p; + + if (conn->sec_level == BT_SECURITY_SDP) + conn->sec_level = BT_SECURITY_LOW; + + if (conn->pending_sec_level > conn->sec_level) + conn->sec_level = conn->pending_sec_level; + + hci_proto_encrypt_cfm(conn, status, encrypt); + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->security_cfm) + cb->security_cfm(conn, status, encrypt); + } + read_unlock_bh(&hci_cb_list_lock); +} + +static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status) +{ + struct list_head *p; + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->key_change_cfm) + cb->key_change_cfm(conn, status); + } + read_unlock_bh(&hci_cb_list_lock); +} + +static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, + __u8 role) +{ + struct list_head *p; + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->role_switch_cfm) + cb->role_switch_cfm(conn, status, role); + } + read_unlock_bh(&hci_cb_list_lock); +} + +int hci_register_cb(struct hci_cb *hcb); +int hci_unregister_cb(struct hci_cb *hcb); + +int hci_register_notifier(struct notifier_block *nb); +int hci_unregister_notifier(struct notifier_block *nb); + +int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); +void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); +void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); + +void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); + +void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); + +/* ----- HCI Sockets ----- */ +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, + struct sock *skip_sk); + +/* Management interface */ +int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); +int mgmt_index_added(struct hci_dev *hdev); +int mgmt_index_removed(struct hci_dev *hdev); +int mgmt_powered(struct hci_dev *hdev, u8 powered); +int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); +int mgmt_connectable(struct hci_dev *hdev, u8 connectable); +int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); +int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, + u8 persistent); +int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int mgmt_disconnect_failed(struct hci_dev *hdev); +int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, + u8 status); +int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure); +int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 status); +int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 status); +int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, + __le32 value, u8 confirm_hint); +int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 status); +int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 status); +int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); +int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); +int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, + u8 *randomizer, u8 status); +int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, + u8 *dev_class, s8 rssi, u8 *eir); +int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name); +int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status); +int mgmt_discovering(struct hci_dev *hdev, u8 discovering); +int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr); +int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr); + +/* HCI info for socket */ +#define hci_pi(sk) ((struct hci_pinfo *) sk) + +struct hci_pinfo { + struct bt_sock bt; + struct hci_dev *hdev; + struct hci_filter filter; + __u32 cmsg_mask; + unsigned short channel; +}; + +/* HCI security filter */ +#define HCI_SFLT_MAX_OGF 5 + +struct hci_sec_filter { + __u32 type_mask; + __u32 event_mask[2]; + __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; +}; + +/* ----- HCI requests ----- */ +#define HCI_REQ_DONE 0 +#define HCI_REQ_PEND 1 +#define HCI_REQ_CANCELED 2 + +#define hci_req_lock(d) mutex_lock(&d->req_lock) +#define hci_req_unlock(d) mutex_unlock(&d->req_lock) + +void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result); + +void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, + u16 latency, u16 to_multiplier); +void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], + __u8 ltk[16]); +void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]); +void hci_le_ltk_neg_reply(struct hci_conn *conn); + +int hci_do_inquiry(struct hci_dev *hdev, u8 length); +int hci_cancel_inquiry(struct hci_dev *hdev); + +#endif /* __HCI_CORE_H */ diff --git a/include/compat/net/bluetooth/l2cap.h b/include/compat/net/bluetooth/l2cap.h new file mode 100644 index 00000000..875021ad --- /dev/null +++ b/include/compat/net/bluetooth/l2cap.h @@ -0,0 +1,814 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (C) 2009-2010 Gustavo F. Padovan + Copyright (C) 2010 Google Inc. + + Written 2000,2001 by Maxim Krasnyansky + + 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __L2CAP_H +#define __L2CAP_H + +#include + +/* L2CAP defaults */ +#define L2CAP_DEFAULT_MTU 672 +#define L2CAP_DEFAULT_MIN_MTU 48 +#define L2CAP_DEFAULT_FLUSH_TO 0xffff +#define L2CAP_DEFAULT_TX_WINDOW 63 +#define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF +#define L2CAP_DEFAULT_MAX_TX 3 +#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */ +#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ +#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ +#define L2CAP_DEFAULT_ACK_TO 200 +#define L2CAP_LE_DEFAULT_MTU 23 +#define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF +#define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF +#define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF + +#define L2CAP_DISC_TIMEOUT (100) +#define L2CAP_DISC_REJ_TIMEOUT (5000) /* 5 seconds */ +#define L2CAP_ENC_TIMEOUT (5000) /* 5 seconds */ +#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ +#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ + +/* L2CAP socket address */ +struct sockaddr_l2 { + sa_family_t l2_family; + __le16 l2_psm; + bdaddr_t l2_bdaddr; + __le16 l2_cid; +}; + +/* L2CAP socket options */ +#define L2CAP_OPTIONS 0x01 +struct l2cap_options { + __u16 omtu; + __u16 imtu; + __u16 flush_to; + __u8 mode; + __u8 fcs; + __u8 max_tx; + __u16 txwin_size; +}; + +#define L2CAP_CONNINFO 0x02 +struct l2cap_conninfo { + __u16 hci_handle; + __u8 dev_class[3]; +}; + +#define L2CAP_LM 0x03 +#define L2CAP_LM_MASTER 0x0001 +#define L2CAP_LM_AUTH 0x0002 +#define L2CAP_LM_ENCRYPT 0x0004 +#define L2CAP_LM_TRUSTED 0x0008 +#define L2CAP_LM_RELIABLE 0x0010 +#define L2CAP_LM_SECURE 0x0020 + +/* L2CAP command codes */ +#define L2CAP_COMMAND_REJ 0x01 +#define L2CAP_CONN_REQ 0x02 +#define L2CAP_CONN_RSP 0x03 +#define L2CAP_CONF_REQ 0x04 +#define L2CAP_CONF_RSP 0x05 +#define L2CAP_DISCONN_REQ 0x06 +#define L2CAP_DISCONN_RSP 0x07 +#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_INFO_REQ 0x0a +#define L2CAP_INFO_RSP 0x0b +#define L2CAP_CREATE_CHAN_REQ 0x0c +#define L2CAP_CREATE_CHAN_RSP 0x0d +#define L2CAP_MOVE_CHAN_REQ 0x0e +#define L2CAP_MOVE_CHAN_RSP 0x0f +#define L2CAP_MOVE_CHAN_CFM 0x10 +#define L2CAP_MOVE_CHAN_CFM_RSP 0x11 +#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12 +#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13 + +/* L2CAP extended feature mask */ +#define L2CAP_FEAT_FLOWCTL 0x00000001 +#define L2CAP_FEAT_RETRANS 0x00000002 +#define L2CAP_FEAT_BIDIR_QOS 0x00000004 +#define L2CAP_FEAT_ERTM 0x00000008 +#define L2CAP_FEAT_STREAMING 0x00000010 +#define L2CAP_FEAT_FCS 0x00000020 +#define L2CAP_FEAT_EXT_FLOW 0x00000040 +#define L2CAP_FEAT_FIXED_CHAN 0x00000080 +#define L2CAP_FEAT_EXT_WINDOW 0x00000100 +#define L2CAP_FEAT_UCD 0x00000200 + +/* L2CAP checksum option */ +#define L2CAP_FCS_NONE 0x00 +#define L2CAP_FCS_CRC16 0x01 + +/* L2CAP fixed channels */ +#define L2CAP_FC_L2CAP 0x02 +#define L2CAP_FC_A2MP 0x08 + +/* L2CAP Control Field bit masks */ +#define L2CAP_CTRL_SAR 0xC000 +#define L2CAP_CTRL_REQSEQ 0x3F00 +#define L2CAP_CTRL_TXSEQ 0x007E +#define L2CAP_CTRL_SUPERVISE 0x000C + +#define L2CAP_CTRL_RETRANS 0x0080 +#define L2CAP_CTRL_FINAL 0x0080 +#define L2CAP_CTRL_POLL 0x0010 +#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */ + +#define L2CAP_CTRL_TXSEQ_SHIFT 1 +#define L2CAP_CTRL_SUPER_SHIFT 2 +#define L2CAP_CTRL_REQSEQ_SHIFT 8 +#define L2CAP_CTRL_SAR_SHIFT 14 + +/* L2CAP Extended Control Field bit mask */ +#define L2CAP_EXT_CTRL_TXSEQ 0xFFFC0000 +#define L2CAP_EXT_CTRL_SAR 0x00030000 +#define L2CAP_EXT_CTRL_SUPERVISE 0x00030000 +#define L2CAP_EXT_CTRL_REQSEQ 0x0000FFFC + +#define L2CAP_EXT_CTRL_POLL 0x00040000 +#define L2CAP_EXT_CTRL_FINAL 0x00000002 +#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */ + +#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2 +#define L2CAP_EXT_CTRL_SAR_SHIFT 16 +#define L2CAP_EXT_CTRL_SUPER_SHIFT 16 +#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18 + +/* L2CAP Supervisory Function */ +#define L2CAP_SUPER_RR 0x00 +#define L2CAP_SUPER_REJ 0x01 +#define L2CAP_SUPER_RNR 0x02 +#define L2CAP_SUPER_SREJ 0x03 + +/* L2CAP Segmentation and Reassembly */ +#define L2CAP_SAR_UNSEGMENTED 0x00 +#define L2CAP_SAR_START 0x01 +#define L2CAP_SAR_END 0x02 +#define L2CAP_SAR_CONTINUE 0x03 + +/* L2CAP Command rej. reasons */ +#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000 +#define L2CAP_REJ_MTU_EXCEEDED 0x0001 +#define L2CAP_REJ_INVALID_CID 0x0002 + +/* L2CAP structures */ +struct l2cap_hdr { + __le16 len; + __le16 cid; +} __packed; +#define L2CAP_HDR_SIZE 4 +#define L2CAP_ENH_HDR_SIZE 6 +#define L2CAP_EXT_HDR_SIZE 8 + +#define L2CAP_FCS_SIZE 2 +#define L2CAP_SDULEN_SIZE 2 +#define L2CAP_PSMLEN_SIZE 2 + +struct l2cap_cmd_hdr { + __u8 code; + __u8 ident; + __le16 len; +} __packed; +#define L2CAP_CMD_HDR_SIZE 4 + +struct l2cap_cmd_rej_unk { + __le16 reason; +} __packed; + +struct l2cap_cmd_rej_mtu { + __le16 reason; + __le16 max_mtu; +} __packed; + +struct l2cap_cmd_rej_cid { + __le16 reason; + __le16 scid; + __le16 dcid; +} __packed; + +struct l2cap_conn_req { + __le16 psm; + __le16 scid; +} __packed; + +struct l2cap_conn_rsp { + __le16 dcid; + __le16 scid; + __le16 result; + __le16 status; +} __packed; + +/* channel indentifier */ +#define L2CAP_CID_SIGNALING 0x0001 +#define L2CAP_CID_CONN_LESS 0x0002 +#define L2CAP_CID_LE_DATA 0x0004 +#define L2CAP_CID_LE_SIGNALING 0x0005 +#define L2CAP_CID_SMP 0x0006 +#define L2CAP_CID_DYN_START 0x0040 +#define L2CAP_CID_DYN_END 0xffff + +/* connect/create channel results */ +#define L2CAP_CR_SUCCESS 0x0000 +#define L2CAP_CR_PEND 0x0001 +#define L2CAP_CR_BAD_PSM 0x0002 +#define L2CAP_CR_SEC_BLOCK 0x0003 +#define L2CAP_CR_NO_MEM 0x0004 +#define L2CAP_CR_BAD_AMP 0x0005 + +/* connect/create channel status */ +#define L2CAP_CS_NO_INFO 0x0000 +#define L2CAP_CS_AUTHEN_PEND 0x0001 +#define L2CAP_CS_AUTHOR_PEND 0x0002 + +struct l2cap_conf_req { + __le16 dcid; + __le16 flags; + __u8 data[0]; +} __packed; + +struct l2cap_conf_rsp { + __le16 scid; + __le16 flags; + __le16 result; + __u8 data[0]; +} __packed; + +#define L2CAP_CONF_SUCCESS 0x0000 +#define L2CAP_CONF_UNACCEPT 0x0001 +#define L2CAP_CONF_REJECT 0x0002 +#define L2CAP_CONF_UNKNOWN 0x0003 +#define L2CAP_CONF_PENDING 0x0004 +#define L2CAP_CONF_EFS_REJECT 0x0005 + +struct l2cap_conf_opt { + __u8 type; + __u8 len; + __u8 val[0]; +} __packed; +#define L2CAP_CONF_OPT_SIZE 2 + +#define L2CAP_CONF_HINT 0x80 +#define L2CAP_CONF_MASK 0x7f + +#define L2CAP_CONF_MTU 0x01 +#define L2CAP_CONF_FLUSH_TO 0x02 +#define L2CAP_CONF_QOS 0x03 +#define L2CAP_CONF_RFC 0x04 +#define L2CAP_CONF_FCS 0x05 +#define L2CAP_CONF_EFS 0x06 +#define L2CAP_CONF_EWS 0x07 + +#define L2CAP_CONF_MAX_SIZE 22 + +struct l2cap_conf_rfc { + __u8 mode; + __u8 txwin_size; + __u8 max_transmit; + __le16 retrans_timeout; + __le16 monitor_timeout; + __le16 max_pdu_size; +} __packed; + +#define L2CAP_MODE_BASIC 0x00 +#define L2CAP_MODE_RETRANS 0x01 +#define L2CAP_MODE_FLOWCTL 0x02 +#define L2CAP_MODE_ERTM 0x03 +#define L2CAP_MODE_STREAMING 0x04 + +struct l2cap_conf_efs { + __u8 id; + __u8 stype; + __le16 msdu; + __le32 sdu_itime; + __le32 acc_lat; + __le32 flush_to; +} __packed; + +#define L2CAP_SERV_NOTRAFIC 0x00 +#define L2CAP_SERV_BESTEFFORT 0x01 +#define L2CAP_SERV_GUARANTEED 0x02 + +#define L2CAP_BESTEFFORT_ID 0x01 + +struct l2cap_disconn_req { + __le16 dcid; + __le16 scid; +} __packed; + +struct l2cap_disconn_rsp { + __le16 dcid; + __le16 scid; +} __packed; + +struct l2cap_info_req { + __le16 type; +} __packed; + +struct l2cap_info_rsp { + __le16 type; + __le16 result; + __u8 data[0]; +} __packed; + +struct l2cap_create_chan_req { + __le16 psm; + __le16 scid; + __u8 amp_id; +} __packed; + +struct l2cap_create_chan_rsp { + __le16 dcid; + __le16 scid; + __le16 result; + __le16 status; +} __packed; + +struct l2cap_move_chan_req { + __le16 icid; + __u8 dest_amp_id; +} __packed; + +struct l2cap_move_chan_rsp { + __le16 icid; + __le16 result; +} __packed; + +#define L2CAP_MR_SUCCESS 0x0000 +#define L2CAP_MR_PEND 0x0001 +#define L2CAP_MR_BAD_ID 0x0002 +#define L2CAP_MR_SAME_ID 0x0003 +#define L2CAP_MR_NOT_SUPP 0x0004 +#define L2CAP_MR_COLLISION 0x0005 +#define L2CAP_MR_NOT_ALLOWED 0x0006 + +struct l2cap_move_chan_cfm { + __le16 icid; + __le16 result; +} __packed; + +#define L2CAP_MC_CONFIRMED 0x0000 +#define L2CAP_MC_UNCONFIRMED 0x0001 + +struct l2cap_move_chan_cfm_rsp { + __le16 icid; +} __packed; + +/* info type */ +#define L2CAP_IT_CL_MTU 0x0001 +#define L2CAP_IT_FEAT_MASK 0x0002 +#define L2CAP_IT_FIXED_CHAN 0x0003 + +/* info result */ +#define L2CAP_IR_SUCCESS 0x0000 +#define L2CAP_IR_NOTSUPP 0x0001 + +struct l2cap_conn_param_update_req { + __le16 min; + __le16 max; + __le16 latency; + __le16 to_multiplier; +} __packed; + +struct l2cap_conn_param_update_rsp { + __le16 result; +} __packed; + +/* Connection Parameters result */ +#define L2CAP_CONN_PARAM_ACCEPTED 0x0000 +#define L2CAP_CONN_PARAM_REJECTED 0x0001 + +/* ----- L2CAP channels and connections ----- */ +struct srej_list { + __u16 tx_seq; + struct list_head list; +}; + +struct l2cap_chan { + struct sock *sk; + + struct l2cap_conn *conn; + + __u8 state; + + atomic_t refcnt; + + __le16 psm; + __u16 dcid; + __u16 scid; + + __u16 imtu; + __u16 omtu; + __u16 flush_to; + __u8 mode; + __u8 chan_type; + __u8 chan_policy; + + __le16 sport; + + __u8 sec_level; + + __u8 ident; + + __u8 conf_req[64]; + __u8 conf_len; + __u8 num_conf_req; + __u8 num_conf_rsp; + + __u8 fcs; + + __u16 tx_win; + __u16 tx_win_max; + __u8 max_tx; + __u16 retrans_timeout; + __u16 monitor_timeout; + __u16 mps; + + unsigned long conf_state; + unsigned long conn_state; + unsigned long flags; + + __u16 next_tx_seq; + __u16 expected_ack_seq; + __u16 expected_tx_seq; + __u16 buffer_seq; + __u16 buffer_seq_srej; + __u16 srej_save_reqseq; + __u16 frames_sent; + __u16 unacked_frames; + __u8 retry_count; + __u8 num_acked; + __u16 sdu_len; + struct sk_buff *sdu; + struct sk_buff *sdu_last_frag; + + __u16 remote_tx_win; + __u8 remote_max_tx; + __u16 remote_mps; + + __u8 local_id; + __u8 local_stype; + __u16 local_msdu; + __u32 local_sdu_itime; + __u32 local_acc_lat; + __u32 local_flush_to; + + __u8 remote_id; + __u8 remote_stype; + __u16 remote_msdu; + __u32 remote_sdu_itime; + __u32 remote_acc_lat; + __u32 remote_flush_to; + + struct timer_list chan_timer; + struct timer_list retrans_timer; + struct timer_list monitor_timer; + struct timer_list ack_timer; + struct sk_buff *tx_send_head; + struct sk_buff_head tx_q; + struct sk_buff_head srej_q; + struct list_head srej_l; + + struct list_head list; + struct list_head global_l; + + void *data; + struct l2cap_ops *ops; +}; + +struct l2cap_ops { + char *name; + + struct l2cap_chan *(*new_connection) (void *data); + int (*recv) (void *data, struct sk_buff *skb); + void (*close) (void *data); + void (*state_change) (void *data, int state); +}; + +struct l2cap_conn { + struct hci_conn *hcon; + struct hci_chan *hchan; + + bdaddr_t *dst; + bdaddr_t *src; + + unsigned int mtu; + + __u32 feat_mask; + + __u8 info_state; + __u8 info_ident; + + struct timer_list info_timer; + + spinlock_t lock; + + struct sk_buff *rx_skb; + __u32 rx_len; + __u8 tx_ident; + + __u8 disc_reason; + + struct timer_list security_timer; + struct smp_chan *smp_chan; + + struct list_head chan_l; + rwlock_t chan_lock; +}; + +#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 +#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 +#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 + +#define L2CAP_CHAN_RAW 1 +#define L2CAP_CHAN_CONN_LESS 2 +#define L2CAP_CHAN_CONN_ORIENTED 3 + +/* ----- L2CAP socket info ----- */ +#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) + +struct l2cap_pinfo { + struct bt_sock bt; + struct l2cap_chan *chan; + struct sk_buff *rx_busy_skb; +}; + +enum { + CONF_REQ_SENT, + CONF_INPUT_DONE, + CONF_OUTPUT_DONE, + CONF_MTU_DONE, + CONF_MODE_DONE, + CONF_CONNECT_PEND, + CONF_NO_FCS_RECV, + CONF_STATE2_DEVICE, + CONF_EWS_RECV, + CONF_LOC_CONF_PEND, + CONF_REM_CONF_PEND, +}; + +#define L2CAP_CONF_MAX_CONF_REQ 2 +#define L2CAP_CONF_MAX_CONF_RSP 2 + +enum { + CONN_SREJ_SENT, + CONN_WAIT_F, + CONN_SREJ_ACT, + CONN_SEND_PBIT, + CONN_REMOTE_BUSY, + CONN_LOCAL_BUSY, + CONN_REJ_ACT, + CONN_SEND_FBIT, + CONN_RNR_SENT, +}; + +/* Definitions for flags in l2cap_chan */ +enum { + FLAG_ROLE_SWITCH, + FLAG_FORCE_ACTIVE, + FLAG_FORCE_RELIABLE, + FLAG_FLUSHABLE, + FLAG_EXT_CTRL, + FLAG_EFS_ENABLE, +}; + +#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) +#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) +#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ + L2CAP_DEFAULT_RETRANS_TO); +#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) +#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ + L2CAP_DEFAULT_MONITOR_TO); +#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) +#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ + L2CAP_DEFAULT_ACK_TO); +#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) + +static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) +{ + int offset; + + offset = (seq1 - seq2) % (chan->tx_win_max + 1); + if (offset < 0) + offset += (chan->tx_win_max + 1); + + return offset; +} + +static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq) +{ + return (seq + 1) % (chan->tx_win_max + 1); +} + +static inline int l2cap_tx_window_full(struct l2cap_chan *ch) +{ + int sub; + + sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64; + + if (sub < 0) + sub += 64; + + return sub == ch->remote_tx_win; +} + +static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >> + L2CAP_EXT_CTRL_REQSEQ_SHIFT; + else + return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; +} + +static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) & + L2CAP_EXT_CTRL_REQSEQ; + else + return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ; +} + +static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >> + L2CAP_EXT_CTRL_TXSEQ_SHIFT; + else + return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT; +} + +static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) & + L2CAP_EXT_CTRL_TXSEQ; + else + return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ; +} + +static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE; + else + return ctrl & L2CAP_CTRL_FRAME_TYPE; +} + +static inline __u32 __set_sframe(struct l2cap_chan *chan) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return L2CAP_EXT_CTRL_FRAME_TYPE; + else + return L2CAP_CTRL_FRAME_TYPE; +} + +static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT; + else + return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT; +} + +static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR; + else + return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR; +} + +static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl) +{ + return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START; +} + +static inline __u32 __get_sar_mask(struct l2cap_chan *chan) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return L2CAP_EXT_CTRL_SAR; + else + return L2CAP_CTRL_SAR; +} + +static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >> + L2CAP_EXT_CTRL_SUPER_SHIFT; + else + return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT; +} + +static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) & + L2CAP_EXT_CTRL_SUPERVISE; + else + return (super << L2CAP_CTRL_SUPER_SHIFT) & + L2CAP_CTRL_SUPERVISE; +} + +static inline __u32 __set_ctrl_final(struct l2cap_chan *chan) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return L2CAP_EXT_CTRL_FINAL; + else + return L2CAP_CTRL_FINAL; +} + +static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return ctrl & L2CAP_EXT_CTRL_FINAL; + else + return ctrl & L2CAP_CTRL_FINAL; +} + +static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return L2CAP_EXT_CTRL_POLL; + else + return L2CAP_CTRL_POLL; +} + +static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return ctrl & L2CAP_EXT_CTRL_POLL; + else + return ctrl & L2CAP_CTRL_POLL; +} + +static inline __u32 __get_control(struct l2cap_chan *chan, void *p) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return get_unaligned_le32(p); + else + return get_unaligned_le16(p); +} + +static inline void __put_control(struct l2cap_chan *chan, __u32 control, + void *p) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return put_unaligned_le32(control, p); + else + return put_unaligned_le16(control, p); +} + +static inline __u8 __ctrl_size(struct l2cap_chan *chan) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE; + else + return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE; +} + +extern int disable_ertm; +extern int enable_hs; + +int l2cap_init_sockets(void); +void l2cap_cleanup_sockets(void); + +void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); +int __l2cap_wait_ack(struct sock *sk); + +int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); +int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); + +struct l2cap_chan *l2cap_chan_create(struct sock *sk); +void l2cap_chan_close(struct l2cap_chan *chan, int reason); +void l2cap_chan_destroy(struct l2cap_chan *chan); +int l2cap_chan_connect(struct l2cap_chan *chan); +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, + u32 priority); +void l2cap_chan_busy(struct l2cap_chan *chan, int busy); + +#endif /* __L2CAP_H */ diff --git a/include/compat/net/bluetooth/mgmt.h b/include/compat/net/bluetooth/mgmt.h new file mode 100644 index 00000000..3e320c9c --- /dev/null +++ b/include/compat/net/bluetooth/mgmt.h @@ -0,0 +1,324 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + + Copyright (C) 2010 Nokia 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#define MGMT_INDEX_NONE 0xFFFF + +struct mgmt_hdr { + __le16 opcode; + __le16 index; + __le16 len; +} __packed; + +#define MGMT_OP_READ_VERSION 0x0001 +struct mgmt_rp_read_version { + __u8 version; + __le16 revision; +} __packed; + +#define MGMT_OP_READ_INDEX_LIST 0x0003 +struct mgmt_rp_read_index_list { + __le16 num_controllers; + __le16 index[0]; +} __packed; + +/* Reserve one extra byte for names in management messages so that they + * are always guaranteed to be nul-terminated */ +#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) + +#define MGMT_OP_READ_INFO 0x0004 +struct mgmt_rp_read_info { + __u8 type; + __u8 powered; + __u8 connectable; + __u8 discoverable; + __u8 pairable; + __u8 sec_mode; + bdaddr_t bdaddr; + __u8 dev_class[3]; + __u8 features[8]; + __u16 manufacturer; + __u8 hci_ver; + __u16 hci_rev; + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; + +struct mgmt_mode { + __u8 val; +} __packed; + +#define MGMT_OP_SET_POWERED 0x0005 + +#define MGMT_OP_SET_DISCOVERABLE 0x0006 +struct mgmt_cp_set_discoverable { + __u8 val; + __u16 timeout; +} __packed; + +#define MGMT_OP_SET_CONNECTABLE 0x0007 + +#define MGMT_OP_SET_PAIRABLE 0x0008 + +#define MGMT_OP_ADD_UUID 0x0009 +struct mgmt_cp_add_uuid { + __u8 uuid[16]; + __u8 svc_hint; +} __packed; + +#define MGMT_OP_REMOVE_UUID 0x000A +struct mgmt_cp_remove_uuid { + __u8 uuid[16]; +} __packed; + +#define MGMT_OP_SET_DEV_CLASS 0x000B +struct mgmt_cp_set_dev_class { + __u8 major; + __u8 minor; +} __packed; + +#define MGMT_OP_SET_SERVICE_CACHE 0x000C +struct mgmt_cp_set_service_cache { + __u8 enable; +} __packed; + +struct mgmt_link_key_info { + bdaddr_t bdaddr; + u8 type; + u8 val[16]; + u8 pin_len; +} __packed; + +#define MGMT_OP_LOAD_LINK_KEYS 0x000D +struct mgmt_cp_load_link_keys { + __u8 debug_keys; + __le16 key_count; + struct mgmt_link_key_info keys[0]; +} __packed; + +#define MGMT_OP_REMOVE_KEYS 0x000E +struct mgmt_cp_remove_keys { + bdaddr_t bdaddr; + __u8 disconnect; +} __packed; + +#define MGMT_OP_DISCONNECT 0x000F +struct mgmt_cp_disconnect { + bdaddr_t bdaddr; +} __packed; +struct mgmt_rp_disconnect { + bdaddr_t bdaddr; +} __packed; + +#define MGMT_ADDR_BREDR 0x00 +#define MGMT_ADDR_LE 0x01 +#define MGMT_ADDR_BREDR_LE 0x02 +#define MGMT_ADDR_INVALID 0xff + +struct mgmt_addr_info { + bdaddr_t bdaddr; + __u8 type; +} __packed; + +#define MGMT_OP_GET_CONNECTIONS 0x0010 +struct mgmt_rp_get_connections { + __le16 conn_count; + struct mgmt_addr_info addr[0]; +} __packed; + +#define MGMT_OP_PIN_CODE_REPLY 0x0011 +struct mgmt_cp_pin_code_reply { + bdaddr_t bdaddr; + __u8 pin_len; + __u8 pin_code[16]; +} __packed; +struct mgmt_rp_pin_code_reply { + bdaddr_t bdaddr; + uint8_t status; +} __packed; + +#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0012 +struct mgmt_cp_pin_code_neg_reply { + bdaddr_t bdaddr; +} __packed; + +#define MGMT_OP_SET_IO_CAPABILITY 0x0013 +struct mgmt_cp_set_io_capability { + __u8 io_capability; +} __packed; + +#define MGMT_OP_PAIR_DEVICE 0x0014 +struct mgmt_cp_pair_device { + bdaddr_t bdaddr; + __u8 io_cap; +} __packed; +struct mgmt_rp_pair_device { + bdaddr_t bdaddr; + __u8 status; +} __packed; + +#define MGMT_OP_USER_CONFIRM_REPLY 0x0015 +struct mgmt_cp_user_confirm_reply { + bdaddr_t bdaddr; +} __packed; +struct mgmt_rp_user_confirm_reply { + bdaddr_t bdaddr; + __u8 status; +} __packed; + +#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016 + +#define MGMT_OP_SET_LOCAL_NAME 0x0017 +struct mgmt_cp_set_local_name { + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; + +#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0018 +struct mgmt_rp_read_local_oob_data { + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0019 +struct mgmt_cp_add_remote_oob_data { + bdaddr_t bdaddr; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x001A +struct mgmt_cp_remove_remote_oob_data { + bdaddr_t bdaddr; +} __packed; + +#define MGMT_OP_START_DISCOVERY 0x001B + +#define MGMT_OP_STOP_DISCOVERY 0x001C + +#define MGMT_OP_BLOCK_DEVICE 0x001D +struct mgmt_cp_block_device { + bdaddr_t bdaddr; +} __packed; + +#define MGMT_OP_UNBLOCK_DEVICE 0x001E +struct mgmt_cp_unblock_device { + bdaddr_t bdaddr; +} __packed; + +#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F +struct mgmt_cp_set_fast_connectable { + __u8 enable; +} __packed; + +#define MGMT_EV_CMD_COMPLETE 0x0001 +struct mgmt_ev_cmd_complete { + __le16 opcode; + __u8 data[0]; +} __packed; + +#define MGMT_EV_CMD_STATUS 0x0002 +struct mgmt_ev_cmd_status { + __u8 status; + __le16 opcode; +} __packed; + +#define MGMT_EV_CONTROLLER_ERROR 0x0003 +struct mgmt_ev_controller_error { + __u8 error_code; +} __packed; + +#define MGMT_EV_INDEX_ADDED 0x0004 + +#define MGMT_EV_INDEX_REMOVED 0x0005 + +#define MGMT_EV_POWERED 0x0006 + +#define MGMT_EV_DISCOVERABLE 0x0007 + +#define MGMT_EV_CONNECTABLE 0x0008 + +#define MGMT_EV_PAIRABLE 0x0009 + +#define MGMT_EV_NEW_LINK_KEY 0x000A +struct mgmt_ev_new_link_key { + __u8 store_hint; + struct mgmt_link_key_info key; +} __packed; + +#define MGMT_EV_CONNECTED 0x000B + +#define MGMT_EV_DISCONNECTED 0x000C + +#define MGMT_EV_CONNECT_FAILED 0x000D +struct mgmt_ev_connect_failed { + struct mgmt_addr_info addr; + __u8 status; +} __packed; + +#define MGMT_EV_PIN_CODE_REQUEST 0x000E +struct mgmt_ev_pin_code_request { + bdaddr_t bdaddr; + __u8 secure; +} __packed; + +#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F +struct mgmt_ev_user_confirm_request { + bdaddr_t bdaddr; + __u8 confirm_hint; + __le32 value; +} __packed; + +#define MGMT_EV_AUTH_FAILED 0x0010 +struct mgmt_ev_auth_failed { + bdaddr_t bdaddr; + __u8 status; +} __packed; + +#define MGMT_EV_LOCAL_NAME_CHANGED 0x0011 +struct mgmt_ev_local_name_changed { + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; + +#define MGMT_EV_DEVICE_FOUND 0x0012 +struct mgmt_ev_device_found { + struct mgmt_addr_info addr; + __u8 dev_class[3]; + __s8 rssi; + __u8 eir[HCI_MAX_EIR_LENGTH]; +} __packed; + +#define MGMT_EV_REMOTE_NAME 0x0013 +struct mgmt_ev_remote_name { + bdaddr_t bdaddr; + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; + +#define MGMT_EV_DISCOVERING 0x0014 + +#define MGMT_EV_DEVICE_BLOCKED 0x0015 +struct mgmt_ev_device_blocked { + bdaddr_t bdaddr; +} __packed; + +#define MGMT_EV_DEVICE_UNBLOCKED 0x0016 +struct mgmt_ev_device_unblocked { + bdaddr_t bdaddr; +} __packed; diff --git a/include/compat/net/bluetooth/rfcomm.h b/include/compat/net/bluetooth/rfcomm.h new file mode 100644 index 00000000..e2e3ecad --- /dev/null +++ b/include/compat/net/bluetooth/rfcomm.h @@ -0,0 +1,372 @@ +/* + RFCOMM implementation for Linux Bluetooth stack (BlueZ) + Copyright (C) 2002 Maxim Krasnyansky + Copyright (C) 2002 Marcel Holtmann + + 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __RFCOMM_H +#define __RFCOMM_H + +#define RFCOMM_PSM 3 + +#define RFCOMM_CONN_TIMEOUT (HZ * 30) +#define RFCOMM_DISC_TIMEOUT (HZ * 20) +#define RFCOMM_AUTH_TIMEOUT (HZ * 25) +#define RFCOMM_IDLE_TIMEOUT (HZ * 2) + +#define RFCOMM_DEFAULT_MTU 127 +#define RFCOMM_DEFAULT_CREDITS 7 + +#define RFCOMM_MAX_L2CAP_MTU 1013 +#define RFCOMM_MAX_CREDITS 40 + +#define RFCOMM_SKB_HEAD_RESERVE 8 +#define RFCOMM_SKB_TAIL_RESERVE 2 +#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE) + +#define RFCOMM_SABM 0x2f +#define RFCOMM_DISC 0x43 +#define RFCOMM_UA 0x63 +#define RFCOMM_DM 0x0f +#define RFCOMM_UIH 0xef + +#define RFCOMM_TEST 0x08 +#define RFCOMM_FCON 0x28 +#define RFCOMM_FCOFF 0x18 +#define RFCOMM_MSC 0x38 +#define RFCOMM_RPN 0x24 +#define RFCOMM_RLS 0x14 +#define RFCOMM_PN 0x20 +#define RFCOMM_NSC 0x04 + +#define RFCOMM_V24_FC 0x02 +#define RFCOMM_V24_RTC 0x04 +#define RFCOMM_V24_RTR 0x08 +#define RFCOMM_V24_IC 0x40 +#define RFCOMM_V24_DV 0x80 + +#define RFCOMM_RPN_BR_2400 0x0 +#define RFCOMM_RPN_BR_4800 0x1 +#define RFCOMM_RPN_BR_7200 0x2 +#define RFCOMM_RPN_BR_9600 0x3 +#define RFCOMM_RPN_BR_19200 0x4 +#define RFCOMM_RPN_BR_38400 0x5 +#define RFCOMM_RPN_BR_57600 0x6 +#define RFCOMM_RPN_BR_115200 0x7 +#define RFCOMM_RPN_BR_230400 0x8 + +#define RFCOMM_RPN_DATA_5 0x0 +#define RFCOMM_RPN_DATA_6 0x1 +#define RFCOMM_RPN_DATA_7 0x2 +#define RFCOMM_RPN_DATA_8 0x3 + +#define RFCOMM_RPN_STOP_1 0 +#define RFCOMM_RPN_STOP_15 1 + +#define RFCOMM_RPN_PARITY_NONE 0x0 +#define RFCOMM_RPN_PARITY_ODD 0x1 +#define RFCOMM_RPN_PARITY_EVEN 0x3 +#define RFCOMM_RPN_PARITY_MARK 0x5 +#define RFCOMM_RPN_PARITY_SPACE 0x7 + +#define RFCOMM_RPN_FLOW_NONE 0x00 + +#define RFCOMM_RPN_XON_CHAR 0x11 +#define RFCOMM_RPN_XOFF_CHAR 0x13 + +#define RFCOMM_RPN_PM_BITRATE 0x0001 +#define RFCOMM_RPN_PM_DATA 0x0002 +#define RFCOMM_RPN_PM_STOP 0x0004 +#define RFCOMM_RPN_PM_PARITY 0x0008 +#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010 +#define RFCOMM_RPN_PM_XON 0x0020 +#define RFCOMM_RPN_PM_XOFF 0x0040 +#define RFCOMM_RPN_PM_FLOW 0x3F00 + +#define RFCOMM_RPN_PM_ALL 0x3F7F + +struct rfcomm_hdr { + u8 addr; + u8 ctrl; + u8 len; /* Actual size can be 2 bytes */ +} __packed; + +struct rfcomm_cmd { + u8 addr; + u8 ctrl; + u8 len; + u8 fcs; +} __packed; + +struct rfcomm_mcc { + u8 type; + u8 len; +} __packed; + +struct rfcomm_pn { + u8 dlci; + u8 flow_ctrl; + u8 priority; + u8 ack_timer; + __le16 mtu; + u8 max_retrans; + u8 credits; +} __packed; + +struct rfcomm_rpn { + u8 dlci; + u8 bit_rate; + u8 line_settings; + u8 flow_ctrl; + u8 xon_char; + u8 xoff_char; + __le16 param_mask; +} __packed; + +struct rfcomm_rls { + u8 dlci; + u8 status; +} __packed; + +struct rfcomm_msc { + u8 dlci; + u8 v24_sig; +} __packed; + +/* ---- Core structures, flags etc ---- */ + +struct rfcomm_session { + struct list_head list; + struct socket *sock; + struct timer_list timer; + unsigned long state; + unsigned long flags; + atomic_t refcnt; + int initiator; + + /* Default DLC parameters */ + int cfc; + uint mtu; + + struct list_head dlcs; +}; + +struct rfcomm_dlc { + struct list_head list; + struct rfcomm_session *session; + struct sk_buff_head tx_queue; + struct timer_list timer; + + spinlock_t lock; + unsigned long state; + unsigned long flags; + atomic_t refcnt; + u8 dlci; + u8 addr; + u8 priority; + u8 v24_sig; + u8 remote_v24_sig; + u8 mscex; + u8 out; + u8 sec_level; + u8 role_switch; + u32 defer_setup; + + uint mtu; + uint cfc; + uint rx_credits; + uint tx_credits; + + void *owner; + + void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb); + void (*state_change)(struct rfcomm_dlc *d, int err); + void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig); +}; + +/* DLC and session flags */ +#define RFCOMM_RX_THROTTLED 0 +#define RFCOMM_TX_THROTTLED 1 +#define RFCOMM_TIMED_OUT 2 +#define RFCOMM_MSC_PENDING 3 +#define RFCOMM_SEC_PENDING 4 +#define RFCOMM_AUTH_PENDING 5 +#define RFCOMM_AUTH_ACCEPT 6 +#define RFCOMM_AUTH_REJECT 7 +#define RFCOMM_DEFER_SETUP 8 +#define RFCOMM_ENC_DROP 9 + +/* Scheduling flags and events */ +#define RFCOMM_SCHED_WAKEUP 31 + +/* MSC exchange flags */ +#define RFCOMM_MSCEX_TX 1 +#define RFCOMM_MSCEX_RX 2 +#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) + +/* CFC states */ +#define RFCOMM_CFC_UNKNOWN -1 +#define RFCOMM_CFC_DISABLED 0 +#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS + +/* ---- RFCOMM SEND RPN ---- */ +int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, + u8 bit_rate, u8 data_bits, u8 stop_bits, + u8 parity, u8 flow_ctrl_settings, + u8 xon_char, u8 xoff_char, u16 param_mask); + +/* ---- RFCOMM DLCs (channels) ---- */ +struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio); +void rfcomm_dlc_free(struct rfcomm_dlc *d); +int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, + u8 channel); +int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason); +int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); +int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); +int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); +void rfcomm_dlc_accept(struct rfcomm_dlc *d); + +#define rfcomm_dlc_lock(d) spin_lock(&d->lock) +#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) + +static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) +{ + atomic_inc(&d->refcnt); +} + +static inline void rfcomm_dlc_put(struct rfcomm_dlc *d) +{ + if (atomic_dec_and_test(&d->refcnt)) + rfcomm_dlc_free(d); +} + +extern void __rfcomm_dlc_throttle(struct rfcomm_dlc *d); +extern void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d); + +static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d) +{ + if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags)) + __rfcomm_dlc_throttle(d); +} + +static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +{ + if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags)) + __rfcomm_dlc_unthrottle(d); +} + +/* ---- RFCOMM sessions ---- */ +void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, + bdaddr_t *dst); + +static inline void rfcomm_session_hold(struct rfcomm_session *s) +{ + atomic_inc(&s->refcnt); +} + +/* ---- RFCOMM sockets ---- */ +struct sockaddr_rc { + sa_family_t rc_family; + bdaddr_t rc_bdaddr; + u8 rc_channel; +}; + +#define RFCOMM_CONNINFO 0x02 +struct rfcomm_conninfo { + __u16 hci_handle; + __u8 dev_class[3]; +}; + +#define RFCOMM_LM 0x03 +#define RFCOMM_LM_MASTER 0x0001 +#define RFCOMM_LM_AUTH 0x0002 +#define RFCOMM_LM_ENCRYPT 0x0004 +#define RFCOMM_LM_TRUSTED 0x0008 +#define RFCOMM_LM_RELIABLE 0x0010 +#define RFCOMM_LM_SECURE 0x0020 + +#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk) + +struct rfcomm_pinfo { + struct bt_sock bt; + struct rfcomm_dlc *dlc; + u8 channel; + u8 sec_level; + u8 role_switch; +}; + +int rfcomm_init_sockets(void); +void rfcomm_cleanup_sockets(void); + +int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, + struct rfcomm_dlc **d); + +/* ---- RFCOMM TTY ---- */ +#define RFCOMM_MAX_DEV 256 + +#define RFCOMMCREATEDEV _IOW('R', 200, int) +#define RFCOMMRELEASEDEV _IOW('R', 201, int) +#define RFCOMMGETDEVLIST _IOR('R', 210, int) +#define RFCOMMGETDEVINFO _IOR('R', 211, int) +#define RFCOMMSTEALDLC _IOW('R', 220, int) + +#define RFCOMM_REUSE_DLC 0 +#define RFCOMM_RELEASE_ONHUP 1 +#define RFCOMM_HANGUP_NOW 2 +#define RFCOMM_TTY_ATTACHED 3 +#define RFCOMM_TTY_RELEASED 4 + +struct rfcomm_dev_req { + s16 dev_id; + u32 flags; + bdaddr_t src; + bdaddr_t dst; + u8 channel; +}; + +struct rfcomm_dev_info { + s16 id; + u32 flags; + u16 state; + bdaddr_t src; + bdaddr_t dst; + u8 channel; +}; + +struct rfcomm_dev_list_req { + u16 dev_num; + struct rfcomm_dev_info dev_info[0]; +}; + +int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); + +#ifdef CONFIG_BT_RFCOMM_TTY +int rfcomm_init_ttys(void); +void rfcomm_cleanup_ttys(void); +#else +static inline int rfcomm_init_ttys(void) +{ + return 0; +} +static inline void rfcomm_cleanup_ttys(void) +{ +} +#endif +#endif /* __RFCOMM_H */ diff --git a/include/compat/net/bluetooth/smp.h b/include/compat/net/bluetooth/smp.h new file mode 100644 index 00000000..15b97d54 --- /dev/null +++ b/include/compat/net/bluetooth/smp.h @@ -0,0 +1,140 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + + 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __SMP_H +#define __SMP_H + +struct smp_command_hdr { + __u8 code; +} __packed; + +#define SMP_CMD_PAIRING_REQ 0x01 +#define SMP_CMD_PAIRING_RSP 0x02 +struct smp_cmd_pairing { + __u8 io_capability; + __u8 oob_flag; + __u8 auth_req; + __u8 max_key_size; + __u8 init_key_dist; + __u8 resp_key_dist; +} __packed; + +#define SMP_IO_DISPLAY_ONLY 0x00 +#define SMP_IO_DISPLAY_YESNO 0x01 +#define SMP_IO_KEYBOARD_ONLY 0x02 +#define SMP_IO_NO_INPUT_OUTPUT 0x03 +#define SMP_IO_KEYBOARD_DISPLAY 0x04 + +#define SMP_OOB_NOT_PRESENT 0x00 +#define SMP_OOB_PRESENT 0x01 + +#define SMP_DIST_ENC_KEY 0x01 +#define SMP_DIST_ID_KEY 0x02 +#define SMP_DIST_SIGN 0x04 + +#define SMP_AUTH_NONE 0x00 +#define SMP_AUTH_BONDING 0x01 +#define SMP_AUTH_MITM 0x04 + +#define SMP_CMD_PAIRING_CONFIRM 0x03 +struct smp_cmd_pairing_confirm { + __u8 confirm_val[16]; +} __packed; + +#define SMP_CMD_PAIRING_RANDOM 0x04 +struct smp_cmd_pairing_random { + __u8 rand_val[16]; +} __packed; + +#define SMP_CMD_PAIRING_FAIL 0x05 +struct smp_cmd_pairing_fail { + __u8 reason; +} __packed; + +#define SMP_CMD_ENCRYPT_INFO 0x06 +struct smp_cmd_encrypt_info { + __u8 ltk[16]; +} __packed; + +#define SMP_CMD_MASTER_IDENT 0x07 +struct smp_cmd_master_ident { + __u16 ediv; + __u8 rand[8]; +} __packed; + +#define SMP_CMD_IDENT_INFO 0x08 +struct smp_cmd_ident_info { + __u8 irk[16]; +} __packed; + +#define SMP_CMD_IDENT_ADDR_INFO 0x09 +struct smp_cmd_ident_addr_info { + __u8 addr_type; + bdaddr_t bdaddr; +} __packed; + +#define SMP_CMD_SIGN_INFO 0x0a +struct smp_cmd_sign_info { + __u8 csrk[16]; +} __packed; + +#define SMP_CMD_SECURITY_REQ 0x0b +struct smp_cmd_security_req { + __u8 auth_req; +} __packed; + +#define SMP_PASSKEY_ENTRY_FAILED 0x01 +#define SMP_OOB_NOT_AVAIL 0x02 +#define SMP_AUTH_REQUIREMENTS 0x03 +#define SMP_CONFIRM_FAILED 0x04 +#define SMP_PAIRING_NOTSUPP 0x05 +#define SMP_ENC_KEY_SIZE 0x06 +#define SMP_CMD_NOTSUPP 0x07 +#define SMP_UNSPECIFIED 0x08 +#define SMP_REPEATED_ATTEMPTS 0x09 + +#define SMP_MIN_ENC_KEY_SIZE 7 +#define SMP_MAX_ENC_KEY_SIZE 16 + +struct smp_chan { + struct l2cap_conn *conn; + u8 preq[7]; /* SMP Pairing Request */ + u8 prsp[7]; /* SMP Pairing Response */ + u8 prnd[16]; /* SMP Pairing Random (local) */ + u8 rrnd[16]; /* SMP Pairing Random (remote) */ + u8 pcnf[16]; /* SMP Pairing Confirm */ + u8 tk[16]; /* SMP Temporary Key */ + u8 smp_key_size; + struct crypto_blkcipher *tfm; + struct work_struct confirm; + struct work_struct random; + +}; + +/* SMP Commands */ +int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level); +int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); +int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); + +void smp_chan_destroy(struct l2cap_conn *conn); + +#endif /* __SMP_H */ diff --git a/include/compat/net/cfg80211-wext.h b/include/compat/net/cfg80211-wext.h new file mode 100644 index 00000000..25baddc4 --- /dev/null +++ b/include/compat/net/cfg80211-wext.h @@ -0,0 +1,55 @@ +#ifndef __NET_CFG80211_WEXT_H +#define __NET_CFG80211_WEXT_H +/* + * 802.11 device and configuration interface -- wext handlers + * + * Copyright 2006-2010 Johannes Berg + * + * 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 +#include +#include + +/* + * Temporary wext handlers & helper functions + * + * These are used only by drivers that aren't yet fully + * converted to cfg80211. + */ +int cfg80211_wext_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra); +int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra); +int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra); +int cfg80211_wext_siwscan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int cfg80211_wext_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra); +int cfg80211_wext_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra); +int cfg80211_wext_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra); +int cfg80211_wext_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra); +int cfg80211_wext_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra); + +#endif /* __NET_CFG80211_WEXT_H */ diff --git a/include/compat/net/cfg80211.h b/include/compat/net/cfg80211.h new file mode 100644 index 00000000..17376bd7 --- /dev/null +++ b/include/compat/net/cfg80211.h @@ -0,0 +1,3479 @@ +#ifndef __NET_CFG80211_H +#define __NET_CFG80211_H +/* + * 802.11 device and configuration interface + * + * Copyright 2006-2010 Johannes Berg + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: Introduction + * + * cfg80211 is the configuration API for 802.11 devices in Linux. It bridges + * userspace and drivers, and offers some utility functionality associated + * with 802.11. cfg80211 must, directly or indirectly via mac80211, be used + * by all modern wireless drivers in Linux, so that they offer a consistent + * API through nl80211. For backward compatibility, cfg80211 also offers + * wireless extensions to userspace, but hides them from drivers completely. + * + * Additionally, cfg80211 contains code to help enforce regulatory spectrum + * use restrictions. + */ + + +/** + * DOC: Device registration + * + * In order for a driver to use cfg80211, it must register the hardware device + * with cfg80211. This happens through a number of hardware capability structs + * described below. + * + * The fundamental structure for each device is the 'wiphy', of which each + * instance describes a physical wireless device connected to the system. Each + * such wiphy can have zero, one, or many virtual interfaces associated with + * it, which need to be identified as such by pointing the network interface's + * @ieee80211_ptr pointer to a &struct wireless_dev which further describes + * the wireless part of the interface, normally this struct is embedded in the + * network interface's private data area. Drivers can optionally allow creating + * or destroying virtual interfaces on the fly, but without at least one or the + * ability to create some the wireless device isn't useful. + * + * Each wiphy structure contains device capability information, and also has + * a pointer to the various operations the driver offers. The definitions and + * structures here describe these capabilities in detail. + */ + +/* + * wireless hardware capability structures + */ + +/** + * enum ieee80211_band - supported frequency bands + * + * The bands are assigned this way because the supported + * bitrates differ in these bands. + * + * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band + * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) + * @IEEE80211_NUM_BANDS: number of defined bands + */ +enum ieee80211_band { + IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, + IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, + + /* keep last */ + IEEE80211_NUM_BANDS +}; + +/** + * enum ieee80211_channel_flags - channel flags + * + * Channel flags set by the regulatory control code. + * + * @IEEE80211_CHAN_DISABLED: This channel is disabled. + * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted + * on this channel. + * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. + * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. + * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel + * is not permitted. + * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel + * is not permitted. + */ +enum ieee80211_channel_flags { + IEEE80211_CHAN_DISABLED = 1<<0, + IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, + IEEE80211_CHAN_NO_IBSS = 1<<2, + IEEE80211_CHAN_RADAR = 1<<3, + IEEE80211_CHAN_NO_HT40PLUS = 1<<4, + IEEE80211_CHAN_NO_HT40MINUS = 1<<5, +}; + +#define IEEE80211_CHAN_NO_HT40 \ + (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) + +/** + * struct ieee80211_channel - channel definition + * + * This structure describes a single channel for use + * with cfg80211. + * + * @center_freq: center frequency in MHz + * @hw_value: hardware-specific value for the channel + * @flags: channel flags from &enum ieee80211_channel_flags. + * @orig_flags: channel flags at registration time, used by regulatory + * code to support devices with additional restrictions + * @band: band this channel belongs to. + * @max_antenna_gain: maximum antenna gain in dBi + * @max_power: maximum transmission power (in dBm) + * @beacon_found: helper to regulatory code to indicate when a beacon + * has been found on this channel. Use regulatory_hint_found_beacon() + * to enable this, this is useful only on 5 GHz band. + * @orig_mag: internal use + * @orig_mpwr: internal use + */ +struct ieee80211_channel { + enum ieee80211_band band; + u16 center_freq; + u16 hw_value; + u32 flags; + int max_antenna_gain; + int max_power; + bool beacon_found; + u32 orig_flags; + int orig_mag, orig_mpwr; +}; + +/** + * enum ieee80211_rate_flags - rate flags + * + * Hardware/specification flags for rates. These are structured + * in a way that allows using the same bitrate structure for + * different bands/PHY modes. + * + * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short + * preamble on this bitrate; only relevant in 2.4GHz band and + * with CCK rates. + * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate + * when used with 802.11a (on the 5 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate + * when used with 802.11b (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate + * when used with 802.11g (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. + */ +enum ieee80211_rate_flags { + IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, + IEEE80211_RATE_MANDATORY_A = 1<<1, + IEEE80211_RATE_MANDATORY_B = 1<<2, + IEEE80211_RATE_MANDATORY_G = 1<<3, + IEEE80211_RATE_ERP_G = 1<<4, +}; + +/** + * struct ieee80211_rate - bitrate definition + * + * This structure describes a bitrate that an 802.11 PHY can + * operate with. The two values @hw_value and @hw_value_short + * are only for driver use when pointers to this structure are + * passed around. + * + * @flags: rate-specific flags + * @bitrate: bitrate in units of 100 Kbps + * @hw_value: driver/hardware value for this rate + * @hw_value_short: driver/hardware value for this rate when + * short preamble is used + */ +struct ieee80211_rate { + u32 flags; + u16 bitrate; + u16 hw_value, hw_value_short; +}; + +/** + * struct ieee80211_sta_ht_cap - STA's HT capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11n HT capabilities for an STA. + * + * @ht_supported: is HT supported by the STA + * @cap: HT capabilities map as described in 802.11n spec + * @ampdu_factor: Maximum A-MPDU length factor + * @ampdu_density: Minimum A-MPDU spacing + * @mcs: Supported MCS rates + */ +struct ieee80211_sta_ht_cap { + u16 cap; /* use IEEE80211_HT_CAP_ */ + bool ht_supported; + u8 ampdu_factor; + u8 ampdu_density; + struct ieee80211_mcs_info mcs; +}; + +/** + * struct ieee80211_supported_band - frequency band definition + * + * This structure describes a frequency band a wiphy + * is able to operate in. + * + * @channels: Array of channels the hardware can operate in + * in this band. + * @band: the band this structure represents + * @n_channels: Number of channels in @channels + * @bitrates: Array of bitrates the hardware can operate with + * in this band. Must be sorted to give a valid "supported + * rates" IE, i.e. CCK rates first, then OFDM. + * @n_bitrates: Number of bitrates in @bitrates + * @ht_cap: HT capabilities in this band + */ +struct ieee80211_supported_band { + struct ieee80211_channel *channels; + struct ieee80211_rate *bitrates; + enum ieee80211_band band; + int n_channels; + int n_bitrates; + struct ieee80211_sta_ht_cap ht_cap; +}; + +/* + * Wireless hardware/device configuration structures and methods + */ + +/** + * DOC: Actions and configuration + * + * Each wireless device and each virtual interface offer a set of configuration + * operations and other actions that are invoked by userspace. Each of these + * actions is described in the operations structure, and the parameters these + * operations use are described separately. + * + * Additionally, some operations are asynchronous and expect to get status + * information via some functions that drivers need to call. + * + * Scanning and BSS list handling with its associated functionality is described + * in a separate chapter. + */ + +/** + * struct vif_params - describes virtual interface parameters + * @use_4addr: use 4-address frames + */ +struct vif_params { + int use_4addr; +}; + +/** + * struct key_params - key information + * + * Information about a key + * + * @key: key material + * @key_len: length of key material + * @cipher: cipher suite selector + * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used + * with the get_key() callback, must be in little endian, + * length given by @seq_len. + * @seq_len: length of @seq. + */ +struct key_params { + u8 *key; + u8 *seq; + int key_len; + int seq_len; + u32 cipher; +}; + +/** + * enum survey_info_flags - survey information flags + * + * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in + * @SURVEY_INFO_IN_USE: channel is currently being used + * @SURVEY_INFO_CHANNEL_TIME: channel active time (in ms) was filled in + * @SURVEY_INFO_CHANNEL_TIME_BUSY: channel busy time was filled in + * @SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: extension channel busy time was filled in + * @SURVEY_INFO_CHANNEL_TIME_RX: channel receive time was filled in + * @SURVEY_INFO_CHANNEL_TIME_TX: channel transmit time was filled in + * + * Used by the driver to indicate which info in &struct survey_info + * it has filled in during the get_survey(). + */ +enum survey_info_flags { + SURVEY_INFO_NOISE_DBM = 1<<0, + SURVEY_INFO_IN_USE = 1<<1, + SURVEY_INFO_CHANNEL_TIME = 1<<2, + SURVEY_INFO_CHANNEL_TIME_BUSY = 1<<3, + SURVEY_INFO_CHANNEL_TIME_EXT_BUSY = 1<<4, + SURVEY_INFO_CHANNEL_TIME_RX = 1<<5, + SURVEY_INFO_CHANNEL_TIME_TX = 1<<6, +}; + +/** + * struct survey_info - channel survey response + * + * @channel: the channel this survey record reports, mandatory + * @filled: bitflag of flags from &enum survey_info_flags + * @noise: channel noise in dBm. This and all following fields are + * optional + * @channel_time: amount of time in ms the radio spent on the channel + * @channel_time_busy: amount of time the primary channel was sensed busy + * @channel_time_ext_busy: amount of time the extension channel was sensed busy + * @channel_time_rx: amount of time the radio spent receiving data + * @channel_time_tx: amount of time the radio spent transmitting data + * + * Used by dump_survey() to report back per-channel survey information. + * + * This structure can later be expanded with things like + * channel duty cycle etc. + */ +struct survey_info { + struct ieee80211_channel *channel; + u64 channel_time; + u64 channel_time_busy; + u64 channel_time_ext_busy; + u64 channel_time_rx; + u64 channel_time_tx; + u32 filled; + s8 noise; +}; + +/** + * struct cfg80211_crypto_settings - Crypto settings + * @wpa_versions: indicates which, if any, WPA versions are enabled + * (from enum nl80211_wpa_versions) + * @cipher_group: group key cipher suite (or 0 if unset) + * @n_ciphers_pairwise: number of AP supported unicast ciphers + * @ciphers_pairwise: unicast key cipher suites + * @n_akm_suites: number of AKM suites + * @akm_suites: AKM suites + * @control_port: Whether user space controls IEEE 802.1X port, i.e., + * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is + * required to assume that the port is unauthorized until authorized by + * user space. Otherwise, port is marked authorized by default. + * @control_port_ethertype: the control port protocol that should be + * allowed through even on unauthorized ports + * @control_port_no_encrypt: TRUE to prevent encryption of control port + * protocol frames. + */ +struct cfg80211_crypto_settings { + u32 wpa_versions; + u32 cipher_group; + int n_ciphers_pairwise; + u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES]; + int n_akm_suites; + u32 akm_suites[NL80211_MAX_NR_AKM_SUITES]; + bool control_port; + __be16 control_port_ethertype; + bool control_port_no_encrypt; +}; + +/** + * struct beacon_parameters - beacon parameters + * + * Used to configure the beacon for an interface. + * + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed + * @tail: tail portion of beacon (after TIM IE) + * or %NULL if not changed + * @interval: beacon interval or zero if not changed + * @dtim_period: DTIM period or zero if not changed + * @head_len: length of @head + * @tail_len: length of @tail + * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from + * user space) + * @ssid_len: length of @ssid + * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames + * @crypto: crypto settings + * @privacy: the BSS uses privacy + * @acl_mac: Enable or disable mac address based acl in driver, + * valid only for the drivers which have this support implemented. + * @auth_type: Authentication type (algorithm) + * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL + * @beacon_ies_len: length of beacon_ies in octets + * @proberesp_ies: extra information element(s) to add into Probe Response + * frames or %NULL + * @proberesp_ies_len: length of proberesp_ies in octets + * @assocresp_ies: extra information element(s) to add into (Re)Association + * Response frames or %NULL + * @assocresp_ies_len: length of assocresp_ies in octets + * @probe_resp_len: length of probe response template (@probe_resp) + * @probe_resp: probe response template (AP mode only) + */ +struct beacon_parameters { + u8 *head, *tail; + int interval, dtim_period; + int head_len, tail_len; + const u8 *ssid; + size_t ssid_len; + enum nl80211_hidden_ssid hidden_ssid; + struct cfg80211_crypto_settings crypto; + bool privacy; + bool acl_mac; + enum nl80211_auth_type auth_type; + const u8 *beacon_ies; + size_t beacon_ies_len; + const u8 *proberesp_ies; + size_t proberesp_ies_len; + const u8 *assocresp_ies; + size_t assocresp_ies_len; + int probe_resp_len; + u8 *probe_resp; + enum nl80211_sta_capab_req_options sta_cap_req; + u8 auto_channel_select; +}; + +/** + * enum plink_action - actions to perform in mesh peers + * + * @PLINK_ACTION_INVALID: action 0 is reserved + * @PLINK_ACTION_OPEN: start mesh peer link establishment + * @PLINK_ACTION_BLOCK: block traffic from this mesh peer + */ +enum plink_actions { + PLINK_ACTION_INVALID, + PLINK_ACTION_OPEN, + PLINK_ACTION_BLOCK, +}; + +/** + * enum station_parameters_apply_mask - station parameter values to apply + * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) + * + * Not all station parameters have in-band "no change" signalling, + * for those that don't these flags will are used. + */ +enum station_parameters_apply_mask { + STATION_PARAM_APPLY_UAPSD = BIT(0), +}; + +/** + * struct station_parameters - station parameters + * + * Used to change and create a new station. + * + * @vlan: vlan interface station should belong to + * @supported_rates: supported rates in IEEE 802.11 format + * (or NULL for no change) + * @supported_rates_len: number of supported rates + * @sta_flags_mask: station flags that changed + * (bitmask of BIT(NL80211_STA_FLAG_...)) + * @sta_flags_set: station flags values + * (bitmask of BIT(NL80211_STA_FLAG_...)) + * @listen_interval: listen interval or -1 for no change + * @aid: AID or zero for no change + * @plink_action: plink action to take + * @plink_state: set the peer link state for a station + * @ht_capa: HT capabilities of station + * @uapsd_queues: bitmap of queues configured for uapsd. same format + * as the AC bitmap in the QoS info field + * @max_sp: max Service Period. same format as the MAX_SP in the + * QoS info field (but already shifted down) + * @sta_modify_mask: bitmap indicating which parameters changed + * (for those that don't have a natural "no change" value), + * see &enum station_parameters_apply_mask + */ +struct station_parameters { + u8 *supported_rates; + struct net_device *vlan; + u32 sta_flags_mask, sta_flags_set; + u32 sta_modify_mask; + int listen_interval; + u16 aid; + u8 supported_rates_len; + u8 plink_action; + u8 plink_state; + struct ieee80211_ht_cap *ht_capa; + u8 uapsd_queues; + u8 max_sp; +}; + +/** + * enum station_info_flags - station information flags + * + * Used by the driver to indicate which info in &struct station_info + * it has filled in during get_station() or dump_station(). + * + * @STATION_INFO_INACTIVE_TIME: @inactive_time filled + * @STATION_INFO_RX_BYTES: @rx_bytes filled + * @STATION_INFO_TX_BYTES: @tx_bytes filled + * @STATION_INFO_LLID: @llid filled + * @STATION_INFO_PLID: @plid filled + * @STATION_INFO_PLINK_STATE: @plink_state filled + * @STATION_INFO_SIGNAL: @signal filled + * @STATION_INFO_TX_BITRATE: @txrate fields are filled + * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) + * @STATION_INFO_RX_PACKETS: @rx_packets filled + * @STATION_INFO_TX_PACKETS: @tx_packets filled + * @STATION_INFO_TX_RETRIES: @tx_retries filled + * @STATION_INFO_TX_FAILED: @tx_failed filled + * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled + * @STATION_INFO_SIGNAL_AVG: @signal_avg filled + * @STATION_INFO_RX_BITRATE: @rxrate fields are filled + * @STATION_INFO_BSS_PARAM: @bss_param filled + * @STATION_INFO_CONNECTED_TIME: @connected_time filled + * @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled + * @STATION_INFO_STA_FLAGS: @sta_flags filled + */ +enum station_info_flags { + STATION_INFO_INACTIVE_TIME = 1<<0, + STATION_INFO_RX_BYTES = 1<<1, + STATION_INFO_TX_BYTES = 1<<2, + STATION_INFO_LLID = 1<<3, + STATION_INFO_PLID = 1<<4, + STATION_INFO_PLINK_STATE = 1<<5, + STATION_INFO_SIGNAL = 1<<6, + STATION_INFO_TX_BITRATE = 1<<7, + STATION_INFO_RX_PACKETS = 1<<8, + STATION_INFO_TX_PACKETS = 1<<9, + STATION_INFO_TX_RETRIES = 1<<10, + STATION_INFO_TX_FAILED = 1<<11, + STATION_INFO_RX_DROP_MISC = 1<<12, + STATION_INFO_SIGNAL_AVG = 1<<13, + STATION_INFO_RX_BITRATE = 1<<14, + STATION_INFO_BSS_PARAM = 1<<15, + STATION_INFO_CONNECTED_TIME = 1<<16, + STATION_INFO_ASSOC_REQ_IES = 1<<17, + STATION_INFO_STA_FLAGS = 1<<18 +}; + +/** + * enum station_info_rate_flags - bitrate info flags + * + * Used by the driver to indicate the specific rate transmission + * type for 802.11n transmissions. + * + * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled + * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission + * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval + */ +enum rate_info_flags { + RATE_INFO_FLAGS_MCS = 1<<0, + RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, + RATE_INFO_FLAGS_SHORT_GI = 1<<2, +}; + +/** + * struct rate_info - bitrate information + * + * Information about a receiving or transmitting bitrate + * + * @flags: bitflag of flags from &enum rate_info_flags + * @mcs: mcs index if struct describes a 802.11n bitrate + * @legacy: bitrate in 100kbit/s for 802.11abg + */ +struct rate_info { + u8 flags; + u8 mcs; + u16 legacy; +}; + +/** + * enum station_info_rate_flags - bitrate info flags + * + * Used by the driver to indicate the specific rate transmission + * type for 802.11n transmissions. + * + * @BSS_PARAM_FLAGS_CTS_PROT: whether CTS protection is enabled + * @BSS_PARAM_FLAGS_SHORT_PREAMBLE: whether short preamble is enabled + * @BSS_PARAM_FLAGS_SHORT_SLOT_TIME: whether short slot time is enabled + */ +enum bss_param_flags { + BSS_PARAM_FLAGS_CTS_PROT = 1<<0, + BSS_PARAM_FLAGS_SHORT_PREAMBLE = 1<<1, + BSS_PARAM_FLAGS_SHORT_SLOT_TIME = 1<<2, +}; + +/** + * struct sta_bss_parameters - BSS parameters for the attached station + * + * Information about the currently associated BSS + * + * @flags: bitflag of flags from &enum bss_param_flags + * @dtim_period: DTIM period for the BSS + * @beacon_interval: beacon interval + */ +struct sta_bss_parameters { + u8 flags; + u8 dtim_period; + u16 beacon_interval; +}; + +/** + * struct station_info - station information + * + * Station information filled by driver for get_station() and dump_station. + * + * @filled: bitflag of flags from &enum station_info_flags + * @connected_time: time(in secs) since a station is last connected + * @inactive_time: time since last station activity (tx/rx) in milliseconds + * @rx_bytes: bytes received from this station + * @tx_bytes: bytes transmitted to this station + * @llid: mesh local link id + * @plid: mesh peer link id + * @plink_state: mesh peer link state + * @signal: signal strength of last received packet in dBm + * @signal_avg: signal strength average in dBm + * @txrate: current unicast bitrate from this station + * @rxrate: current unicast bitrate to this station + * @rx_packets: packets received from this station + * @tx_packets: packets transmitted to this station + * @tx_retries: cumulative retry counts + * @tx_failed: number of failed transmissions (retries exceeded, no ACK) + * @rx_dropped_misc: Dropped for un-specified reason. + * @bss_param: current BSS parameters + * @generation: generation number for nl80211 dumps. + * This number should increase every time the list of stations + * changes, i.e. when a station is added or removed, so that + * userspace can tell whether it got a consistent snapshot. + * @assoc_req_ies: IEs from (Re)Association Request. + * This is used only when in AP mode with drivers that do not use + * user space MLME/SME implementation. The information is provided for + * the cfg80211_new_sta() calls to notify user space of the IEs. + * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets. + * @sta_flags: station flags mask & values + */ +struct station_info { + u32 filled; + u32 connected_time; + u32 inactive_time; + u32 rx_bytes; + u32 tx_bytes; + u16 llid; + u16 plid; + u8 plink_state; + s8 signal; + s8 signal_avg; + struct rate_info txrate; + struct rate_info rxrate; + u32 rx_packets; + u32 tx_packets; + u32 tx_retries; + u32 tx_failed; + u32 rx_dropped_misc; + struct sta_bss_parameters bss_param; + struct nl80211_sta_flag_update sta_flags; + + int generation; + + const u8 *assoc_req_ies; + size_t assoc_req_ies_len; + + /* + * Note: Add a new enum station_info_flags value for each new field and + * use it to check which fields are initialized. + */ +}; + +/** + * enum monitor_flags - monitor flags + * + * Monitor interface configuration flags. Note that these must be the bits + * according to the nl80211 flags. + * + * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS + * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @MONITOR_FLAG_CONTROL: pass control frames + * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering + * @MONITOR_FLAG_COOK_FRAMES: report frames after processing + */ +enum monitor_flags { + MONITOR_FLAG_FCSFAIL = 1<bss_priv_size bytes + */ +struct cfg80211_bss { + struct ieee80211_channel *channel; + + u8 bssid[ETH_ALEN]; + u64 tsf; + u16 beacon_interval; + u16 capability; + u8 *information_elements; + size_t len_information_elements; + u8 *beacon_ies; + size_t len_beacon_ies; + u8 *proberesp_ies; + size_t len_proberesp_ies; + + s32 signal; + + void (*free_priv)(struct cfg80211_bss *bss); + u8 priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + +/** + * ieee80211_bss_get_ie - find IE with given ID + * @bss: the bss to search + * @ie: the IE ID + * Returns %NULL if not found. + */ +const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); + + +/** + * struct cfg80211_auth_request - Authentication request data + * + * This structure provides information needed to complete IEEE 802.11 + * authentication. + * + * @bss: The BSS to authenticate with. + * @auth_type: Authentication type (algorithm) + * @ie: Extra IEs to add to Authentication frame or %NULL + * @ie_len: Length of ie buffer in octets + * @key_len: length of WEP key for shared key authentication + * @key_idx: index of WEP key for shared key authentication + * @key: WEP key for shared key authentication + * @local_state_change: This is a request for a local state only, i.e., no + * Authentication frame is to be transmitted and authentication state is + * to be changed without having to wait for a response from the peer STA + * (AP). + */ +struct cfg80211_auth_request { + struct cfg80211_bss *bss; + const u8 *ie; + size_t ie_len; + enum nl80211_auth_type auth_type; + const u8 *key; + u8 key_len, key_idx; + bool local_state_change; +}; + +/** + * struct cfg80211_assoc_request - (Re)Association request data + * + * This structure provides information needed to complete IEEE 802.11 + * (re)association. + * @bss: The BSS to associate with. + * @ie: Extra IEs to add to (Re)Association Request frame or %NULL + * @ie_len: Length of ie buffer in octets + * @use_mfp: Use management frame protection (IEEE 802.11w) in this association + * @crypto: crypto settings + * @prev_bssid: previous BSSID, if not %NULL use reassociate frame + */ +struct cfg80211_assoc_request { + struct cfg80211_bss *bss; + const u8 *ie, *prev_bssid; + size_t ie_len; + struct cfg80211_crypto_settings crypto; + bool use_mfp; +}; + +/** + * struct cfg80211_deauth_request - Deauthentication request data + * + * This structure provides information needed to complete IEEE 802.11 + * deauthentication. + * + * @bss: the BSS to deauthenticate from + * @ie: Extra IEs to add to Deauthentication frame or %NULL + * @ie_len: Length of ie buffer in octets + * @reason_code: The reason code for the deauthentication + * @local_state_change: This is a request for a local state only, i.e., no + * Deauthentication frame is to be transmitted. + */ +struct cfg80211_deauth_request { + struct cfg80211_bss *bss; + const u8 *ie; + size_t ie_len; + u16 reason_code; + bool local_state_change; +}; + +/** + * struct cfg80211_disassoc_request - Disassociation request data + * + * This structure provides information needed to complete IEEE 802.11 + * disassocation. + * + * @bss: the BSS to disassociate from + * @ie: Extra IEs to add to Disassociation frame or %NULL + * @ie_len: Length of ie buffer in octets + * @reason_code: The reason code for the disassociation + * @local_state_change: This is a request for a local state only, i.e., no + * Disassociation frame is to be transmitted. + */ +struct cfg80211_disassoc_request { + struct cfg80211_bss *bss; + const u8 *ie; + size_t ie_len; + u16 reason_code; + bool local_state_change; +}; + +/** + * struct cfg80211_ibss_params - IBSS parameters + * + * This structure defines the IBSS parameters for the join_ibss() + * method. + * + * @ssid: The SSID, will always be non-null. + * @ssid_len: The length of the SSID, will always be non-zero. + * @bssid: Fixed BSSID requested, maybe be %NULL, if set do not + * search for IBSSs with a different BSSID. + * @channel: The channel to use if no IBSS can be found to join. + * @channel_fixed: The channel should be fixed -- do not search for + * IBSSs to join on other channels. + * @ie: information element(s) to include in the beacon + * @ie_len: length of that + * @beacon_interval: beacon interval to use + * @privacy: this is a protected network, keys will be configured + * after joining + * @basic_rates: bitmap of basic rates to use when creating the IBSS + * @mcast_rate: per-band multicast rate index + 1 (0: disabled) + */ +struct cfg80211_ibss_params { + u8 *ssid; + u8 *bssid; + struct ieee80211_channel *channel; + u8 *ie; + u8 ssid_len, ie_len; + u16 beacon_interval; + u32 basic_rates; + bool channel_fixed; + bool privacy; + int mcast_rate[IEEE80211_NUM_BANDS]; +}; + +/** + * struct cfg80211_connect_params - Connection parameters + * + * This structure provides information needed to complete IEEE 802.11 + * authentication and association. + * + * @channel: The channel to use or %NULL if not specified (auto-select based + * on scan results) + * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan + * results) + * @ssid: SSID + * @ssid_len: Length of ssid in octets + * @auth_type: Authentication type (algorithm) + * @ie: IEs for association request + * @ie_len: Length of assoc_ie in octets + * @privacy: indicates whether privacy-enabled APs should be used + * @crypto: crypto settings + * @key_len: length of WEP key for shared key authentication + * @key_idx: index of WEP key for shared key authentication + * @key: WEP key for shared key authentication + * @bg_scan_period: Background scan period in seconds + * or -1 to indicate that default value is to be used. + */ +struct cfg80211_connect_params { + struct ieee80211_channel *channel; + u8 *bssid; + u8 *ssid; + size_t ssid_len; + enum nl80211_auth_type auth_type; + u8 *ie; + size_t ie_len; + bool privacy; + struct cfg80211_crypto_settings crypto; + const u8 *key; + u8 key_len, key_idx; + int bg_scan_period; +}; + +/** + * enum wiphy_params_flags - set_wiphy_params bitfield values + * @WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed + * @WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed + * @WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed + * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed + * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed + */ +enum wiphy_params_flags { + WIPHY_PARAM_RETRY_SHORT = 1 << 0, + WIPHY_PARAM_RETRY_LONG = 1 << 1, + WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, + WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, + WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, +}; + +/* + * cfg80211_bitrate_mask - masks for bitrate control + */ +struct cfg80211_bitrate_mask { + struct { + u32 legacy; + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; + } control[IEEE80211_NUM_BANDS]; +}; +/** + * struct cfg80211_pmksa - PMK Security Association + * + * This structure is passed to the set/del_pmksa() method for PMKSA + * caching. + * + * @bssid: The AP's BSSID. + * @pmkid: The PMK material itself. + */ +struct cfg80211_pmksa { + u8 *bssid; + u8 *pmkid; +}; + +/** + * struct cfg80211_wowlan_trig_pkt_pattern - packet pattern + * @mask: bitmask where to match pattern and where to ignore bytes, + * one bit per byte, in same format as nl80211 + * @pattern: bytes to match where bitmask is 1 + * @pattern_len: length of pattern (in bytes) + * + * Internal note: @mask and @pattern are allocated in one chunk of + * memory, free @mask only! + */ +struct cfg80211_wowlan_trig_pkt_pattern { + u8 *mask, *pattern; + int pattern_len; +}; + +/** + * struct cfg80211_wowlan - Wake on Wireless-LAN support info + * + * This structure defines the enabled WoWLAN triggers for the device. + * @any: wake up on any activity -- special trigger if device continues + * operating as normal during suspend + * @disconnect: wake up if getting disconnected + * @magic_pkt: wake up on receiving magic packet + * @patterns: wake up on receiving packet matching a pattern + * @n_patterns: number of patterns + * @gtk_rekey_failure: wake up on GTK rekey failure + * @eap_identity_req: wake up on EAP identity request packet + * @four_way_handshake: wake up on 4-way handshake + * @rfkill_release: wake up when rfkill is released + */ +struct cfg80211_wowlan { + bool any, disconnect, magic_pkt, gtk_rekey_failure, + eap_identity_req, four_way_handshake, + rfkill_release; + struct cfg80211_wowlan_trig_pkt_pattern *patterns; + int n_patterns; +}; + +/** + * struct cfg80211_gtk_rekey_data - rekey data + * @kek: key encryption key + * @kck: key confirmation key + * @replay_ctr: replay counter + */ +struct cfg80211_gtk_rekey_data { + u8 kek[NL80211_KEK_LEN]; + u8 kck[NL80211_KCK_LEN]; + u8 replay_ctr[NL80211_REPLAY_CTR_LEN]; +}; + +struct mac_address { + u8 addr[ETH_ALEN]; +}; + +/** + * struct cfg80211_acl_params - Access control parameters + * @mac_addrs: List of mac addresses of stations to be used for acl + * @acl_policy: Access control policy to be applied on the station's + * entry specified by mac_addr + */ +struct cfg80211_acl_params { + enum nl80211_acl_policy_attr acl_policy; + int n_acl_entries; + + /* Keep it last */ + struct mac_address mac_addrs[0]; +}; + +/** + * struct cfg80211_ops - backend description for wireless configuration + * + * This struct is registered by fullmac card drivers and/or wireless stacks + * in order to handle configuration requests on their interfaces. + * + * All callbacks except where otherwise noted should return 0 + * on success or a negative error code. + * + * All operations are currently invoked under rtnl for consistency with the + * wireless extensions but this is subject to reevaluation as soon as this + * code is used more widely and we have a first user without wext. + * + * @suspend: wiphy device needs to be suspended. The variable @wow will + * be %NULL or contain the enabled Wake-on-Wireless triggers that are + * configured for the device. + * @resume: wiphy device needs to be resumed + * + * @add_virtual_intf: create a new virtual interface with the given name, + * must set the struct wireless_dev's iftype. Beware: You must create + * the new netdev in the wiphy's network namespace! Returns the netdev, + * or an ERR_PTR. + * + * @del_virtual_intf: remove the virtual interface determined by ifindex. + * + * @change_virtual_intf: change type/configuration of virtual interface, + * keep the struct wireless_dev's iftype updated. + * + * @add_key: add a key with the given parameters. @mac_addr will be %NULL + * when adding a group key. + * + * @get_key: get information about the key with the given parameters. + * @mac_addr will be %NULL when requesting information for a group + * key. All pointers given to the @callback function need not be valid + * after it returns. This function should return an error if it is + * not possible to retrieve the key, -ENOENT if it doesn't exist. + * + * @del_key: remove a key given the @mac_addr (%NULL for a group key) + * and @key_index, return -ENOENT if the key doesn't exist. + * + * @set_default_key: set the default key on an interface + * + * @set_default_mgmt_key: set the default management frame key on an interface + * + * @set_rekey_data: give the data necessary for GTK rekeying to the driver + * + * @add_beacon: Add a beacon with given parameters, @head, @interval + * and @dtim_period will be valid, @tail is optional. + * @set_beacon: Change the beacon parameters for an access point mode + * interface. This should reject the call when no beacon has been + * configured. + * @del_beacon: Remove beacon configuration and stop sending the beacon. + * + * @add_station: Add a new station. + * @del_station: Remove a station; @mac may be NULL to remove all stations. + * @change_station: Modify a given station. + * @get_station: get station information for the station identified by @mac + * @dump_station: dump station callback -- resume dump at index @idx + * + * @add_mpath: add a fixed mesh path + * @del_mpath: delete a given mesh path + * @change_mpath: change a given mesh path + * @get_mpath: get a mesh path for the given parameters + * @dump_mpath: dump mesh path callback -- resume dump at index @idx + * @join_mesh: join the mesh network with the specified parameters + * @leave_mesh: leave the current mesh network + * + * @get_mesh_config: Get the current mesh configuration + * + * @update_mesh_config: Update mesh parameters on a running mesh. + * The mask is a bitfield which tells us which parameters to + * set, and which to leave alone. + * + * @change_bss: Modify parameters for a given BSS. + * + * @set_txq_params: Set TX queue parameters + * + * @set_channel: Set channel for a given wireless interface. Some devices + * may support multi-channel operation (by channel hopping) so cfg80211 + * doesn't verify much. Note, however, that the passed netdev may be + * %NULL as well if the user requested changing the channel for the + * device itself, or for a monitor interface. + * @get_channel: Get the current operating channel, should return %NULL if + * there's no single defined operating channel if for example the + * device implements channel hopping for multi-channel virtual interfaces. + * + * @scan: Request to do a scan. If returning zero, the scan request is given + * the driver, and will be valid until passed to cfg80211_scan_done(). + * For scan results, call cfg80211_inform_bss(); you can call this outside + * the scan/scan_done bracket too. + * + * @auth: Request to authenticate with the specified peer + * @assoc: Request to (re)associate with the specified peer + * @deauth: Request to deauthenticate from the specified peer + * @disassoc: Request to disassociate from the specified peer + * + * @connect: Connect to the ESS with the specified parameters. When connected, + * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. + * If the connection fails for some reason, call cfg80211_connect_result() + * with the status from the AP. + * @disconnect: Disconnect from the BSS/ESS. + * + * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call + * cfg80211_ibss_joined(), also call that function when changing BSSID due + * to a merge. + * @leave_ibss: Leave the IBSS. + * + * @set_wiphy_params: Notify that wiphy parameters have changed; + * @changed bitfield (see &enum wiphy_params_flags) describes which values + * have changed. The actual parameter values are available in + * struct wiphy. If returning an error, no value should be changed. + * + * @set_tx_power: set the transmit power according to the parameters + * @get_tx_power: store the current TX power into the dbm variable; + * return 0 if successful + * + * @set_wds_peer: set the WDS peer for a WDS interface + * + * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting + * functions to adjust rfkill hw state + * + * @dump_survey: get site survey information. + * + * @remain_on_channel: Request the driver to remain awake on the specified + * channel for the specified duration to complete an off-channel + * operation (e.g., public action frame exchange). When the driver is + * ready on the requested channel, it must indicate this with an event + * notification by calling cfg80211_ready_on_channel(). + * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. + * This allows the operation to be terminated prior to timeout based on + * the duration value. + * @mgmt_tx: Transmit a management frame. + * @mgmt_tx_cancel_wait: Cancel the wait time from transmitting a management + * frame on another channel + * + * @testmode_cmd: run a test mode command + * @testmode_dump: Implement a test mode dump. The cb->args[2] and up may be + * used by the function, but 0 and 1 must not be touched. Additionally, + * return error codes other than -ENOBUFS and -ENOENT will terminate the + * dump and return to userspace with an error, so be careful. If any data + * was passed in from userspace then the data/len arguments will be present + * and point to the data contained in %NL80211_ATTR_TESTDATA. + * + * @set_bitrate_mask: set the bitrate mask configuration + * + * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac + * devices running firmwares capable of generating the (re) association + * RSN IE. It allows for faster roaming between WPA2 BSSIDs. + * @del_pmksa: Delete a cached PMKID. + * @flush_pmksa: Flush all cached PMKIDs. + * @set_power_mgmt: Configure WLAN power management. A timeout value of -1 + * allows the driver to adjust the dynamic ps timeout value. + * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. + * @set_cqm_txe_config: Configure connection quality monitor TX error + * thresholds. + * @sched_scan_start: Tell the driver to start a scheduled scan. + * @sched_scan_stop: Tell the driver to stop an ongoing scheduled + * scan. The driver_initiated flag specifies whether the driver + * itself has informed that the scan has stopped. + * + * @mgmt_frame_register: Notify driver that a management frame type was + * registered. Note that this callback may not sleep, and cannot run + * concurrently with itself. + * + * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device. + * Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may + * reject TX/RX mask combinations they cannot support by returning -EINVAL + * (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX). + * + * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). + * + * @set_ringparam: Set tx and rx ring sizes. + * + * @get_ringparam: Get tx and rx ring current and maximum sizes. + * + * @tdls_mgmt: Transmit a TDLS management frame. + * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup). + * + * @probe_client: probe an associated client, must return a cookie that it + * later passes to cfg80211_probe_status(). + * + * @notify_btcoex: Send BT coex WMI command. + * + * @set_mac_acl: Set stations' mac address to driver's access control list in + * AP and P2P GO mode. Parameters are mac address of list of stations, + * number of entries and acl policy to be used with this list. If there + * is already a list in driver for this acl policy, this new list may + * replace the existing one. When no entry is passed in the list of mac + * address, driver has to clear it's acl list for that acl policy. Drivers + * which advertises the support for mac address based access control can + * implement this callback. + * + */ + +struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); + int (*resume)(struct wiphy *wiphy); + + struct net_device * (*add_virtual_intf)(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); + int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev); + int (*change_virtual_intf)(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params); + + int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params); + int (*get_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr, + void *cookie, + void (*callback)(void *cookie, struct key_params*)); + int (*del_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr); + int (*set_default_key)(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index, bool unicast, bool multicast); + int (*set_default_mgmt_key)(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index); + + int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); + + + int (*add_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); + int (*del_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac); + int (*change_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); + int (*get_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo); + int (*dump_station)(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo); + + int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop); + int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst); + int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop); + int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop, + struct mpath_info *pinfo); + int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *dst, u8 *next_hop, + struct mpath_info *pinfo); + int (*get_mesh_config)(struct wiphy *wiphy, + struct net_device *dev, + struct mesh_config *conf); + int (*update_mesh_config)(struct wiphy *wiphy, + struct net_device *dev, u32 mask, + const struct mesh_config *nconf); + int (*join_mesh)(struct wiphy *wiphy, struct net_device *dev, + const struct mesh_config *conf, + const struct mesh_setup *setup); + int (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev); + + int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params); + + int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_txq_params *params); + + int (*set_channel)(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); + + int (*scan)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request); + + int (*auth)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_auth_request *req); + int (*assoc)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_assoc_request *req); + int (*deauth)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_deauth_request *req, + void *cookie); + int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_disassoc_request *req, + void *cookie); + + int (*connect)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); + int (*disconnect)(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); + + int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); + int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); + + int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); + + int (*set_tx_power)(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, int mbm); + int (*get_tx_power)(struct wiphy *wiphy, int *dbm); + + int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, + const u8 *addr); + + void (*rfkill_poll)(struct wiphy *wiphy); + +#ifdef CONFIG_NL80211_TESTMODE + int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); + int (*testmode_dump)(struct wiphy *wiphy, struct sk_buff *skb, + struct netlink_callback *cb, + void *data, int len); +#endif + + int (*set_bitrate_mask)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask); + + int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, + int idx, struct survey_info *info); + + int (*set_pmksa)(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + int (*del_pmksa)(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); + + int (*remain_on_channel)(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, + u64 *cookie); + int (*cancel_remain_on_channel)(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie); + + int (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie); + int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie); + + int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout); + + int (*set_cqm_rssi_config)(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst); + + int (*set_cqm_txe_config)(struct wiphy *wiphy, + struct net_device *dev, + u32 rate, u32 pkts, u32 intvl); + + void (*mgmt_frame_register)(struct wiphy *wiphy, + struct net_device *dev, + u16 frame_type, bool reg); + + int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); + int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); + + int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx); + void (*get_ringparam)(struct wiphy *wiphy, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); + + int (*sched_scan_start)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request); + int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev); + + int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_gtk_rekey_data *data); + + int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, const u8 *buf, size_t len); + int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, + u8 *peer, enum nl80211_tdls_operation oper); + + int (*probe_client)(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u64 *cookie); + + struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy); + + int (*notify_btcoex)(struct wiphy *wiphy, + u8 *buf, int len); + + int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_acl_params *params); + + int (*set_wow_mode)(struct wiphy *wiphy, + struct cfg80211_wowlan *wow); + + int (*clr_wow_mode)(struct wiphy *wiphy); +}; + +/* + * wireless hardware and networking interfaces structures + * and registration/helper functions + */ + +/** + * enum wiphy_flags - wiphy capability flags + * + * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device + * has its own custom regulatory domain and cannot identify the + * ISO / IEC 3166 alpha2 it belongs to. When this is enabled + * we will disregard the first regulatory hint (when the + * initiator is %REGDOM_SET_BY_CORE). + * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will + * ignore regulatory domain settings until it gets its own regulatory + * domain via its regulatory_hint() unless the regulatory hint is + * from a country IE. After its gets its own regulatory domain it will + * only allow further regulatory domain settings to further enhance + * compliance. For example if channel 13 and 14 are disabled by this + * regulatory domain no user regulatory domain can enable these channels + * at a later time. This can be used for devices which do not have + * calibration information guaranteed for frequencies or settings + * outside of its regulatory domain. + * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure + * that passive scan flags and beaconing flags may not be lifted by + * cfg80211 due to regulatory beacon hints. For more information on beacon + * hints read the documenation for regulatory_hint_found_beacon() + * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this + * wiphy at all + * @WIPHY_FLAG_ENFORCE_COMBINATIONS: Set this flag to enforce interface + * combinations for this device. This flag is used for backward + * compatibility only until all drivers advertise combinations and + * they will always be enforced. + * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled + * by default -- this flag will be set depending on the kernel's default + * on wiphy_new(), but can be changed by the driver if it has a good + * reason to override the default + * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station + * on a VLAN interface) + * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station + * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the + * control port protocol ethertype. The device also honours the + * control_port_no_encrypt flag. + * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. + * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing + * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH. + * @WIPHY_FLAG_SUPPORTS_SCHED_SCAN: The device supports scheduled scans. + * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the + * firmware. + * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP. + * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation. + * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z) + * link setup/discovery operations internally. Setup, discovery and + * teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT + * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be + * used for asking the driver/firmware to perform a TDLS operation. + * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME + * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes + * when there are virtual interfaces in AP mode by calling + * cfg80211_report_obss_beacon(). + * @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device + * responds to probe-requests in hardware. + */ +enum wiphy_flags { + WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), + WIPHY_FLAG_STRICT_REGULATORY = BIT(1), + WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), + WIPHY_FLAG_NETNS_OK = BIT(3), + WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), + WIPHY_FLAG_4ADDR_AP = BIT(5), + WIPHY_FLAG_4ADDR_STATION = BIT(6), + WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), + WIPHY_FLAG_IBSS_RSN = BIT(8), + WIPHY_FLAG_MESH_AUTH = BIT(10), + WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), + WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), + WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), + WIPHY_FLAG_AP_UAPSD = BIT(14), + WIPHY_FLAG_SUPPORTS_TDLS = BIT(15), + WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16), + WIPHY_FLAG_HAVE_AP_SME = BIT(17), + WIPHY_FLAG_REPORTS_OBSS = BIT(18), + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19), + WIPHY_FLAG_SUPPORTS_ACS = BIT(20), +}; + +/** + * struct ieee80211_iface_limit - limit on certain interface types + * @max: maximum number of interfaces of these types + * @types: interface types (bits) + */ +struct ieee80211_iface_limit { + u16 max; + u16 types; +}; + +/** + * struct ieee80211_iface_combination - possible interface combination + * @limits: limits for the given interface types + * @n_limits: number of limitations + * @num_different_channels: can use up to this many different channels + * @max_interfaces: maximum number of interfaces in total allowed in this + * group + * @beacon_int_infra_match: In this combination, the beacon intervals + * between infrastructure and AP types must match. This is required + * only in special cases. + * + * These examples can be expressed as follows: + * + * Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total: + * + * struct ieee80211_iface_limit limits1[] = { + * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, + * { .max = 1, .types = BIT(NL80211_IFTYPE_AP}, }, + * }; + * struct ieee80211_iface_combination combination1 = { + * .limits = limits1, + * .n_limits = ARRAY_SIZE(limits1), + * .max_interfaces = 2, + * .beacon_int_infra_match = true, + * }; + * + * + * Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total: + * + * struct ieee80211_iface_limit limits2[] = { + * { .max = 8, .types = BIT(NL80211_IFTYPE_AP) | + * BIT(NL80211_IFTYPE_P2P_GO), }, + * }; + * struct ieee80211_iface_combination combination2 = { + * .limits = limits2, + * .n_limits = ARRAY_SIZE(limits2), + * .max_interfaces = 8, + * .num_different_channels = 1, + * }; + * + * + * Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total. + * This allows for an infrastructure connection and three P2P connections. + * + * struct ieee80211_iface_limit limits3[] = { + * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, + * { .max = 3, .types = BIT(NL80211_IFTYPE_P2P_GO) | + * BIT(NL80211_IFTYPE_P2P_CLIENT), }, + * }; + * struct ieee80211_iface_combination combination3 = { + * .limits = limits3, + * .n_limits = ARRAY_SIZE(limits3), + * .max_interfaces = 4, + * .num_different_channels = 2, + * }; + */ +struct ieee80211_iface_combination { + const struct ieee80211_iface_limit *limits; + u32 num_different_channels; + u16 max_interfaces; + u8 n_limits; + bool beacon_int_infra_match; +}; + +struct ieee80211_txrx_stypes { + u16 tx, rx; +}; + +/** + * enum wiphy_wowlan_support_flags - WoWLAN support flags + * @WIPHY_WOWLAN_ANY: supports wakeup for the special "any" + * trigger that keeps the device operating as-is and + * wakes up the host on any activity, for example a + * received packet that passed filtering; note that the + * packet should be preserved in that case + * @WIPHY_WOWLAN_MAGIC_PKT: supports wakeup on magic packet + * (see nl80211.h) + * @WIPHY_WOWLAN_DISCONNECT: supports wakeup on disconnect + * @WIPHY_WOWLAN_SUPPORTS_GTK_REKEY: supports GTK rekeying while asleep + * @WIPHY_WOWLAN_GTK_REKEY_FAILURE: supports wakeup on GTK rekey failure + * @WIPHY_WOWLAN_EAP_IDENTITY_REQ: supports wakeup on EAP identity request + * @WIPHY_WOWLAN_4WAY_HANDSHAKE: supports wakeup on 4-way handshake failure + * @WIPHY_WOWLAN_RFKILL_RELEASE: supports wakeup on RF-kill release + */ +enum wiphy_wowlan_support_flags { + WIPHY_WOWLAN_ANY = BIT(0), + WIPHY_WOWLAN_MAGIC_PKT = BIT(1), + WIPHY_WOWLAN_DISCONNECT = BIT(2), + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY = BIT(3), + WIPHY_WOWLAN_GTK_REKEY_FAILURE = BIT(4), + WIPHY_WOWLAN_EAP_IDENTITY_REQ = BIT(5), + WIPHY_WOWLAN_4WAY_HANDSHAKE = BIT(6), + WIPHY_WOWLAN_RFKILL_RELEASE = BIT(7), +}; + +/** + * struct wiphy_wowlan_support - WoWLAN support data + * @flags: see &enum wiphy_wowlan_support_flags + * @n_patterns: number of supported wakeup patterns + * (see nl80211.h for the pattern definition) + * @pattern_max_len: maximum length of each pattern + * @pattern_min_len: minimum length of each pattern + */ +struct wiphy_wowlan_support { + u32 flags; + int n_patterns; + int pattern_max_len; + int pattern_min_len; +}; + +/** + * struct wiphy - wireless hardware description + * @reg_notifier: the driver's regulatory notification callback, + * note that if your driver uses wiphy_apply_custom_regulatory() + * the reg_notifier's request can be passed as NULL + * @regd: the driver's regulatory domain, if one was requested via + * the regulatory_hint() API. This can be used by the driver + * on the reg_notifier() if it chooses to ignore future + * regulatory domain changes caused by other drivers. + * @signal_type: signal type reported in &struct cfg80211_bss. + * @cipher_suites: supported cipher suites + * @n_cipher_suites: number of supported cipher suites + * @retry_short: Retry limit for short frames (dot11ShortRetryLimit) + * @retry_long: Retry limit for long frames (dot11LongRetryLimit) + * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); + * -1 = fragmentation disabled, only odd values >= 256 used + * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled + * @_net: the network namespace this wiphy currently lives in + * @perm_addr: permanent MAC address of this device + * @addr_mask: If the device supports multiple MAC addresses by masking, + * set this to a mask with variable bits set to 1, e.g. if the last + * four bits are variable then set it to 00:...:00:0f. The actual + * variable bits shall be determined by the interfaces added, with + * interfaces not matching the mask being rejected to be brought up. + * @n_addresses: number of addresses in @addresses. + * @addresses: If the device has more than one address, set this pointer + * to a list of addresses (6 bytes each). The first one will be used + * by default for perm_addr. In this case, the mask should be set to + * all-zeroes. In this case it is assumed that the device can handle + * the same number of arbitrary MAC addresses. + * @registered: protects ->resume and ->suspend sysfs callbacks against + * unregister hardware + * @debugfsdir: debugfs directory used for this wiphy, will be renamed + * automatically on wiphy renames + * @dev: (virtual) struct device for this wiphy + * @registered: helps synchronize suspend/resume with wiphy unregister + * @wext: wireless extension handlers + * @priv: driver private data (sized according to wiphy_new() parameter) + * @interface_modes: bitmask of interfaces types valid for this wiphy, + * must be set by driver + * @iface_combinations: Valid interface combinations array, should not + * list single interface types. + * @n_iface_combinations: number of entries in @iface_combinations array. + * @software_iftypes: bitmask of software interface types, these are not + * subject to any restrictions since they are purely managed in SW. + * @flags: wiphy flags, see &enum wiphy_flags + * @features: features advertised to nl80211, see &enum nl80211_feature_flags. + * @bss_priv_size: each BSS struct has private data allocated with it, + * this variable determines its size + * @max_scan_ssids: maximum number of SSIDs the device can scan for in + * any given scan + * @max_sched_scan_ssids: maximum number of SSIDs the device can scan + * for in any given scheduled scan + * @max_match_sets: maximum number of match sets the device can handle + * when performing a scheduled scan, 0 if filtering is not + * supported. + * @max_scan_ie_len: maximum length of user-controlled IEs device can + * add to probe request frames transmitted during a scan, must not + * include fixed IEs like supported rates + * @max_sched_scan_ie_len: same as max_scan_ie_len, but for scheduled + * scans + * @coverage_class: current coverage class + * @fw_version: firmware version for ethtool reporting + * @hw_version: hardware version for ethtool reporting + * @max_num_pmkids: maximum number of PMKIDs supported by device + * @privid: a pointer that drivers can use to identify if an arbitrary + * wiphy is theirs, e.g. in global notifiers + * @bands: information about bands/channels supported by this device + * + * @mgmt_stypes: bitmasks of frame subtypes that can be subscribed to or + * transmitted through nl80211, points to an array indexed by interface + * type + * + * @available_antennas_tx: bitmap of antennas which are available to be + * configured as TX antennas. Antenna configuration commands will be + * rejected unless this or @available_antennas_rx is set. + * + * @available_antennas_rx: bitmap of antennas which are available to be + * configured as RX antennas. Antenna configuration commands will be + * rejected unless this or @available_antennas_tx is set. + * + * @max_remain_on_channel_duration: Maximum time a remain-on-channel operation + * may request, if implemented. + * + * @wowlan: WoWLAN support information + * + * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features. + * + * @max_acl_mac_addrs: Maximum number of mac addresses that the device + * supports for ACL. Driver having ACL based on MAC address support + * has to fill this. This limit is common for both (white and black) + * the acl policies. + */ +struct wiphy { + /* assign these fields before you register the wiphy */ + +#define WIPHY_COMPAT_PAD_SIZE 2048 + u8 padding[WIPHY_COMPAT_PAD_SIZE]; + + /* permanent MAC address(es) */ + u8 perm_addr[ETH_ALEN]; + u8 addr_mask[ETH_ALEN]; + + struct mac_address *addresses; + + const struct ieee80211_txrx_stypes *mgmt_stypes; + + const struct ieee80211_iface_combination *iface_combinations; + int n_iface_combinations; + u16 software_iftypes; + + u16 n_addresses; + + /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ + u16 interface_modes; + + u32 flags, features; + + u32 ap_sme_capa; + + enum cfg80211_signal_type signal_type; + + int bss_priv_size; + u8 max_scan_ssids; + u8 max_sched_scan_ssids; + u8 max_match_sets; + u16 max_scan_ie_len; + u16 max_sched_scan_ie_len; + + int n_cipher_suites; + const u32 *cipher_suites; + + u8 retry_short; + u8 retry_long; + u32 frag_threshold; + u32 rts_threshold; + u8 coverage_class; + + char fw_version[ETHTOOL_BUSINFO_LEN]; + u32 hw_version; + + struct wiphy_wowlan_support wowlan; + + u16 max_remain_on_channel_duration; + + u8 max_num_pmkids; + + u32 available_antennas_tx; + u32 available_antennas_rx; + + /* + * Bitmap of supported protocols for probe response offloading + * see &enum nl80211_probe_resp_offload_support_attr. Only valid + * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set. + */ + u32 probe_resp_offload; + + /* If multiple wiphys are registered and you're handed e.g. + * a regular netdev with assigned ieee80211_ptr, you won't + * know whether it points to a wiphy your driver has registered + * or not. Assign this to something global to your driver to + * help determine whether you own this wiphy or not. */ + const void *privid; + + struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; + + /* Lets us get back the wiphy on the callback */ + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request); + + /* fields below are read-only, assigned by cfg80211 */ + + const struct ieee80211_regdomain *regd; + + /* the item in /sys/class/ieee80211/ points to this, + * you need use set_wiphy_dev() (see below) */ + struct device dev; + + /* protects ->resume, ->suspend sysfs callbacks against unregister hw */ + bool registered; + + /* dir in debugfs: ieee80211/ */ + struct dentry *debugfsdir; + +#ifdef CONFIG_NET_NS + /* the network namespace this phy lives in currently */ + struct net *_net; +#endif + +#ifdef CONFIG_CFG80211_WEXT + const struct iw_handler_def *wext; +#endif + + /* + * Maximum number of mac address entries that device can + * support for access control based on mac address. + */ + u8 max_acl_mac_addrs; + + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +static inline struct net *wiphy_net(struct wiphy *wiphy) +{ + return read_pnet(&wiphy->_net); +} + +static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net) +{ + write_pnet(&wiphy->_net, net); +} + +/** + * wiphy_priv - return priv from wiphy + * + * @wiphy: the wiphy whose priv pointer to return + */ +static inline void *wiphy_priv(struct wiphy *wiphy) +{ + BUG_ON(!wiphy); + return &wiphy->priv; +} + +/** + * priv_to_wiphy - return the wiphy containing the priv + * + * @priv: a pointer previously returned by wiphy_priv + */ +static inline struct wiphy *priv_to_wiphy(void *priv) +{ + BUG_ON(!priv); + return container_of(priv, struct wiphy, priv); +} + +/** + * set_wiphy_dev - set device pointer for wiphy + * + * @wiphy: The wiphy whose device to bind + * @dev: The device to parent it to + */ +static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev) +{ + wiphy->dev.parent = dev; +} + +/** + * wiphy_dev - get wiphy dev pointer + * + * @wiphy: The wiphy whose device struct to look up + */ +static inline struct device *wiphy_dev(struct wiphy *wiphy) +{ + return wiphy->dev.parent; +} + +/** + * wiphy_name - get wiphy name + * + * @wiphy: The wiphy whose name to return + */ +static inline const char *wiphy_name(const struct wiphy *wiphy) +{ + return dev_name(&wiphy->dev); +} + +/** + * wiphy_new - create a new wiphy for use with cfg80211 + * + * @ops: The configuration operations for this device + * @sizeof_priv: The size of the private area to allocate + * + * Create a new wiphy and associate the given operations with it. + * @sizeof_priv bytes are allocated for private use. + * + * The returned pointer must be assigned to each netdev's + * ieee80211_ptr for proper operation. + */ +struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv); + +/** + * wiphy_register - register a wiphy with cfg80211 + * + * @wiphy: The wiphy to register. + * + * Returns a non-negative wiphy index or a negative error code. + */ +extern int wiphy_register(struct wiphy *wiphy); + +/** + * wiphy_unregister - deregister a wiphy from cfg80211 + * + * @wiphy: The wiphy to unregister. + * + * After this call, no more requests can be made with this priv + * pointer, but the call may sleep to wait for an outstanding + * request that is being handled. + */ +extern void wiphy_unregister(struct wiphy *wiphy); + +/** + * wiphy_free - free wiphy + * + * @wiphy: The wiphy to free + */ +extern void wiphy_free(struct wiphy *wiphy); + +/* internal structs */ +struct cfg80211_conn; +struct cfg80211_internal_bss; +struct cfg80211_cached_keys; + +#define MAX_AUTH_BSSES 4 + +/** + * struct wireless_dev - wireless per-netdev state + * + * This structure must be allocated by the driver/stack + * that uses the ieee80211_ptr field in struct net_device + * (this is intentional so it can be allocated along with + * the netdev.) + * + * @wiphy: pointer to hardware description + * @iftype: interface type + * @list: (private) Used to collect the interfaces + * @netdev: (private) Used to reference back to the netdev + * @current_bss: (private) Used by the internal configuration code + * @channel: (private) Used by the internal configuration code to track + * user-set AP, monitor and WDS channels for wireless extensions + * @bssid: (private) Used by the internal configuration code + * @ssid: (private) Used by the internal configuration code + * @ssid_len: (private) Used by the internal configuration code + * @mesh_id_len: (private) Used by the internal configuration code + * @mesh_id_up_len: (private) Used by the internal configuration code + * @wext: (private) Used by the internal wireless extensions compat code + * @use_4addr: indicates 4addr mode is used on this interface, must be + * set by driver (if supported) on add_interface BEFORE registering the + * netdev and may otherwise be used by driver read-only, will be update + * by cfg80211 on change_interface + * @mgmt_registrations: list of registrations for management frames + * @mgmt_registrations_lock: lock for the list + * @mtx: mutex used to lock data in this struct + * @cleanup_work: work struct used for cleanup that can't be done directly + * @beacon_interval: beacon interval used on this device for transmitting + * beacons, 0 when not valid + */ +struct wireless_dev { + struct wiphy *wiphy; + enum nl80211_iftype iftype; + + /* the remainder of this struct should be private to cfg80211 */ + struct list_head list; + struct net_device *netdev; + + struct list_head mgmt_registrations; + spinlock_t mgmt_registrations_lock; + + struct mutex mtx; + + struct work_struct cleanup_work; + + bool use_4addr; + + /* currently used for IBSS and SME - might be rearranged later */ + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len, mesh_id_len, mesh_id_up_len; + enum { + CFG80211_SME_IDLE, + CFG80211_SME_CONNECTING, + CFG80211_SME_CONNECTED, + } sme_state; + struct cfg80211_conn *conn; + struct cfg80211_cached_keys *connect_keys; + + struct list_head event_list; + spinlock_t event_lock; + + struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; + struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; + struct cfg80211_internal_bss *current_bss; /* associated / joined */ + struct ieee80211_channel *channel; + + bool ps; + int ps_timeout; + + int beacon_interval; + + u32 ap_unexpected_nlpid; + +#ifdef CONFIG_CFG80211_WEXT + /* wext data */ + struct { + struct cfg80211_ibss_params ibss; + struct cfg80211_connect_params connect; + struct cfg80211_cached_keys *keys; + u8 *ie; + size_t ie_len; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + s8 default_key, default_mgmt_key; + bool prev_bssid_valid; + } wext; +#endif +}; + +/** + * wdev_priv - return wiphy priv from wireless_dev + * + * @wdev: The wireless device whose wiphy's priv pointer to return + */ +static inline void *wdev_priv(struct wireless_dev *wdev) +{ + BUG_ON(!wdev); + return wiphy_priv(wdev->wiphy); +} + +/** + * DOC: Utility functions + * + * cfg80211 offers a number of utility functions that can be useful. + */ + +/** + * ieee80211_channel_to_frequency - convert channel number to frequency + * @chan: channel number + * @band: band, necessary due to channel number overlap + */ +extern int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band); + +/** + * ieee80211_frequency_to_channel - convert frequency to channel number + * @freq: center frequency + */ +extern int ieee80211_frequency_to_channel(int freq); + +/* + * Name indirection necessary because the ieee80211 code also has + * a function named "ieee80211_get_channel", so if you include + * cfg80211's header file you get cfg80211's version, if you try + * to include both header files you'll (rightfully!) get a symbol + * clash. + */ +extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, + int freq); +/** + * ieee80211_get_channel - get channel struct from wiphy for specified frequency + * @wiphy: the struct wiphy to get the channel for + * @freq: the center frequency of the channel + */ +static inline struct ieee80211_channel * +ieee80211_get_channel(struct wiphy *wiphy, int freq) +{ + return __ieee80211_get_channel(wiphy, freq); +} + +/** + * ieee80211_get_response_rate - get basic rate for a given rate + * + * @sband: the band to look for rates in + * @basic_rates: bitmap of basic rates + * @bitrate: the bitrate for which to find the basic rate + * + * This function returns the basic rate corresponding to a given + * bitrate, that is the next lower bitrate contained in the basic + * rate map, which is, for this function, given as a bitmap of + * indices of rates in the band's bitrate table. + */ +struct ieee80211_rate * +ieee80211_get_response_rate(struct ieee80211_supported_band *sband, + u32 basic_rates, int bitrate); + +/* + * Radiotap parsing functions -- for controlled injection support + * + * Implemented in net/wireless/radiotap.c + * Documentation in Documentation/networking/radiotap-headers.txt + */ + +struct radiotap_align_size { + uint8_t align:4, size:4; +}; + +struct ieee80211_radiotap_namespace { + const struct radiotap_align_size *align_size; + int n_bits; + uint32_t oui; + uint8_t subns; +}; + +struct ieee80211_radiotap_vendor_namespaces { + const struct ieee80211_radiotap_namespace *ns; + int n_ns; +}; + +/** + * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args + * @this_arg_index: index of current arg, valid after each successful call + * to ieee80211_radiotap_iterator_next() + * @this_arg: pointer to current radiotap arg; it is valid after each + * call to ieee80211_radiotap_iterator_next() but also after + * ieee80211_radiotap_iterator_init() where it will point to + * the beginning of the actual data portion + * @this_arg_size: length of the current arg, for convenience + * @current_namespace: pointer to the current namespace definition + * (or internally %NULL if the current namespace is unknown) + * @is_radiotap_ns: indicates whether the current namespace is the default + * radiotap namespace or not + * + * @_rtheader: pointer to the radiotap header we are walking through + * @_max_length: length of radiotap header in cpu byte ordering + * @_arg_index: next argument index + * @_arg: next argument pointer + * @_next_bitmap: internal pointer to next present u32 + * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present + * @_vns: vendor namespace definitions + * @_next_ns_data: beginning of the next namespace's data + * @_reset_on_ext: internal; reset the arg index to 0 when going to the + * next bitmap word + * + * Describes the radiotap parser state. Fields prefixed with an underscore + * must not be used by users of the parser, only by the parser internally. + */ + +struct ieee80211_radiotap_iterator { + struct ieee80211_radiotap_header *_rtheader; + const struct ieee80211_radiotap_vendor_namespaces *_vns; + const struct ieee80211_radiotap_namespace *current_namespace; + + unsigned char *_arg, *_next_ns_data; + __le32 *_next_bitmap; + + unsigned char *this_arg; + int this_arg_index; + int this_arg_size; + + int is_radiotap_ns; + + int _max_length; + int _arg_index; + uint32_t _bitmap_shifter; + int _reset_on_ext; +}; + +extern int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns); + +extern int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator); + + +extern const unsigned char rfc1042_header[6]; +extern const unsigned char bridge_tunnel_header[6]; + +/* Parsed Information Elements */ +struct ieee802_11_elems { + u8 *ie_start; + size_t total_len; + + /* pointers to IEs */ + u8 *ssid; + u8 *supp_rates; + u8 *fh_params; + u8 *ds_params; + u8 *cf_params; + struct ieee80211_tim_ie *tim; + u8 *ibss_params; + u8 *challenge; + u8 *wpa; + u8 *rsn; + u8 *erp_info; + u8 *ext_supp_rates; + u8 *wmm_info; + u8 *wmm_param; + struct ieee80211_ht_cap *ht_cap_elem; + struct ieee80211_ht_info *ht_info_elem; + struct ieee80211_meshconf_ie *mesh_config; + u8 *mesh_id; + u8 *peering; + u8 *preq; + u8 *prep; + u8 *perr; + struct ieee80211_rann_ie *rann; + u8 *ch_switch_elem; + u8 *country_elem; + u8 *pwr_constr_elem; + u8 *quiet_elem; /* first quite element */ + u8 *timeout_int; + + /* length of them, respectively */ + u8 ssid_len; + u8 supp_rates_len; + u8 fh_params_len; + u8 ds_params_len; + u8 cf_params_len; + u8 tim_len; + u8 ibss_params_len; + u8 challenge_len; + u8 wpa_len; + u8 rsn_len; + u8 erp_info_len; + u8 ext_supp_rates_len; + u8 wmm_info_len; + u8 wmm_param_len; + u8 mesh_id_len; + u8 peering_len; + u8 preq_len; + u8 prep_len; + u8 perr_len; + u8 ch_switch_elem_len; + u8 country_elem_len; + u8 pwr_constr_elem_len; + u8 quiet_elem_len; + u8 num_of_quiet_elem; /* can be more the one */ + u8 timeout_int_len; +}; + +/** + * ieee80211_get_hdrlen_from_skb - get header length from data + * + * Given an skb with a raw 802.11 header at the data pointer this function + * returns the 802.11 header length in bytes (not including encryption + * headers). If the data in the sk_buff is too short to contain a valid 802.11 + * header the function returns 0. + * + * @skb: the frame + */ +unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); + +/** + * ieee80211_hdrlen - get header length in bytes from frame control + * @fc: frame control field in little-endian format + */ +unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc); + +/** + * DOC: Data path helpers + * + * In addition to generic utilities, cfg80211 also offers + * functions that help implement the data path for devices + * that do not do the 802.11/802.3 conversion on the device. + */ + +/** + * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3 + * @skb: the 802.11 data frame + * @addr: the device MAC address + * @iftype: the virtual interface type + */ +int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, + enum nl80211_iftype iftype); + +/** + * ieee80211_data_from_8023 - convert an 802.3 frame to 802.11 + * @skb: the 802.3 frame + * @addr: the device MAC address + * @iftype: the virtual interface type + * @bssid: the network bssid (used only for iftype STATION and ADHOC) + * @qos: build 802.11 QoS data frame + */ +int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, + enum nl80211_iftype iftype, u8 *bssid, bool qos); + +/** + * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame + * + * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of + * 802.3 frames. The @list will be empty if the decode fails. The + * @skb is consumed after the function returns. + * + * @skb: The input IEEE 802.11n A-MSDU frame. + * @list: The output list of 802.3 frames. It must be allocated and + * initialized by by the caller. + * @addr: The device MAC address. + * @iftype: The device interface type. + * @extra_headroom: The hardware extra headroom for SKBs in the @list. + * @has_80211_header: Set it true if SKB is with IEEE 802.11 header. + */ +void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, + const u8 *addr, enum nl80211_iftype iftype, + const unsigned int extra_headroom, + bool has_80211_header); + +/** + * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame + * @skb: the data frame + */ +unsigned int cfg80211_classify8021d(struct sk_buff *skb); + +/** + * cfg80211_find_ie - find information element in data + * + * @eid: element ID + * @ies: data consisting of IEs + * @len: length of data + * + * This function will return %NULL if the element ID could + * not be found or if the element is invalid (claims to be + * longer than the given data), or a pointer to the first byte + * of the requested element, that is the byte containing the + * element ID. There are no checks on the element length + * other than having to fit into the given data. + */ +const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len); + +/** + * cfg80211_find_vendor_ie - find vendor specific information element in data + * + * @oui: vendor OUI + * @oui_type: vendor-specific OUI type + * @ies: data consisting of IEs + * @len: length of data + * + * This function will return %NULL if the vendor specific element ID + * could not be found or if the element is invalid (claims to be + * longer than the given data), or a pointer to the first byte + * of the requested element, that is the byte containing the + * element ID. There are no checks on the element length + * other than having to fit into the given data. + */ +const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, + const u8 *ies, int len); + +/** + * DOC: Regulatory enforcement infrastructure + * + * TODO + */ + +/** + * regulatory_hint - driver hint to the wireless core a regulatory domain + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) + * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain + * should be in. If @rd is set this should be NULL. Note that if you + * set this to NULL you should still set rd->alpha2 to some accepted + * alpha2. + * + * Wireless drivers can use this function to hint to the wireless core + * what it believes should be the current regulatory domain by + * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory + * domain should be in or by providing a completely build regulatory domain. + * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried + * for a regulatory domain structure for the respective country. + * + * The wiphy must have been registered to cfg80211 prior to this call. + * For cfg80211 drivers this means you must first use wiphy_register(), + * for mac80211 drivers you must first use ieee80211_register_hw(). + * + * Drivers should check the return value, its possible you can get + * an -ENOMEM. + */ +extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2); + +/** + * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain + * @wiphy: the wireless device we want to process the regulatory domain on + * @regd: the custom regulatory domain to use for this wiphy + * + * Drivers can sometimes have custom regulatory domains which do not apply + * to a specific country. Drivers can use this to apply such custom regulatory + * domains. This routine must be called prior to wiphy registration. The + * custom regulatory domain will be trusted completely and as such previous + * default channel settings will be disregarded. If no rule is found for a + * channel on the regulatory domain the channel will be disabled. + */ +extern void wiphy_apply_custom_regulatory( + struct wiphy *wiphy, + const struct ieee80211_regdomain *regd); + +/** + * freq_reg_info - get regulatory information for the given frequency + * @wiphy: the wiphy for which we want to process this rule for + * @center_freq: Frequency in KHz for which we want regulatory information for + * @desired_bw_khz: the desired max bandwidth you want to use per + * channel. Note that this is still 20 MHz if you want to use HT40 + * as HT40 makes use of two channels for its 40 MHz width bandwidth. + * If set to 0 we'll assume you want the standard 20 MHz. + * @reg_rule: the regulatory rule which we have for this frequency + * + * Use this function to get the regulatory rule for a specific frequency on + * a given wireless device. If the device has a specific regulatory domain + * it wants to follow we respect that unless a country IE has been received + * and processed already. + * + * Returns 0 if it was able to find a valid regulatory rule which does + * apply to the given center_freq otherwise it returns non-zero. It will + * also return -ERANGE if we determine the given center_freq does not even have + * a regulatory rule for a frequency range in the center_freq's band. See + * freq_in_rule_band() for our current definition of a band -- this is purely + * subjective and right now its 802.11 specific. + */ +extern int freq_reg_info(struct wiphy *wiphy, + u32 center_freq, + u32 desired_bw_khz, + const struct ieee80211_reg_rule **reg_rule); + +/* + * callbacks for asynchronous cfg80211 methods, notification + * functions and BSS handling helpers + */ + +/** + * cfg80211_scan_done - notify that scan finished + * + * @request: the corresponding scan request + * @aborted: set to true if the scan was aborted for any reason, + * userspace will be notified of that + */ +void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted); + +/** + * cfg80211_sched_scan_results - notify that new scan results are available + * + * @wiphy: the wiphy which got scheduled scan results + */ +void cfg80211_sched_scan_results(struct wiphy *wiphy); + +/** + * cfg80211_sched_scan_stopped - notify that the scheduled scan has stopped + * + * @wiphy: the wiphy on which the scheduled scan stopped + * + * The driver can call this function to inform cfg80211 that the + * scheduled scan had to be stopped, for whatever reason. The driver + * is then called back via the sched_scan_stop operation when done. + */ +void cfg80211_sched_scan_stopped(struct wiphy *wiphy); + +/** + * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame + * + * @wiphy: the wiphy reporting the BSS + * @channel: The channel the frame was received on + * @mgmt: the management frame (probe response or beacon) + * @len: length of the management frame + * @signal: the signal strength, type depends on the wiphy's signal_type + * @gfp: context flags + * + * This informs cfg80211 that BSS information was found and + * the BSS should be updated/added. + * + * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()! + */ +struct cfg80211_bss * __must_check +cfg80211_inform_bss_frame(struct wiphy *wiphy, + struct ieee80211_channel *channel, + struct ieee80211_mgmt *mgmt, size_t len, + s32 signal, gfp_t gfp); + +/** + * cfg80211_inform_bss - inform cfg80211 of a new BSS + * + * @wiphy: the wiphy reporting the BSS + * @channel: The channel the frame was received on + * @bssid: the BSSID of the BSS + * @timestamp: the TSF timestamp sent by the peer + * @capability: the capability field sent by the peer + * @beacon_interval: the beacon interval announced by the peer + * @ie: additional IEs sent by the peer + * @ielen: length of the additional IEs + * @signal: the signal strength, type depends on the wiphy's signal_type + * @gfp: context flags + * + * This informs cfg80211 that BSS information was found and + * the BSS should be updated/added. + * + * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()! + */ +struct cfg80211_bss * __must_check +cfg80211_inform_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + u64 timestamp, u16 capability, u16 beacon_interval, + const u8 *ie, size_t ielen, + s32 signal, gfp_t gfp); + +struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len, + u16 capa_mask, u16 capa_val); +static inline struct cfg80211_bss * +cfg80211_get_ibss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *ssid, size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len, + WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); +} + +struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *meshid, size_t meshidlen, + const u8 *meshcfg); +void cfg80211_put_bss(struct cfg80211_bss *bss); + +/** + * cfg80211_unlink_bss - unlink BSS from internal data structures + * @wiphy: the wiphy + * @bss: the bss to remove + * + * This function removes the given BSS from the internal data structures + * thereby making it no longer show up in scan results etc. Use this + * function when you detect a BSS is gone. Normally BSSes will also time + * out, so it is not necessary to use this function at all. + */ +void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); + +void cfg80211_unlink_allbss(struct wiphy *wiphy); + +/** + * cfg80211_send_rx_auth - notification of processed authentication + * @dev: network device + * @buf: authentication frame (header + body) + * @len: length of the frame data + * + * This function is called whenever an authentication has been processed in + * station mode. The driver is required to call either this function or + * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth() + * call. This function may sleep. + */ +void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); + +/** + * cfg80211_send_auth_timeout - notification of timed out authentication + * @dev: network device + * @addr: The MAC address of the device with which the authentication timed out + * + * This function may sleep. + */ +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); + +/** + * __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled + * @dev: network device + * @addr: The MAC address of the device with which the authentication timed out + * + * When a pending authentication had no action yet, the driver may decide + * to not send a deauth frame, but in that case must calls this function + * to tell cfg80211 about this decision. It is only valid to call this + * function within the deauth() callback. + */ +void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr); + +/** + * cfg80211_send_rx_assoc - notification of processed association + * @dev: network device + * @buf: (re)association response frame (header + body) + * @len: length of the frame data + * + * This function is called whenever a (re)association response has been + * processed in station mode. The driver is required to call either this + * function or cfg80211_send_assoc_timeout() to indicate the result of + * cfg80211_ops::assoc() call. This function may sleep. + */ +void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); + +/** + * cfg80211_send_assoc_timeout - notification of timed out association + * @dev: network device + * @addr: The MAC address of the device with which the association timed out + * + * This function may sleep. + */ +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); + +/** + * cfg80211_send_deauth - notification of processed deauthentication + * @dev: network device + * @buf: deauthentication frame (header + body) + * @len: length of the frame data + * + * This function is called whenever deauthentication has been processed in + * station mode. This includes both received deauthentication frames and + * locally generated ones. This function may sleep. + */ +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); + +/** + * __cfg80211_send_deauth - notification of processed deauthentication + * @dev: network device + * @buf: deauthentication frame (header + body) + * @len: length of the frame data + * + * Like cfg80211_send_deauth(), but doesn't take the wdev lock. + */ +void __cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); + +/** + * cfg80211_send_disassoc - notification of processed disassociation + * @dev: network device + * @buf: disassociation response frame (header + body) + * @len: length of the frame data + * + * This function is called whenever disassociation has been processed in + * station mode. This includes both received disassociation frames and locally + * generated ones. This function may sleep. + */ +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); + +/** + * __cfg80211_send_disassoc - notification of processed disassociation + * @dev: network device + * @buf: disassociation response frame (header + body) + * @len: length of the frame data + * + * Like cfg80211_send_disassoc(), but doesn't take the wdev lock. + */ +void __cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, + size_t len); + +/** + * cfg80211_send_unprot_deauth - notification of unprotected deauthentication + * @dev: network device + * @buf: deauthentication frame (header + body) + * @len: length of the frame data + * + * This function is called whenever a received Deauthentication frame has been + * dropped in station mode because of MFP being used but the Deauthentication + * frame was not protected. This function may sleep. + */ +void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, + size_t len); + +/** + * cfg80211_send_unprot_disassoc - notification of unprotected disassociation + * @dev: network device + * @buf: disassociation frame (header + body) + * @len: length of the frame data + * + * This function is called whenever a received Disassociation frame has been + * dropped in station mode because of MFP being used but the Disassociation + * frame was not protected. This function may sleep. + */ +void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, + size_t len); + +/** + * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) + * @dev: network device + * @addr: The source MAC address of the frame + * @key_type: The key type that the received frame used + * @key_id: Key identifier (0..3). Can be -1 if missing. + * @tsc: The TSC value of the frame that generated the MIC failure (6 octets) + * @gfp: allocation flags + * + * This function is called whenever the local MAC detects a MIC failure in a + * received frame. This matches with MLME-MICHAELMICFAILURE.indication() + * primitive. + */ +void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc, gfp_t gfp); + +/** + * cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS + * + * @dev: network device + * @bssid: the BSSID of the IBSS joined + * @gfp: allocation flags + * + * This function notifies cfg80211 that the device joined an IBSS or + * switched to a different BSSID. Before this function can be called, + * either a beacon has to have been received from the IBSS, or one of + * the cfg80211_inform_bss{,_frame} functions must have been called + * with the locally generated beacon -- this guarantees that there is + * always a scan result for this IBSS. cfg80211 will handle the rest. + */ +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); + +/** + * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate + * + * @dev: network device + * @macaddr: the MAC address of the new candidate + * @ie: information elements advertised by the peer candidate + * @ie_len: lenght of the information elements buffer + * @gfp: allocation flags + * + * This function notifies cfg80211 that the mesh peer candidate has been + * detected, most likely via a beacon or, less likely, via a probe response. + * cfg80211 then sends a notification to userspace. + */ +void cfg80211_notify_new_peer_candidate(struct net_device *dev, + const u8 *macaddr, const u8 *ie, u8 ie_len, gfp_t gfp); + +/** + * DOC: RFkill integration + * + * RFkill integration in cfg80211 is almost invisible to drivers, + * as cfg80211 automatically registers an rfkill instance for each + * wireless device it knows about. Soft kill is also translated + * into disconnecting and turning all interfaces off, drivers are + * expected to turn off the device when all interfaces are down. + * + * However, devices may have a hard RFkill line, in which case they + * also need to interact with the rfkill subsystem, via cfg80211. + * They can do this with a few helper functions documented here. + */ + +/** + * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state + * @wiphy: the wiphy + * @blocked: block status + */ +void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked); + +/** + * wiphy_rfkill_start_polling - start polling rfkill + * @wiphy: the wiphy + */ +void wiphy_rfkill_start_polling(struct wiphy *wiphy); + +/** + * wiphy_rfkill_stop_polling - stop polling rfkill + * @wiphy: the wiphy + */ +void wiphy_rfkill_stop_polling(struct wiphy *wiphy); + +#ifdef CONFIG_NL80211_TESTMODE +/** + * DOC: Test mode + * + * Test mode is a set of utility functions to allow drivers to + * interact with driver-specific tools to aid, for instance, + * factory programming. + * + * This chapter describes how drivers interact with it, for more + * information see the nl80211 book's chapter on it. + */ + +/** + * cfg80211_testmode_alloc_reply_skb - allocate testmode reply + * @wiphy: the wiphy + * @approxlen: an upper bound of the length of the data that will + * be put into the skb + * + * This function allocates and pre-fills an skb for a reply to + * the testmode command. Since it is intended for a reply, calling + * it outside of the @testmode_cmd operation is invalid. + * + * The returned skb (or %NULL if any errors happen) is pre-filled + * with the wiphy index and set up in a way that any data that is + * put into the skb (with skb_put(), nla_put() or similar) will end + * up being within the %NL80211_ATTR_TESTDATA attribute, so all that + * needs to be done with the skb is adding data for the corresponding + * userspace tool which can then read that data out of the testdata + * attribute. You must not modify the skb in any other way. + * + * When done, call cfg80211_testmode_reply() with the skb and return + * its error code as the result of the @testmode_cmd operation. + */ +struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, + int approxlen); + +/** + * cfg80211_testmode_reply - send the reply skb + * @skb: The skb, must have been allocated with + * cfg80211_testmode_alloc_reply_skb() + * + * Returns an error code or 0 on success, since calling this + * function will usually be the last thing before returning + * from the @testmode_cmd you should return the error code. + * Note that this function consumes the skb regardless of the + * return value. + */ +int cfg80211_testmode_reply(struct sk_buff *skb); + +/** + * cfg80211_testmode_alloc_event_skb - allocate testmode event + * @wiphy: the wiphy + * @approxlen: an upper bound of the length of the data that will + * be put into the skb + * @gfp: allocation flags + * + * This function allocates and pre-fills an skb for an event on the + * testmode multicast group. + * + * The returned skb (or %NULL if any errors happen) is set up in the + * same way as with cfg80211_testmode_alloc_reply_skb() but prepared + * for an event. As there, you should simply add data to it that will + * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must + * not modify the skb in any other way. + * + * When done filling the skb, call cfg80211_testmode_event() with the + * skb to send the event. + */ +struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, + int approxlen, gfp_t gfp); + +/** + * cfg80211_testmode_event - send the event + * @skb: The skb, must have been allocated with + * cfg80211_testmode_alloc_event_skb() + * @gfp: allocation flags + * + * This function sends the given @skb, which must have been allocated + * by cfg80211_testmode_alloc_event_skb(), as an event. It always + * consumes it. + */ +void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp); + +#define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd), +#define CFG80211_TESTMODE_DUMP(cmd) .testmode_dump = (cmd), +#else +#define CFG80211_TESTMODE_CMD(cmd) +#define CFG80211_TESTMODE_DUMP(cmd) +#endif + +/** + * cfg80211_connect_result - notify cfg80211 of connection result + * + * @dev: network device + * @bssid: the BSSID of the AP + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @status: status code, 0 for successful connection, use + * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you + * the real status code for failures. + * @gfp: allocation flags + * + * It should be called by the underlying driver whenever connect() has + * succeeded. + */ +void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp); + +/** + * cfg80211_roamed - notify cfg80211 of roaming + * + * @dev: network device + * @channel: the channel of the new AP + * @bssid: the BSSID of the new AP + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @gfp: allocation flags + * + * It should be called by the underlying driver whenever it roamed + * from one AP to another while connected. + */ +void cfg80211_roamed(struct net_device *dev, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); + +/** + * cfg80211_roamed_bss - notify cfg80211 of roaming + * + * @dev: network device + * @bss: entry of bss to which STA got roamed + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @gfp: allocation flags + * + * This is just a wrapper to notify cfg80211 of roaming event with driver + * passing bss to avoid a race in timeout of the bss entry. It should be + * called by the underlying driver whenever it roamed from one AP to another + * while connected. Drivers which have roaming implemented in firmware + * may use this function to avoid a race in bss entry timeout where the bss + * entry of the new AP is seen in the driver, but gets timed out by the time + * it is accessed in __cfg80211_roamed() due to delay in scheduling + * rdev->event_work. In case of any failures, the reference is released + * either in cfg80211_roamed_bss() or in __cfg80211_romed(), Otherwise, + * it will be released while diconneting from the current bss. + */ +void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); + +/** + * cfg80211_disconnected - notify cfg80211 that connection was dropped + * + * @dev: network device + * @ie: information elements of the deauth/disassoc frame (may be %NULL) + * @ie_len: length of IEs + * @reason: reason code for the disconnection, set it to 0 if unknown + * @gfp: allocation flags + * + * After it calls this function, the driver should enter an idle state + * and not try to connect to any AP any more. + */ +void cfg80211_disconnected(struct net_device *dev, u16 reason, + u8 *ie, size_t ie_len, gfp_t gfp); + +/** + * cfg80211_ready_on_channel - notification of remain_on_channel start + * @dev: network device + * @cookie: the request cookie + * @chan: The current channel (from remain_on_channel request) + * @channel_type: Channel type + * @duration: Duration in milliseconds that the driver intents to remain on the + * channel + * @gfp: allocation flags + */ +void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp); + +/** + * cfg80211_remain_on_channel_expired - remain_on_channel duration expired + * @dev: network device + * @cookie: the request cookie + * @chan: The current channel (from remain_on_channel request) + * @channel_type: Channel type + * @gfp: allocation flags + */ +void cfg80211_remain_on_channel_expired(struct net_device *dev, + u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + gfp_t gfp); + + +/** + * cfg80211_new_sta - notify userspace about station + * + * @dev: the netdev + * @mac_addr: the station's address + * @sinfo: the station information + * @gfp: allocation flags + */ +void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp); + +/** + * cfg80211_del_sta - notify userspace about deletion of a station + * + * @dev: the netdev + * @mac_addr: the station's address + * @gfp: allocation flags + */ +void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); + +/** + * cfg80211_conn_failed - connection request failed notification + * + * @dev: the netdev + * @mac_addr: the station's address + * @reason: the reason for connection failure + * @gfp: allocation flags + * + * Whenever a station tries to connect to an AP and if the station + * could not connect to the AP as the AP has rejected the connection + * for some reasons, this function is called. + * + * The reason for connection failure can be any of the value from + * nl80211_connect_failed_reason enum + */ +void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, + enum nl80211_connect_failed_reason reason, + gfp_t gfp); + +/** + * cfg80211_rx_mgmt - notification of received, unprocessed management frame + * @dev: network device + * @freq: Frequency on which the frame was received in MHz + * @buf: Management frame (header + body) + * @len: length of the frame data + * @gfp: context flags + * + * Returns %true if a user space application has registered for this frame. + * For action frames, that makes it responsible for rejecting unrecognized + * action frames; %false otherwise, in which case for action frames the + * driver is responsible for rejecting the frame. + * + * This function is called whenever an Action frame is received for a station + * mode interface, but is not processed in kernel. + */ +bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, + size_t len, gfp_t gfp); + +/** + * cfg80211_mgmt_tx_status - notification of TX status for management frame + * @dev: network device + * @cookie: Cookie returned by cfg80211_ops::mgmt_tx() + * @buf: Management frame (header + body) + * @len: length of the frame data + * @ack: Whether frame was acknowledged + * @gfp: context flags + * + * This function is called whenever a management frame was requested to be + * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the + * transmission attempt. + */ +void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, + const u8 *buf, size_t len, bool ack, gfp_t gfp); + + +/** + * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event + * @dev: network device + * @rssi_event: the triggered RSSI event + * @gfp: context flags + * + * This function is called when a configured connection quality monitoring + * rssi threshold reached event occurs. + */ +void cfg80211_cqm_rssi_notify(struct net_device *dev, + enum nl80211_cqm_rssi_threshold_event rssi_event, + gfp_t gfp); + +/** + * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer + * @dev: network device + * @peer: peer's MAC address + * @num_packets: how many packets were lost -- should be a fixed threshold + * but probably no less than maybe 50, or maybe a throughput dependent + * threshold (to account for temporary interference) + * @gfp: context flags + */ +void cfg80211_cqm_pktloss_notify(struct net_device *dev, + const u8 *peer, u32 num_packets, gfp_t gfp); + +/** + * cfg80211_cqm_txe_notify - TX error rate event + * @dev: network device + * @peer: peer's MAC address + * @num_packets: how many packets were lost + * @rate: % of packets which failed transmission + * @intvl: interval (in s) over which the TX failure threshold was breached. + * @gfp: context flags + * + * Notify userspace when configured % TX failures over number of packets in a + * given interval is exceeded. + */ +void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer, + u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); + +/** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying + * @dev: network device + * @bssid: BSSID of AP (to avoid races) + * @replay_ctr: new replay counter + * @gfp: allocation flags + */ +void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp); + +/** + * cfg80211_pmksa_candidate_notify - notify about PMKSA caching candidate + * @dev: network device + * @index: candidate index (the smaller the index, the higher the priority) + * @bssid: BSSID of AP + * @preauth: Whether AP advertises support for RSN pre-authentication + * @gfp: allocation flags + */ +void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, + const u8 *bssid, bool preauth, gfp_t gfp); + +/** + * cfg80211_rx_spurious_frame - inform userspace about a spurious frame + * @dev: The device the frame matched to + * @addr: the transmitter address + * @gfp: context flags + * + * This function is used in AP mode (only!) to inform userspace that + * a spurious class 3 frame was received, to be able to deauth the + * sender. + * Returns %true if the frame was passed to userspace (or this failed + * for a reason other than not having a subscription.) + */ +bool cfg80211_rx_spurious_frame(struct net_device *dev, + const u8 *addr, gfp_t gfp); + +/** + * cfg80211_rx_unexpected_4addr_frame - inform about unexpected WDS frame + * @dev: The device the frame matched to + * @addr: the transmitter address + * @gfp: context flags + * + * This function is used in AP mode (only!) to inform userspace that + * an associated station sent a 4addr frame but that wasn't expected. + * It is allowed and desirable to send this event only once for each + * station to avoid event flooding. + * Returns %true if the frame was passed to userspace (or this failed + * for a reason other than not having a subscription.) + */ +bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, + const u8 *addr, gfp_t gfp); + +/** + * cfg80211_probe_status - notify userspace about probe status + * @dev: the device the probe was sent on + * @addr: the address of the peer + * @cookie: the cookie filled in @probe_client previously + * @acked: indicates whether probe was acked or not + * @gfp: allocation flags + */ +void cfg80211_probe_status(struct net_device *dev, const u8 *addr, + u64 cookie, bool acked, gfp_t gfp); + +/** + * cfg80211_report_obss_beacon - report beacon from other APs + * @wiphy: The wiphy that received the beacon + * @frame: the frame + * @len: length of the frame + * @freq: frequency the frame was received on + * @gfp: allocation flags + * + * Use this function to report to userspace when a beacon was + * received. It is not useful to call this when there is no + * netdev that is in AP/GO mode. + */ +void cfg80211_report_obss_beacon(struct wiphy *wiphy, + const u8 *frame, size_t len, + int freq, gfp_t gfp); + +/* + * cfg80211_ch_switch_notify - update wdev channel and notify userspace + * @dev: the device which switched channels + * @freq: new channel frequency (in MHz) + * @type: channel type + * + * Acquires wdev_lock, so must only be called from sleepable driver context! + */ +void cfg80211_ch_switch_notify(struct net_device *dev, int freq, + enum nl80211_channel_type type); + +/* Logging, debugging and troubleshooting/diagnostic helpers. */ + +/* wiphy_printk helpers, similar to dev_printk */ + +#define wiphy_printk(level, wiphy, format, args...) \ + dev_printk(level, &(wiphy)->dev, format, ##args) +#define wiphy_emerg(wiphy, format, args...) \ + dev_emerg(&(wiphy)->dev, format, ##args) +#define wiphy_alert(wiphy, format, args...) \ + dev_alert(&(wiphy)->dev, format, ##args) +#define wiphy_crit(wiphy, format, args...) \ + dev_crit(&(wiphy)->dev, format, ##args) +#define wiphy_err(wiphy, format, args...) \ + dev_err(&(wiphy)->dev, format, ##args) +#define wiphy_warn(wiphy, format, args...) \ + dev_warn(&(wiphy)->dev, format, ##args) +#define wiphy_notice(wiphy, format, args...) \ + dev_notice(&(wiphy)->dev, format, ##args) +#define wiphy_info(wiphy, format, args...) \ + dev_info(&(wiphy)->dev, format, ##args) + +#define wiphy_debug(wiphy, format, args...) \ + wiphy_printk(KERN_DEBUG, wiphy, format, ##args) + +#define wiphy_dbg(wiphy, format, args...) \ + dev_dbg(&(wiphy)->dev, format, ##args) + +#if defined(VERBOSE_DEBUG) +#define wiphy_vdbg wiphy_dbg +#else +#define wiphy_vdbg(wiphy, format, args...) \ +({ \ + if (0) \ + wiphy_printk(KERN_DEBUG, wiphy, format, ##args); \ + 0; \ +}) +#endif + +/* + * wiphy_WARN() acts like wiphy_printk(), but with the key difference + * of using a WARN/WARN_ON to get the message out, including the + * file/line information and a backtrace. + */ +#define wiphy_WARN(wiphy, format, args...) \ + WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args); + +#endif /* __NET_CFG80211_H */ diff --git a/include/compat/net/ieee80211_radiotap.h b/include/compat/net/ieee80211_radiotap.h new file mode 100644 index 00000000..71392545 --- /dev/null +++ b/include/compat/net/ieee80211_radiotap.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2003, 2004 David Young. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of David Young may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID + * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* + * Modifications to fit into the linux IEEE 802.11 stack, + * Mike Kershaw (dragorn@kismetwireless.net) + */ + +#ifndef IEEE80211RADIOTAP_H +#define IEEE80211RADIOTAP_H + +#include +#include +#include + +/* Base version of the radiotap packet header data */ +#define PKTHDR_RADIOTAP_VERSION 0 + +/* A generic radio capture format is desirable. There is one for + * Linux, but it is neither rigidly defined (there were not even + * units given for some fields) nor easily extensible. + * + * I suggest the following extensible radio capture format. It is + * based on a bitmap indicating which fields are present. + * + * I am trying to describe precisely what the application programmer + * should expect in the following, and for that reason I tell the + * units and origin of each measurement (where it applies), or else I + * use sufficiently weaselly language ("is a monotonically nondecreasing + * function of...") that I cannot set false expectations for lawyerly + * readers. + */ + +/* + * The radio capture header precedes the 802.11 header. + * All data in the header is little endian on all platforms. + */ +struct ieee80211_radiotap_header { + u8 it_version; /* Version 0. Only increases + * for drastic changes, + * introduction of compatible + * new fields does not count. + */ + u8 it_pad; + __le16 it_len; /* length of the whole + * header in bytes, including + * it_version, it_pad, + * it_len, and data fields. + */ + __le32 it_present; /* A bitmap telling which + * fields are present. Set bit 31 + * (0x80000000) to extend the + * bitmap by another 32 bits. + * Additional extensions are made + * by setting bit 31. + */ +} __packed; + +/* Name Data type Units + * ---- --------- ----- + * + * IEEE80211_RADIOTAP_TSFT __le64 microseconds + * + * Value in microseconds of the MAC's 64-bit 802.11 Time + * Synchronization Function timer when the first bit of the + * MPDU arrived at the MAC. For received frames, only. + * + * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap + * + * Tx/Rx frequency in MHz, followed by flags (see below). + * + * IEEE80211_RADIOTAP_FHSS __le16 see below + * + * For frequency-hopping radios, the hop set (first byte) + * and pattern (second byte). + * + * IEEE80211_RADIOTAP_RATE u8 500kb/s + * + * Tx/Rx data rate + * + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from + * one milliwatt (dBm) + * + * RF signal power at the antenna, decibel difference from + * one milliwatt. + * + * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from + * one milliwatt (dBm) + * + * RF noise power at the antenna, decibel difference from one + * milliwatt. + * + * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) + * + * RF signal power at the antenna, decibel difference from an + * arbitrary, fixed reference. + * + * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) + * + * RF noise power at the antenna, decibel difference from an + * arbitrary, fixed reference point. + * + * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless + * + * Quality of Barker code lock. Unitless. Monotonically + * nondecreasing with "better" lock strength. Called "Signal + * Quality" in datasheets. (Is there a standard way to measure + * this?) + * + * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless + * + * Transmit power expressed as unitless distance from max + * power set at factory calibration. 0 is max power. + * Monotonically nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB) + * + * Transmit power expressed as decibel distance from max power + * set at factory calibration. 0 is max power. Monotonically + * nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from + * one milliwatt (dBm) + * + * Transmit power expressed as dBm (decibels from a 1 milliwatt + * reference). This is the absolute power level measured at + * the antenna port. + * + * IEEE80211_RADIOTAP_FLAGS u8 bitmap + * + * Properties of transmitted and received frames. See flags + * defined below. + * + * IEEE80211_RADIOTAP_ANTENNA u8 antenna index + * + * Unitless indication of the Rx/Tx antenna for this packet. + * The first antenna is antenna 0. + * + * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap + * + * Properties of received frames. See flags defined below. + * + * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap + * + * Properties of transmitted frames. See flags defined below. + * + * IEEE80211_RADIOTAP_RTS_RETRIES u8 data + * + * Number of rts retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_DATA_RETRIES u8 data + * + * Number of unicast retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless + * + * Contains a bitmap of known fields/flags, the flags, and + * the MCS index. + * + */ +enum ieee80211_radiotap_type { + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + IEEE80211_RADIOTAP_ANTENNA = 11, + IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + + IEEE80211_RADIOTAP_MCS = 19, + + /* valid in every it_present bitmap, even vendor namespaces */ + IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, + IEEE80211_RADIOTAP_EXT = 31 +}; + +/* Channel flags. */ +#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ + +/* For IEEE80211_RADIOTAP_FLAGS */ +#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received + * during CFP + */ +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received + * with short + * preamble + */ +#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received + * with WEP encryption + */ +#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received + * with fragmentation + */ +#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between + * 802.11 header and payload + * (to 32-bit boundary) + */ +#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* bad FCS */ + +/* For IEEE80211_RADIOTAP_RX_FLAGS */ +#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* frame has bad PLCP */ + +/* For IEEE80211_RADIOTAP_TX_FLAGS */ +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive + * retries */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ +#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ack */ + + +/* For IEEE80211_RADIOTAP_MCS */ +#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01 +#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02 +#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 +#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 +#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 + +#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 +#define IEEE80211_RADIOTAP_MCS_BW_20 0 +#define IEEE80211_RADIOTAP_MCS_BW_40 1 +#define IEEE80211_RADIOTAP_MCS_BW_20L 2 +#define IEEE80211_RADIOTAP_MCS_BW_20U 3 +#define IEEE80211_RADIOTAP_MCS_SGI 0x04 +#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 +#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 + + +/* helpers */ +static inline int ieee80211_get_radiotap_len(unsigned char *data) +{ + struct ieee80211_radiotap_header *hdr = + (struct ieee80211_radiotap_header *)data; + + return get_unaligned_le16(&hdr->it_len); +} + +#endif /* IEEE80211_RADIOTAP_H */ diff --git a/include/compat/net/lib80211.h b/include/compat/net/lib80211.h new file mode 100644 index 00000000..d178c26a --- /dev/null +++ b/include/compat/net/lib80211.h @@ -0,0 +1,124 @@ +/* + * lib80211.h -- common bits for IEEE802.11 wireless drivers + * + * Copyright (c) 2008, John W. Linville + * + * Some bits copied from old ieee80211 component, w/ original copyright + * notices below: + * + * Original code based on Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * + * Copyright (c) 2004, Intel Corporation + * + */ + +#ifndef LIB80211_H +#define LIB80211_H + +#include +#include +#include +#include +#include +#include +#include +/* print_ssid() is intended to be used in debug (and possibly error) + * messages. It should never be used for passing ssid to user space. */ +const char *print_ssid(char *buf, const char *ssid, u8 ssid_len); +#define DECLARE_SSID_BUF(var) char var[IEEE80211_MAX_SSID_LEN * 4 + 1] __maybe_unused + +#define NUM_WEP_KEYS 4 + +enum { + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0), +}; + +struct module; + +struct lib80211_crypto_ops { + const char *name; + struct list_head list; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void *(*init) (int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit) (void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key) (void *key, int len, u8 * seq, void *priv); + int (*get_key) (void *key, int len, u8 * seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + char *(*print_stats) (char *p, void *priv); + + /* Crypto specific flag get/set for configuration settings */ + unsigned long (*get_flags) (void *priv); + unsigned long (*set_flags) (unsigned long flags, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_mpdu_prefix_len, extra_mpdu_postfix_len; + int extra_msdu_prefix_len, extra_msdu_postfix_len; + + struct module *owner; +}; + +struct lib80211_crypt_data { + struct list_head list; /* delayed deletion list */ + struct lib80211_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +struct lib80211_crypt_info { + char *name; + /* Most clients will already have a lock, + so just point to that. */ + spinlock_t *lock; + + struct lib80211_crypt_data *crypt[NUM_WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct list_head crypt_deinit_list; + struct timer_list crypt_deinit_timer; + int crypt_quiesced; +}; + +int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name, + spinlock_t *lock); +void lib80211_crypt_info_free(struct lib80211_crypt_info *info); +int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops); +int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops); +struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name); +void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt); + +#endif /* LIB80211_H */ diff --git a/include/compat/net/mac80211.h b/include/compat/net/mac80211.h new file mode 100644 index 00000000..48953e20 --- /dev/null +++ b/include/compat/net/mac80211.h @@ -0,0 +1,3686 @@ +/* + * mac80211 <-> driver interface + * + * Copyright 2002-2005, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007-2010 Johannes Berg + * + * 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 MAC80211_H +#define MAC80211_H + +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: Introduction + * + * mac80211 is the Linux stack for 802.11 hardware that implements + * only partial functionality in hard- or firmware. This document + * defines the interface between mac80211 and low-level hardware + * drivers. + */ + +/** + * DOC: Calling mac80211 from interrupts + * + * Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be + * called in hardware interrupt context. The low-level driver must not call any + * other functions in hardware interrupt context. If there is a need for such + * call, the low-level driver should first ACK the interrupt and perform the + * IEEE 802.11 code call after this, e.g. from a scheduled workqueue or even + * tasklet function. + * + * NOTE: If the driver opts to use the _irqsafe() functions, it may not also + * use the non-IRQ-safe functions! + */ + +/** + * DOC: Warning + * + * If you're reading this document and not the header file itself, it will + * be incomplete because not all documentation has been converted yet. + */ + +/** + * DOC: Frame format + * + * As a general rule, when frames are passed between mac80211 and the driver, + * they start with the IEEE 802.11 header and include the same octets that are + * sent over the air except for the FCS which should be calculated by the + * hardware. + * + * There are, however, various exceptions to this rule for advanced features: + * + * The first exception is for hardware encryption and decryption offload + * where the IV/ICV may or may not be generated in hardware. + * + * Secondly, when the hardware handles fragmentation, the frame handed to + * the driver from mac80211 is the MSDU, not the MPDU. + * + * Finally, for received frames, the driver is able to indicate that it has + * filled a radiotap header and put that in front of the frame; if it does + * not do so then mac80211 may add this under certain circumstances. + */ + +/** + * DOC: mac80211 workqueue + * + * mac80211 provides its own workqueue for drivers and internal mac80211 use. + * The workqueue is a single threaded workqueue and can only be accessed by + * helpers for sanity checking. Drivers must ensure all work added onto the + * mac80211 workqueue should be cancelled on the driver stop() callback. + * + * mac80211 will flushed the workqueue upon interface removal and during + * suspend. + * + * All work performed on the mac80211 workqueue must not acquire the RTNL lock. + * + */ + +/** + * enum ieee80211_max_queues - maximum number of queues + * + * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. + */ +enum ieee80211_max_queues { + IEEE80211_MAX_QUEUES = 4, +}; + +/** + * enum ieee80211_ac_numbers - AC numbers as used in mac80211 + * @IEEE80211_AC_VO: voice + * @IEEE80211_AC_VI: video + * @IEEE80211_AC_BE: best effort + * @IEEE80211_AC_BK: background + */ +enum ieee80211_ac_numbers { + IEEE80211_AC_VO = 0, + IEEE80211_AC_VI = 1, + IEEE80211_AC_BE = 2, + IEEE80211_AC_BK = 3, +}; +#define IEEE80211_NUM_ACS 4 + +/** + * struct ieee80211_tx_queue_params - transmit queue configuration + * + * The information provided in this structure is required for QoS + * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29. + * + * @aifs: arbitration interframe space [0..255] + * @cw_min: minimum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @cw_max: maximum contention window [like @cw_min] + * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled + * @uapsd: is U-APSD mode enabled for the queue + */ +struct ieee80211_tx_queue_params { + u16 txop; + u16 cw_min; + u16 cw_max; + u8 aifs; + bool uapsd; +}; + +struct ieee80211_low_level_stats { + unsigned int dot11ACKFailureCount; + unsigned int dot11RTSFailureCount; + unsigned int dot11FCSErrorCount; + unsigned int dot11RTSSuccessCount; +}; + +/** + * enum ieee80211_bss_change - BSS change notification flags + * + * These flags are used with the bss_info_changed() callback + * to indicate which BSS parameter changed. + * + * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated), + * also implies a change in the AID. + * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed + * @BSS_CHANGED_ERP_PREAMBLE: preamble changed + * @BSS_CHANGED_ERP_SLOT: slot timing changed + * @BSS_CHANGED_HT: 802.11n parameters changed + * @BSS_CHANGED_BASIC_RATES: Basic rateset changed + * @BSS_CHANGED_BEACON_INT: Beacon interval changed + * @BSS_CHANGED_BSSID: BSSID changed, for whatever + * reason (IBSS and managed mode) + * @BSS_CHANGED_BEACON: Beacon data changed, retrieve + * new beacon (beaconing modes) + * @BSS_CHANGED_BEACON_ENABLED: Beaconing should be + * enabled/disabled (beaconing modes) + * @BSS_CHANGED_CQM: Connection quality monitor config changed + * @BSS_CHANGED_IBSS: IBSS join status changed + * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed. + * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note + * that it is only ever disabled for station mode. + * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface. + * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) + * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) + */ +enum ieee80211_bss_change { + BSS_CHANGED_ASSOC = 1<<0, + BSS_CHANGED_ERP_CTS_PROT = 1<<1, + BSS_CHANGED_ERP_PREAMBLE = 1<<2, + BSS_CHANGED_ERP_SLOT = 1<<3, + BSS_CHANGED_HT = 1<<4, + BSS_CHANGED_BASIC_RATES = 1<<5, + BSS_CHANGED_BEACON_INT = 1<<6, + BSS_CHANGED_BSSID = 1<<7, + BSS_CHANGED_BEACON = 1<<8, + BSS_CHANGED_BEACON_ENABLED = 1<<9, + BSS_CHANGED_CQM = 1<<10, + BSS_CHANGED_IBSS = 1<<11, + BSS_CHANGED_ARP_FILTER = 1<<12, + BSS_CHANGED_QOS = 1<<13, + BSS_CHANGED_IDLE = 1<<14, + BSS_CHANGED_SSID = 1<<15, + BSS_CHANGED_AP_PROBE_RESP = 1<<16, + + /* when adding here, make sure to change ieee80211_reconfig */ +}; + +/* + * The maximum number of IPv4 addresses listed for ARP filtering. If the number + * of addresses for an interface increase beyond this value, hardware ARP + * filtering will be disabled. + */ +#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4 + +/** + * enum ieee80211_rssi_event - RSSI threshold event + * An indicator for when RSSI goes below/above a certain threshold. + * @RSSI_EVENT_HIGH: AP's rssi crossed the high threshold set by the driver. + * @RSSI_EVENT_LOW: AP's rssi crossed the low threshold set by the driver. + */ +enum ieee80211_rssi_event { + RSSI_EVENT_HIGH, + RSSI_EVENT_LOW, +}; + +/** + * struct ieee80211_bss_conf - holds the BSS's changing parameters + * + * This structure keeps information about a BSS (and an association + * to that BSS) that can change during the lifetime of the BSS. + * + * @assoc: association status + * @ibss_joined: indicates whether this station is part of an IBSS + * or not + * @aid: association ID number, valid only when @assoc is true + * @use_cts_prot: use CTS protection + * @use_short_preamble: use 802.11b short preamble; + * if the hardware cannot handle this it must set the + * IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE hardware flag + * @use_short_slot: use short slot time (only relevant for ERP); + * if the hardware cannot handle this it must set the + * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag + * @dtim_period: num of beacons before the next DTIM, for beaconing, + * valid in station mode only while @assoc is true and if also + * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf + * @ps_dtim_period) + * @timestamp: beacon timestamp + * @beacon_int: beacon interval + * @assoc_capability: capabilities taken from assoc resp + * @basic_rates: bitmap of basic rates, each bit stands for an + * index into the rate table configured by the driver in + * the current band. + * @mcast_rate: per-band multicast rate index + 1 (0: disabled) + * @bssid: The BSSID for this BSS + * @enable_beacon: whether beaconing should be enabled or not + * @channel_type: Channel type for this BSS -- the hardware might be + * configured for HT40+ while this BSS only uses no-HT, for + * example. + * @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info). + * This field is only valid when the channel type is one of the HT types. + * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value + * implies disabled + * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis + * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The + * may filter ARP queries targeted for other addresses than listed here. + * The driver must allow ARP queries targeted for all address listed here + * to pass through. An empty list implies no ARP queries need to pass. + * @arp_addr_cnt: Number of addresses currently on the list. + * @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may + * filter ARP queries based on the @arp_addr_list, if disabled, the + * hardware must not perform any ARP filtering. Note, that the filter will + * be enabled also in promiscuous mode. + * @qos: This is a QoS-enabled BSS. + * @idle: This interface is idle. There's also a global idle flag in the + * hardware config which may be more appropriate depending on what + * your driver/device needs to do. + * @ssid: The SSID of the current vif. Only valid in AP-mode. + * @ssid_len: Length of SSID given in @ssid. + * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. + */ +struct ieee80211_bss_conf { + const u8 *bssid; + /* association related data */ + bool assoc, ibss_joined; + u16 aid; + /* erp related data */ + bool use_cts_prot; + bool use_short_preamble; + bool use_short_slot; + bool enable_beacon; + u8 dtim_period; + u16 beacon_int; + u16 assoc_capability; + u64 timestamp; + u32 basic_rates; + int mcast_rate[IEEE80211_NUM_BANDS]; + u16 ht_operation_mode; + s32 cqm_rssi_thold; + u32 cqm_rssi_hyst; + enum nl80211_channel_type channel_type; + __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; + u8 arp_addr_cnt; + bool arp_filter_enabled; + bool qos; + bool idle; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + size_t ssid_len; + bool hidden_ssid; +}; + +/** + * enum mac80211_tx_control_flags - flags to describe transmission information/status + * + * These flags are used with the @flags member of &ieee80211_tx_info. + * + * @IEEE80211_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. + * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence + * number to this frame, taking care of not overwriting the fragment + * number and increasing the sequence number only when the + * IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly + * assign sequence numbers to QoS-data frames but cannot do so correctly + * for non-QoS-data and management frames because beacons need them from + * that counter as well and mac80211 cannot guarantee proper sequencing. + * If this flag is set, the driver should instruct the hardware to + * assign a sequence number to the frame or assign one itself. Cf. IEEE + * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for + * beacons and always be clear for frames without a sequence number field. + * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack + * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination + * station + * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame + * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon + * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU + * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. + * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted + * because the destination STA was in powersave mode. Note that to + * avoid race conditions, the filter must be set by the hardware or + * firmware upon receiving a frame that indicates that the station + * went to sleep (must be done on device to filter frames already on + * the queue) and may only be unset after mac80211 gives the OK for + * that by setting the IEEE80211_TX_CTL_CLEAR_PS_FILT (see above), + * since only then is it guaranteed that no more frames are in the + * hardware queue. + * @IEEE80211_TX_STAT_ACK: Frame was acknowledged + * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status + * is for the whole aggregation. + * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, + * so consider using block ack request (BAR). + * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be + * set by rate control algorithms to indicate probe rate, will + * be cleared for fragmented frames (except on the last fragment) + * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, + * used to indicate that a pending frame requires TX processing before + * it can be sent out. + * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, + * used to indicate that a frame was already retried due to PS + * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, + * used to indicate frame should not be encrypted + * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll + * frame (PS-Poll or uAPSD) and should be sent although the station + * is in powersave mode. + * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the + * transmit function after the current frame, this can be used + * by drivers to kick the DMA queue only if unset or when the + * queue gets full. + * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted + * after TX status because the destination was asleep, it must not + * be modified again (no seqno assignment, crypto, etc.) + * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 + * MLME command (internal to mac80211 to figure out whether to send TX + * status to user space) + * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame + * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this + * frame and selects the maximum number of streams that it can use. + * @IEEE80211_TX_CTL_TX_OFFCHAN: Marks this packet to be transmitted on + * the off-channel channel when a remain-on-channel offload is done + * in hardware -- normal packets still flow and are expected to be + * handled properly by the device. + * @IEEE80211_TX_INTFL_TKIP_MIC_FAILURE: Marks this packet to be used for TKIP + * testing. It will be sent out with incorrect Michael MIC key to allow + * TKIP countermeasures to be tested. + * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate. + * This flag is actually used for management frame especially for P2P + * frames not being sent at CCK rate in 2GHz band. + * @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period, + * when its status is reported the service period ends. For frames in + * an SP that mac80211 transmits, it is already set; for driver frames + * the driver may set this flag. It is also used to do the same for + * PS-Poll responses. + * @IEEE80211_TX_CTL_USE_MINRATE: This frame will be sent at lowest rate. + * This flag is used to send nullfunc frame at minimum rate when + * the nullfunc is used for connection monitoring purpose. + * @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it + * would be fragmented by size (this is optional, only used for + * monitor injection). + * + * Note: If you have to add new flags to the enumeration, then don't + * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. + */ +enum mac80211_tx_control_flags { + IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), + IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), + IEEE80211_TX_CTL_NO_ACK = BIT(2), + IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3), + IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4), + IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5), + IEEE80211_TX_CTL_AMPDU = BIT(6), + IEEE80211_TX_CTL_INJECTED = BIT(7), + IEEE80211_TX_STAT_TX_FILTERED = BIT(8), + IEEE80211_TX_STAT_ACK = BIT(9), + IEEE80211_TX_STAT_AMPDU = BIT(10), + IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), + IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), + IEEE80211_TX_INTFL_RETRIED = BIT(15), + IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), + IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17), + IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), + IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), + /* hole at 20, use later */ + IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), + IEEE80211_TX_CTL_LDPC = BIT(22), + IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24), + IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25), + IEEE80211_TX_INTFL_TKIP_MIC_FAILURE = BIT(26), + IEEE80211_TX_CTL_NO_CCK_RATE = BIT(27), + IEEE80211_TX_STATUS_EOSP = BIT(28), + IEEE80211_TX_CTL_USE_MINRATE = BIT(29), + IEEE80211_TX_CTL_DONTFRAG = BIT(30), +}; + +#define IEEE80211_TX_CTL_STBC_SHIFT 23 + +/* + * This definition is used as a mask to clear all temporary flags, which are + * set by the tx handlers for each transmission attempt by the mac80211 stack. + */ +#define IEEE80211_TX_TEMPORARY_FLAGS (IEEE80211_TX_CTL_NO_ACK | \ + IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT | \ + IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ + IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ + IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ + IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE | \ + IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ + IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP) + +/** + * enum mac80211_rate_control_flags - per-rate flags set by the + * Rate Control algorithm. + * + * These flags are set by the Rate control algorithm for each rate during tx, + * in the @flags member of struct ieee80211_tx_rate. + * + * @IEEE80211_TX_RC_USE_RTS_CTS: Use RTS/CTS exchange for this rate. + * @IEEE80211_TX_RC_USE_CTS_PROTECT: CTS-to-self protection is required. + * This is set if the current BSS requires ERP protection. + * @IEEE80211_TX_RC_USE_SHORT_PREAMBLE: Use short preamble. + * @IEEE80211_TX_RC_MCS: HT rate. + * @IEEE80211_TX_RC_GREEN_FIELD: Indicates whether this rate should be used in + * Greenfield mode. + * @IEEE80211_TX_RC_40_MHZ_WIDTH: Indicates if the Channel Width should be 40 MHz. + * @IEEE80211_TX_RC_DUP_DATA: The frame should be transmitted on both of the + * adjacent 20 MHz channels, if the current channel type is + * NL80211_CHAN_HT40MINUS or NL80211_CHAN_HT40PLUS. + * @IEEE80211_TX_RC_SHORT_GI: Short Guard interval should be used for this rate. + */ +enum mac80211_rate_control_flags { + IEEE80211_TX_RC_USE_RTS_CTS = BIT(0), + IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), + IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), + + /* rate index is an MCS rate number instead of an index */ + IEEE80211_TX_RC_MCS = BIT(3), + IEEE80211_TX_RC_GREEN_FIELD = BIT(4), + IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), + IEEE80211_TX_RC_DUP_DATA = BIT(6), + IEEE80211_TX_RC_SHORT_GI = BIT(7), +}; + + +/* there are 40 bytes if you don't need the rateset to be kept */ +#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40 + +/* if you do need the rateset, then you have less space */ +#define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 + +/* maximum number of rate stages */ +#define IEEE80211_TX_MAX_RATES 5 + +/** + * struct ieee80211_tx_rate - rate selection/status + * + * @idx: rate index to attempt to send with + * @flags: rate control flags (&enum mac80211_rate_control_flags) + * @count: number of tries in this rate before going to the next rate + * + * A value of -1 for @idx indicates an invalid rate and, if used + * in an array of retry rates, that no more rates should be tried. + * + * When used for transmit status reporting, the driver should + * always report the rate along with the flags it used. + * + * &struct ieee80211_tx_info contains an array of these structs + * in the control information, and it will be filled by the rate + * control algorithm according to what should be sent. For example, + * if this array contains, in the format { , } the + * information + * { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 } + * then this means that the frame should be transmitted + * up to twice at rate 3, up to twice at rate 2, and up to four + * times at rate 1 if it doesn't get acknowledged. Say it gets + * acknowledged by the peer after the fifth attempt, the status + * information should then contain + * { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ... + * since it was transmitted twice at rate 3, twice at rate 2 + * and once at rate 1 after which we received an acknowledgement. + */ +struct ieee80211_tx_rate { + s8 idx; + u8 count; + u8 flags; +} __packed; + +/** + * struct ieee80211_tx_info - skb transmit information + * + * This structure is placed in skb->cb for three uses: + * (1) mac80211 TX control - mac80211 tells the driver what to do + * (2) driver internal use (if applicable) + * (3) TX status information - driver tells mac80211 what happened + * + * The TX control's sta pointer is only valid during the ->tx call, + * it may be NULL. + * + * @flags: transmit info flags, defined above + * @band: the band to transmit on (use for checking for races) + * @antenna_sel_tx: antenna to use, 0 for automatic diversity + * @ack_frame_id: internal frame ID for TX status, used internally + * @control: union for control data + * @status: union for status data + * @driver_data: array of driver_data pointers + * @ampdu_ack_len: number of acked aggregated frames. + * relevant only if IEEE80211_TX_STAT_AMPDU was set. + * @ampdu_len: number of aggregated frames. + * relevant only if IEEE80211_TX_STAT_AMPDU was set. + * @ack_signal: signal strength of the ACK frame + */ +struct ieee80211_tx_info { + /* common information */ + u32 flags; + u8 band; + + u8 antenna_sel_tx; + + u16 ack_frame_id; + + union { + struct { + union { + /* rate control */ + struct { + struct ieee80211_tx_rate rates[ + IEEE80211_TX_MAX_RATES]; + s8 rts_cts_rate_idx; + }; + /* only needed before rate control */ + unsigned long jiffies; + }; + /* NB: vif can be NULL for injected frames */ + struct ieee80211_vif *vif; + struct ieee80211_key_conf *hw_key; + struct ieee80211_sta *sta; + } control; + struct { + struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; + u8 ampdu_ack_len; + int ack_signal; + u8 ampdu_len; + /* 15 bytes free */ + } status; + struct { + struct ieee80211_tx_rate driver_rates[ + IEEE80211_TX_MAX_RATES]; + void *rate_driver_data[ + IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; + }; + void *driver_data[ + IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)]; + }; +}; + +/** + * struct ieee80211_sched_scan_ies - scheduled scan IEs + * + * This structure is used to pass the appropriate IEs to be used in scheduled + * scans for all bands. It contains both the IEs passed from the userspace + * and the ones generated by mac80211. + * + * @ie: array with the IEs for each supported band + * @len: array with the total length of the IEs for each band + */ +struct ieee80211_sched_scan_ies { + u8 *ie[IEEE80211_NUM_BANDS]; + size_t len[IEEE80211_NUM_BANDS]; +}; + +static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) +{ + return (struct ieee80211_tx_info *)skb->cb; +} + +static inline struct ieee80211_rx_status *IEEE80211_SKB_RXCB(struct sk_buff *skb) +{ + return (struct ieee80211_rx_status *)skb->cb; +} + +/** + * ieee80211_tx_info_clear_status - clear TX status + * + * @info: The &struct ieee80211_tx_info to be cleared. + * + * When the driver passes an skb back to mac80211, it must report + * a number of things in TX status. This function clears everything + * in the TX status but the rate control information (it does clear + * the count since you need to fill that in anyway). + * + * NOTE: You can only use this function if you do NOT use + * info->driver_data! Use info->rate_driver_data + * instead if you need only the less space that allows. + */ +static inline void +ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) +{ + int i; + + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, control.rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, driver_rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8); + /* clear the rate counts */ + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) + info->status.rates[i].count = 0; + + BUILD_BUG_ON( + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); +} + + +/** + * enum mac80211_rx_flags - receive flags + * + * These flags are used with the @flag member of &struct ieee80211_rx_status. + * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame. + * Use together with %RX_FLAG_MMIC_STRIPPED. + * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. + * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, + * verification has been done by the hardware. + * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. + * If this flag is set, the stack cannot do any replay detection + * hence the driver or hardware will have to do that. + * @RX_FLAG_FAILED_FCS_CRC: Set this flag if the FCS check failed on + * the frame. + * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on + * the frame. + * @RX_FLAG_MACTIME_MPDU: The timestamp passed in the RX status (@mactime + * field) is valid and contains the time the first symbol of the MPDU + * was received. This is useful in monitor mode and for proper IBSS + * merging. + * @RX_FLAG_SHORTPRE: Short preamble was used for this frame + * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index + * @RX_FLAG_40MHZ: HT40 (40 MHz) was used + * @RX_FLAG_SHORT_GI: Short guard interval was used + */ +enum mac80211_rx_flags { + RX_FLAG_MMIC_ERROR = 1<<0, + RX_FLAG_DECRYPTED = 1<<1, + RX_FLAG_MMIC_STRIPPED = 1<<3, + RX_FLAG_IV_STRIPPED = 1<<4, + RX_FLAG_FAILED_FCS_CRC = 1<<5, + RX_FLAG_FAILED_PLCP_CRC = 1<<6, + RX_FLAG_MACTIME_MPDU = 1<<7, + RX_FLAG_SHORTPRE = 1<<8, + RX_FLAG_HT = 1<<9, + RX_FLAG_40MHZ = 1<<10, + RX_FLAG_SHORT_GI = 1<<11, +}; + +/** + * struct ieee80211_rx_status - receive status + * + * The low-level driver should provide this information (the subset + * supported by hardware) to the 802.11 code with each received + * frame, in the skb's control buffer (cb). + * + * @mactime: value in microseconds of the 64-bit Time Synchronization Function + * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. + * @band: the active band when this frame was received + * @freq: frequency the radio was tuned to when receiving this frame, in MHz + * @signal: signal strength when receiving this frame, either in dBm, in dB or + * unspecified depending on the hardware capabilities flags + * @IEEE80211_HW_SIGNAL_* + * @antenna: antenna used + * @rate_idx: index of data rate into band's supported rates or MCS index if + * HT rates are use (RX_FLAG_HT) + * @flag: %RX_FLAG_* + * @rx_flags: internal RX flags for mac80211 + */ +struct ieee80211_rx_status { + u64 mactime; + enum ieee80211_band band; + int freq; + int signal; + int antenna; + int rate_idx; + int flag; + unsigned int rx_flags; +}; + +/** + * enum ieee80211_conf_flags - configuration flags + * + * Flags to define PHY configuration options + * + * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this + * to determine for example whether to calculate timestamps for packets + * or not, do not use instead of filter flags! + * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only). + * This is the power save mode defined by IEEE 802.11-2007 section 11.2, + * meaning that the hardware still wakes up for beacons, is able to + * transmit frames and receive the possible acknowledgment frames. + * Not to be confused with hardware specific wakeup/sleep states, + * driver is responsible for that. See the section "Powersave support" + * for more. + * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set + * the driver should be prepared to handle configuration requests but + * may turn the device off as much as possible. Typically, this flag will + * be set when an interface is set UP but not associated or scanning, but + * it can also be unset in that case when monitor interfaces are active. + * @IEEE80211_CONF_OFFCHANNEL: The device is currently not on its main + * operating channel. + */ +enum ieee80211_conf_flags { + IEEE80211_CONF_MONITOR = (1<<0), + IEEE80211_CONF_PS = (1<<1), + IEEE80211_CONF_IDLE = (1<<2), + IEEE80211_CONF_OFFCHANNEL = (1<<3), +}; + + +/** + * enum ieee80211_conf_changed - denotes which configuration changed + * + * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed + * @IEEE80211_CONF_CHANGE_MONITOR: the monitor flag changed + * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed + * @IEEE80211_CONF_CHANGE_POWER: the TX power changed + * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed + * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed + * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed + * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed + */ +enum ieee80211_conf_changed { + IEEE80211_CONF_CHANGE_SMPS = BIT(1), + IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), + IEEE80211_CONF_CHANGE_MONITOR = BIT(3), + IEEE80211_CONF_CHANGE_PS = BIT(4), + IEEE80211_CONF_CHANGE_POWER = BIT(5), + IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), + IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), + IEEE80211_CONF_CHANGE_IDLE = BIT(8), +}; + +/** + * enum ieee80211_smps_mode - spatial multiplexing power save mode + * + * @IEEE80211_SMPS_AUTOMATIC: automatic + * @IEEE80211_SMPS_OFF: off + * @IEEE80211_SMPS_STATIC: static + * @IEEE80211_SMPS_DYNAMIC: dynamic + * @IEEE80211_SMPS_NUM_MODES: internal, don't use + */ +enum ieee80211_smps_mode { + IEEE80211_SMPS_AUTOMATIC, + IEEE80211_SMPS_OFF, + IEEE80211_SMPS_STATIC, + IEEE80211_SMPS_DYNAMIC, + + /* keep last */ + IEEE80211_SMPS_NUM_MODES, +}; + +/** + * struct ieee80211_conf - configuration of the device + * + * This struct indicates how the driver shall configure the hardware. + * + * @flags: configuration flags defined above + * + * @listen_interval: listen interval in units of beacon interval + * @max_sleep_period: the maximum number of beacon intervals to sleep for + * before checking the beacon for a TIM bit (managed mode only); this + * value will be only achievable between DTIM frames, the hardware + * needs to check for the multicast traffic bit in DTIM beacons. + * This variable is valid only when the CONF_PS flag is set. + * @ps_dtim_period: The DTIM period of the AP we're connected to, for use + * in power saving. Power saving will not be enabled until a beacon + * has been received and the DTIM period is known. + * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the + * powersave documentation below. This variable is valid only when + * the CONF_PS flag is set. + * + * @power_level: requested transmit power (in dBm) + * + * @channel: the channel to tune to + * @channel_type: the channel (HT) type + * + * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame + * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, + * but actually means the number of transmissions not the number of retries + * @short_frame_max_tx_count: Maximum number of transmissions for a "short" + * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the + * number of transmissions not the number of retries + * + * @smps_mode: spatial multiplexing powersave mode; note that + * %IEEE80211_SMPS_STATIC is used when the device is not + * configured for an HT channel + */ +struct ieee80211_conf { + u32 flags; + int power_level, dynamic_ps_timeout; + int max_sleep_period; + + u16 listen_interval; + u8 ps_dtim_period; + + u8 long_frame_max_tx_count, short_frame_max_tx_count; + + struct ieee80211_channel *channel; + enum nl80211_channel_type channel_type; + enum ieee80211_smps_mode smps_mode; +}; + +/** + * struct ieee80211_channel_switch - holds the channel switch data + * + * The information provided in this structure is required for channel switch + * operation. + * + * @timestamp: value in microseconds of the 64-bit Time Synchronization + * Function (TSF) timer when the frame containing the channel switch + * announcement was received. This is simply the rx.mactime parameter + * the driver passed into mac80211. + * @block_tx: Indicates whether transmission must be blocked before the + * scheduled channel switch, as indicated by the AP. + * @channel: the new channel to switch to + * @count: the number of TBTT's until the channel switch event + */ +struct ieee80211_channel_switch { + u64 timestamp; + bool block_tx; + struct ieee80211_channel *channel; + u8 count; +}; + +/** + * struct ieee80211_vif - per-interface data + * + * Data in this structure is continually present for driver + * use during the life of a virtual interface. + * + * @type: type of this virtual interface + * @bss_conf: BSS configuration for this interface, either our own + * or the BSS we're associated to + * @addr: address of this interface + * @p2p: indicates whether this AP or STA interface is a p2p + * interface, i.e. a GO or p2p-sta respectively + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *). + */ +struct ieee80211_vif { + enum nl80211_iftype type; + struct ieee80211_bss_conf bss_conf; + u8 addr[ETH_ALEN]; + bool p2p; + /* must be last */ + u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + +static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) +{ +#ifdef CONFIG_MAC80211_MESH + return vif->type == NL80211_IFTYPE_MESH_POINT; +#endif + return false; +} + +/** + * enum ieee80211_key_flags - key flags + * + * These flags are used for communication about keys between the driver + * and mac80211, with the @flags parameter of &struct ieee80211_key_conf. + * + * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates + * that the STA this key will be used with could be using QoS. + * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the + * driver to indicate that it requires IV generation for this + * particular key. + * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by + * the driver for a TKIP key if it requires Michael MIC + * generation in software. + * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates + * that the key is pairwise rather then a shared key. + * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a + * CCMP key if it requires CCMP encryption of management frames (MFP) to + * be done in software. + * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver + * for a CCMP key if space should be prepared for the IV, but the IV + * itself should not be generated. Do not set together with + * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. + */ +enum ieee80211_key_flags { + IEEE80211_KEY_FLAG_WMM_STA = 1<<0, + IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, + IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, + IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, + IEEE80211_KEY_FLAG_SW_MGMT = 1<<4, + IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5, +}; + +/** + * struct ieee80211_key_conf - key information + * + * This key information is given by mac80211 to the driver by + * the set_key() callback in &struct ieee80211_ops. + * + * @hw_key_idx: To be set by the driver, this is the key index the driver + * wants to be given when a frame is transmitted and needs to be + * encrypted in hardware. + * @cipher: The key's cipher suite selector. + * @flags: key flags, see &enum ieee80211_key_flags. + * @keyidx: the key index (0-3) + * @keylen: key material length + * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte) + * data block: + * - Temporal Encryption Key (128 bits) + * - Temporal Authenticator Tx MIC Key (64 bits) + * - Temporal Authenticator Rx MIC Key (64 bits) + * @icv_len: The ICV length for this key type + * @iv_len: The IV length for this key type + */ +struct ieee80211_key_conf { + u32 cipher; + u8 icv_len; + u8 iv_len; + u8 hw_key_idx; + u8 flags; + s8 keyidx; + u8 keylen; + u8 key[0]; +}; + +/** + * enum set_key_cmd - key command + * + * Used with the set_key() callback in &struct ieee80211_ops, this + * indicates whether a key is being removed or added. + * + * @SET_KEY: a key is set + * @DISABLE_KEY: a key must be disabled + */ +enum set_key_cmd { + SET_KEY, DISABLE_KEY, +}; + +/** + * struct ieee80211_sta - station table entry + * + * A station table entry represents a station we are possibly + * communicating with. Since stations are RCU-managed in + * mac80211, any ieee80211_sta pointer you get access to must + * either be protected by rcu_read_lock() explicitly or implicitly, + * or you must take good care to not use such a pointer after a + * call to your sta_remove callback that removed it. + * + * @addr: MAC address + * @aid: AID we assigned to the station if we're an AP + * @supp_rates: Bitmap of supported rates (per band) + * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities + * @wme: indicates whether the STA supports WME. Only valid during AP-mode. + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *), size is determined in hw information. + * @uapsd_queues: bitmap of queues configured for uapsd. Only valid + * if wme is supported. + * @max_sp: max Service Period. Only valid if wme is supported. + */ +struct ieee80211_sta { + u32 supp_rates[IEEE80211_NUM_BANDS]; + u8 addr[ETH_ALEN]; + u16 aid; + struct ieee80211_sta_ht_cap ht_cap; + bool wme; + u8 uapsd_queues; + u8 max_sp; + + /* must be last */ + u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + +/** + * enum sta_notify_cmd - sta notify command + * + * Used with the sta_notify() callback in &struct ieee80211_ops, this + * indicates if an associated station made a power state transition. + * + * @STA_NOTIFY_SLEEP: a station is now sleeping + * @STA_NOTIFY_AWAKE: a sleeping station woke up + */ +enum sta_notify_cmd { + STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, +}; + +/** + * enum ieee80211_hw_flags - hardware flags + * + * These flags are used to indicate hardware capabilities to + * the stack. Generally, flags here should have their meaning + * done in a way that the simplest hardware doesn't need setting + * any particular flags. There are some exceptions to this rule, + * however, so you are advised to review these flags carefully. + * + * @IEEE80211_HW_HAS_RATE_CONTROL: + * The hardware or firmware includes rate control, and cannot be + * controlled by the stack. As such, no rate control algorithm + * should be instantiated, and the TX rate reported to userspace + * will be taken from the TX status instead of the rate control + * algorithm. + * Note that this requires that the driver implement a number of + * callbacks so it has the correct information, it needs to have + * the @set_rts_threshold callback and must look at the BSS config + * @use_cts_prot for G/N protection, @use_short_slot for slot + * timing in 2.4 GHz and @use_short_preamble for preambles for + * CCK frames. + * + * @IEEE80211_HW_RX_INCLUDES_FCS: + * Indicates that received frames passed to the stack include + * the FCS at the end. + * + * @IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING: + * Some wireless LAN chipsets buffer broadcast/multicast frames + * for power saving stations in the hardware/firmware and others + * rely on the host system for such buffering. This option is used + * to configure the IEEE 802.11 upper layer to buffer broadcast and + * multicast frames when there are power saving stations so that + * the driver can fetch them with ieee80211_get_buffered_bc(). + * + * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE: + * Hardware is not capable of short slot operation on the 2.4 GHz band. + * + * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: + * Hardware is not capable of receiving frames with short preamble on + * the 2.4 GHz band. + * + * @IEEE80211_HW_SIGNAL_UNSPEC: + * Hardware can provide signal values but we don't know its units. We + * expect values between 0 and @max_signal. + * If possible please provide dB or dBm instead. + * + * @IEEE80211_HW_SIGNAL_DBM: + * Hardware gives signal values in dBm, decibel difference from + * one milliwatt. This is the preferred method since it is standardized + * between different devices. @max_signal does not need to be set. + * + * @IEEE80211_HW_SPECTRUM_MGMT: + * Hardware supports spectrum management defined in 802.11h + * Measurement, Channel Switch, Quieting, TPC + * + * @IEEE80211_HW_AMPDU_AGGREGATION: + * Hardware supports 11n A-MPDU aggregation. + * + * @IEEE80211_HW_SUPPORTS_PS: + * Hardware has power save support (i.e. can go to sleep). + * + * @IEEE80211_HW_PS_NULLFUNC_STACK: + * Hardware requires nullfunc frame handling in stack, implies + * stack support for dynamic PS. + * + * @IEEE80211_HW_SUPPORTS_DYNAMIC_PS: + * Hardware has support for dynamic PS. + * + * @IEEE80211_HW_MFP_CAPABLE: + * Hardware supports management frame protection (MFP, IEEE 802.11w). + * + * @IEEE80211_HW_BEACON_FILTER: + * Hardware supports dropping of irrelevant beacon frames to + * avoid waking up cpu. + * + * @IEEE80211_HW_SUPPORTS_STATIC_SMPS: + * Hardware supports static spatial multiplexing powersave, + * ie. can turn off all but one chain even on HT connections + * that should be using more chains. + * + * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS: + * Hardware supports dynamic spatial multiplexing powersave, + * ie. can turn off all but one chain and then wake the rest + * up as required after, for example, rts/cts handshake. + * + * @IEEE80211_HW_SUPPORTS_UAPSD: + * Hardware supports Unscheduled Automatic Power Save Delivery + * (U-APSD) in managed mode. The mode is configured with + * conf_tx() operation. + * + * @IEEE80211_HW_REPORTS_TX_ACK_STATUS: + * Hardware can provide ack status reports of Tx frames to + * the stack. + * + * @IEEE80211_HW_CONNECTION_MONITOR: + * The hardware performs its own connection monitoring, including + * periodic keep-alives to the AP and probing the AP on beacon loss. + * When this flag is set, signaling beacon-loss will cause an immediate + * change to disassociated state. + * + * @IEEE80211_HW_SUPPORTS_CQM_RSSI: + * Hardware can do connection quality monitoring - i.e. it can monitor + * connection quality related parameters, such as the RSSI level and + * provide notifications if configured trigger levels are reached. + * + * @IEEE80211_HW_NEED_DTIM_PERIOD: + * This device needs to know the DTIM period for the BSS before + * associating. + * + * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports + * per-station GTKs as used by IBSS RSN or during fast transition. If + * the device doesn't support per-station GTKs, but can be asked not + * to decrypt group addressed frames, then IBSS RSN support is still + * possible but software crypto will be used. Advertise the wiphy flag + * only in that case. + * + * @IEEE80211_HW_AP_LINK_PS: When operating in AP mode the device + * autonomously manages the PS status of connected stations. When + * this flag is set mac80211 will not trigger PS mode for connected + * stations based on the PM bit of incoming frames. + * Use ieee80211_start_ps()/ieee8021_end_ps() to manually configure + * the PS mode of connected stations. + * + * @IEEE80211_HW_TX_AMPDU_SETUP_IN_HW: The device handles TX A-MPDU session + * setup strictly in HW. mac80211 should not attempt to do this in + * software. + */ +enum ieee80211_hw_flags { + IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, + IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, + IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, + IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, + IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, + IEEE80211_HW_SIGNAL_DBM = 1<<6, + IEEE80211_HW_NEED_DTIM_PERIOD = 1<<7, + IEEE80211_HW_SPECTRUM_MGMT = 1<<8, + IEEE80211_HW_AMPDU_AGGREGATION = 1<<9, + IEEE80211_HW_SUPPORTS_PS = 1<<10, + IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11, + IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, + IEEE80211_HW_MFP_CAPABLE = 1<<13, + IEEE80211_HW_BEACON_FILTER = 1<<14, + IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, + IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, + IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, + IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, + IEEE80211_HW_CONNECTION_MONITOR = 1<<19, + IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20, + IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, + IEEE80211_HW_AP_LINK_PS = 1<<22, + IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, +}; + +/** + * struct ieee80211_hw - hardware information and state + * + * This structure contains the configuration and hardware + * information for an 802.11 PHY. + * + * @wiphy: This points to the &struct wiphy allocated for this + * 802.11 PHY. You must fill in the @perm_addr and @dev + * members of this structure using SET_IEEE80211_DEV() + * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported + * bands (with channels, bitrates) are registered here. + * + * @conf: &struct ieee80211_conf, device configuration, don't use. + * + * @priv: pointer to private area that was allocated for driver use + * along with this structure. + * + * @flags: hardware flags, see &enum ieee80211_hw_flags. + * + * @extra_tx_headroom: headroom to reserve in each transmit skb + * for use by the driver (e.g. for transmit headers.) + * + * @channel_change_time: time (in microseconds) it takes to change channels. + * + * @max_signal: Maximum value for signal (rssi) in RX information, used + * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB + * + * @max_listen_interval: max listen interval in units of beacon interval + * that HW supports + * + * @queues: number of available hardware transmit queues for + * data packets. WMM/QoS requires at least four, these + * queues need to have configurable access parameters. + * + * @rate_control_algorithm: rate control algorithm for this hardware. + * If unset (NULL), the default algorithm will be used. Must be + * set before calling ieee80211_register_hw(). + * + * @vif_data_size: size (in bytes) of the drv_priv data area + * within &struct ieee80211_vif. + * @sta_data_size: size (in bytes) of the drv_priv data area + * within &struct ieee80211_sta. + * + * @max_rates: maximum number of alternate rate retry stages the hw + * can handle. + * @max_report_rates: maximum number of alternate rate retry stages + * the hw can report back. + * @max_rate_tries: maximum number of tries for each stage + * + * @napi_weight: weight used for NAPI polling. You must specify an + * appropriate value here if a napi_poll operation is provided + * by your driver. + * + * @max_rx_aggregation_subframes: maximum buffer size (number of + * sub-frames) to be used for A-MPDU block ack receiver + * aggregation. + * This is only relevant if the device has restrictions on the + * number of subframes, if it relies on mac80211 to do reordering + * it shouldn't be set. + * + * @max_tx_aggregation_subframes: maximum number of subframes in an + * aggregate an HT driver will transmit, used by the peer as a + * hint to size its reorder buffer. + */ +struct ieee80211_hw { + struct ieee80211_conf conf; + struct wiphy *wiphy; + const char *rate_control_algorithm; + void *priv; + u32 flags; + unsigned int extra_tx_headroom; + int channel_change_time; + int vif_data_size; + int sta_data_size; + int napi_weight; + u16 queues; + u16 max_listen_interval; + s8 max_signal; + u8 max_rates; + u8 max_report_rates; + u8 max_rate_tries; + u8 max_rx_aggregation_subframes; + u8 max_tx_aggregation_subframes; +}; + +/** + * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy + * + * @wiphy: the &struct wiphy which we want to query + * + * mac80211 drivers can use this to get to their respective + * &struct ieee80211_hw. Drivers wishing to get to their own private + * structure can then access it via hw->priv. Note that mac802111 drivers should + * not use wiphy_priv() to try to get their private driver structure as this + * is already used internally by mac80211. + */ +struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy); + +/** + * SET_IEEE80211_DEV - set device for 802.11 hardware + * + * @hw: the &struct ieee80211_hw to set the device for + * @dev: the &struct device of this 802.11 device + */ +static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev) +{ + set_wiphy_dev(hw->wiphy, dev); +} + +/** + * SET_IEEE80211_PERM_ADDR - set the permanent MAC address for 802.11 hardware + * + * @hw: the &struct ieee80211_hw to set the MAC address for + * @addr: the address to set + */ +static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) +{ + memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); +} + +static inline struct ieee80211_rate * +ieee80211_get_tx_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c) +{ + if (WARN_ON(c->control.rates[0].idx < 0)) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c) +{ + if (c->control.rts_cts_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c, int idx) +{ + if (c->control.rates[idx + 1].idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx]; +} + +/** + * ieee80211_free_txskb - free TX skb + * @hw: the hardware + * @skb: the skb + * + * Free a transmit skb. Use this funtion when some failure + * to transmit happened and thus status cannot be reported. + */ +void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); + +/** + * DOC: Hardware crypto acceleration + * + * mac80211 is capable of taking advantage of many hardware + * acceleration designs for encryption and decryption operations. + * + * The set_key() callback in the &struct ieee80211_ops for a given + * device is called to enable hardware acceleration of encryption and + * decryption. The callback takes a @sta parameter that will be NULL + * for default keys or keys used for transmission only, or point to + * the station information for the peer for individual keys. + * Multiple transmission keys with the same key index may be used when + * VLANs are configured for an access point. + * + * When transmitting, the TX control data will use the @hw_key_idx + * selected by the driver by modifying the &struct ieee80211_key_conf + * pointed to by the @key parameter to the set_key() function. + * + * The set_key() call for the %SET_KEY command should return 0 if + * the key is now in use, -%EOPNOTSUPP or -%ENOSPC if it couldn't be + * added; if you return 0 then hw_key_idx must be assigned to the + * hardware key index, you are free to use the full u8 range. + * + * When the cmd is %DISABLE_KEY then it must succeed. + * + * Note that it is permissible to not decrypt a frame even if a key + * for it has been uploaded to hardware, the stack will not make any + * decision based on whether a key has been uploaded or not but rather + * based on the receive flags. + * + * The &struct ieee80211_key_conf structure pointed to by the @key + * parameter is guaranteed to be valid until another call to set_key() + * removes it, but it can only be used as a cookie to differentiate + * keys. + * + * In TKIP some HW need to be provided a phase 1 key, for RX decryption + * acceleration (i.e. iwlwifi). Those drivers should provide update_tkip_key + * handler. + * The update_tkip_key() call updates the driver with the new phase 1 key. + * This happens every time the iv16 wraps around (every 65536 packets). The + * set_key() call will happen only once for each key (unless the AP did + * rekeying), it will not include a valid phase 1 key. The valid phase 1 key is + * provided by update_tkip_key only. The trigger that makes mac80211 call this + * handler is software decryption with wrap around of iv16. + */ + +/** + * DOC: Powersave support + * + * mac80211 has support for various powersave implementations. + * + * First, it can support hardware that handles all powersaving by itself, + * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware + * flag. In that case, it will be told about the desired powersave mode + * with the %IEEE80211_CONF_PS flag depending on the association status. + * The hardware must take care of sending nullfunc frames when necessary, + * i.e. when entering and leaving powersave mode. The hardware is required + * to look at the AID in beacons and signal to the AP that it woke up when + * it finds traffic directed to it. + * + * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in + * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused + * with hardware wakeup and sleep states. Driver is responsible for waking + * up the hardware before issuing commands to the hardware and putting it + * back to sleep at appropriate times. + * + * When PS is enabled, hardware needs to wakeup for beacons and receive the + * buffered multicast/broadcast frames after the beacon. Also it must be + * possible to send frames and receive the acknowledment frame. + * + * Other hardware designs cannot send nullfunc frames by themselves and also + * need software support for parsing the TIM bitmap. This is also supported + * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and + * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still + * required to pass up beacons. The hardware is still required to handle + * waking up for multicast traffic; if it cannot the driver must handle that + * as best as it can, mac80211 is too slow to do that. + * + * Dynamic powersave is an extension to normal powersave in which the + * hardware stays awake for a user-specified period of time after sending a + * frame so that reply frames need not be buffered and therefore delayed to + * the next wakeup. It's compromise of getting good enough latency when + * there's data traffic and still saving significantly power in idle + * periods. + * + * Dynamic powersave is simply supported by mac80211 enabling and disabling + * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS + * flag and mac80211 will handle everything automatically. Additionally, + * hardware having support for the dynamic PS feature may set the + * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support + * dynamic PS mode itself. The driver needs to look at the + * @dynamic_ps_timeout hardware configuration value and use it that value + * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable + * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS + * enabled whenever user has enabled powersave. + * + * Some hardware need to toggle a single shared antenna between WLAN and + * Bluetooth to facilitate co-existence. These types of hardware set + * limitations on the use of host controlled dynamic powersave whenever there + * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the + * driver may request temporarily going into full power save, in order to + * enable toggling the antenna between BT and WLAN. If the driver requests + * disabling dynamic powersave, the @dynamic_ps_timeout value will be + * temporarily set to zero until the driver re-enables dynamic powersave. + * + * Driver informs U-APSD client support by enabling + * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the + * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS + * Nullfunc frames and stay awake until the service period has ended. To + * utilize U-APSD, dynamic powersave is disabled for voip AC and all frames + * from that AC are transmitted with powersave enabled. + * + * Note: U-APSD client mode is not yet supported with + * %IEEE80211_HW_PS_NULLFUNC_STACK. + */ + +/** + * DOC: Beacon filter support + * + * Some hardware have beacon filter support to reduce host cpu wakeups + * which will reduce system power consumption. It usuallly works so that + * the firmware creates a checksum of the beacon but omits all constantly + * changing elements (TSF, TIM etc). Whenever the checksum changes the + * beacon is forwarded to the host, otherwise it will be just dropped. That + * way the host will only receive beacons where some relevant information + * (for example ERP protection or WMM settings) have changed. + * + * Beacon filter support is advertised with the %IEEE80211_HW_BEACON_FILTER + * hardware capability. The driver needs to enable beacon filter support + * whenever power save is enabled, that is %IEEE80211_CONF_PS is set. When + * power save is enabled, the stack will not check for beacon loss and the + * driver needs to notify about loss of beacons with ieee80211_beacon_loss(). + * + * The time (or number of beacons missed) until the firmware notifies the + * driver of a beacon loss event (which in turn causes the driver to call + * ieee80211_beacon_loss()) should be configurable and will be controlled + * by mac80211 and the roaming algorithm in the future. + * + * Since there may be constantly changing information elements that nothing + * in the software stack cares about, we will, in the future, have mac80211 + * tell the driver which information elements are interesting in the sense + * that we want to see changes in them. This will include + * - a list of information element IDs + * - a list of OUIs for the vendor information element + * + * Ideally, the hardware would filter out any beacons without changes in the + * requested elements, but if it cannot support that it may, at the expense + * of some efficiency, filter out only a subset. For example, if the device + * doesn't support checking for OUIs it should pass up all changes in all + * vendor information elements. + * + * Note that change, for the sake of simplification, also includes information + * elements appearing or disappearing from the beacon. + * + * Some hardware supports an "ignore list" instead, just make sure nothing + * that was requested is on the ignore list, and include commonly changing + * information element IDs in the ignore list, for example 11 (BSS load) and + * the various vendor-assigned IEs with unknown contents (128, 129, 133-136, + * 149, 150, 155, 156, 173, 176, 178, 179, 219); for forward compatibility + * it could also include some currently unused IDs. + * + * + * In addition to these capabilities, hardware should support notifying the + * host of changes in the beacon RSSI. This is relevant to implement roaming + * when no traffic is flowing (when traffic is flowing we see the RSSI of + * the received data packets). This can consist in notifying the host when + * the RSSI changes significantly or when it drops below or rises above + * configurable thresholds. In the future these thresholds will also be + * configured by mac80211 (which gets them from userspace) to implement + * them as the roaming algorithm requires. + * + * If the hardware cannot implement this, the driver should ask it to + * periodically pass beacon frames to the host so that software can do the + * signal strength threshold checking. + */ + +/** + * DOC: Spatial multiplexing power save + * + * SMPS (Spatial multiplexing power save) is a mechanism to conserve + * power in an 802.11n implementation. For details on the mechanism + * and rationale, please refer to 802.11 (as amended by 802.11n-2009) + * "11.2.3 SM power save". + * + * The mac80211 implementation is capable of sending action frames + * to update the AP about the station's SMPS mode, and will instruct + * the driver to enter the specific mode. It will also announce the + * requested SMPS mode during the association handshake. Hardware + * support for this feature is required, and can be indicated by + * hardware flags. + * + * The default mode will be "automatic", which nl80211/cfg80211 + * defines to be dynamic SMPS in (regular) powersave, and SMPS + * turned off otherwise. + * + * To support this feature, the driver must set the appropriate + * hardware support flags, and handle the SMPS flag to the config() + * operation. It will then with this mechanism be instructed to + * enter the requested SMPS mode while associated to an HT AP. + */ + +/** + * DOC: Frame filtering + * + * mac80211 requires to see many management frames for proper + * operation, and users may want to see many more frames when + * in monitor mode. However, for best CPU usage and power consumption, + * having as few frames as possible percolate through the stack is + * desirable. Hence, the hardware should filter as much as possible. + * + * To achieve this, mac80211 uses filter flags (see below) to tell + * the driver's configure_filter() function which frames should be + * passed to mac80211 and which should be filtered out. + * + * Before configure_filter() is invoked, the prepare_multicast() + * callback is invoked with the parameters @mc_count and @mc_list + * for the combined multicast address list of all virtual interfaces. + * It's use is optional, and it returns a u64 that is passed to + * configure_filter(). Additionally, configure_filter() has the + * arguments @changed_flags telling which flags were changed and + * @total_flags with the new flag states. + * + * If your device has no multicast address filters your driver will + * need to check both the %FIF_ALLMULTI flag and the @mc_count + * parameter to see whether multicast frames should be accepted + * or dropped. + * + * All unsupported flags in @total_flags must be cleared. + * Hardware does not support a flag if it is incapable of _passing_ + * the frame to the stack. Otherwise the driver must ignore + * the flag, but not clear it. + * You must _only_ clear the flag (announce no support for the + * flag to mac80211) if you are not able to pass the packet type + * to the stack (so the hardware always filters it). + * So for example, you should clear @FIF_CONTROL, if your hardware + * always filters control frames. If your hardware always passes + * control frames to the kernel and is incapable of filtering them, + * you do _not_ clear the @FIF_CONTROL flag. + * This rule applies to all other FIF flags as well. + */ + +/** + * DOC: AP support for powersaving clients + * + * In order to implement AP and P2P GO modes, mac80211 has support for + * client powersaving, both "legacy" PS (PS-Poll/null data) and uAPSD. + * There currently is no support for sAPSD. + * + * There is one assumption that mac80211 makes, namely that a client + * will not poll with PS-Poll and trigger with uAPSD at the same time. + * Both are supported, and both can be used by the same client, but + * they can't be used concurrently by the same client. This simplifies + * the driver code. + * + * The first thing to keep in mind is that there is a flag for complete + * driver implementation: %IEEE80211_HW_AP_LINK_PS. If this flag is set, + * mac80211 expects the driver to handle most of the state machine for + * powersaving clients and will ignore the PM bit in incoming frames. + * Drivers then use ieee80211_sta_ps_transition() to inform mac80211 of + * stations' powersave transitions. In this mode, mac80211 also doesn't + * handle PS-Poll/uAPSD. + * + * In the mode without %IEEE80211_HW_AP_LINK_PS, mac80211 will check the + * PM bit in incoming frames for client powersave transitions. When a + * station goes to sleep, we will stop transmitting to it. There is, + * however, a race condition: a station might go to sleep while there is + * data buffered on hardware queues. If the device has support for this + * it will reject frames, and the driver should give the frames back to + * mac80211 with the %IEEE80211_TX_STAT_TX_FILTERED flag set which will + * cause mac80211 to retry the frame when the station wakes up. The + * driver is also notified of powersave transitions by calling its + * @sta_notify callback. + * + * When the station is asleep, it has three choices: it can wake up, + * it can PS-Poll, or it can possibly start a uAPSD service period. + * Waking up is implemented by simply transmitting all buffered (and + * filtered) frames to the station. This is the easiest case. When + * the station sends a PS-Poll or a uAPSD trigger frame, mac80211 + * will inform the driver of this with the @allow_buffered_frames + * callback; this callback is optional. mac80211 will then transmit + * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE + * on each frame. The last frame in the service period (or the only + * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to + * indicate that it ends the service period; as this frame must have + * TX status report it also sets %IEEE80211_TX_CTL_REQ_TX_STATUS. + * When TX status is reported for this frame, the service period is + * marked has having ended and a new one can be started by the peer. + * + * Another race condition can happen on some devices like iwlwifi + * when there are frames queued for the station and it wakes up + * or polls; the frames that are already queued could end up being + * transmitted first instead, causing reordering and/or wrong + * processing of the EOSP. The cause is that allowing frames to be + * transmitted to a certain station is out-of-band communication to + * the device. To allow this problem to be solved, the driver can + * call ieee80211_sta_block_awake() if frames are buffered when it + * is notified that the station went to sleep. When all these frames + * have been filtered (see above), it must call the function again + * to indicate that the station is no longer blocked. + * + * If the driver buffers frames in the driver for aggregation in any + * way, it must use the ieee80211_sta_set_buffered() call when it is + * notified of the station going to sleep to inform mac80211 of any + * TIDs that have frames buffered. Note that when a station wakes up + * this information is reset (hence the requirement to call it when + * informed of the station going to sleep). Then, when a service + * period starts for any reason, @release_buffered_frames is called + * with the number of frames to be released and which TIDs they are + * to come from. In this case, the driver is responsible for setting + * the EOSP (for uAPSD) and MORE_DATA bits in the released frames, + * to help the @more_data paramter is passed to tell the driver if + * there is more data on other TIDs -- the TIDs to release frames + * from are ignored since mac80211 doesn't know how many frames the + * buffers for those TIDs contain. + * + * If the driver also implement GO mode, where absence periods may + * shorten service periods (or abort PS-Poll responses), it must + * filter those response frames except in the case of frames that + * are buffered in the driver -- those must remain buffered to avoid + * reordering. Because it is possible that no frames are released + * in this case, the driver must call ieee80211_sta_eosp_irqsafe() + * to indicate to mac80211 that the service period ended anyway. + * + * Finally, if frames from multiple TIDs are released from mac80211 + * but the driver might reorder them, it must clear & set the flags + * appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP) + * and also take care of the EOSP and MORE_DATA bits in the frame. + * The driver may also use ieee80211_sta_eosp_irqsafe() in this case. + */ + +/** + * enum ieee80211_filter_flags - hardware filter flags + * + * These flags determine what the filter in hardware should be + * programmed to let through and what should not be passed to the + * stack. It is always safe to pass more frames than requested, + * but this has negative impact on power consumption. + * + * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS, + * think of the BSS as your network segment and then this corresponds + * to the regular ethernet device promiscuous mode. + * + * @FIF_ALLMULTI: pass all multicast frames, this is used if requested + * by the user or if the hardware is not capable of filtering by + * multicast address. + * + * @FIF_FCSFAIL: pass frames with failed FCS (but you need to set the + * %RX_FLAG_FAILED_FCS_CRC for them) + * + * @FIF_PLCPFAIL: pass frames with failed PLCP CRC (but you need to set + * the %RX_FLAG_FAILED_PLCP_CRC for them + * + * @FIF_BCN_PRBRESP_PROMISC: This flag is set during scanning to indicate + * to the hardware that it should not filter beacons or probe responses + * by BSSID. Filtering them can greatly reduce the amount of processing + * mac80211 needs to do and the amount of CPU wakeups, so you should + * honour this flag if possible. + * + * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS + * is not set then only those addressed to this station. + * + * @FIF_OTHER_BSS: pass frames destined to other BSSes + * + * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only + * those addressed to this station. + * + * @FIF_PROBE_REQ: pass probe request frames + */ +enum ieee80211_filter_flags { + FIF_PROMISC_IN_BSS = 1<<0, + FIF_ALLMULTI = 1<<1, + FIF_FCSFAIL = 1<<2, + FIF_PLCPFAIL = 1<<3, + FIF_BCN_PRBRESP_PROMISC = 1<<4, + FIF_CONTROL = 1<<5, + FIF_OTHER_BSS = 1<<6, + FIF_PSPOLL = 1<<7, + FIF_PROBE_REQ = 1<<8, +}; + +/** + * enum ieee80211_ampdu_mlme_action - A-MPDU actions + * + * These flags are used with the ampdu_action() callback in + * &struct ieee80211_ops to indicate which action is needed. + * + * Note that drivers MUST be able to deal with a TX aggregation + * session being stopped even before they OK'ed starting it by + * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer + * might receive the addBA frame and send a delBA right away! + * + * @IEEE80211_AMPDU_RX_START: start Rx aggregation + * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation + * @IEEE80211_AMPDU_TX_START: start Tx aggregation + * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation + * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational + */ +enum ieee80211_ampdu_mlme_action { + IEEE80211_AMPDU_RX_START, + IEEE80211_AMPDU_RX_STOP, + IEEE80211_AMPDU_TX_START, + IEEE80211_AMPDU_TX_STOP, + IEEE80211_AMPDU_TX_OPERATIONAL, +}; + +/** + * enum ieee80211_tx_sync_type - TX sync type + * @IEEE80211_TX_SYNC_AUTH: sync TX for authentication + * (and possibly also before direct probe) + * @IEEE80211_TX_SYNC_ASSOC: sync TX for association + * @IEEE80211_TX_SYNC_ACTION: sync TX for action frame + * (not implemented yet) + */ +enum ieee80211_tx_sync_type { + IEEE80211_TX_SYNC_AUTH, + IEEE80211_TX_SYNC_ASSOC, + IEEE80211_TX_SYNC_ACTION, +}; + +/** + * enum ieee80211_frame_release_type - frame release reason + * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll + * @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to + * frame received on trigger-enabled AC + */ +enum ieee80211_frame_release_type { + IEEE80211_FRAME_RELEASE_PSPOLL, + IEEE80211_FRAME_RELEASE_UAPSD, +}; + +/** + * struct ieee80211_ops - callbacks from mac80211 to the driver + * + * This structure contains various callbacks that the driver may + * handle or, in some cases, must handle, for example to configure + * the hardware to a new channel or to transmit a frame. + * + * @tx: Handler that 802.11 module calls for each transmitted frame. + * skb contains the buffer starting from the IEEE 802.11 header. + * The low-level driver should send the frame out based on + * configuration in the TX control data. This handler should, + * preferably, never fail and stop queues appropriately, more + * importantly, however, it must never fail for A-MPDU-queues. + * This function should return NETDEV_TX_OK except in very + * limited cases. + * Must be implemented and atomic. + * + * @start: Called before the first netdevice attached to the hardware + * is enabled. This should turn on the hardware and must turn on + * frame reception (for possibly enabled monitor interfaces.) + * Returns negative error codes, these may be seen in userspace, + * or zero. + * When the device is started it should not have a MAC address + * to avoid acknowledging frames before a non-monitor device + * is added. + * Must be implemented and can sleep. + * + * @stop: Called after last netdevice attached to the hardware + * is disabled. This should turn off the hardware (at least + * it must turn off frame reception.) + * May be called right after add_interface if that rejects + * an interface. If you added any work onto the mac80211 workqueue + * you should ensure to cancel it on this callback. + * Must be implemented and can sleep. + * + * @suspend: Suspend the device; mac80211 itself will quiesce before and + * stop transmitting and doing any other configuration, and then + * ask the device to suspend. This is only invoked when WoWLAN is + * configured, otherwise the device is deconfigured completely and + * reconfigured at resume time. + * The driver may also impose special conditions under which it + * wants to use the "normal" suspend (deconfigure), say if it only + * supports WoWLAN when the device is associated. In this case, it + * must return 1 from this function. + * + * @resume: If WoWLAN was configured, this indicates that mac80211 is + * now resuming its operation, after this the device must be fully + * functional again. If this returns an error, the only way out is + * to also unregister the device. If it returns 1, then mac80211 + * will also go through the regular complete restart on resume. + * + * @add_interface: Called when a netdevice attached to the hardware is + * enabled. Because it is not called for monitor mode devices, @start + * and @stop must be implemented. + * The driver should perform any initialization it needs before + * the device can be enabled. The initial configuration for the + * interface is given in the conf parameter. + * The callback may refuse to add an interface by returning a + * negative error code (which will be seen in userspace.) + * Must be implemented and can sleep. + * + * @change_interface: Called when a netdevice changes type. This callback + * is optional, but only if it is supported can interface types be + * switched while the interface is UP. The callback may sleep. + * Note that while an interface is being switched, it will not be + * found by the interface iteration callbacks. + * + * @remove_interface: Notifies a driver that an interface is going down. + * The @stop callback is called after this if it is the last interface + * and no monitor interfaces are present. + * When all interfaces are removed, the MAC address in the hardware + * must be cleared so the device no longer acknowledges packets, + * the mac_addr member of the conf structure is, however, set to the + * MAC address of the device going away. + * Hence, this callback must be implemented. It can sleep. + * + * @config: Handler for configuration requests. IEEE 802.11 code calls this + * function to change hardware configuration, e.g., channel. + * This function should never fail but returns a negative error code + * if it does. The callback can sleep. + * + * @bss_info_changed: Handler for configuration requests related to BSS + * parameters that may vary during BSS's lifespan, and may affect low + * level driver (e.g. assoc/disassoc status, erp parameters). + * This function should not be used if no BSS has been set, unless + * for association indication. The @changed parameter indicates which + * of the bss parameters has changed when a call is made. The callback + * can sleep. + * + * @tx_sync: Called before a frame is sent to an AP/GO. In the GO case, the + * driver should sync with the GO's powersaving so the device doesn't + * transmit the frame while the GO is asleep. In the regular AP case + * it may be used by drivers for devices implementing other restrictions + * on talking to APs, e.g. due to regulatory enforcement or just HW + * restrictions. + * This function is called for every authentication, association and + * action frame separately since applications might attempt to auth + * with multiple APs before chosing one to associate to. If it returns + * an error, the corresponding authentication, association or frame + * transmission is aborted and reported as having failed. It is always + * called after tuning to the correct channel. + * The callback might be called multiple times before @finish_tx_sync + * (but @finish_tx_sync will be called once for each) but in practice + * this is unlikely to happen. It can also refuse in that case if the + * driver cannot handle that situation. + * This callback can sleep. + * @finish_tx_sync: Called as a counterpart to @tx_sync, unless that returned + * an error. This callback can sleep. + * + * @prepare_multicast: Prepare for multicast filter configuration. + * This callback is optional, and its return value is passed + * to configure_filter(). This callback must be atomic. + * + * @configure_filter: Configure the device's RX filter. + * See the section "Frame filtering" for more information. + * This callback must be implemented and can sleep. + * + * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit + * must be set or cleared for a given STA. Must be atomic. + * + * @set_key: See the section "Hardware crypto acceleration" + * This callback is only called between add_interface and + * remove_interface calls, i.e. while the given virtual interface + * is enabled. + * Returns a negative error code if the key can't be added. + * The callback can sleep. + * + * @update_tkip_key: See the section "Hardware crypto acceleration" + * This callback will be called in the context of Rx. Called for drivers + * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. + * The callback must be atomic. + * + * @set_rekey_data: If the device supports GTK rekeying, for example while the + * host is suspended, it can assign this callback to retrieve the data + * necessary to do GTK rekeying, this is the KEK, KCK and replay counter. + * After rekeying was done it should (for example during resume) notify + * userspace of the new replay counter using ieee80211_gtk_rekey_notify(). + * + * @hw_scan: Ask the hardware to service the scan request, no need to start + * the scan state machine in stack. The scan must honour the channel + * configuration done by the regulatory agent in the wiphy's + * registered bands. The hardware (or the driver) needs to make sure + * that power save is disabled. + * The @req ie/ie_len members are rewritten by mac80211 to contain the + * entire IEs after the SSID, so that drivers need not look at these + * at all but just send them after the SSID -- mac80211 includes the + * (extended) supported rates and HT information (where applicable). + * When the scan finishes, ieee80211_scan_completed() must be called; + * note that it also must be called when the scan cannot finish due to + * any error unless this callback returned a negative error code. + * The callback can sleep. + * + * @cancel_hw_scan: Ask the low-level tp cancel the active hw scan. + * The driver should ask the hardware to cancel the scan (if possible), + * but the scan will be completed only after the driver will call + * ieee80211_scan_completed(). + * This callback is needed for wowlan, to prevent enqueueing a new + * scan_work after the low-level driver was already suspended. + * The callback can sleep. + * + * @sched_scan_start: Ask the hardware to start scanning repeatedly at + * specific intervals. The driver must call the + * ieee80211_sched_scan_results() function whenever it finds results. + * This process will continue until sched_scan_stop is called. + * + * @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan. + * + * @sw_scan_start: Notifier function that is called just before a software scan + * is started. Can be NULL, if the driver doesn't need this notification. + * The callback can sleep. + * + * @sw_scan_complete: Notifier function that is called just after a + * software scan finished. Can be NULL, if the driver doesn't need + * this notification. + * The callback can sleep. + * + * @get_stats: Return low-level statistics. + * Returns zero if statistics are available. + * The callback can sleep. + * + * @get_tkip_seq: If your device implements TKIP encryption in hardware this + * callback should be provided to read the TKIP transmit IVs (both IV32 + * and IV16) for the given key from hardware. + * The callback must be atomic. + * + * @set_frag_threshold: Configuration of fragmentation threshold. Assign this + * if the device does fragmentation by itself; if this callback is + * implemented then the stack will not do fragmentation. + * The callback can sleep. + * + * @set_rts_threshold: Configuration of RTS threshold (if device needs it) + * The callback can sleep. + * + * @sta_add: Notifies low level driver about addition of an associated station, + * AP, IBSS/WDS/mesh peer etc. This callback can sleep. + * + * @sta_remove: Notifies low level driver about removal of an associated + * station, AP, IBSS/WDS/mesh peer etc. This callback can sleep. + * + * @sta_notify: Notifies low level driver about power state transition of an + * associated station, AP, IBSS/WDS/mesh peer etc. For a VIF operating + * in AP mode, this callback will not be called when the flag + * %IEEE80211_HW_AP_LINK_PS is set. Must be atomic. + * + * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), + * bursting) for a hardware TX queue. + * Returns a negative error code on failure. + * The callback can sleep. + * + * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, + * this is only used for IBSS mode BSSID merging and debugging. Is not a + * required function. + * The callback can sleep. + * + * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware. + * Currently, this is only used for IBSS mode debugging. Is not a + * required function. + * The callback can sleep. + * + * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize + * with other STAs in the IBSS. This is only used in IBSS mode. This + * function is optional if the firmware/hardware takes full care of + * TSF synchronization. + * The callback can sleep. + * + * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. + * This is needed only for IBSS mode and the result of this function is + * used to determine whether to reply to Probe Requests. + * Returns non-zero if this device sent the last beacon. + * The callback can sleep. + * + * @ampdu_action: Perform a certain A-MPDU action + * The RA/TID combination determines the destination and TID we want + * the ampdu action to be performed for. The action is defined through + * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) + * is the first frame we expect to perform the action on. Notice + * that TX/RX_STOP can pass NULL for this parameter. + * The @buf_size parameter is only valid when the action is set to + * %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder + * buffer size (number of subframes) for this session -- the driver + * may neither send aggregates containing more subframes than this + * nor send aggregates in a way that lost frames would exceed the + * buffer size. If just limiting the aggregate size, this would be + * possible with a buf_size of 8: + * - TX: 1.....7 + * - RX: 2....7 (lost frame #1) + * - TX: 8..1... + * which is invalid since #1 was now re-transmitted well past the + * buffer size of 8. Correct ways to retransmit #1 would be: + * - TX: 1 or 18 or 81 + * Even "189" would be wrong since 1 could be lost again. + * + * Returns a negative error code on failure. + * The callback can sleep. + * + * @get_survey: Return per-channel survey information + * + * @rfkill_poll: Poll rfkill hardware state. If you need this, you also + * need to set wiphy->rfkill_poll to %true before registration, + * and need to call wiphy_rfkill_set_hw_state() in the callback. + * The callback can sleep. + * + * @set_coverage_class: Set slot time for given coverage class as specified + * in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout + * accordingly. This callback is not required and may sleep. + * + * @testmode_cmd: Implement a cfg80211 test mode command. + * The callback can sleep. + * @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep. + * + * @flush: Flush all pending frames from the hardware queue, making sure + * that the hardware queues are empty. If the parameter @drop is set + * to %true, pending frames may be dropped. The callback can sleep. + * + * @channel_switch: Drivers that need (or want) to offload the channel + * switch operation for CSAs received from the AP may implement this + * callback. They must then call ieee80211_chswitch_done() to indicate + * completion of the channel switch. + * + * @napi_poll: Poll Rx queue for incoming data frames. + * + * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device. + * Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may + * reject TX/RX mask combinations they cannot support by returning -EINVAL + * (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX). + * + * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). + * + * @remain_on_channel: Starts an off-channel period on the given channel, must + * call back to ieee80211_ready_on_channel() when on that channel. Note + * that normal channel traffic is not stopped as this is intended for hw + * offload. Frames to transmit on the off-channel channel are transmitted + * normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the + * duration (which will always be non-zero) expires, the driver must call + * ieee80211_remain_on_channel_expired(). This callback may sleep. + * @cancel_remain_on_channel: Requests that an ongoing off-channel period is + * aborted before it expires. This callback may sleep. + * + * @set_ringparam: Set tx and rx ring sizes. + * + * @get_ringparam: Get tx and rx ring current and maximum sizes. + * + * @tx_frames_pending: Check if there is any pending frame in the hardware + * queues before entering power save. + * + * @set_bitrate_mask: Set a mask of rates to be used for rate control selection + * when transmitting a frame. Currently only legacy rates are handled. + * The callback can sleep. + * @rssi_callback: Notify driver when the average RSSI goes above/below + * thresholds that were registered previously. The callback can sleep. + * + * @release_buffered_frames: Release buffered frames according to the given + * parameters. In the case where the driver buffers some frames for + * sleeping stations mac80211 will use this callback to tell the driver + * to release some frames, either for PS-poll or uAPSD. + * Note that if the @more_data paramter is %false the driver must check + * if there are more frames on the given TIDs, and if there are more than + * the frames being released then it must still set the more-data bit in + * the frame. If the @more_data parameter is %true, then of course the + * more-data bit must always be set. + * The @tids parameter tells the driver which TIDs to release frames + * from, for PS-poll it will always have only a single bit set. + * In the case this is used for a PS-poll initiated release, the + * @num_frames parameter will always be 1 so code can be shared. In + * this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag + * on the TX status (and must report TX status) so that the PS-poll + * period is properly ended. This is used to avoid sending multiple + * responses for a retried PS-poll frame. + * In the case this is used for uAPSD, the @num_frames parameter may be + * bigger than one, but the driver may send fewer frames (it must send + * at least one, however). In this case it is also responsible for + * setting the EOSP flag in the QoS header of the frames. Also, when the + * service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP + * on the last frame in the SP. Alternatively, it may call the function + * ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP. + * This callback must be atomic. + * @allow_buffered_frames: Prepare device to allow the given number of frames + * to go out to the given station. The frames will be sent by mac80211 + * via the usual TX path after this call. The TX information for frames + * released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set + * and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case + * frames from multiple TIDs are released and the driver might reorder + * them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag + * on the last frame and clear it on all others and also handle the EOSP + * bit in the QoS header correctly. Alternatively, it can also call the + * ieee80211_sta_eosp_irqsafe() function. + * The @tids parameter is a bitmap and tells the driver which TIDs the + * frames will be on; it will at most have two bits set. + * This callback must be atomic. + */ +struct ieee80211_ops { + void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); + int (*start)(struct ieee80211_hw *hw); + void (*stop)(struct ieee80211_hw *hw); +#ifdef CONFIG_PM + int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); + int (*resume)(struct ieee80211_hw *hw); +#endif + int (*add_interface)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + int (*change_interface)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype new_type, bool p2p); + void (*remove_interface)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + int (*config)(struct ieee80211_hw *hw, u32 changed); + void (*bss_info_changed)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed); + + int (*tx_sync)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *bssid, enum ieee80211_tx_sync_type type); + void (*finish_tx_sync)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *bssid, + enum ieee80211_tx_sync_type type); + + u64 (*prepare_multicast)(struct ieee80211_hw *hw, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) + struct netdev_hw_addr_list *mc_list); +#else + int mc_count, struct dev_addr_list *mc_list); +#endif + void (*configure_filter)(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast); + int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set); + int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); + void (*update_tkip_key)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *conf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key); + void (*set_rekey_data)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data); + int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_scan_request *req); + void (*cancel_hw_scan)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + int (*sched_scan_start)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies); + void (*sched_scan_stop)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + void (*sw_scan_start)(struct ieee80211_hw *hw); + void (*sw_scan_complete)(struct ieee80211_hw *hw); + int (*get_stats)(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats); + void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, + u32 *iv32, u16 *iv16); + int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); + int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); + int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd, struct ieee80211_sta *sta); + int (*conf_tx)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params); + u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf); + void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + int (*tx_last_beacon)(struct ieee80211_hw *hw); + int (*ampdu_action)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size); + int (*get_survey)(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); + void (*rfkill_poll)(struct ieee80211_hw *hw); + void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); +#ifdef CONFIG_NL80211_TESTMODE + int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); + int (*testmode_dump)(struct ieee80211_hw *hw, struct sk_buff *skb, + struct netlink_callback *cb, + void *data, int len); +#endif + void (*flush)(struct ieee80211_hw *hw, bool drop); + void (*channel_switch)(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch); + int (*napi_poll)(struct ieee80211_hw *hw, int budget); + int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); + int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); + + int (*remain_on_channel)(struct ieee80211_hw *hw, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + int duration); + int (*cancel_remain_on_channel)(struct ieee80211_hw *hw); + int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); + void (*get_ringparam)(struct ieee80211_hw *hw, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); + bool (*tx_frames_pending)(struct ieee80211_hw *hw); + int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask); + void (*rssi_callback)(struct ieee80211_hw *hw, + enum ieee80211_rssi_event rssi_event); + + void (*allow_buffered_frames)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data); + void (*release_buffered_frames)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data); +}; + +/** + * ieee80211_alloc_hw - Allocate a new hardware device + * + * This must be called once for each hardware device. The returned pointer + * must be used to refer to this device when calling other functions. + * mac80211 allocates a private data area for the driver pointed to by + * @priv in &struct ieee80211_hw, the size of this area is given as + * @priv_data_len. + * + * @priv_data_len: length of private data + * @ops: callbacks for this device + */ +struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, + const struct ieee80211_ops *ops); + +/** + * ieee80211_register_hw - Register hardware device + * + * You must call this function before any other functions in + * mac80211. Note that before a hardware can be registered, you + * need to fill the contained wiphy's information. + * + * @hw: the device to register as returned by ieee80211_alloc_hw() + */ +int ieee80211_register_hw(struct ieee80211_hw *hw); + +/** + * struct ieee80211_tpt_blink - throughput blink description + * @throughput: throughput in Kbit/sec + * @blink_time: blink time in milliseconds + * (full cycle, ie. one off + one on period) + */ +struct ieee80211_tpt_blink { + int throughput; + int blink_time; +}; + +/** + * enum ieee80211_tpt_led_trigger_flags - throughput trigger flags + * @IEEE80211_TPT_LEDTRIG_FL_RADIO: enable blinking with radio + * @IEEE80211_TPT_LEDTRIG_FL_WORK: enable blinking when working + * @IEEE80211_TPT_LEDTRIG_FL_CONNECTED: enable blinking when at least one + * interface is connected in some way, including being an AP + */ +enum ieee80211_tpt_led_trigger_flags { + IEEE80211_TPT_LEDTRIG_FL_RADIO = BIT(0), + IEEE80211_TPT_LEDTRIG_FL_WORK = BIT(1), + IEEE80211_TPT_LEDTRIG_FL_CONNECTED = BIT(2), +}; + +#ifdef CONFIG_MAC80211_LEDS +extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_create_tpt_led_trigger( + struct ieee80211_hw *hw, unsigned int flags, + const struct ieee80211_tpt_blink *blink_table, + unsigned int blink_table_len); +#endif +/** + * ieee80211_get_tx_led_name - get name of TX LED + * + * mac80211 creates a transmit LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_tx_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_get_rx_led_name - get name of RX LED + * + * mac80211 creates a receive LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_rx_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_get_assoc_led_name - get name of association LED + * + * mac80211 creates a association LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_assoc_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_get_radio_led_name - get name of radio LED + * + * mac80211 creates a radio change LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_radio_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_create_tpt_led_trigger - create throughput LED trigger + * @hw: the hardware to create the trigger for + * @flags: trigger flags, see &enum ieee80211_tpt_led_trigger_flags + * @blink_table: the blink table -- needs to be ordered by throughput + * @blink_table_len: size of the blink table + * + * This function returns %NULL (in case of error, or if no LED + * triggers are configured) or the name of the new trigger. + * This function must be called before ieee80211_register_hw(). + */ +static inline char * +ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, unsigned int flags, + const struct ieee80211_tpt_blink *blink_table, + unsigned int blink_table_len) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_create_tpt_led_trigger(hw, flags, blink_table, + blink_table_len); +#else + return NULL; +#endif +} + +/** + * ieee80211_unregister_hw - Unregister a hardware device + * + * This function instructs mac80211 to free allocated resources + * and unregister netdevices from the networking subsystem. + * + * @hw: the hardware to unregister + */ +void ieee80211_unregister_hw(struct ieee80211_hw *hw); + +/** + * ieee80211_free_hw - free hardware descriptor + * + * This function frees everything that was allocated, including the + * private data for the driver. You must call ieee80211_unregister_hw() + * before calling this function. + * + * @hw: the hardware to free + */ +void ieee80211_free_hw(struct ieee80211_hw *hw); + +/** + * ieee80211_restart_hw - restart hardware completely + * + * Call this function when the hardware was restarted for some reason + * (hardware error, ...) and the driver is unable to restore its state + * by itself. mac80211 assumes that at this point the driver/hardware + * is completely uninitialised and stopped, it starts the process by + * calling the ->start() operation. The driver will need to reset all + * internal state that it has prior to calling this function. + * + * @hw: the hardware to restart + */ +void ieee80211_restart_hw(struct ieee80211_hw *hw); + +/** ieee80211_napi_schedule - schedule NAPI poll + * + * Use this function to schedule NAPI polling on a device. + * + * @hw: the hardware to start polling + */ +void ieee80211_napi_schedule(struct ieee80211_hw *hw); + +/** ieee80211_napi_complete - complete NAPI polling + * + * Use this function to finish NAPI polling on a device. + * + * @hw: the hardware to stop polling + */ +void ieee80211_napi_complete(struct ieee80211_hw *hw); + +/** + * ieee80211_rx - receive frame + * + * Use this function to hand received frames to mac80211. The receive + * buffer in @skb must start with an IEEE 802.11 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee80211 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls to + * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be + * mixed for a single hardware. + * + * In process context use instead ieee80211_rx_ni(). + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + */ +void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); + +/** + * ieee80211_rx_irqsafe - receive frame + * + * Like ieee80211_rx() but can be called in IRQ context + * (internally defers to a tasklet.) + * + * Calls to this function, ieee80211_rx() or ieee80211_rx_ni() may not + * be mixed for a single hardware. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + */ +void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); + +/** + * ieee80211_rx_ni - receive frame (in process context) + * + * Like ieee80211_rx() but can be called in process context + * (internally disables bottom halves). + * + * Calls to this function, ieee80211_rx() and ieee80211_rx_irqsafe() may + * not be mixed for a single hardware. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + */ +static inline void ieee80211_rx_ni(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + local_bh_disable(); + ieee80211_rx(hw, skb); + local_bh_enable(); +} + +/** + * ieee80211_sta_ps_transition - PS transition for connected sta + * + * When operating in AP mode with the %IEEE80211_HW_AP_LINK_PS + * flag set, use this function to inform mac80211 about a connected station + * entering/leaving PS mode. + * + * This function may not be called in IRQ context or with softirqs enabled. + * + * Calls to this function for a single hardware must be synchronized against + * each other. + * + * The function returns -EINVAL when the requested PS mode is already set. + * + * @sta: currently connected sta + * @start: start or stop PS + */ +int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start); + +/** + * ieee80211_sta_ps_transition_ni - PS transition for connected sta + * (in process context) + * + * Like ieee80211_sta_ps_transition() but can be called in process context + * (internally disables bottom halves). Concurrent call restriction still + * applies. + * + * @sta: currently connected sta + * @start: start or stop PS + */ +static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, + bool start) +{ + int ret; + + local_bh_disable(); + ret = ieee80211_sta_ps_transition(sta, start); + local_bh_enable(); + + return ret; +} + +/* + * The TX headroom reserved by mac80211 for its own tx_status functions. + * This is enough for the radiotap header. + */ +#define IEEE80211_TX_STATUS_HEADROOM 14 + +/** + * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames + * @sta: &struct ieee80211_sta pointer for the sleeping station + * @tid: the TID that has buffered frames + * @buffered: indicates whether or not frames are buffered for this TID + * + * If a driver buffers frames for a powersave station instead of passing + * them back to mac80211 for retransmission, the station may still need + * to be told that there are buffered frames via the TIM bit. + * + * This function informs mac80211 whether or not there are frames that are + * buffered in the driver for a given TID; mac80211 can then use this data + * to set the TIM bit (NOTE: This may call back into the driver's set_tim + * call! Beware of the locking!) + * + * If all frames are released to the station (due to PS-poll or uAPSD) + * then the driver needs to inform mac80211 that there no longer are + * frames buffered. However, when the station wakes up mac80211 assumes + * that all buffered frames will be transmitted and clears this data, + * drivers need to make sure they inform mac80211 about all buffered + * frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP). + * + * Note that technically mac80211 only needs to know this per AC, not per + * TID, but since driver buffering will inevitably happen per TID (since + * it is related to aggregation) it is easier to make mac80211 map the + * TID to the AC as required instead of keeping track in all drivers that + * use this API. + */ +void ieee80211_sta_set_buffered(struct ieee80211_sta *sta, + u8 tid, bool buffered); + +/** + * ieee80211_tx_status - transmit status callback + * + * Call this function for all transmitted frames after they have been + * transmitted. It is permissible to not call this function for + * multicast frames but this can affect statistics. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls + * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe() + * may not be mixed for a single hardware. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + */ +void ieee80211_tx_status(struct ieee80211_hw *hw, + struct sk_buff *skb); + +/** + * ieee80211_tx_status_ni - transmit status callback (in process context) + * + * Like ieee80211_tx_status() but can be called in process context. + * + * Calls to this function, ieee80211_tx_status() and + * ieee80211_tx_status_irqsafe() may not be mixed + * for a single hardware. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + */ +static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + local_bh_disable(); + ieee80211_tx_status(hw, skb); + local_bh_enable(); +} + +/** + * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback + * + * Like ieee80211_tx_status() but can be called in IRQ context + * (internally defers to a tasklet.) + * + * Calls to this function, ieee80211_tx_status() and + * ieee80211_tx_status_ni() may not be mixed for a single hardware. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + */ +void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, + struct sk_buff *skb); + +/** + * ieee80211_report_low_ack - report non-responding station + * + * When operating in AP-mode, call this function to report a non-responding + * connected STA. + * + * @sta: the non-responding connected sta + * @num_packets: number of packets sent to @sta without a response + */ +void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); + +/** + * ieee80211_beacon_get_tim - beacon generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @tim_offset: pointer to variable that will receive the TIM IE offset. + * Set to 0 if invalid (in non-AP modes). + * @tim_length: pointer to variable that will receive the TIM IE length, + * (including the ID and length bytes!). + * Set to 0 if invalid (in non-AP modes). + * + * If the driver implements beaconing modes, it must use this function to + * obtain the beacon frame/template. + * + * If the beacon frames are generated by the host system (i.e., not in + * hardware/firmware), the driver uses this function to get each beacon + * frame from mac80211 -- it is responsible for calling this function + * before the beacon is needed (e.g. based on hardware interrupt). + * + * If the beacon frames are generated by the device, then the driver + * must use the returned beacon as the template and change the TIM IE + * according to the current DTIM parameters/TIM bitmap. + * + * The driver is responsible for freeing the returned skb. + */ +struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 *tim_offset, u16 *tim_length); + +/** + * ieee80211_beacon_get - beacon generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * See ieee80211_beacon_get_tim(). + */ +static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); +} + +/** + * ieee80211_proberesp_get - retrieve a Probe Response template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a Probe Response template which can, for example, be uploaded to + * hardware. The destination address should be set by the caller. + * + * Can only be called in AP mode. + */ +struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** + * ieee80211_pspoll_get - retrieve a PS Poll template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a PS Poll a template which can, for example, uploaded to + * hardware. The template must be updated after association so that correct + * AID, BSSID and MAC address is used. + * + * Note: Caller (or hardware) is responsible for setting the + * &IEEE80211_FCTL_PM bit. + */ +struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** + * ieee80211_nullfunc_get - retrieve a nullfunc template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a Nullfunc template which can, for example, uploaded to + * hardware. The template must be updated after association so that correct + * BSSID and address is used. + * + * Note: Caller (or hardware) is responsible for setting the + * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields. + */ +struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** + * ieee80211_probereq_get - retrieve a Probe Request template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @ssid: SSID buffer + * @ssid_len: length of SSID + * @ie: buffer containing all IEs except SSID for the template + * @ie_len: length of the IE buffer + * + * Creates a Probe Request template which can, for example, be uploaded to + * hardware. + */ +struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len); + +/** + * ieee80211_rts_get - RTS frame generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame: pointer to the frame that is going to be protected by the RTS. + * @frame_len: the frame length (in octets). + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * @rts: The buffer where to store the RTS frame. + * + * If the RTS frames are generated by the host system (i.e., not in + * hardware/firmware), the low-level driver uses this function to receive + * the next RTS frame from the 802.11 code. The low-level is responsible + * for calling this function before and RTS frame is needed. + */ +void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const void *frame, size_t frame_len, + const struct ieee80211_tx_info *frame_txctl, + struct ieee80211_rts *rts); + +/** + * ieee80211_rts_duration - Get the duration field for an RTS frame + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame_len: the length of the frame that is going to be protected by the RTS. + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * + * If the RTS is generated in firmware, but the host system must provide + * the duration field, the low-level driver uses this function to receive + * the duration field value in little-endian byteorder. + */ +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, size_t frame_len, + const struct ieee80211_tx_info *frame_txctl); + +/** + * ieee80211_ctstoself_get - CTS-to-self frame generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame: pointer to the frame that is going to be protected by the CTS-to-self. + * @frame_len: the frame length (in octets). + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * @cts: The buffer where to store the CTS-to-self frame. + * + * If the CTS-to-self frames are generated by the host system (i.e., not in + * hardware/firmware), the low-level driver uses this function to receive + * the next CTS-to-self frame from the 802.11 code. The low-level is responsible + * for calling this function before and CTS-to-self frame is needed. + */ +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const void *frame, size_t frame_len, + const struct ieee80211_tx_info *frame_txctl, + struct ieee80211_cts *cts); + +/** + * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * + * If the CTS-to-self is generated in firmware, but the host system must provide + * the duration field, the low-level driver uses this function to receive + * the duration field value in little-endian byteorder. + */ +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + size_t frame_len, + const struct ieee80211_tx_info *frame_txctl); + +/** + * ieee80211_generic_frame_duration - Calculate the duration field for a frame + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame_len: the length of the frame. + * @rate: the rate at which the frame is going to be transmitted. + * + * Calculate the duration field of some generic frame, given its + * length and transmission rate (in 100kbps). + */ +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + size_t frame_len, + struct ieee80211_rate *rate); + +/** + * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Function for accessing buffered broadcast and multicast frames. If + * hardware/firmware does not implement buffering of broadcast/multicast + * frames when power saving is used, 802.11 code buffers them in the host + * memory. The low-level driver uses this function to fetch next buffered + * frame. In most cases, this is used when generating beacon frame. This + * function returns a pointer to the next buffered skb or NULL if no more + * buffered frames are available. + * + * Note: buffered frames are returned only after DTIM beacon frame was + * generated with ieee80211_beacon_get() and the low-level driver must thus + * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns + * NULL if the previous generated beacon was not DTIM, so the low-level driver + * does not need to check for DTIM beacons separately and should be able to + * use common code for all beacons. + */ +struct sk_buff * +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + +/** + * ieee80211_get_tkip_p1k_iv - get a TKIP phase 1 key for IV32 + * + * This function returns the TKIP phase 1 key for the given IV32. + * + * @keyconf: the parameter passed with the set key + * @iv32: IV32 to get the P1K for + * @p1k: a buffer to which the key will be written, as 5 u16 values + */ +void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, + u32 iv32, u16 *p1k); + +/** + * ieee80211_get_tkip_p1k - get a TKIP phase 1 key + * + * This function returns the TKIP phase 1 key for the IV32 taken + * from the given packet. + * + * @keyconf: the parameter passed with the set key + * @skb: the packet to take the IV32 value from that will be encrypted + * with this P1K + * @p1k: a buffer to which the key will be written, as 5 u16 values + */ +static inline void ieee80211_get_tkip_p1k(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, u16 *p1k) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); + u32 iv32 = get_unaligned_le32(&data[4]); + + ieee80211_get_tkip_p1k_iv(keyconf, iv32, p1k); +} + +/** + * ieee80211_get_tkip_rx_p1k - get a TKIP phase 1 key for RX + * + * This function returns the TKIP phase 1 key for the given IV32 + * and transmitter address. + * + * @keyconf: the parameter passed with the set key + * @ta: TA that will be used with the key + * @iv32: IV32 to get the P1K for + * @p1k: a buffer to which the key will be written, as 5 u16 values + */ +void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf, + const u8 *ta, u32 iv32, u16 *p1k); + +/** + * ieee80211_get_tkip_p2k - get a TKIP phase 2 key + * + * This function computes the TKIP RC4 key for the IV values + * in the packet. + * + * @keyconf: the parameter passed with the set key + * @skb: the packet to take the IV32/IV16 values from that will be + * encrypted with this key + * @p2k: a buffer to which the key will be written, 16 bytes + */ +void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, u8 *p2k); + +/** + * struct ieee80211_key_seq - key sequence counter + * + * @tkip: TKIP data, containing IV32 and IV16 in host byte order + * @ccmp: PN data, most significant byte first (big endian, + * reverse order than in packet) + * @aes_cmac: PN data, most significant byte first (big endian, + * reverse order than in packet) + */ +struct ieee80211_key_seq { + union { + struct { + u32 iv32; + u16 iv16; + } tkip; + struct { + u8 pn[6]; + } ccmp; + struct { + u8 pn[6]; + } aes_cmac; + }; +}; + +/** + * ieee80211_get_key_tx_seq - get key TX sequence counter + * + * @keyconf: the parameter passed with the set key + * @seq: buffer to receive the sequence data + * + * This function allows a driver to retrieve the current TX IV/PN + * for the given key. It must not be called if IV generation is + * offloaded to the device. + * + * Note that this function may only be called when no TX processing + * can be done concurrently, for example when queues are stopped + * and the stop has been synchronized. + */ +void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, + struct ieee80211_key_seq *seq); + +/** + * ieee80211_get_key_rx_seq - get key RX sequence counter + * + * @keyconf: the parameter passed with the set key + * @tid: The TID, or -1 for the management frame value (CCMP only); + * the value on TID 0 is also used for non-QoS frames. For + * CMAC, only TID 0 is valid. + * @seq: buffer to receive the sequence data + * + * This function allows a driver to retrieve the current RX IV/PNs + * for the given key. It must not be called if IV checking is done + * by the device and not by mac80211. + * + * Note that this function may only be called when no RX processing + * can be done concurrently. + */ +void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, + int tid, struct ieee80211_key_seq *seq); + +/** + * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying + * @vif: virtual interface the rekeying was done on + * @bssid: The BSSID of the AP, for checking association + * @replay_ctr: the new replay counter after GTK rekeying + * @gfp: allocation flags + */ +void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp); + +/** + * ieee80211_wake_queue - wake specific queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_wake_queue. + */ +void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); + +/** + * ieee80211_stop_queue - stop specific queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_stop_queue. + */ +void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); + +/** + * ieee80211_queue_stopped - test status of the queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_stop_queue. + */ + +int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue); + +/** + * ieee80211_stop_queues - stop all queues + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * + * Drivers should use this function instead of netif_stop_queue. + */ +void ieee80211_stop_queues(struct ieee80211_hw *hw); + +/** + * ieee80211_wake_queues - wake all queues + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * + * Drivers should use this function instead of netif_wake_queue. + */ +void ieee80211_wake_queues(struct ieee80211_hw *hw); + +/** + * ieee80211_scan_completed - completed hardware scan + * + * When hardware scan offload is used (i.e. the hw_scan() callback is + * assigned) this function needs to be called by the driver to notify + * mac80211 that the scan finished. This function can be called from + * any context, including hardirq context. + * + * @hw: the hardware that finished the scan + * @aborted: set to true if scan was aborted + */ +void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted); + +/** + * ieee80211_sched_scan_results - got results from scheduled scan + * + * When a scheduled scan is running, this function needs to be called by the + * driver whenever there are new scan results available. + * + * @hw: the hardware that is performing scheduled scans + */ +void ieee80211_sched_scan_results(struct ieee80211_hw *hw); + +/** + * ieee80211_sched_scan_stopped - inform that the scheduled scan has stopped + * + * When a scheduled scan is running, this function can be called by + * the driver if it needs to stop the scan to perform another task. + * Usual scenarios are drivers that cannot continue the scheduled scan + * while associating, for instance. + * + * @hw: the hardware that is performing scheduled scans + */ +void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw); + +/** + * ieee80211_iterate_active_interfaces - iterate active interfaces + * + * This function iterates over the interfaces associated with a given + * hardware that are currently active and calls the callback for them. + * This function allows the iterator function to sleep, when the iterator + * function is atomic @ieee80211_iterate_active_interfaces_atomic can + * be used. + * Does not iterate over a new interface during add_interface() + * + * @hw: the hardware struct of which the interfaces should be iterated over + * @iterator: the iterator function to call + * @data: first argument of the iterator function + */ +void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data); + +/** + * ieee80211_iterate_active_interfaces_atomic - iterate active interfaces + * + * This function iterates over the interfaces associated with a given + * hardware that are currently active and calls the callback for them. + * This function requires the iterator callback function to be atomic, + * if that is not desired, use @ieee80211_iterate_active_interfaces instead. + * Does not iterate over a new interface during add_interface() + * + * @hw: the hardware struct of which the interfaces should be iterated over + * @iterator: the iterator function to call, cannot sleep + * @data: first argument of the iterator function + */ +void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, + void (*iterator)(void *data, + u8 *mac, + struct ieee80211_vif *vif), + void *data); + +/** + * ieee80211_queue_work - add work onto the mac80211 workqueue + * + * Drivers and mac80211 use this to add work onto the mac80211 workqueue. + * This helper ensures drivers are not queueing work when they should not be. + * + * @hw: the hardware struct for the interface we are adding work for + * @work: the work we want to add onto the mac80211 workqueue + */ +void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work); + +/** + * ieee80211_queue_delayed_work - add work onto the mac80211 workqueue + * + * Drivers and mac80211 use this to queue delayed work onto the mac80211 + * workqueue. + * + * @hw: the hardware struct for the interface we are adding work for + * @dwork: delayable work to queue onto the mac80211 workqueue + * @delay: number of jiffies to wait before queueing + */ +void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, + struct delayed_work *dwork, + unsigned long delay); + +/** + * ieee80211_start_tx_ba_session - Start a tx Block Ack session. + * @sta: the station for which to start a BA session + * @tid: the TID to BA on. + * @timeout: session timeout value (in TUs) + * + * Return: success if addBA request was sent, failure otherwise + * + * Although mac80211/low level driver/user space application can estimate + * the need to start aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid, + u16 timeout); + +/** + * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. + * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @ra: receiver address of the BA session recipient. + * @tid: the TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session. It can be called + * from any context. + */ +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, + u16 tid); + +/** + * ieee80211_stop_tx_ba_session - Stop a Block Ack session. + * @sta: the station whose BA session to stop + * @tid: the TID to stop BA. + * + * Return: negative error if the TID is invalid, or no aggregation active + * + * Although mac80211/low level driver/user space application can estimate + * the need to stop aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid); + +/** + * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. + * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @ra: receiver address of the BA session recipient. + * @tid: the desired TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session tear down. It + * can be called from any context. + */ +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, + u16 tid); + +/** + * ieee80211_find_sta - find a station + * + * @vif: virtual interface to look for station on + * @addr: station's address + * + * This function must be called under RCU lock and the + * resulting pointer is only valid under RCU lock as well. + */ +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, + const u8 *addr); + +/** + * ieee80211_find_sta_by_ifaddr - find a station on hardware + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @addr: remote station's address + * @localaddr: local address (vif->sdata->vif.addr). Use NULL for 'any'. + * + * This function must be called under RCU lock and the + * resulting pointer is only valid under RCU lock as well. + * + * NOTE: You may pass NULL for localaddr, but then you will just get + * the first STA that matches the remote address 'addr'. + * We can have multiple STA associated with multiple + * logical stations (e.g. consider a station connecting to another + * BSSID on the same AP hardware without disconnecting first). + * In this case, the result of this method with localaddr NULL + * is not reliable. + * + * DO NOT USE THIS FUNCTION with localaddr NULL if at all possible. + */ +struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, + const u8 *addr, + const u8 *localaddr); + +/** + * ieee80211_sta_block_awake - block station from waking up + * @hw: the hardware + * @pubsta: the station + * @block: whether to block or unblock + * + * Some devices require that all frames that are on the queues + * for a specific station that went to sleep are flushed before + * a poll response or frames after the station woke up can be + * delivered to that it. Note that such frames must be rejected + * by the driver as filtered, with the appropriate status flag. + * + * This function allows implementing this mode in a race-free + * manner. + * + * To do this, a driver must keep track of the number of frames + * still enqueued for a specific station. If this number is not + * zero when the station goes to sleep, the driver must call + * this function to force mac80211 to consider the station to + * be asleep regardless of the station's actual state. Once the + * number of outstanding frames reaches zero, the driver must + * call this function again to unblock the station. That will + * cause mac80211 to be able to send ps-poll responses, and if + * the station queried in the meantime then frames will also + * be sent out as a result of this. Additionally, the driver + * will be notified that the station woke up some time after + * it is unblocked, regardless of whether the station actually + * woke up while blocked or not. + */ +void ieee80211_sta_block_awake(struct ieee80211_hw *hw, + struct ieee80211_sta *pubsta, bool block); + +/** + * ieee80211_sta_eosp - notify mac80211 about end of SP + * @pubsta: the station + * + * When a device transmits frames in a way that it can't tell + * mac80211 in the TX status about the EOSP, it must clear the + * %IEEE80211_TX_STATUS_EOSP bit and call this function instead. + * This applies for PS-Poll as well as uAPSD. + * + * Note that there is no non-_irqsafe version right now as + * it wasn't needed, but just like _tx_status() and _rx() + * must not be mixed in irqsafe/non-irqsafe versions, this + * function must not be mixed with those either. Use the + * all irqsafe, or all non-irqsafe, don't mix! If you need + * the non-irqsafe version of this, you need to add it. + */ +void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta); + +/** + * ieee80211_iter_keys - iterate keys programmed into the device + * @hw: pointer obtained from ieee80211_alloc_hw() + * @vif: virtual interface to iterate, may be %NULL for all + * @iter: iterator function that will be called for each key + * @iter_data: custom data to pass to the iterator function + * + * This function can be used to iterate all the keys known to + * mac80211, even those that weren't previously programmed into + * the device. This is intended for use in WoWLAN if the device + * needs reprogramming of the keys during suspend. Note that due + * to locking reasons, it is also only safe to call this at few + * spots since it must hold the RTNL and be able to sleep. + * + * The order in which the keys are iterated matches the order + * in which they were originally installed and handed to the + * set_key callback. + */ +void ieee80211_iter_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + void (*iter)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data), + void *iter_data); + +/** + * ieee80211_ap_probereq_get - retrieve a Probe Request template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a Probe Request template which can, for example, be uploaded to + * hardware. The template is filled with bssid, ssid and supported rate + * information. This function must only be called from within the + * .bss_info_changed callback function and only in managed mode. The function + * is only useful when the interface is associated, otherwise it will return + * NULL. + */ +struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** + * ieee80211_beacon_loss - inform hardware does not receive beacons + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER and + * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the + * hardware is not receiving beacons with this function. + */ +void ieee80211_beacon_loss(struct ieee80211_vif *vif); + +/** + * ieee80211_connection_loss - inform hardware has lost connection to the AP + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER, and + * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver + * needs to inform if the connection to the AP has been lost. + * + * This function will cause immediate change to disassociated state, + * without connection recovery attempts. + */ +void ieee80211_connection_loss(struct ieee80211_vif *vif); + +/** + * ieee80211_resume_disconnect - disconnect from AP after resume + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Instructs mac80211 to disconnect from the AP after resume. + * Drivers can use this after WoWLAN if they know that the + * connection cannot be kept up, for example because keys were + * used while the device was asleep but the replay counters or + * similar cannot be retrieved from the device during resume. + * + * Note that due to implementation issues, if the driver uses + * the reconfiguration functionality during resume the interface + * will still be added as associated first during resume and then + * disconnect normally later. + * + * This function can only be called from the resume callback and + * the driver must not be holding any of its own locks while it + * calls this function, or at least not any locks it needs in the + * key configuration paths (if it supports HW crypto). + */ +void ieee80211_resume_disconnect(struct ieee80211_vif *vif); + +/** + * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Some hardware require full power save to manage simultaneous BT traffic + * on the WLAN frequency. Full PSM is required periodically, whenever there are + * burst of BT traffic. The hardware gets information of BT traffic via + * hardware co-existence lines, and consequentially requests mac80211 to + * (temporarily) enter full psm. + * This function will only temporarily disable dynamic PS, not enable PSM if + * it was not already enabled. + * The driver must make sure to re-enable dynamic PS using + * ieee80211_enable_dyn_ps() if the driver has disabled it. + * + */ +void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif); + +/** + * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * This function restores dynamic PS after being temporarily disabled via + * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must + * be coupled with an eventual call to this function. + * + */ +void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif); + +/** + * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring + * rssi threshold triggered + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @rssi_event: the RSSI trigger event type + * @gfp: context flags + * + * When the %IEEE80211_HW_SUPPORTS_CQM_RSSI is set, and a connection quality + * monitoring is configured with an rssi threshold, the driver will inform + * whenever the rssi level reaches the threshold. + */ +void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, + enum nl80211_cqm_rssi_threshold_event rssi_event, + gfp_t gfp); + +/** + * ieee80211_get_operstate - get the operstate of the vif + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * The driver might need to know the operstate of the net_device + * (specifically, whether the link is IF_OPER_UP after resume) + */ +unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif); + +/** + * ieee80211_chswitch_done - Complete channel switch process + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @success: make the channel switch successful or not + * + * Complete the channel switch post-process: set the new operational channel + * and wake up the suspended queues. + */ +void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success); + +/** + * ieee80211_request_smps - request SM PS transition + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @smps_mode: new SM PS mode + * + * This allows the driver to request an SM PS transition in managed + * mode. This is useful when the driver has more information than + * the stack about possible interference, for example by bluetooth. + */ +void ieee80211_request_smps(struct ieee80211_vif *vif, + enum ieee80211_smps_mode smps_mode); + +/** + * ieee80211_key_removed - disable hw acceleration for key + * @key_conf: The key hw acceleration should be disabled for + * + * This allows drivers to indicate that the given key has been + * removed from hardware acceleration, due to a new key that + * was added. Don't use this if the key can continue to be used + * for TX, if the key restriction is on RX only it is permitted + * to keep the key for TX only and not call this function. + * + * Due to locking constraints, it may only be called during + * @set_key. This function must be allowed to sleep, and the + * key it tries to disable may still be used until it returns. + */ +void ieee80211_key_removed(struct ieee80211_key_conf *key_conf); + +/** + * ieee80211_ready_on_channel - notification of remain-on-channel start + * @hw: pointer as obtained from ieee80211_alloc_hw() + */ +void ieee80211_ready_on_channel(struct ieee80211_hw *hw); + +/** + * ieee80211_remain_on_channel_expired - remain_on_channel duration expired + * @hw: pointer as obtained from ieee80211_alloc_hw() + */ +void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw); + +/** + * ieee80211_stop_rx_ba_session - callback to stop existing BA sessions + * + * in order not to harm the system performance and user experience, the device + * may request not to allow any rx ba session and tear down existing rx ba + * sessions based on system constraints such as periodic BT activity that needs + * to limit wlan activity (eg.sco or a2dp)." + * in such cases, the intention is to limit the duration of the rx ppdu and + * therefore prevent the peer device to use a-mpdu aggregation. + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @ba_rx_bitmap: Bit map of open rx ba per tid + * @addr: & to bssid mac address + */ +void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, + const u8 *addr); + +/** + * ieee80211_send_bar - send a BlockAckReq frame + * + * can be used to flush pending frames from the peer's aggregation reorder + * buffer. + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @ra: the peer's destination address + * @tid: the TID of the aggregation session + * @ssn: the new starting sequence number for the receiver + */ +void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn); + +/* Rate control API */ + +/** + * enum rate_control_changed - flags to indicate which parameter changed + * + * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have + * changed, rate control algorithm can update its internal state if needed. + */ +enum rate_control_changed { + IEEE80211_RC_HT_CHANGED = BIT(0) +}; + +/** + * struct ieee80211_tx_rate_control - rate control information for/from RC algo + * + * @hw: The hardware the algorithm is invoked for. + * @sband: The band this frame is being transmitted on. + * @bss_conf: the current BSS configuration + * @reported_rate: The rate control algorithm can fill this in to indicate + * which rate should be reported to userspace as the current rate and + * used for rate calculations in the mesh network. + * @rts: whether RTS will be used for this frame because it is longer than the + * RTS threshold + * @short_preamble: whether mac80211 will request short-preamble transmission + * if the selected rate supports it + * @max_rate_idx: user-requested maximum rate (not MCS for now) + * (deprecated; this will be removed once drivers get updated to use + * rate_idx_mask) + * @rate_idx_mask: user-requested rate mask (not MCS for now) + * @skb: the skb that will be transmitted, the control information in it needs + * to be filled in + * @bss: whether this frame is sent out in AP or IBSS mode + */ +struct ieee80211_tx_rate_control { + struct ieee80211_hw *hw; + struct ieee80211_supported_band *sband; + struct ieee80211_bss_conf *bss_conf; + struct sk_buff *skb; + struct ieee80211_tx_rate reported_rate; + bool rts, short_preamble; + u8 max_rate_idx; + u32 rate_idx_mask; + bool bss; +}; + +struct rate_control_ops { + struct module *module; + const char *name; + void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); + void (*free)(void *priv); + + void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); + void (*rate_init)(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta); + void (*rate_update)(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, + void *priv_sta, u32 changed, + enum nl80211_channel_type oper_chan_type); + void (*free_sta)(void *priv, struct ieee80211_sta *sta, + void *priv_sta); + + void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + struct sk_buff *skb); + void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc); + + void (*add_sta_debugfs)(void *priv, void *priv_sta, + struct dentry *dir); + void (*remove_sta_debugfs)(void *priv, void *priv_sta); +}; + +static inline int rate_supported(struct ieee80211_sta *sta, + enum ieee80211_band band, + int index) +{ + return (sta == NULL || sta->supp_rates[band] & BIT(index)); +} + +/** + * rate_control_send_low - helper for drivers for management/no-ack frames + * + * Rate control algorithms that agree to use the lowest rate to + * send management frames and NO_ACK data with the respective hw + * retries should use this in the beginning of their mac80211 get_rate + * callback. If true is returned the rate control can simply return. + * If false is returned we guarantee that sta and sta and priv_sta is + * not null. + * + * Rate control algorithms wishing to do more intelligent selection of + * rate for multicast/broadcast frames may choose to not use this. + * + * @sta: &struct ieee80211_sta pointer to the target destination. Note + * that this may be null. + * @priv_sta: private rate control structure. This may be null. + * @txrc: rate control information we sholud populate for mac80211. + */ +bool rate_control_send_low(struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc); + + +static inline s8 +rate_lowest_index(struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) +{ + int i; + + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) + return i; + + /* warn when we cannot find a rate. */ + WARN_ON_ONCE(1); + + /* and return 0 (the lowest index) */ + return 0; +} + +static inline +bool rate_usable_index_exists(struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) +{ + unsigned int i; + + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) + return true; + return false; +} + +int ieee80211_rate_control_register(struct rate_control_ops *ops); +void ieee80211_rate_control_unregister(struct rate_control_ops *ops); + +static inline bool +conf_is_ht20(struct ieee80211_conf *conf) +{ + return conf->channel_type == NL80211_CHAN_HT20; +} + +static inline bool +conf_is_ht40_minus(struct ieee80211_conf *conf) +{ + return conf->channel_type == NL80211_CHAN_HT40MINUS; +} + +static inline bool +conf_is_ht40_plus(struct ieee80211_conf *conf) +{ + return conf->channel_type == NL80211_CHAN_HT40PLUS; +} + +static inline bool +conf_is_ht40(struct ieee80211_conf *conf) +{ + return conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf); +} + +static inline bool +conf_is_ht(struct ieee80211_conf *conf) +{ + return conf->channel_type != NL80211_CHAN_NO_HT; +} + +static inline enum nl80211_iftype +ieee80211_iftype_p2p(enum nl80211_iftype type, bool p2p) +{ + if (p2p) { + switch (type) { + case NL80211_IFTYPE_STATION: + return NL80211_IFTYPE_P2P_CLIENT; + case NL80211_IFTYPE_AP: + return NL80211_IFTYPE_P2P_GO; + default: + break; + } + } + return type; +} + +static inline enum nl80211_iftype +ieee80211_vif_type_p2p(struct ieee80211_vif *vif) +{ + return ieee80211_iftype_p2p(vif->type, vif->p2p); +} + +void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, + int rssi_min_thold, + int rssi_max_thold); + +void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); + +int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb); + +int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, + struct sk_buff *skb); +#endif /* MAC80211_H */ diff --git a/include/compat/net/net_namespace.h b/include/compat/net/net_namespace.h new file mode 100644 index 00000000..0f74944b --- /dev/null +++ b/include/compat/net/net_namespace.h @@ -0,0 +1,10 @@ +#ifndef _COMPAT_NET_NET_NAMESPACE_H +#define _COMPAT_NET_NET_NAMESPACE_H 1 + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)) +#include_next +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)) */ + +#endif /* _COMPAT_NET_NET_NAMESPACE_H */ diff --git a/include/compat/net/regulatory.h b/include/compat/net/regulatory.h new file mode 100644 index 00000000..eb7d3c2d --- /dev/null +++ b/include/compat/net/regulatory.h @@ -0,0 +1,116 @@ +#ifndef __NET_REGULATORY_H +#define __NET_REGULATORY_H +/* + * regulatory support structures + * + * Copyright 2008-2009 Luis R. Rodriguez + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + + +/** + * enum environment_cap - Environment parsed from country IE + * @ENVIRON_ANY: indicates country IE applies to both indoor and + * outdoor operation. + * @ENVIRON_INDOOR: indicates country IE applies only to indoor operation + * @ENVIRON_OUTDOOR: indicates country IE applies only to outdoor operation + */ +enum environment_cap { + ENVIRON_ANY, + ENVIRON_INDOOR, + ENVIRON_OUTDOOR, +}; + +/** + * struct regulatory_request - used to keep track of regulatory requests + * + * @wiphy_idx: this is set if this request's initiator is + * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This + * can be used by the wireless core to deal with conflicts + * and potentially inform users of which devices specifically + * cased the conflicts. + * @initiator: indicates who sent this request, could be any of + * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) + * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested + * regulatory domain. We have a few special codes: + * 00 - World regulatory domain + * 99 - built by driver but a specific alpha2 cannot be determined + * 98 - result of an intersection between two regulatory domains + * 97 - regulatory domain has not yet been configured + * @intersect: indicates whether the wireless core should intersect + * the requested regulatory domain with the presently set regulatory + * domain. + * @processed: indicates whether or not this requests has already been + * processed. When the last request is processed it means that the + * currently regulatory domain set on cfg80211 is updated from + * CRDA and can be used by other regulatory requests. When a + * the last request is not yet processed we must yield until it + * is processed before processing any new requests. + * @country_ie_checksum: checksum of the last processed and accepted + * country IE + * @country_ie_env: lets us know if the AP is telling us we are outdoor, + * indoor, or if it doesn't matter + * @list: used to insert into the reg_requests_list linked list + */ +struct regulatory_request { + int wiphy_idx; + enum nl80211_reg_initiator initiator; + char alpha2[2]; + bool intersect; + bool processed; + enum environment_cap country_ie_env; + struct list_head list; +}; + +struct ieee80211_freq_range { + u32 start_freq_khz; + u32 end_freq_khz; + u32 max_bandwidth_khz; +}; + +struct ieee80211_power_rule { + u32 max_antenna_gain; + u32 max_eirp; +}; + +struct ieee80211_reg_rule { + struct ieee80211_freq_range freq_range; + struct ieee80211_power_rule power_rule; + u32 flags; +}; + +struct ieee80211_regdomain { + u32 n_reg_rules; + char alpha2[2]; + struct ieee80211_reg_rule reg_rules[]; +}; + +#define MHZ_TO_KHZ(freq) ((freq) * 1000) +#define KHZ_TO_MHZ(freq) ((freq) / 1000) +#define DBI_TO_MBI(gain) ((gain) * 100) +#define MBI_TO_DBI(gain) ((gain) / 100) +#define DBM_TO_MBM(gain) ((gain) * 100) +#define MBM_TO_DBM(gain) ((gain) / 100) + +#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ +{ \ + .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ + .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ + .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ + .power_rule.max_antenna_gain = DBI_TO_MBI(gain),\ + .power_rule.max_eirp = DBM_TO_MBM(eirp), \ + .flags = reg_flags, \ +} + +#endif diff --git a/include/linux/Kbuild b/include/linux/Kbuild index dc15414c..3251d7d4 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -260,7 +260,6 @@ header-y += mroute6.h header-y += msdos_fs.h header-y += msg.h header-y += msm_adc.h -header-y += msm_ion.h header-y += mtio.h header-y += n_r3964.h header-y += nbd.h diff --git a/include/linux/audit.h b/include/linux/audit.h index acc4ff37..89381a27 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -70,6 +70,8 @@ #define AUDIT_TTY_GET 1016 /* Get TTY auditing status */ #define AUDIT_TTY_SET 1017 /* Set TTY auditing status */ +#define LSM_AUDIT_DATA_IOCTL_OP 11 + #define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ #define AUDIT_USER_AVC 1107 /* We filter this differently */ #define AUDIT_USER_TTY 1124 /* Non-ICANON TTY input meaning */ @@ -480,14 +482,14 @@ static inline void audit_syscall_entry(int arch, int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) __audit_syscall_entry(arch, major, a0, a1, a2, a3); } static inline void audit_syscall_exit(void *pt_regs) { if (unlikely(current->audit_context)) { int success = is_syscall_success(pt_regs); - long return_code = regs_return_value(pt_regs); + int return_code = regs_return_value(pt_regs); __audit_syscall_exit(success, return_code); } diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 68117aa6..4f88b069 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -117,30 +117,50 @@ enum { /* Need to know about CPUs going up/down? */ #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) #define cpu_notifier(fn, pri) { \ - static struct notifier_block fn##_nb = \ + static struct notifier_block fn##_nb __cpuinitdata = \ { .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); @@ -148,19 +168,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) { } @@ -169,6 +202,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; @@ -180,8 +221,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) int cpu_down(unsigned int cpu); #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE @@ -204,9 +248,12 @@ static inline void cpu_hotplug_driver_unlock(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 diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 8ca59c07..997efc68 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -360,27 +360,116 @@ extern struct cpufreq_governor cpufreq_gov_performance; #endif #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_performance) -#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE) -extern struct cpufreq_governor cpufreq_gov_powersave; -#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_powersave) -#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE) -extern struct cpufreq_governor cpufreq_gov_userspace; -#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_userspace) -#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND) -extern struct cpufreq_governor cpufreq_gov_ondemand; -#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_ondemand) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE) +extern struct cpufreq_governor cpufreq_gov_adaptive; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_adaptive) #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE) extern struct cpufreq_governor cpufreq_gov_conservative; #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER) +extern struct cpufreq_governor cpufreq_gov_hyper; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_hyper) #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE) extern struct cpufreq_governor cpufreq_gov_interactive; #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_interactive) -#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG) -extern struct cpufreq_governor cpufreq_gov_hotplug; -#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_hotplug) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_LULZACTIVE) +extern struct cpufreq_governor cpufreq_gov_lulzactive; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_lulzactive) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVEX) +extern struct cpufreq_governor cpufreq_gov_interactivex; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_interactivex) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_LIONHEART) +extern struct cpufreq_governor cpufreq_gov_lionheart; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_lionheart) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND) +extern struct cpufreq_governor cpufreq_gov_ondemand; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_ondemand) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMANDX) +extern struct cpufreq_governor cpufreq_gov_ondemandx; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_ondemandx) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE) +extern struct cpufreq_governor cpufreq_gov_powersave; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_powersave) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2) +extern struct cpufreq_governor cpufreq_gov_smartass2; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_smartass2) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE) +extern struct cpufreq_governor cpufreq_gov_userspace; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_userspace) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND) +extern struct cpufreq_governor cpufreq_gov_intellidemand; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_intellidemand) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ASSWAX) +extern struct cpufreq_governor cpufreq_gov_asswax; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_asswax) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_BADASS) +extern struct cpufreq_governor cpufreq_gov_badass; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_badass) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_DANCEDANCE) +extern struct cpufreq_governor cpufreq_gov_dancedance; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_dancedance) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASSH3) +extern struct cpufreq_governor cpufreq_gov_smartassh3; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_smartassh3) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_WHEATLEY) +extern struct cpufreq_governor cpufreq_gov_wheatley; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_wheatley) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_LAGFREE) +extern struct cpufreq_governor cpufreq_gov_lagfree; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_lagfree) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SAVAGEDZEN) +extern struct cpufreq_governor cpufreq_gov_savagedzen; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_savagedzen) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_BRAZILLIANWAX) +extern struct cpufreq_governor cpufreq_gov_brazilianwax; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_brazilianwax) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_LULZACTIVEW) +extern struct cpufreq_governor cpufreq_gov_lulzactivew; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_lulzactivew) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_MINMAX) +extern struct cpufreq_governor cpufreq_gov_minmax; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_minmax) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SCARY) +extern struct cpufreq_governor cpufreq_gov_scary; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_scary) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ZZMOOVE) +extern struct cpufreq_governor cpufreq_gov_zzmoove; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_zzmoove) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SKYWALKER) +extern struct cpufreq_governor cpufreq_gov_skywalker; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_skywalker) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_VIRTUOUS) +extern struct cpufreq_governor cpufreq_gov_virtuous; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_virtuous) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTMAX_EPS) +extern struct cpufreq_governor cpufreq_gov_smartmax_eps; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_smartmax_eps) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SUPERBAD) +extern struct cpufreq_governor cpufreq_gov_superbad; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_superbad) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SMOOTHASS) +extern struct cpufreq_governor cpufreq_gov_smoothass; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_smoothass) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIACTIVE) +extern struct cpufreq_governor cpufreq_gov_intelliactive; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_intelliactive) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIMM) +extern struct cpufreq_governor cpufreq_gov_intellimm; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_intellimm) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_STOCKDEMAND) +extern struct cpufreq_governor cpufreq_gov_stockdemand; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_stockdemand) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_YANKDEMAND) +extern struct cpufreq_governor cpufreq_gov_yankdemand; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_yankdemand) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER) +extern struct cpufreq_governor cpufreq_gov_hyper; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_hyper) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD) +extern struct cpufreq_governor cpufreq_gov_alucard; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_alucard) #endif - /********************************************************************* * FREQUENCY TABLE HELPERS * *********************************************************************/ diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h index 547ab568..18513e37 100644 --- a/include/linux/dma-attrs.h +++ b/include/linux/dma-attrs.h @@ -15,6 +15,8 @@ enum dma_attr { DMA_ATTR_WEAK_ORDERING, DMA_ATTR_WRITE_COMBINE, DMA_ATTR_NON_CONSISTENT, + DMA_ATTR_NO_KERNEL_MAPPING, + DMA_ATTR_STRONGLY_ORDERED, DMA_ATTR_MAX, }; diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 7d4e0356..bc53c52b 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -22,6 +22,9 @@ typedef void (elevator_bio_merged_fn) (struct request_queue *, typedef int (elevator_dispatch_fn) (struct request_queue *, int); typedef void (elevator_add_req_fn) (struct request_queue *, struct request *); +typedef int (elevator_reinsert_req_fn) (struct request_queue *, + struct request *); +typedef bool (elevator_is_urgent_fn) (struct request_queue *); typedef struct request *(elevator_request_list_fn) (struct request_queue *, struct request *); typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *); typedef int (elevator_may_queue_fn) (struct request_queue *, int); @@ -35,6 +38,7 @@ typedef void (elevator_deactivate_req_fn) (struct request_queue *, struct reques typedef void *(elevator_init_fn) (struct request_queue *); typedef void (elevator_exit_fn) (struct elevator_queue *); +typedef void (elevator_registered_fn) (struct request_queue *); struct elevator_ops { @@ -46,6 +50,9 @@ struct elevator_ops elevator_dispatch_fn *elevator_dispatch_fn; elevator_add_req_fn *elevator_add_req_fn; + elevator_reinsert_req_fn *elevator_reinsert_req_fn; + elevator_is_urgent_fn *elevator_is_urgent_fn; + elevator_activate_req_fn *elevator_activate_req_fn; elevator_deactivate_req_fn *elevator_deactivate_req_fn; @@ -64,6 +71,7 @@ struct elevator_ops elevator_init_fn *elevator_init_fn; elevator_exit_fn *elevator_exit_fn; + elevator_registered_fn *elevator_registered_fn; }; #define ELV_NAME_MAX (16) @@ -122,6 +130,7 @@ extern void elv_merged_request(struct request_queue *, struct request *, int); extern void elv_bio_merged(struct request_queue *q, struct request *, struct bio *); extern void elv_requeue_request(struct request_queue *, struct request *); +extern int elv_reinsert_request(struct request_queue *, struct request *); extern struct request *elv_former_request(struct request_queue *, struct request *); extern struct request *elv_latter_request(struct request_queue *, struct request *); extern int elv_register_queue(struct request_queue *q); diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 51da65b6..9dcdb625 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -49,6 +49,8 @@ enum { FRA_TABLE, /* Extended table id */ FRA_FWMASK, /* mask for netfilter mark */ FRA_OIFNAME, + FRA_UID_START, /* UID range */ + FRA_UID_END, __FRA_MAX }; diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 23fd3840..9f61f6d9 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -167,7 +167,7 @@ static inline bool freezer_should_skip(struct task_struct *p) __retval; \ }) -#define wait_event_freezable_exclusive(wq, condition) \ +#define wait_event_freezable_exclusive(wq, condition) \ ({ \ int __retval; \ freezer_do_not_count(); \ diff --git a/include/linux/frontswap.h b/include/linux/frontswap.h new file mode 100644 index 00000000..30442547 --- /dev/null +++ b/include/linux/frontswap.h @@ -0,0 +1,129 @@ +#ifndef _LINUX_FRONTSWAP_H +#define _LINUX_FRONTSWAP_H + +#include +#include +#include + +struct frontswap_ops { + void (*init)(unsigned); + int (*store)(unsigned, pgoff_t, struct page *); + int (*load)(unsigned, pgoff_t, struct page *); + void (*invalidate_page)(unsigned, pgoff_t); + void (*invalidate_area)(unsigned); +}; + +extern bool frontswap_enabled; +extern struct frontswap_ops + frontswap_register_ops(struct frontswap_ops *ops); +extern void frontswap_shrink(unsigned long); +extern unsigned long frontswap_curr_pages(void); +extern void frontswap_writethrough(bool); +#define FRONTSWAP_HAS_EXCLUSIVE_GETS +extern void frontswap_tmem_exclusive_gets(bool); + +extern void __frontswap_init(unsigned type); +extern int __frontswap_store(struct page *page); +extern int __frontswap_load(struct page *page); +extern void __frontswap_invalidate_page(unsigned, pgoff_t); +extern void __frontswap_invalidate_area(unsigned); + +#ifdef CONFIG_FRONTSWAP + +static inline bool frontswap_test(struct swap_info_struct *sis, pgoff_t offset) +{ + bool ret = false; + + if (frontswap_enabled && sis->frontswap_map) + ret = test_bit(offset, sis->frontswap_map); + return ret; +} + +static inline void frontswap_set(struct swap_info_struct *sis, pgoff_t offset) +{ + if (frontswap_enabled && sis->frontswap_map) + set_bit(offset, sis->frontswap_map); +} + +static inline void frontswap_clear(struct swap_info_struct *sis, pgoff_t offset) +{ + if (frontswap_enabled && sis->frontswap_map) + clear_bit(offset, sis->frontswap_map); +} + +static inline void frontswap_map_set(struct swap_info_struct *p, + unsigned long *map) +{ + p->frontswap_map = map; +} + +static inline unsigned long *frontswap_map_get(struct swap_info_struct *p) +{ + return p->frontswap_map; +} +#else +/* all inline routines become no-ops and all externs are ignored */ + +#define frontswap_enabled (0) + +static inline bool frontswap_test(struct swap_info_struct *sis, pgoff_t offset) +{ + return false; +} + +static inline void frontswap_set(struct swap_info_struct *sis, pgoff_t offset) +{ +} + +static inline void frontswap_clear(struct swap_info_struct *sis, pgoff_t offset) +{ +} + +static inline void frontswap_map_set(struct swap_info_struct *p, + unsigned long *map) +{ +} + +static inline unsigned long *frontswap_map_get(struct swap_info_struct *p) +{ + return NULL; +} +#endif + +static inline int frontswap_store(struct page *page) +{ + int ret = -1; + + if (frontswap_enabled) + ret = __frontswap_store(page); + return ret; +} + +static inline int frontswap_load(struct page *page) +{ + int ret = -1; + + if (frontswap_enabled) + ret = __frontswap_load(page); + return ret; +} + +static inline void frontswap_invalidate_page(unsigned type, pgoff_t offset) +{ + if (frontswap_enabled) + __frontswap_invalidate_page(type, offset); +} + +static inline void frontswap_invalidate_area(unsigned type) +{ + if (frontswap_enabled) + __frontswap_invalidate_area(type); +} + +static inline void frontswap_init(unsigned type) +{ + if (frontswap_enabled) + __frontswap_init(type); +} + +#endif /* _LINUX_FRONTSWAP_H */ diff --git a/include/linux/genlock.h b/include/linux/genlock.h index 587c49df..e2336629 100644 --- a/include/linux/genlock.h +++ b/include/linux/genlock.h @@ -8,6 +8,7 @@ struct genlock_handle; struct genlock_handle *genlock_get_handle(void); struct genlock_handle *genlock_get_handle_fd(int fd); +int genlock_get_fd_handle(struct genlock_handle *handle); void genlock_put_handle(struct genlock_handle *handle); struct genlock *genlock_create_lock(struct genlock_handle *); struct genlock *genlock_attach_lock(struct genlock_handle *, int fd); diff --git a/include/linux/ion.h b/include/linux/ion.h index 02aebb68..b47cb8aa 100644 --- a/include/linux/ion.h +++ b/include/linux/ion.h @@ -40,18 +40,15 @@ enum ion_heap_type { ION_HEAP_TYPE_SYSTEM, ION_HEAP_TYPE_SYSTEM_CONTIG, ION_HEAP_TYPE_CARVEOUT, - ION_HEAP_TYPE_IOMMU, - ION_HEAP_TYPE_CP, ION_HEAP_TYPE_DMA, ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always are at the end of this enum */ - ION_NUM_HEAPS = 16, + ION_NUM_HEAPS, }; #define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) #define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) #define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) -#define ION_HEAP_CP_MASK (1 << ION_HEAP_TYPE_CP) #define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) /** @@ -63,86 +60,6 @@ enum ion_heap_type { maintenance when the buffer is mapped for dma */ -/** - * These are the only ids that should be used for Ion heap ids. - * The ids listed are the order in which allocation will be attempted - * if specified. Don't swap the order of heap ids unless you know what - * you are doing! - * Id's are spaced by purpose to allow new Id's to be inserted in-between (for - * possible fallbacks) - */ - -enum ion_heap_ids { - INVALID_HEAP_ID = -1, - ION_CP_MM_HEAP_ID = 8, - ION_CP_MFC_HEAP_ID = 12, - ION_CP_WB_HEAP_ID = 16, /* 8660 only */ - ION_CAMERA_HEAP_ID = 20, /* 8660 only */ - ION_SF_HEAP_ID = 24, - ION_IOMMU_HEAP_ID = 25, - ION_QSECOM_HEAP_ID = 26, - ION_AUDIO_HEAP_BL_ID = 27, - ION_AUDIO_HEAP_ID = 28, - - ION_MM_FIRMWARE_HEAP_ID = 29, - ION_SYSTEM_HEAP_ID = 30, - - ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */ -}; - -enum ion_fixed_position { - NOT_FIXED, - FIXED_LOW, - FIXED_MIDDLE, - FIXED_HIGH, -}; - -enum cp_mem_usage { - VIDEO_BITSTREAM = 0x1, - VIDEO_PIXEL = 0x2, - VIDEO_NONPIXEL = 0x3, - MAX_USAGE = 0x4, - UNKNOWN = 0x7FFFFFFF, -}; - -/** - * Flag to use when allocating to indicate that a heap is secure. - */ -#define ION_SECURE (1 << ION_HEAP_ID_RESERVED) - -/** - * Macro should be used with ion_heap_ids defined above. - */ -#define ION_HEAP(bit) (1 << (bit)) - -#define ION_VMALLOC_HEAP_NAME "vmalloc" -#define ION_AUDIO_HEAP_NAME "audio" -#define ION_AUDIO_BL_HEAP_NAME "bl_mem_audio" -#define ION_SF_HEAP_NAME "sf" -#define ION_MM_HEAP_NAME "mm" -#define ION_CAMERA_HEAP_NAME "camera_preview" -#define ION_IOMMU_HEAP_NAME "iommu" -#define ION_MFC_HEAP_NAME "mfc" -#define ION_WB_HEAP_NAME "wb" -#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw" -#define ION_QSECOM_HEAP_NAME "qsecom" -#define ION_FMEM_HEAP_NAME "fmem" - -#define CACHED 1 -#define UNCACHED 0 - -#define ION_CACHE_SHIFT 0 - -#define ION_SET_CACHE(__cache) ((__cache) << ION_CACHE_SHIFT) - -#define ION_IS_CACHED(__flags) ((__flags) & (1 << ION_CACHE_SHIFT)) - -/* - * This flag allows clients when mapping into the IOMMU to specify to - * defer un-mapping from the IOMMU until the buffer memory is freed. - */ -#define ION_IOMMU_UNMAP_DELAYED 1 - #ifdef __KERNEL__ #include #include @@ -184,73 +101,6 @@ struct ion_platform_heap { void *priv; }; -/** - * struct ion_cp_heap_pdata - defines a content protection heap in the given - * platform - * @permission_type: Memory ID used to identify the memory to TZ - * @align: Alignment requirement for the memory - * @secure_base: Base address for securing the heap. - * Note: This might be different from actual base address - * of this heap in the case of a shared heap. - * @secure_size: Memory size for securing the heap. - * Note: This might be different from actual size - * of this heap in the case of a shared heap. - * @reusable Flag indicating whether this heap is reusable of not. - * (see FMEM) - * @mem_is_fmem Flag indicating whether this memory is coming from fmem - * or not. - * @fixed_position If nonzero, position in the fixed area. - * @virt_addr: Virtual address used when using fmem. - * @iommu_map_all: Indicates whether we should map whole heap into IOMMU. - * @iommu_2x_map_domain: Indicates the domain to use for overmapping. - * @request_region: function to be called when the number of allocations - * goes from 0 -> 1 - * @release_region: function to be called when the number of allocations - * goes from 1 -> 0 - * @setup_region: function to be called upon ion registration - * - */ -struct ion_cp_heap_pdata { - enum ion_permission_type permission_type; - unsigned int align; - ion_phys_addr_t secure_base; /* Base addr used when heap is shared */ - size_t secure_size; /* Size used for securing heap when heap is shared*/ - int reusable; - int mem_is_fmem; - int is_cma; - enum ion_fixed_position fixed_position; - int iommu_map_all; - int iommu_2x_map_domain; - ion_virt_addr_t *virt_addr; - int (*request_region)(void *); - int (*release_region)(void *); - void *(*setup_region)(void); -}; - -/** - * struct ion_co_heap_pdata - defines a carveout heap in the given platform - * @adjacent_mem_id: Id of heap that this heap must be adjacent to. - * @align: Alignment requirement for the memory - * @mem_is_fmem Flag indicating whether this memory is coming from fmem - * or not. - * @fixed_position If nonzero, position in the fixed area. - * @request_region: function to be called when the number of allocations - * goes from 0 -> 1 - * @release_region: function to be called when the number of allocations - * goes from 1 -> 0 - * @setup_region: function to be called upon ion registration - * - */ -struct ion_co_heap_pdata { - int adjacent_mem_id; - unsigned int align; - int mem_is_fmem; - enum ion_fixed_position fixed_position; - int (*request_region)(void *); - int (*release_region)(void *); - void *(*setup_region)(void); -}; - /** * struct ion_platform_data - array of platform heaps passed from board file * @has_outer_cache: set to 1 if outer cache is used, 0 otherwise. @@ -321,14 +171,18 @@ void ion_client_destroy(struct ion_client *client); * @len: size of the allocation * @align: requested allocation alignment, lots of hardware blocks have * alignment requirements of some kind - * @flags: mask of heaps to allocate from, if multiple bits are set + * @heap_mask: mask of heaps to allocate from, if multiple bits are set * heaps will be tried in order from lowest to highest order bit + * @flags: heap flags, the low 16 bits are consumed by ion, the high 16 + * bits are passed on to the respective heap and can be heap + * custom * * Allocate memory in one of the heaps provided in heap mask and return * an opaque handle to it. */ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, - size_t align, unsigned int flags); + size_t align, unsigned int heap_mask, + unsigned int flags); /** * ion_free - free a handle @@ -379,8 +233,7 @@ struct sg_table *ion_sg_table(struct ion_client *client, * can be used to access this address. If no flags are specified, this * will return a non-secure uncached mapping. */ -void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle, - unsigned long flags); +void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle); /** * ion_unmap_kernel() - destroy a kernel mapping for a handle @@ -508,50 +361,6 @@ int ion_secure_heap(struct ion_device *dev, int heap_id, int version, int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version, void *data); -/** - * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap. - * - * @heap_id - heap id to secure. - * - * Secure a heap - * Returns 0 on success - */ -int msm_ion_secure_heap(int heap_id); - -/** - * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap. - * - * @heap_id - heap id to secure. - * - * Un-secure a heap - * Returns 0 on success - */ -int msm_ion_unsecure_heap(int heap_id); - -/** - * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs - * Wrapper around ion_secure_heap. - * - * @heap_id - heap id to secure. - * @usage - usage hint to TZ - * - * Secure a heap - * Returns 0 on success - */ -int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage); - -/** - * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs. - * Wrapper around ion_unsecure_heap. - * - * @heap_id - heap id to secure. - * @usage - usage hint to TZ - * - * Un-secure a heap - * Returns 0 on success - */ -int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage); - /** * msm_ion_do_cache_op - do cache operations. * @@ -590,7 +399,9 @@ static inline struct ion_client *msm_ion_client_create(unsigned int heap_mask, static inline void ion_client_destroy(struct ion_client *client) { } static inline struct ion_handle *ion_alloc(struct ion_client *client, - size_t len, size_t align, unsigned int flags) + size_t len, size_t align, + unsigned int heap_mask, + unsigned int flags) { return ERR_PTR(-ENODEV); } @@ -667,28 +478,6 @@ static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id, return -ENODEV; } -static inline int msm_ion_secure_heap(int heap_id) -{ - return -ENODEV; - -} - -static inline int msm_ion_unsecure_heap(int heap_id) -{ - return -ENODEV; -} - -static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage) -{ - return -ENODEV; -} - -static inline int msm_ion_unsecure_heap_2_0(int heap_id, - enum cp_mem_usage usage) -{ - return -ENODEV; -} - static inline int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle, void *vaddr, unsigned long len, unsigned int cmd) @@ -711,6 +500,7 @@ static inline int msm_ion_do_cache_op(struct ion_client *client, * struct ion_allocation_data - metadata passed from userspace for allocations * @len: size of the allocation * @align: required alignment of the allocation + * @heap_mask: mask of heaps to allocate from * @flags: flags passed to heap * @handle: pointer that will be populated with a cookie to use to refer * to this allocation @@ -718,6 +508,14 @@ static inline int msm_ion_do_cache_op(struct ion_client *client, * Provided by userspace as an argument to the ioctl */ struct ion_allocation_data { + size_t len; + size_t align; + unsigned int heap_mask; + unsigned int flags; + struct ion_handle *handle; +}; + +struct ion_allocation_data_old { size_t len; size_t align; unsigned int flags; @@ -759,41 +557,6 @@ struct ion_custom_data { unsigned int cmd; unsigned long arg; }; - - -/* struct ion_flush_data - data passed to ion for flushing caches - * - * @handle: handle with data to flush - * @fd: fd to flush - * @vaddr: userspace virtual address mapped with mmap - * @offset: offset into the handle to flush - * @length: length of handle to flush - * - * Performs cache operations on the handle. If p is the start address - * of the handle, p + offset through p + offset + length will have - * the cache operations performed - */ -struct ion_flush_data { - struct ion_handle *handle; - int fd; - void *vaddr; - unsigned int offset; - unsigned int length; -}; - -/* struct ion_flag_data - information about flags for this buffer - * - * @handle: handle to get flags from - * @flags: flags of this handle - * - * Takes handle as an input and outputs the flags from the handle - * in the flag field. - */ -struct ion_flag_data { - struct ion_handle *handle; - unsigned long flags; -}; - #define ION_IOC_MAGIC 'I' /** @@ -804,6 +567,8 @@ struct ion_flag_data { */ #define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ struct ion_allocation_data) +#define ION_IOC_ALLOC_COMPAT _IOWR(ION_IOC_MAGIC, 0, \ + struct ion_allocation_data_old) /** * DOC: ION_IOC_FREE - free memory @@ -840,7 +605,7 @@ struct ion_flag_data { * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle * filed set to the corresponding opaque handle. */ -#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, int) +#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) /** * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl @@ -851,26 +616,27 @@ struct ion_flag_data { #define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) +/* For compat with old-API blobs. These were moved to the MSM header */ /** * DOC: ION_IOC_CLEAN_CACHES - clean the caches * * Clean the caches of the handle specified. */ -#define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MAGIC, 7, \ +#define ION_IOC_CLEAN_CACHES_COMPAT _IOWR(ION_IOC_MAGIC, 7, \ struct ion_flush_data) /** * DOC: ION_MSM_IOC_INV_CACHES - invalidate the caches * * Invalidate the caches of the handle specified. */ -#define ION_IOC_INV_CACHES _IOWR(ION_IOC_MAGIC, 8, \ +#define ION_IOC_INV_CACHES_COMPAT _IOWR(ION_IOC_MAGIC, 8, \ struct ion_flush_data) /** * DOC: ION_MSM_IOC_CLEAN_CACHES - clean and invalidate the caches * * Clean and invalidate the caches of the handle specified. */ -#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MAGIC, 9, \ +#define ION_IOC_CLEAN_INV_CACHES_COMPAT _IOWR(ION_IOC_MAGIC, 9, \ struct ion_flush_data) /** @@ -879,15 +645,8 @@ struct ion_flag_data { * Gets the flags of the current handle which indicate cachability, * secure state etc. */ -#define ION_IOC_GET_FLAGS _IOWR(ION_IOC_MAGIC, 10, \ +#define ION_IOC_GET_FLAGS_COMPAT _IOWR(ION_IOC_MAGIC, 10, \ struct ion_flag_data) -/** - * DOC: ION_IOC_SYNC - BOGUS - * - * NOT SUPPORTED - */ -#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 42, \ - struct ion_flag_data) #endif /* _LINUX_ION_H */ diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index fad48aab..9323a986 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -40,6 +40,11 @@ struct lsm_network_audit { } fam; }; +struct lsm_ioctlop_audit { + struct path path; + u16 cmd; +}; + /* Auxiliary data to use in generating the audit record. */ struct common_audit_data { char type; @@ -53,6 +58,7 @@ struct common_audit_data { #define LSM_AUDIT_DATA_KMOD 8 #define LSM_AUDIT_DATA_INODE 9 #define LSM_AUDIT_DATA_DENTRY 10 +#define LSM_AUDIT_DATA_IOCTL_OP 11 struct task_struct *tsk; union { struct path path; @@ -69,6 +75,7 @@ struct common_audit_data { } key_struct; #endif char *kmod_name; + struct lsm_ioctlop_audit *op; } u; /* this union contains LSM specific data */ union { diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h index 0e28e541..599e4362 100644 --- a/include/linux/msm_ion.h +++ b/include/linux/msm_ion.h @@ -1,7 +1,6 @@ /* - * include/linux/ion.h * - * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -19,4 +18,316 @@ #include +enum msm_ion_heap_types { + ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1, + ION_HEAP_TYPE_IOMMU = ION_HEAP_TYPE_MSM_START, + ION_HEAP_TYPE_CP, +}; + +/** + * These are the only ids that should be used for Ion heap ids. + * The ids listed are the order in which allocation will be attempted + * if specified. Don't swap the order of heap ids unless you know what + * you are doing! + * Id's are spaced by purpose to allow new Id's to be inserted in-between (for + * possible fallbacks) + */ + +enum ion_heap_ids { + INVALID_HEAP_ID = -1, + ION_CP_MM_HEAP_ID = 8, + ION_CP_MFC_HEAP_ID = 12, + ION_CP_WB_HEAP_ID = 16, /* 8660 only */ + ION_CAMERA_HEAP_ID = 20, /* 8660 only */ + ION_SYSTEM_CONTIG_HEAP_ID = 21, + ION_ADSP_HEAP_ID = 22, + ION_SF_HEAP_ID = 24, + ION_IOMMU_HEAP_ID = 25, + ION_QSECOM_HEAP_ID = 26, + ION_AUDIO_HEAP_BL_ID = 27, + ION_AUDIO_HEAP_ID = 28, + + ION_MM_FIRMWARE_HEAP_ID = 29, + ION_SYSTEM_HEAP_ID = 30, + + ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */ +}; + +enum ion_fixed_position { + NOT_FIXED, + FIXED_LOW, + FIXED_MIDDLE, + FIXED_HIGH, +}; + +enum cp_mem_usage { + VIDEO_BITSTREAM = 0x1, + VIDEO_PIXEL = 0x2, + VIDEO_NONPIXEL = 0x3, + MAX_USAGE = 0x4, + UNKNOWN = 0x7FFFFFFF, +}; + +#define ION_HEAP_CP_MASK (1 << ION_HEAP_TYPE_CP) + +/** + * Flag to use when allocating to indicate that a heap is secure. + */ +#define ION_FLAG_SECURE (1 << ION_HEAP_ID_RESERVED) + +/** + * Flag for clients to force contiguous memort allocation + * + * Use of this flag is carefully monitored! + */ +#define ION_FLAG_FORCE_CONTIGUOUS (1 << 30) + +/** +* Deprecated! Please use the corresponding ION_FLAG_* +*/ +#define ION_SECURE ION_FLAG_SECURE +#define ION_FORCE_CONTIGUOUS ION_FLAG_FORCE_CONTIGUOUS + +/** + * Macro should be used with ion_heap_ids defined above. + */ +#define ION_HEAP(bit) (1 << (bit)) + +#define ION_ADSP_HEAP_NAME "adsp" +#define ION_VMALLOC_HEAP_NAME "vmalloc" +#define ION_KMALLOC_HEAP_NAME "kmalloc" +#define ION_AUDIO_HEAP_NAME "audio" +#define ION_AUDIO_BL_HEAP_NAME "bl_mem_audio" +#define ION_SF_HEAP_NAME "sf" +#define ION_MM_HEAP_NAME "mm" +#define ION_CAMERA_HEAP_NAME "camera_preview" +#define ION_IOMMU_HEAP_NAME "iommu" +#define ION_MFC_HEAP_NAME "mfc" +#define ION_WB_HEAP_NAME "wb" +#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw" +#define ION_QSECOM_HEAP_NAME "qsecom" +#define ION_FMEM_HEAP_NAME "fmem" + +#define ION_SET_CACHED(__cache) (__cache | ION_FLAG_CACHED) +#define ION_SET_UNCACHED(__cache) (__cache & ~ION_FLAG_CACHED) + +#define ION_IS_CACHED(__flags) ((__flags) & ION_FLAG_CACHED) + +#ifdef __KERNEL__ + +/* + * This flag allows clients when mapping into the IOMMU to specify to + * defer un-mapping from the IOMMU until the buffer memory is freed. + */ +#define ION_IOMMU_UNMAP_DELAYED 1 + +/** + * struct ion_cp_heap_pdata - defines a content protection heap in the given + * platform + * @permission_type: Memory ID used to identify the memory to TZ + * @align: Alignment requirement for the memory + * @secure_base: Base address for securing the heap. + * Note: This might be different from actual base address + * of this heap in the case of a shared heap. + * @secure_size: Memory size for securing the heap. + * Note: This might be different from actual size + * of this heap in the case of a shared heap. + * @reusable Flag indicating whether this heap is reusable of not. + * (see FMEM) + * @mem_is_fmem Flag indicating whether this memory is coming from fmem + * or not. + * @fixed_position If nonzero, position in the fixed area. + * @virt_addr: Virtual address used when using fmem. + * @iommu_map_all: Indicates whether we should map whole heap into IOMMU. + * @iommu_2x_map_domain: Indicates the domain to use for overmapping. + * @request_region: function to be called when the number of allocations + * goes from 0 -> 1 + * @release_region: function to be called when the number of allocations + * goes from 1 -> 0 + * @setup_region: function to be called upon ion registration + * @memory_type:Memory type used for the heap + * @no_nonsecure_alloc: don't allow non-secure allocations from this heap + * + */ +struct ion_cp_heap_pdata { + enum ion_permission_type permission_type; + unsigned int align; + ion_phys_addr_t secure_base; /* Base addr used when heap is shared */ + size_t secure_size; /* Size used for securing heap when heap is shared*/ + int reusable; + int mem_is_fmem; + int is_cma; + enum ion_fixed_position fixed_position; + int iommu_map_all; + int iommu_2x_map_domain; + ion_virt_addr_t *virt_addr; + int (*request_region)(void *); + int (*release_region)(void *); + void *(*setup_region)(void); + enum ion_memory_types memory_type; + int no_nonsecure_alloc; +}; + +/** + * struct ion_co_heap_pdata - defines a carveout heap in the given platform + * @adjacent_mem_id: Id of heap that this heap must be adjacent to. + * @align: Alignment requirement for the memory + * @mem_is_fmem Flag indicating whether this memory is coming from fmem + * or not. + * @fixed_position If nonzero, position in the fixed area. + * @request_region: function to be called when the number of allocations + * goes from 0 -> 1 + * @release_region: function to be called when the number of allocations + * goes from 1 -> 0 + * @setup_region: function to be called upon ion registration + * @memory_type:Memory type used for the heap + * + */ +struct ion_co_heap_pdata { + int adjacent_mem_id; + unsigned int align; + int mem_is_fmem; + enum ion_fixed_position fixed_position; + int (*request_region)(void *); + int (*release_region)(void *); + void *(*setup_region)(void); + enum ion_memory_types memory_type; +}; + +#ifdef CONFIG_ION +/** + * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap. + * + * @heap_id - heap id to secure. + * + * Secure a heap + * Returns 0 on success + */ +int msm_ion_secure_heap(int heap_id); + +/** + * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap. + * + * @heap_id - heap id to secure. + * + * Un-secure a heap + * Returns 0 on success + */ +int msm_ion_unsecure_heap(int heap_id); + +/** + * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs + * Wrapper around ion_secure_heap. + * + * @heap_id - heap id to secure. + * @usage - usage hint to TZ + * + * Secure a heap + * Returns 0 on success + */ +int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage); + +/** + * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs. + * Wrapper around ion_unsecure_heap. + * + * @heap_id - heap id to secure. + * @usage - usage hint to TZ + * + * Un-secure a heap + * Returns 0 on success + */ +int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage); +#else +static inline int msm_ion_secure_heap(int heap_id) +{ + return -ENODEV; + +} + +static inline int msm_ion_unsecure_heap(int heap_id) +{ + return -ENODEV; +} + +static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage) +{ + return -ENODEV; +} + +static inline int msm_ion_unsecure_heap_2_0(int heap_id, + enum cp_mem_usage usage) +{ + return -ENODEV; +} +#endif /* CONFIG_ION */ + +#endif /* __KERNEL */ + +/* struct ion_flush_data - data passed to ion for flushing caches + * + * @handle: handle with data to flush + * @fd: fd to flush + * @vaddr: userspace virtual address mapped with mmap + * @offset: offset into the handle to flush + * @length: length of handle to flush + * + * Performs cache operations on the handle. If p is the start address + * of the handle, p + offset through p + offset + length will have + * the cache operations performed + */ +struct ion_flush_data { + struct ion_handle *handle; + int fd; + void *vaddr; + unsigned int offset; + unsigned int length; +}; + +/* struct ion_flag_data - information about flags for this buffer + * + * @handle: handle to get flags from + * @flags: flags of this handle + * + * Takes handle as an input and outputs the flags from the handle + * in the flag field. + */ +struct ion_flag_data { + struct ion_handle *handle; + unsigned long flags; +}; + +#define ION_IOC_MSM_MAGIC 'M' + +/** + * DOC: ION_IOC_CLEAN_CACHES - clean the caches + * + * Clean the caches of the handle specified. + */ +#define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MSM_MAGIC, 0, \ + struct ion_flush_data) +/** + * DOC: ION_IOC_INV_CACHES - invalidate the caches + * + * Invalidate the caches of the handle specified. + */ +#define ION_IOC_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 1, \ + struct ion_flush_data) +/** + * DOC: ION_IOC_CLEAN_INV_CACHES - clean and invalidate the caches + * + * Clean and invalidate the caches of the handle specified. + */ +#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 2, \ + struct ion_flush_data) + +/** + * DOC: ION_IOC_GET_FLAGS - get the flags of the handle + * + * Gets the flags of the current handle which indicate cachability, + * secure state etc. + */ +#define ION_IOC_GET_FLAGS _IOWR(ION_IOC_MSM_MAGIC, 3, \ + struct ion_flag_data) + #endif diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index 1449b68b..f4898397 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -1,7 +1,7 @@ /* include/linux/msm_mdp.h * * Copyright (C) 2007 Google Incorporated - * Copyright (c) 2012 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -70,7 +70,16 @@ #define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp) #define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int) #define MSMFB_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int) -#define MSMFB_METADATA_SET _IOW(MSMFB_IOCTL_MAGIC, 162, struct msmfb_metadata) +#define MSMFB_BUFFER_SYNC _IOW(MSMFB_IOCTL_MAGIC, 162, struct mdp_buf_sync) +#define MSMFB_OVERLAY_COMMIT _IO(MSMFB_IOCTL_MAGIC, 163) +#define MSMFB_DISPLAY_COMMIT _IOW(MSMFB_IOCTL_MAGIC, 164, \ + struct mdp_display_commit) +#define MSMFB_METADATA_SET _IOW(MSMFB_IOCTL_MAGIC, 165, struct msmfb_metadata) +#define MSMFB_METADATA_GET _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata) +#define MSMFB_WRITEBACK_SET_MIRRORING_HINT _IOW(MSMFB_IOCTL_MAGIC, 167, \ + unsigned int) +#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int) + #define FB_TYPE_3D_PANEL 0x10101010 #define MDP_IMGTYPE2_START 0x10000 #define MSMFB_DRIVER_VERSION 0xF9E8D701 @@ -89,6 +98,7 @@ enum { MDP_RGB_888, /* RGB 888 planer */ MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planer w/ Cr is in MSB */ MDP_YCRYCB_H2V1, /* YCrYCb interleave */ + MDP_CBYCRY_H2V1, /* CbYCrY interleave */ MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ MDP_Y_CRCB_H1V2, @@ -106,6 +116,18 @@ enum { MDP_YCRCB_H1V1, /* YCrCb interleave */ MDP_YCBCR_H1V1, /* YCbCr interleave */ MDP_BGR_565, /* BGR 565 planer */ + MDP_BGR_888, /* BGR 888 */ + MDP_Y_CBCR_H2V2_VENUS, + MDP_BGRX_8888, /* BGRX 8888 */ + MDP_RGBA_8888_TILE, /* RGBA 8888 in tile format */ + MDP_ARGB_8888_TILE, /* ARGB 8888 in tile format */ + MDP_ABGR_8888_TILE, /* ABGR 8888 in tile format */ + MDP_BGRA_8888_TILE, /* BGRA 8888 in tile format */ + MDP_RGBX_8888_TILE, /* RGBX 8888 in tile format */ + MDP_XRGB_8888_TILE, /* XRGB 8888 in tile format */ + MDP_XBGR_8888_TILE, /* XBGR 8888 in tile format */ + MDP_BGRX_8888_TILE, /* BGRX 8888 in tile format */ + MDP_YCBYCR_H2V1, /* YCbYCr interleave */ MDP_IMGTYPE_LIMIT, MDP_RGB_BORDERFILL, /* border fill pipe */ MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */ @@ -127,6 +149,7 @@ enum { #define MDSS_MDP_ROT_ONLY 0x80 #define MDSS_MDP_RIGHT_MIXER 0x100 +#define MDSS_MDP_DUAL_PIPE 0x200 /* mdp_blit_req flag values */ #define MDP_ROT_NOP 0 @@ -154,12 +177,14 @@ enum { #define MDP_DEINTERLACE_ODD 0x00400000 #define MDP_OV_PLAY_NOWAIT 0x00200000 #define MDP_SOURCE_ROTATED_90 0x00100000 -#define MDP_DPP_HSIC 0x00080000 +#define MDP_OVERLAY_PP_CFG_EN 0x00080000 #define MDP_BACKEND_COMPOSITION 0x00040000 #define MDP_BORDERFILL_SUPPORTED 0x00010000 #define MDP_SECURE_OVERLAY_SESSION 0x00008000 +#define MDP_OV_PIPE_FORCE_DMA 0x00004000 #define MDP_MEMORY_ID_TYPE_FB 0x00001000 - +#define MDP_BWC_EN 0x00000400 +#define MDP_DECIMATION_EN 0x00000800 #define MDP_TRANSP_NOP 0xffffffff #define MDP_ALPHA_NOP 0xff @@ -271,15 +296,132 @@ struct msmfb_writeback_data { struct msmfb_img img; }; -struct dpp_ctrl { - /* - *'sharp_strength' has inputs = -128 <-> 127 - * Increasingly positive values correlate with increasingly sharper - * picture. Increasingly negative values correlate with increasingly - * smoothed picture. - */ - int8_t sharp_strength; - int8_t hsic_params[NUM_HSIC_PARAM]; +#define MDP_PP_OPS_ENABLE 0x1 +#define MDP_PP_OPS_READ 0x2 +#define MDP_PP_OPS_WRITE 0x4 +#define MDP_PP_OPS_DISABLE 0x8 +#define MDP_PP_IGC_FLAG_ROM0 0x10 +#define MDP_PP_IGC_FLAG_ROM1 0x20 + +#define MDSS_PP_DSPP_CFG 0x000 +#define MDSS_PP_SSPP_CFG 0x100 +#define MDSS_PP_LM_CFG 0x200 +#define MDSS_PP_WB_CFG 0x300 + +#define MDSS_PP_ARG_MASK 0x3C00 +#define MDSS_PP_ARG_NUM 4 +#define MDSS_PP_ARG_SHIFT 10 +#define MDSS_PP_LOCATION_MASK 0x0300 +#define MDSS_PP_LOGICAL_MASK 0x00FF + +#define MDSS_PP_ADD_ARG(var, arg) ((var) | (0x1 << (MDSS_PP_ARG_SHIFT + (arg)))) +#define PP_ARG(x, var) ((var) & (0x1 << (MDSS_PP_ARG_SHIFT + (x)))) +#define PP_LOCAT(var) ((var) & MDSS_PP_LOCATION_MASK) +#define PP_BLOCK(var) ((var) & MDSS_PP_LOGICAL_MASK) + +struct mdp_qseed_cfg { + uint32_t table_num; + uint32_t ops; + uint32_t len; + uint32_t *data; +}; + +struct mdp_qseed_cfg_data { + uint32_t block; + struct mdp_qseed_cfg qseed_data; +}; + +struct mdp_sharp_cfg { + uint32_t flags; + uint32_t strength; + uint32_t edge_thr; + uint32_t smooth_thr; + uint32_t noise_thr; +}; + +#define MDP_OVERLAY_PP_CSC_CFG 0x1 +#define MDP_OVERLAY_PP_QSEED_CFG 0x2 +#define MDP_OVERLAY_PP_PA_CFG 0x4 +#define MDP_OVERLAY_PP_IGC_CFG 0x8 +#define MDP_OVERLAY_PP_SHARP_CFG 0x10 + +#define MDP_CSC_FLAG_ENABLE 0x1 +#define MDP_CSC_FLAG_YUV_IN 0x2 +#define MDP_CSC_FLAG_YUV_OUT 0x4 + +struct mdp_csc_cfg { + /* flags for enable CSC, toggling RGB,YUV input/output */ + uint32_t flags; + uint32_t csc_mv[9]; + uint32_t csc_pre_bv[3]; + uint32_t csc_post_bv[3]; + uint32_t csc_pre_lv[6]; + uint32_t csc_post_lv[6]; +}; + +struct mdp_csc_cfg_data { + uint32_t block; + struct mdp_csc_cfg csc_data; +}; + +struct mdp_pa_cfg { + uint32_t flags; + uint32_t hue_adj; + uint32_t sat_adj; + uint32_t val_adj; + uint32_t cont_adj; +}; + +struct mdp_igc_lut_data { + uint32_t block; + uint32_t len, ops; + uint32_t *c0_c1_data; + uint32_t *c2_data; +}; + +struct mdp_histogram_cfg { + uint32_t ops; + uint32_t block; + uint8_t frame_cnt; + uint8_t bit_mask; + uint16_t num_bins; +}; + +struct mdp_overlay_pp_params { + uint32_t config_ops; + struct mdp_csc_cfg csc_cfg; + struct mdp_qseed_cfg qseed_cfg[2]; + struct mdp_pa_cfg pa_cfg; + struct mdp_igc_lut_data igc_cfg; + struct mdp_sharp_cfg sharp_cfg; + struct mdp_histogram_cfg hist_cfg; +}; + +/** + * enum mdss_mdp_blend_op - Different blend operations set by userspace + * + * @BLEND_OP_NOT_DEFINED: No blend operation defined for the layer. + * @BLEND_OP_OPAQUE: Apply a constant blend operation. The layer + * would appear opaque in case fg plane alpha is + * 0xff. + * @BLEND_OP_PREMULTIPLIED: Apply source over blend rule. Layer already has + * alpha pre-multiplication done. If fg plane alpha + * is less than 0xff, apply modulation as well. This + * operation is intended on layers having alpha + * channel. + * @BLEND_OP_COVERAGE: Apply source over blend rule. Layer is not alpha + * pre-multiplied. Apply pre-multiplication. If fg + * plane alpha is less than 0xff, apply modulation as + * well. + * @BLEND_OP_MAX: Used to track maximum blend operation possible by + * mdp. + */ +enum { + BLEND_OP_NOT_DEFINED = 0, + BLEND_OP_OPAQUE, + BLEND_OP_PREMULTIPLIED, + BLEND_OP_COVERAGE, + BLEND_OP_MAX, }; struct mdp_overlay { @@ -290,10 +432,11 @@ struct mdp_overlay { uint32_t is_fg; /* control alpha & transp */ uint32_t alpha; uint32_t transp_mask; + uint32_t blend_op; uint32_t flags; uint32_t id; uint32_t user_data[8]; - struct dpp_ctrl dpp; + struct mdp_overlay_pp_params overlay_pp_cfg; }; struct msmfb_overlay_3d { @@ -319,15 +462,44 @@ struct mdp_histogram { uint32_t *b; }; +enum { + DISPLAY_MISR_EDP, + DISPLAY_MISR_DSI0, + DISPLAY_MISR_DSI1, + DISPLAY_MISR_HDMI, + DISPLAY_MISR_LCDC, + DISPLAY_MISR_ATV, + DISPLAY_MISR_DSI_CMD, + DISPLAY_MISR_MAX +}; + +enum { + MISR_OP_NONE, + MISR_OP_SFM, + MISR_OP_MFM, + MISR_OP_BM, + MISR_OP_MAX +}; + +struct mdp_misr { + uint32_t block_id; + uint32_t frame_count; + uint32_t crc_op_mode; + uint32_t crc_value[32]; +}; + /* - mdp_block_type defines the identifiers for each of pipes in MDP 4.3 + mdp_block_type defines the identifiers for pipes in MDP 4.3 and up MDP_BLOCK_RESERVED is provided for backward compatibility and is deprecated. It corresponds to DMA_P. So MDP_BLOCK_DMA_P should be used instead. + MDP_LOGICAL_BLOCK_DISP_0 identifies the display pipe which fb0 uses, + same for others. + */ enum { @@ -342,6 +514,9 @@ enum { MDP_BLOCK_DMA_S, MDP_BLOCK_DMA_E, MDP_BLOCK_OVERLAY_2, + MDP_LOGICAL_BLOCK_DISP_0 = 0x1000, + MDP_LOGICAL_BLOCK_DISP_1, + MDP_LOGICAL_BLOCK_DISP_2, MDP_BLOCK_MAX, }; @@ -381,25 +556,6 @@ struct mdp_pcc_cfg_data { struct mdp_pcc_coeff r, g, b; }; -#define MDP_CSC_FLAG_ENABLE 0x1 -#define MDP_CSC_FLAG_YUV_IN 0x2 -#define MDP_CSC_FLAG_YUV_OUT 0x4 - -struct mdp_csc_cfg { - /* flags for enable CSC, toggling RGB,YUV input/output */ - uint32_t flags; - uint32_t csc_mv[9]; - uint32_t csc_pre_bv[3]; - uint32_t csc_post_bv[3]; - uint32_t csc_pre_lv[6]; - uint32_t csc_post_lv[6]; -}; - -struct mdp_csc_cfg_data { - uint32_t block; - struct mdp_csc_cfg csc_data; -}; - enum { mdp_lut_igc, mdp_lut_pgc, @@ -407,14 +563,6 @@ enum { mdp_lut_max, }; - -struct mdp_igc_lut_data { - uint32_t block; - uint32_t len, ops; - uint32_t *c0_c1_data; - uint32_t *c2_data; -}; - struct mdp_ar_gc_lut_data { uint32_t x_start; uint32_t slope; @@ -449,25 +597,30 @@ struct mdp_lut_cfg_data { } data; }; -struct mdp_qseed_cfg_data { - uint32_t block; - uint32_t table_num; - uint32_t ops; - uint32_t len; - uint32_t *data; -}; - struct mdp_bl_scale_data { uint32_t min_lvl; uint32_t scale; }; +struct mdp_calib_config_data { + uint32_t ops; + uint32_t addr; + uint32_t data; +}; + +struct mdp_pa_cfg_data { + uint32_t block; + struct mdp_pa_cfg pa_data; +}; + enum { mdp_op_pcc_cfg, mdp_op_csc_cfg, mdp_op_lut_cfg, mdp_op_qseed_cfg, mdp_bl_scale_cfg, + mdp_op_calib_cfg, + mdp_op_pa_cfg, mdp_op_max, }; @@ -479,12 +632,15 @@ struct msmfb_mdp_pp { struct mdp_lut_cfg_data lut_cfg_data; struct mdp_qseed_cfg_data qseed_cfg_data; struct mdp_bl_scale_data bl_scale_data; + struct mdp_calib_config_data calib_cfg; + struct mdp_pa_cfg_data pa_cfg_data; } data; }; enum { metadata_op_none, metadata_op_base_blend, + metadata_op_frame_rate, metadata_op_max }; @@ -492,13 +648,46 @@ struct mdp_blend_cfg { uint32_t is_premultiplied; }; +struct mdp_mixer_cfg { + uint32_t writeback_format; + uint32_t alpha; +}; + struct msmfb_metadata { uint32_t op; uint32_t flags; union { struct mdp_blend_cfg blend_cfg; + uint32_t panel_frame_rate; } data; }; + +#define MDP_MAX_FENCE_FD 32 +#define MDP_BUF_SYNC_FLAG_WAIT 1 + +struct mdp_buf_sync { + uint32_t flags; + uint32_t acq_fen_fd_cnt; + uint32_t session_id; + int *acq_fen_fd; + int *rel_fen_fd; + int *retire_fen_fd; +}; + +struct mdp_async_blit_req_list { + struct mdp_buf_sync sync; + uint32_t count; + struct mdp_blit_req req[]; +}; + +#define MDP_DISPLAY_COMMIT_OVERLAY 0x00000001 + +struct mdp_display_commit { + uint32_t flags; + uint32_t wait_for_finish; + struct fb_var_screeninfo var; +}; + struct mdp_page_protection { uint32_t page_protection; }; @@ -512,7 +701,7 @@ struct mdp_mixer_info { int z_order; }; -#define MAX_PIPE_PER_MIXER 4 +#define MAX_PIPE_PER_MIXER 5 struct msmfb_mixer_info_req { int mixer_num; @@ -525,6 +714,13 @@ enum { ROTATOR_SUBSYSTEM_ID, }; +enum { + MDP_WRITEBACK_MIRROR_OFF, + MDP_WRITEBACK_MIRROR_ON, + MDP_WRITEBACK_MIRROR_PAUSE, + MDP_WRITEBACK_MIRROR_RESUME, +}; + #ifdef __KERNEL__ /* get the framebuffer physical address information */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 577592ea..9db33093 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -283,6 +283,8 @@ enum rtattr_type_t { RTA_MP_ALGO, /* no longer used */ RTA_TABLE, RTA_MARK, + RTA_MFC_STATS, /* not used - backported from the future */ + RTA_UID, __RTA_MAX }; diff --git a/include/linux/sched.h b/include/linux/sched.h index 0b309364..f09ab4c4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -122,7 +122,7 @@ extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift); #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1< #ifdef __KERNEL__ +#include #include #include #include @@ -24,6 +25,7 @@ struct sync_timeline; struct sync_pt; struct sync_fence; +struct seq_file; /** * struct sync_timeline_ops - sync object implementation ops @@ -75,6 +77,14 @@ struct sync_timeline_ops { /* optional */ int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size); + + /* optional */ + void (*timeline_value_str)(struct sync_timeline *timeline, char *str, + int size); + + /* optional */ + void (*pt_value_str)(struct sync_pt *pt, char *str, int size); + }; /** @@ -89,6 +99,7 @@ struct sync_timeline_ops { * @sync_timeline_list: membership in global sync_timeline_list */ struct sync_timeline { + struct kref kref; const struct sync_timeline_ops *ops; char name[32]; @@ -119,6 +130,7 @@ struct sync_pt { struct sync_timeline *parent; struct list_head child_list; + struct list_head signaled_list; struct list_head active_list; struct sync_fence *fence; @@ -145,6 +157,7 @@ struct sync_pt { */ struct sync_fence { struct file *file; + struct kref kref; char name[32]; /* this list is immutable once the fence is created */ @@ -272,6 +285,15 @@ struct sync_fence *sync_fence_merge(const char *name, */ struct sync_fence *sync_fence_fdget(int fd); +/** + * sync_fence_fdget() - get a fence from an fd + * @fd: fd referencing a fence + * + * Ensures @fd references a valid fence, increments the refcount of the backing + * file, and returns the fence. + */ +struct sync_fence *sync_fence_fdget(int fd); + /** * sync_fence_put() - puts a refernnce of a sync fence * @fence: fence to put @@ -384,7 +406,7 @@ struct sync_fence_info_data { * * pass timeout in milliseconds. */ -#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __u32) +#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32) /** * DOC: SYNC_IOC_MERGE - merge two fences diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 0f06a016..3ff94f08 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -141,6 +141,12 @@ extern unsigned int dirty_writeback_active_interval; extern unsigned int dirty_writeback_suspend_interval; #endif +#ifdef CONFIG_DYNAMIC_PAGE_WRITEBACK +extern int dyn_dirty_writeback_enabled; +extern unsigned int dirty_writeback_active_interval; +extern unsigned int dirty_writeback_suspend_interval; +#endif + extern int dirty_background_ratio_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); diff --git a/drivers/staging/zsmalloc/zsmalloc.h b/include/linux/zsmalloc.h similarity index 77% rename from drivers/staging/zsmalloc/zsmalloc.h rename to include/linux/zsmalloc.h index fbe6bec4..e44d634e 100644 --- a/drivers/staging/zsmalloc/zsmalloc.h +++ b/include/linux/zsmalloc.h @@ -2,6 +2,7 @@ * zsmalloc memory allocator * * Copyright (C) 2011 Nitin Gupta + * Copyright (C) 2012, 2013 Minchan Kim * * This code is released using a dual license strategy: BSD/GPL * You can choose the license that better fits your requirements. @@ -18,12 +19,19 @@ /* * zsmalloc mapping modes * - * NOTE: These only make a difference when a mapped object spans pages + * NOTE: These only make a difference when a mapped object spans pages. + * They also have no effect when PGTABLE_MAPPING is selected. */ enum zs_mapmode { ZS_MM_RW, /* normal read-write mapping */ ZS_MM_RO, /* read-only (no copy-out at unmap time) */ ZS_MM_WO /* write-only (no copy-in at map time) */ + /* + * NOTE: ZS_MM_WO should only be used for initializing new + * (uninitialized) allocations. Partial writes to already + * initialized allocations should use ZS_MM_RW to preserve the + * existing data. + */ }; struct zs_pool; diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 15d1817f..0bfccb14 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2010-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 @@ -10,6 +10,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ +// rollback to original BlueZ #ifndef __AMP_H #define __AMP_H @@ -115,7 +116,7 @@ int amp_init(void); void amp_exit(void); /* L2CAP-AMP fixed channel interface */ -void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb); +void amp_conn_ind(struct l2cap_conn *conn, struct sk_buff *skb); /* L2CAP-AMP link interface */ void amp_create_physical(struct l2cap_conn *conn, struct sock *sk); @@ -256,7 +257,7 @@ struct amp_work_state_change { }; struct amp_work_conn_ind { struct work_struct work; - struct hci_conn *hcon; + struct l2cap_conn *conn; struct sk_buff *skb; }; struct amp_work_create_physical { diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index badbd8e5..6579356c 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -21,6 +21,7 @@ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ +// rollback to original BlueZ #ifndef __BLUETOOTH_H #define __BLUETOOTH_H diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index dd4e8f93..f1a90625 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -21,6 +21,7 @@ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ +// rollback to original BlueZ #ifndef __HCI_H #define __HCI_H @@ -700,12 +701,6 @@ struct hci_cp_write_voice_setting { __le16 voice_setting; } __packed; -#define HCI_OP_WRITE_AUTOMATIC_FLUSH_TIMEOUT 0x0c28 -struct hci_cp_write_automatic_flush_timeout { - __le16 handle; - __le16 timeout; -} __packed; - #define HCI_OP_HOST_BUFFER_SIZE 0x0c33 struct hci_cp_host_buffer_size { __le16 acl_mtu; @@ -869,17 +864,6 @@ struct hci_rp_read_data_block_size { __le16 num_blocks; } __packed; -#define HCI_OP_READ_RSSI 0x1405 -struct hci_cp_read_rssi { - __le16 handle; -} __packed; - -struct hci_rp_read_rssi { - __u8 status; - __le16 handle; - __s8 rssi; -} __packed; - #define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 struct hci_rp_read_local_amp_info { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4f06adf2..f1e42166 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012, The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011, Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -21,12 +21,13 @@ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ +// rollback to original BlueZ #ifndef __HCI_CORE_H #define __HCI_CORE_H #include -#include +#include /* HCI upper protocols */ #define HCI_PROTO_L2CAP 0 #define HCI_PROTO_SCO 1 @@ -240,11 +241,8 @@ struct hci_dev { rwlock_t adv_entries_lock; struct timer_list adv_timer; - struct timer_list disco_timer; - struct timer_list disco_le_timer; - __u8 disco_state; - int disco_int_phase; - int disco_int_count; + struct timer_list disc_timer; + struct timer_list disc_le_timer; struct hci_dev_stats stat; @@ -304,29 +302,22 @@ struct hci_conn { __u8 auth_initiator; __u8 power_save; __u16 disc_timeout; - __u16 conn_timeout; unsigned long pend; __u8 remote_cap; __u8 remote_oob; __u8 remote_auth; - __s8 rssi_threshold; - __u16 rssi_update_interval; - __u8 rssi_update_thresh_exceed; - unsigned int sent; struct sk_buff_head data_q; struct timer_list disc_timer; struct timer_list idle_timer; - struct delayed_work rssi_update_work; - struct timer_list encrypt_pause_timer; struct work_struct work_add; struct work_struct work_del; - struct wake_lock idle_lock; + struct device dev; atomic_t devref; @@ -354,7 +345,6 @@ struct hci_conn { __u8 auth; void *smp_conn; struct timer_list smp_timer; - __u8 conn_valid; void (*connect_cfm_cb) (struct hci_conn *conn, u8 status); @@ -578,7 +568,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, struct hci_conn *hci_le_conn_add(struct hci_dev *hdev, bdaddr_t *dst, __u8 addr_type); int hci_conn_del(struct hci_conn *conn); -void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process); +void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev); struct hci_chan *hci_chan_add(struct hci_dev *hdev); @@ -589,7 +579,10 @@ static inline void hci_chan_hold(struct hci_chan *chan) } int hci_chan_put(struct hci_chan *chan); -struct hci_chan *hci_chan_create(struct hci_chan *chan, +struct hci_chan *hci_chan_accept(struct hci_conn *hcon, + struct hci_ext_fs *tx_fs, + struct hci_ext_fs *rx_fs); +struct hci_chan *hci_chan_create(struct hci_conn *hcon, struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs); void hci_chan_modify(struct hci_chan *chan, @@ -599,10 +592,6 @@ void hci_chan_modify(struct hci_chan *chan, struct hci_conn *hci_connect(struct hci_dev *hdev, int type, __u16 pkt_type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type); -struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type, - bdaddr_t *dst, __u8 sec_level, - __u8 auth_type, - struct bt_le_params *le_params); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); int hci_conn_change_link_key(struct hci_conn *conn); @@ -616,10 +605,6 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn); void hci_conn_hold_device(struct hci_conn *conn); void hci_conn_put_device(struct hci_conn *conn); -void hci_conn_set_rssi_reporter(struct hci_conn *conn, - s8 rssi_threshold, u16 interval, u8 updateOnThreshExceed); -void hci_conn_unset_rssi_reporter(struct hci_conn *conn); - static inline void hci_conn_hold(struct hci_conn *conn) { atomic_inc(&conn->refcnt); @@ -634,6 +619,7 @@ static inline void hci_conn_put(struct hci_conn *conn) del_timer(&conn->idle_timer); if (conn->state == BT_CONNECTED) { timeo = msecs_to_jiffies(conn->disc_timeout); + /* ACL_LINK or LE_LINK disconnet timeout from 4secs(timeo *= 2) to 8secs(timeo *= 4)*/ if (!conn->out) timeo *= 4; } else @@ -764,8 +750,7 @@ struct hci_proto { int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); int (*connect_cfm) (struct hci_conn *conn, __u8 status); int (*disconn_ind) (struct hci_conn *conn); - int (*disconn_cfm) (struct hci_conn *conn, __u8 reason, - __u8 is_process); + int (*disconn_cfm) (struct hci_conn *conn, __u8 reason); int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); @@ -822,18 +807,17 @@ static inline int hci_proto_disconn_ind(struct hci_conn *conn) return reason; } -static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason, - __u8 is_process) +static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) { register struct hci_proto *hp; hp = hci_proto[HCI_PROTO_L2CAP]; if (hp && hp->disconn_cfm) - hp->disconn_cfm(conn, reason, is_process); + hp->disconn_cfm(conn, reason); hp = hci_proto[HCI_PROTO_SCO]; if (hp && hp->disconn_cfm) - hp->disconn_cfm(conn, reason, is_process); + hp->disconn_cfm(conn, reason); if (conn->disconn_cfm_cb) conn->disconn_cfm_cb(conn, reason); @@ -946,7 +930,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr if (conn->sec_level == BT_SECURITY_SDP) conn->sec_level = BT_SECURITY_LOW; - if (!status && encrypt && conn->pending_sec_level > conn->sec_level) + if (conn->pending_sec_level > conn->sec_level) conn->sec_level = conn->pending_sec_level; hci_proto_encrypt_cfm(conn, status, encrypt); @@ -1054,21 +1038,13 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, u8 status); int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le, u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir); -void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr, - u16 handle, u8 status); int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name); void mgmt_inquiry_started(u16 index); void mgmt_inquiry_complete_evt(u16 index, u8 status); -void mgmt_disco_timeout(unsigned long data); -void mgmt_disco_le_timeout(unsigned long data); int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status); /* LE SMP Management interface */ int le_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, void *cp); -int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3]); -int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf, - u16 sub_ver); -int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8]); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) @@ -1106,6 +1082,4 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); void hci_le_ltk_neg_reply(struct hci_conn *conn); -void hci_read_rssi(struct hci_conn *conn); - #endif /* __HCI_CORE_H */ diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9c2b735c..b99ffe51 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved. Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. @@ -24,6 +24,8 @@ SOFTWARE IS DISCLAIMED. */ +// rollback to original BlueZ + #ifndef __L2CAP_H #define __L2CAP_H @@ -32,7 +34,6 @@ #define L2CAP_DEFAULT_MIN_MTU 48 #define L2CAP_DEFAULT_MAX_SDU_SIZE 0xffff #define L2CAP_DEFAULT_FLUSH_TO 0xffff -#define L2CAP_MAX_FLUSH_TO 0x7ff #define L2CAP_DEFAULT_TX_WINDOW 63 #define L2CAP_DEFAULT_MAX_TX 3 #define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */ @@ -51,7 +52,7 @@ #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ -#define L2CAP_MOVE_TIMEOUT (4*HZ) /* 4 seconds */ +#define L2CAP_MOVE_TIMEOUT (2*HZ) /* 2 seconds */ #define L2CAP_MOVE_ERTX_TIMEOUT (60*HZ) /* 60 seconds */ /* L2CAP socket address */ @@ -294,6 +295,8 @@ struct l2cap_conf_ext_fs { struct l2cap_conf_prm { __u8 fcs; + __le16 retrans_timeout; + __le16 monitor_timeout; __le32 flush_to; }; @@ -489,7 +492,6 @@ struct l2cap_pinfo { __u8 fixed_channel; __u8 num_conf_req; __u8 num_conf_rsp; - __u8 incoming; __u8 fcs; __u8 sec_level; @@ -650,8 +652,6 @@ struct l2cap_pinfo { #define L2CAP_AMP_STATE_RESEGMENT 12 #define L2CAP_ATT_ERROR 0x01 -#define L2CAP_ATT_MTU_REQ 0x02 -#define L2CAP_ATT_MTU_RSP 0x03 #define L2CAP_ATT_RESPONSE_BIT 0x01 #define L2CAP_ATT_INDICATE 0x1D #define L2CAP_ATT_CONFIRM 0x1E @@ -687,7 +687,6 @@ int l2cap_strm_tx(struct sock *sk, struct sk_buff_head *skbs); int l2cap_ertm_tx(struct sock *sk, struct bt_l2cap_control *control, struct sk_buff_head *skbs, u8 event); -int l2cap_sock_le_params_valid(struct bt_le_params *le_params); void l2cap_sock_set_timer(struct sock *sk, long timeout); void l2cap_sock_clear_timer(struct sock *sk); void __l2cap_sock_close(struct sock *sk, int reason); @@ -695,8 +694,6 @@ void l2cap_sock_kill(struct sock *sk); void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); -struct sock *l2cap_find_sock_by_fixed_cid_and_dir(__le16 cid, bdaddr_t *src, - bdaddr_t *dst, int server); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err); void l2cap_chan_del(struct sock *sk, int err); int l2cap_do_connect(struct sock *sk); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3048339b..228d2790 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -20,6 +20,7 @@ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ +// rollback to original BlueZ #define MGMT_INDEX_NONE 0xFFFF @@ -161,6 +162,7 @@ struct mgmt_cp_set_io_capability { struct mgmt_cp_pair_device { bdaddr_t bdaddr; __u8 io_cap; + __u8 ssp_cap; } __packed; struct mgmt_rp_pair_device { bdaddr_t bdaddr; diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index e736f18f..160e3f0c 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -1,7 +1,7 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Technologies, Inc. - Copyright (c) 2011, The Linux Foundation. All rights reserved. + Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (c) 2011, Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 075f1e3a..58895709 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -23,6 +23,8 @@ struct fib_rule { struct fib_rule __rcu *ctarget; char iifname[IFNAMSIZ]; char oifname[IFNAMSIZ]; + uid_t uid_start; + uid_t uid_end; struct rcu_head rcu; struct net * fr_net; }; @@ -79,7 +81,9 @@ struct fib_rules_ops { [FRA_FWMARK] = { .type = NLA_U32 }, \ [FRA_FWMASK] = { .type = NLA_U32 }, \ [FRA_TABLE] = { .type = NLA_U32 }, \ - [FRA_GOTO] = { .type = NLA_U32 } + [FRA_GOTO] = { .type = NLA_U32 }, \ + [FRA_UID_START] = { .type = NLA_U32 }, \ + [FRA_UID_END] = { .type = NLA_U32 } static inline void fib_rule_get(struct fib_rule *rule) { diff --git a/include/net/flow.h b/include/net/flow.h index 6c469dbd..964a4945 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -23,6 +23,7 @@ struct flowi_common { #define FLOWI_FLAG_PRECOW_METRICS 0x02 #define FLOWI_FLAG_CAN_SLEEP 0x04 __u32 flowic_secid; + uid_t flowic_uid; }; union flowi_uli { @@ -59,6 +60,7 @@ struct flowi4 { #define flowi4_proto __fl_common.flowic_proto #define flowi4_flags __fl_common.flowic_flags #define flowi4_secid __fl_common.flowic_secid +#define flowi4_uid __fl_common.flowic_uid /* (saddr,daddr) must be grouped, same order as in IP header */ __be32 saddr; @@ -78,7 +80,8 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, __u32 mark, __u8 tos, __u8 scope, __u8 proto, __u8 flags, __be32 daddr, __be32 saddr, - __be16 dport, __be16 sport) + __be16 dport, __be32 sport, + uid_t uid) { fl4->flowi4_oif = oif; fl4->flowi4_iif = 0; @@ -88,6 +91,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, fl4->flowi4_proto = proto; fl4->flowi4_flags = flags; fl4->flowi4_secid = 0; + fl4->flowi4_uid = uid; fl4->daddr = daddr; fl4->saddr = saddr; fl4->fl4_dport = dport; @@ -115,6 +119,7 @@ struct flowi6 { #define flowi6_proto __fl_common.flowic_proto #define flowi6_flags __fl_common.flowic_flags #define flowi6_secid __fl_common.flowic_secid +#define flowi6_uid __fl_common.flowic_uid struct in6_addr daddr; struct in6_addr saddr; __be32 flowlabel; @@ -158,6 +163,7 @@ struct flowi { #define flowi_proto u.__fl_common.flowic_proto #define flowi_flags u.__fl_common.flowic_flags #define flowi_secid u.__fl_common.flowic_secid +#define flowi_uid u.__fl_common.flowic_uid } __attribute__((__aligned__(BITS_PER_LONG/8))); static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4) @@ -223,4 +229,5 @@ extern void flow_cache_flush(void); extern void flow_cache_flush_deferred(void); extern atomic_t flow_cache_genid; + #endif diff --git a/include/net/ip.h b/include/net/ip.h index 34d00489..b3523201 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -165,6 +165,7 @@ struct ip_reply_arg { int csumoffset; /* u16 offset of csum in iov[0].iov_base */ /* -1 if not needed */ int bound_dev_if; + uid_t uid; u8 tos; }; diff --git a/include/net/route.h b/include/net/route.h index b1c0d5b5..7488c9ed 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -60,6 +60,7 @@ struct rtable { int rt_iif; int rt_oif; __u32 rt_mark; + uid_t rt_uid; /* Info on neighbour */ __be32 rt_gateway; @@ -146,7 +147,7 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, RT_SCOPE_UNIVERSE, proto, sk ? inet_sk_flowi_flags(sk) : 0, - daddr, saddr, dport, sport); + daddr, saddr, dport, sport, sk ? sock_i_uid(sk) : 0); if (sk) security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); return ip_route_output_flow(net, fl4, sk); @@ -250,7 +251,8 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 flow_flags |= FLOWI_FLAG_CAN_SLEEP; flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, - protocol, flow_flags, dst, src, dport, sport); + protocol, flow_flags, dst, src, dport, sport, + sock_i_uid(sk)); } static inline struct rtable *ip_route_connect(struct flowi4 *fl4, diff --git a/include/trace/binder_trace.h b/include/trace/binder_trace.h new file mode 100644 index 00000000..12ef1e93 --- /dev/null +++ b/include/trace/binder_trace.h @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2012 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. + * + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM binder + +#if !defined(_BINDER_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _BINDER_TRACE_H + +#include + +struct binder_buffer; +struct binder_node; +struct binder_proc; +struct binder_ref; +struct binder_thread; +struct binder_transaction; + +TRACE_EVENT(binder_ioctl, + TP_PROTO(unsigned int cmd, unsigned long arg), + TP_ARGS(cmd, arg), + + TP_STRUCT__entry( + __field(unsigned int, cmd) + __field(unsigned long, arg) + ), + TP_fast_assign( + __entry->cmd = cmd; + __entry->arg = arg; + ), + TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg) +); + +DECLARE_EVENT_CLASS(binder_lock_class, + TP_PROTO(const char *tag), + TP_ARGS(tag), + TP_STRUCT__entry( + __field(const char *, tag) + ), + TP_fast_assign( + __entry->tag = tag; + ), + TP_printk("tag=%s", __entry->tag) +); + +#define DEFINE_BINDER_LOCK_EVENT(name) \ +DEFINE_EVENT(binder_lock_class, name, \ + TP_PROTO(const char *func), \ + TP_ARGS(func)) + +DEFINE_BINDER_LOCK_EVENT(binder_lock); +DEFINE_BINDER_LOCK_EVENT(binder_locked); +DEFINE_BINDER_LOCK_EVENT(binder_unlock); + +DECLARE_EVENT_CLASS(binder_function_return_class, + TP_PROTO(int ret), + TP_ARGS(ret), + TP_STRUCT__entry( + __field(int, ret) + ), + TP_fast_assign( + __entry->ret = ret; + ), + TP_printk("ret=%d", __entry->ret) +); + +#define DEFINE_BINDER_FUNCTION_RETURN_EVENT(name) \ +DEFINE_EVENT(binder_function_return_class, name, \ + TP_PROTO(int ret), \ + TP_ARGS(ret)) + +DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done); +DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done); +DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done); + +TRACE_EVENT(binder_wait_for_work, + TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo), + TP_ARGS(proc_work, transaction_stack, thread_todo), + + TP_STRUCT__entry( + __field(bool, proc_work) + __field(bool, transaction_stack) + __field(bool, thread_todo) + ), + TP_fast_assign( + __entry->proc_work = proc_work; + __entry->transaction_stack = transaction_stack; + __entry->thread_todo = thread_todo; + ), + TP_printk("proc_work=%d transaction_stack=%d thread_todo=%d", + __entry->proc_work, __entry->transaction_stack, + __entry->thread_todo) +); + +TRACE_EVENT(binder_transaction, + TP_PROTO(bool reply, struct binder_transaction *t, + struct binder_node *target_node), + TP_ARGS(reply, t, target_node), + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, target_node) + __field(int, to_proc) + __field(int, to_thread) + __field(int, reply) + __field(unsigned int, code) + __field(unsigned int, flags) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->target_node = target_node ? target_node->debug_id : 0; + __entry->to_proc = t->to_proc->pid; + __entry->to_thread = t->to_thread ? t->to_thread->pid : 0; + __entry->reply = reply; + __entry->code = t->code; + __entry->flags = t->flags; + ), + TP_printk("transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x code=0x%x", + __entry->debug_id, __entry->target_node, + __entry->to_proc, __entry->to_thread, + __entry->reply, __entry->flags, __entry->code) +); + +TRACE_EVENT(binder_transaction_received, + TP_PROTO(struct binder_transaction *t), + TP_ARGS(t), + + TP_STRUCT__entry( + __field(int, debug_id) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + ), + TP_printk("transaction=%d", __entry->debug_id) +); + +TRACE_EVENT(binder_transaction_node_to_ref, + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref *ref), + TP_ARGS(t, node, ref), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, node_debug_id) + __field(void __user *, node_ptr) + __field(int, ref_debug_id) + __field(uint32_t, ref_desc) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->node_debug_id = node->debug_id; + __entry->node_ptr = node->ptr; + __entry->ref_debug_id = ref->debug_id; + __entry->ref_desc = ref->desc; + ), + TP_printk("transaction=%d node=%d src_ptr=0x%p ==> dest_ref=%d dest_desc=%d", + __entry->debug_id, __entry->node_debug_id, __entry->node_ptr, + __entry->ref_debug_id, __entry->ref_desc) +); + +TRACE_EVENT(binder_transaction_ref_to_node, + TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), + TP_ARGS(t, ref), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, ref_debug_id) + __field(uint32_t, ref_desc) + __field(int, node_debug_id) + __field(void __user *, node_ptr) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->ref_debug_id = ref->debug_id; + __entry->ref_desc = ref->desc; + __entry->node_debug_id = ref->node->debug_id; + __entry->node_ptr = ref->node->ptr; + ), + TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%p", + __entry->debug_id, __entry->node_debug_id, + __entry->ref_debug_id, __entry->ref_desc, __entry->node_ptr) +); + +TRACE_EVENT(binder_transaction_ref_to_ref, + TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, + struct binder_ref *dest_ref), + TP_ARGS(t, src_ref, dest_ref), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, node_debug_id) + __field(int, src_ref_debug_id) + __field(uint32_t, src_ref_desc) + __field(int, dest_ref_debug_id) + __field(uint32_t, dest_ref_desc) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->node_debug_id = src_ref->node->debug_id; + __entry->src_ref_debug_id = src_ref->debug_id; + __entry->src_ref_desc = src_ref->desc; + __entry->dest_ref_debug_id = dest_ref->debug_id; + __entry->dest_ref_desc = dest_ref->desc; + ), + TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ref=%d dest_desc=%d", + __entry->debug_id, __entry->node_debug_id, + __entry->src_ref_debug_id, __entry->src_ref_desc, + __entry->dest_ref_debug_id, __entry->dest_ref_desc) +); + +TRACE_EVENT(binder_transaction_fd, + TP_PROTO(struct binder_transaction *t, int src_fd, int dest_fd), + TP_ARGS(t, src_fd, dest_fd), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, src_fd) + __field(int, dest_fd) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->src_fd = src_fd; + __entry->dest_fd = dest_fd; + ), + TP_printk("transaction=%d src_fd=%d ==> dest_fd=%d", + __entry->debug_id, __entry->src_fd, __entry->dest_fd) +); + +DECLARE_EVENT_CLASS(binder_buffer_class, + TP_PROTO(struct binder_buffer *buf), + TP_ARGS(buf), + TP_STRUCT__entry( + __field(int, debug_id) + __field(size_t, data_size) + __field(size_t, offsets_size) + ), + TP_fast_assign( + __entry->debug_id = buf->debug_id; + __entry->data_size = buf->data_size; + __entry->offsets_size = buf->offsets_size; + ), + TP_printk("transaction=%d data_size=%zd offsets_size=%zd", + __entry->debug_id, __entry->data_size, __entry->offsets_size) +); + +DEFINE_EVENT(binder_buffer_class, binder_transaction_alloc_buf, + TP_PROTO(struct binder_buffer *buffer), + TP_ARGS(buffer)); + +DEFINE_EVENT(binder_buffer_class, binder_transaction_buffer_release, + TP_PROTO(struct binder_buffer *buffer), + TP_ARGS(buffer)); + +DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, + TP_PROTO(struct binder_buffer *buffer), + TP_ARGS(buffer)); + +TRACE_EVENT(binder_update_page_range, + TP_PROTO(struct binder_proc *proc, bool allocate, + void *start, void *end), + TP_ARGS(proc, allocate, start, end), + TP_STRUCT__entry( + __field(int, proc) + __field(bool, allocate) + __field(size_t, offset) + __field(size_t, size) + ), + TP_fast_assign( + __entry->proc = proc->pid; + __entry->allocate = allocate; + __entry->offset = start - proc->buffer; + __entry->size = end - start; + ), + TP_printk("proc=%d allocate=%d offset=%zu size=%zu", + __entry->proc, __entry->allocate, + __entry->offset, __entry->size) +); + +TRACE_EVENT(binder_command, + TP_PROTO(uint32_t cmd), + TP_ARGS(cmd), + TP_STRUCT__entry( + __field(uint32_t, cmd) + ), + TP_fast_assign( + __entry->cmd = cmd; + ), + TP_printk("cmd=0x%x %s", + __entry->cmd, + _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_command_strings) ? + binder_command_strings[_IOC_NR(__entry->cmd)] : + "unknown") +); + +TRACE_EVENT(binder_return, + TP_PROTO(uint32_t cmd), + TP_ARGS(cmd), + TP_STRUCT__entry( + __field(uint32_t, cmd) + ), + TP_fast_assign( + __entry->cmd = cmd; + ), + TP_printk("cmd=0x%x %s", + __entry->cmd, + _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_return_strings) ? + binder_return_strings[_IOC_NR(__entry->cmd)] : + "unknown") +); + +#endif /* _BINDER_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE binder_trace +#include "trace/define_trace.h" diff --git a/include/trace/events/sync.h b/include/trace/events/sync.h new file mode 100644 index 00000000..bee06c88 --- /dev/null +++ b/include/trace/events/sync.h @@ -0,0 +1,125 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM sync + +#if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SYNC_H + +#include +#include + +TRACE_EVENT(sync_timeline, + TP_PROTO(struct sync_timeline *timeline), + + TP_ARGS(timeline), + + TP_STRUCT__entry( + __string(name, timeline->name) + __array(char, value, 32) + ), + + TP_fast_assign( + __assign_str(name, timeline->name); + if (timeline->ops->timeline_value_str) { + timeline->ops->timeline_value_str(timeline, + __entry->value, + sizeof(__entry->value)); + } else { + __entry->value[0] = '\0'; + } + ), + + TP_printk("name=%s value=%s", __get_str(name), __entry->value) +); + +TRACE_EVENT(sync_wait, + TP_PROTO(struct sync_fence *fence, int begin), + + TP_ARGS(fence, begin), + + TP_STRUCT__entry( + __string(name, fence->name) + __field(s32, status) + __field(u32, begin) + ), + + TP_fast_assign( + __assign_str(name, fence->name); + __entry->status = fence->status; + __entry->begin = begin; + ), + + TP_printk("%s name=%s state=%d", __entry->begin ? "begin" : "end", + __get_str(name), __entry->status) +); + +TRACE_EVENT(sync_pt, + TP_PROTO(struct sync_pt *pt), + + TP_ARGS(pt), + + TP_STRUCT__entry( + __string(timeline, pt->parent->name) + __array(char, value, 32) + ), + + TP_fast_assign( + __assign_str(timeline, pt->parent->name); + if (pt->parent->ops->pt_value_str) { + pt->parent->ops->pt_value_str(pt, + __entry->value, + sizeof(__entry->value)); + } else { + __entry->value[0] = '\0'; + } + ), + + TP_printk("name=%s value=%s", __get_str(timeline), __entry->value) + ); + + +TRACE_EVENT(sync_alloc, + TP_PROTO(struct sync_fence *fence, int pid), + + TP_ARGS(fence, pid), + + TP_STRUCT__entry( + __string(name, fence->name) + __field(s32, status) + __field(u32, pid) + ), + + TP_fast_assign( + __assign_str(name, fence->name); + __entry->status = fence->status; + __entry->pid = pid; + ), + + TP_printk("PID:%d Fence=%s status=%d", __entry->pid, + __get_str(name), __entry->status) +); + +TRACE_EVENT(sync_free, + TP_PROTO(struct sync_fence *fence, int pid), + + TP_ARGS(fence, pid), + + TP_STRUCT__entry( + __string(name, fence->name) + __field(s32, status) + __field(u32, pid) + ), + + TP_fast_assign( + __assign_str(name, fence->name); + __entry->status = fence->status; + __entry->pid = pid; + ), + + TP_printk("PID:%d Fence =%s status=%d", __entry->pid, + __get_str(name), __entry->status) +); + +#endif /* if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) */ + +/* This part must be outside protection */ +#include diff --git a/kernel/cpu.c b/kernel/cpu.c index 8837eebe..224affbf 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -16,6 +16,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -25,18 +26,23 @@ 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); @@ -58,17 +64,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); @@ -84,6 +103,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); @@ -114,6 +134,7 @@ static void cpu_hotplug_begin(void) { cpu_hotplug.active_writer = current; + cpuhp_lock_acquire(); for (;;) { mutex_lock(&cpu_hotplug.lock); if (likely(!cpu_hotplug.refcount)) @@ -128,6 +149,7 @@ static 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); + static inline void check_for_tasks(int cpu) { struct task_struct *p; @@ -322,7 +356,7 @@ EXPORT_SYMBOL(cpu_down); #endif /*CONFIG_HOTPLUG_CPU*/ /* Requires cpu_add_remove_lock to be held */ -static int _cpu_up(unsigned int cpu, int tasks_frozen) +static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) { int ret, nr_calls = 0; void *hcpu = (void *)(long)cpu; @@ -357,7 +391,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen) return ret; } -int cpu_up(unsigned int cpu) +int __cpuinit cpu_up(unsigned int cpu) { int err = 0; @@ -570,7 +604,7 @@ core_initcall(cpu_hotplug_pm_sync_init); * It must be called by the arch code on the new cpu, before the new cpu * enables interrupts and before the "boot" cpu returns from __cpu_up(). */ -void notify_cpu_starting(unsigned int cpu) +void __cpuinit notify_cpu_starting(unsigned int cpu) { unsigned long val = CPU_STARTING; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 63319e34..9378313c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -87,6 +87,8 @@ #define CREATE_TRACE_POINTS #include +ATOMIC_NOTIFIER_HEAD(migration_notifier_head); + void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period) { unsigned long delta; @@ -110,6 +112,10 @@ void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period) DEFINE_MUTEX(sched_domains_mutex); DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); +#ifdef CONFIG_INTELLI_PLUG +DEFINE_PER_CPU_SHARED_ALIGNED(struct nr_stats_s, runqueue_stats); +#endif + static void update_rq_clock_task(struct rq *rq, s64 delta); void update_rq_clock(struct rq *rq) @@ -1579,15 +1585,17 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) { unsigned long flags; - int cpu, success = 0; + int cpu, src_cpu, success = 0; smp_wmb(); raw_spin_lock_irqsave(&p->pi_lock, flags); + src_cpu = task_cpu(p); + cpu = src_cpu; + if (!(p->state & state)) goto out; success = 1; /* we're going to change ->state */ - cpu = task_cpu(p); if (p->on_rq && ttwu_remote(p, wake_flags)) goto stat; @@ -1624,7 +1632,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) p->sched_class->task_waking(p); cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags); - if (task_cpu(p) != cpu) { + if (src_cpu != cpu) { wake_flags |= WF_MIGRATED; set_task_cpu(p, cpu); } @@ -1636,6 +1644,9 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) out: raw_spin_unlock_irqrestore(&p->pi_lock, flags); + if (src_cpu != cpu && task_notify_on_migrate(p)) + atomic_notifier_call_chain(&migration_notifier_head, + cpu, (void *)src_cpu); return success; } @@ -2171,6 +2182,60 @@ unsigned long this_cpu_load(void) return this->cpu_load[0]; } +#ifdef CONFIG_INTELLI_PLUG +unsigned long avg_nr_running(void) +{ + unsigned long i, sum = 0; + unsigned int seqcnt, ave_nr_running; + + for_each_online_cpu(i) { + struct nr_stats_s *stats = &per_cpu(runqueue_stats, i); + struct rq *q = cpu_rq(i); + + /* + * Update average to avoid reading stalled value if there were + * no run-queue changes for a long time. On the other hand if + * the changes are happening right now, just read current value + * directly. + */ + seqcnt = read_seqcount_begin(&stats->ave_seqcnt); + ave_nr_running = do_avg_nr_running(q); + if (read_seqcount_retry(&stats->ave_seqcnt, seqcnt)) { + read_seqcount_begin(&stats->ave_seqcnt); + ave_nr_running = stats->ave_nr_running; + } + + sum += ave_nr_running; + } + + return sum; +} +EXPORT_SYMBOL(avg_nr_running); + +unsigned long avg_cpu_nr_running(unsigned int cpu) +{ + unsigned int seqcnt, ave_nr_running; + + struct nr_stats_s *stats = &per_cpu(runqueue_stats, cpu); + struct rq *q = cpu_rq(cpu); + + /* + * Update average to avoid reading stalled value if there were + * no run-queue changes for a long time. On the other hand if + * the changes are happening right now, just read current value + * directly. + */ + seqcnt = read_seqcount_begin(&stats->ave_seqcnt); + ave_nr_running = do_avg_nr_running(q); + if (read_seqcount_retry(&stats->ave_seqcnt, seqcnt)) { + read_seqcount_begin(&stats->ave_seqcnt); + ave_nr_running = stats->ave_nr_running; + } + + return ave_nr_running; +} +EXPORT_SYMBOL(avg_cpu_nr_running); +#endif /* * Global load-average calculations @@ -5271,6 +5336,7 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr); static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) { struct rq *rq_dest, *rq_src; + bool moved = false; int ret = 0; if (unlikely(!cpu_active(dest_cpu))) @@ -5297,12 +5363,16 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) set_task_cpu(p, dest_cpu); enqueue_task(rq_dest, p, 0); check_preempt_curr(rq_dest, p, 0); + moved = true; } done: ret = 1; fail: double_rq_unlock(rq_src, rq_dest); raw_spin_unlock(&p->pi_lock); + if (moved && task_notify_on_migrate(p)) + atomic_notifier_call_chain(&migration_notifier_head, + dest_cpu, (void *)src_cpu); return ret; } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 90933dfd..dfcab643 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3109,6 +3109,8 @@ struct lb_env { unsigned int loop_max; }; +static DEFINE_PER_CPU(bool, dbs_boost_needed); + /* * move_task - move a task from one runqueue to another runqueue. * Both runqueues must be locked. @@ -3119,6 +3121,8 @@ static void move_task(struct task_struct *p, struct lb_env *env) set_task_cpu(p, env->dst_cpu); activate_task(env->dst_rq, p, 0); check_preempt_curr(env->dst_rq, p, 0); + if (task_notify_on_migrate(p)) + per_cpu(dbs_boost_needed, env->dst_cpu) = true; } /* diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 71429db2..bf6a0689 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1647,6 +1647,7 @@ static int push_rt_task(struct rq *rq) struct task_struct *next_task; struct rq *lowest_rq; int ret = 0; + bool moved = false; if (!rq->rt.overloaded) return 0; @@ -1716,6 +1717,7 @@ static int push_rt_task(struct rq *rq) deactivate_task(rq, next_task, 0); set_task_cpu(next_task, lowest_rq->cpu); + moved = true; activate_task(lowest_rq, next_task, 0); ret = 1; @@ -1726,6 +1728,11 @@ static int push_rt_task(struct rq *rq) out: put_task_struct(next_task); + if (moved && task_notify_on_migrate(next_task)) + atomic_notifier_call_chain(&migration_notifier_head, + cpu_of(lowest_rq), + (void *)cpu_of(rq)); + return ret; } @@ -1739,8 +1746,10 @@ static void push_rt_tasks(struct rq *rq) static int pull_rt_task(struct rq *this_rq) { int this_cpu = this_rq->cpu, ret = 0, cpu; - struct task_struct *p; + struct task_struct *p = NULL; struct rq *src_rq; + bool moved = false; + int src_cpu = 0; if (likely(!rt_overloaded(this_rq))) return 0; @@ -1801,6 +1810,10 @@ static int pull_rt_task(struct rq *this_rq) deactivate_task(src_rq, p, 0); set_task_cpu(p, this_cpu); activate_task(this_rq, p, 0); + + moved = true; + src_cpu = cpu_of(src_rq); + /* * We continue with the search, just in * case there's an even higher prio task @@ -1812,6 +1825,11 @@ static int pull_rt_task(struct rq *this_rq) double_unlock_balance(this_rq, src_rq); } + if (moved && task_notify_on_migrate(p)) + atomic_notifier_call_chain(&migration_notifier_head, + this_cpu, + (void *)src_cpu); + return ret; } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 4a5e7398..23994fd4 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -104,6 +104,8 @@ struct cfs_bandwidth { struct task_group { struct cgroup_subsys_state css; + bool notify_on_migrate; + #ifdef CONFIG_FAIR_GROUP_SCHED /* schedulable entities of this group on each cpu */ struct sched_entity **se; @@ -482,6 +484,27 @@ DECLARE_PER_CPU(struct rq, runqueues); #define cpu_curr(cpu) (cpu_rq(cpu)->curr) #define raw_rq() (&__raw_get_cpu_var(runqueues)) +#ifdef CONFIG_INTELLI_PLUG +struct nr_stats_s { + /* time-based average load */ + u64 nr_last_stamp; + unsigned int ave_nr_running; + seqcount_t ave_seqcnt; +}; + +/* 27 ~= 134217728ns = 134.2ms + * 26 ~= 67108864ns = 67.1ms + * 25 ~= 33554432ns = 33.5ms + * 24 ~= 16777216ns = 16.8ms + */ +#define NR_AVE_PERIOD_EXP 27 +#define NR_AVE_SCALE(x) ((x) << FSHIFT) +#define NR_AVE_PERIOD (1 << NR_AVE_PERIOD_EXP) +#define NR_AVE_DIV_PERIOD(x) ((x) >> NR_AVE_PERIOD_EXP) + +DECLARE_PER_CPU(struct nr_stats_s, runqueue_stats); +#endif + #ifdef CONFIG_SMP #define rcu_dereference_check_sched_domain(p) \ @@ -551,6 +574,11 @@ static inline struct task_group *task_group(struct task_struct *p) return p->sched_task_group; } +static inline bool task_notify_on_migrate(struct task_struct *p) +{ + return task_group(p)->notify_on_migrate; +} + /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ static inline void set_task_rq(struct task_struct *p, unsigned int cpu) { @@ -911,14 +939,54 @@ extern void cpuacct_charge(struct task_struct *tsk, u64 cputime); static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) {} #endif +#ifdef CONFIG_INTELLI_PLUG +static inline unsigned int do_avg_nr_running(struct rq *rq) +{ + + struct nr_stats_s *nr_stats = &per_cpu(runqueue_stats, rq->cpu); + unsigned int ave_nr_running = nr_stats->ave_nr_running; + s64 nr, deltax; + + deltax = rq->clock_task - nr_stats->nr_last_stamp; + nr = NR_AVE_SCALE(rq->nr_running); + + if (deltax > NR_AVE_PERIOD) + ave_nr_running = nr; + else + ave_nr_running += + NR_AVE_DIV_PERIOD(deltax * (nr - ave_nr_running)); + + return ave_nr_running; +} +#endif + static inline void inc_nr_running(struct rq *rq) { +#ifdef CONFIG_INTELLI_PLUG + struct nr_stats_s *nr_stats = &per_cpu(runqueue_stats, rq->cpu); +#endif + rq->nr_running++; +#ifdef CONFIG_INTELLI_PLUG + write_seqcount_end(&nr_stats->ave_seqcnt); +#endif } static inline void dec_nr_running(struct rq *rq) { +#ifdef CONFIG_INTELLI_PLUG + struct nr_stats_s *nr_stats = &per_cpu(runqueue_stats, rq->cpu); +#endif + +#ifdef CONFIG_INTELLI_PLUG + write_seqcount_begin(&nr_stats->ave_seqcnt); + nr_stats->ave_nr_running = do_avg_nr_running(rq); + nr_stats->nr_last_stamp = rq->clock_task; +#endif rq->nr_running--; +#ifdef CONFIG_INTELLI_PLUG + write_seqcount_end(&nr_stats->ave_seqcnt); +#endif } extern void update_rq_clock(struct rq *rq); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index abdb54bf..82b247ed 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1133,6 +1133,7 @@ static struct ctl_table vm_table[] = { .extra1 = &zero, }, #endif +#endif { .procname = "dirty_expire_centisecs", .data = &dirty_expire_interval, @@ -1598,7 +1599,7 @@ static struct ctl_table debug_table[] = { #endif { } }; - +#if defined(CONFIG_SYSCTL) static struct ctl_table dev_table[] = { { } }; diff --git a/mm/Kconfig b/mm/Kconfig index 621c1d34..8c55931c 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -382,13 +382,30 @@ config CLEANCACHE config DYNAMIC_PAGE_WRITEBACK bool "Dynamically manage the dirty page writebacks during suspend/resume" - default n + default y help This feature allows to use different dirty page writeback intervals when the system is suspended and when the system has been resumed. If unsure, say N to disable this feature +config FRONTSWAP + bool "Enable frontswap to cache swap pages if tmem is present" + depends on SWAP + default n + help + Frontswap is so named because it can be thought of as the opposite + of a "backing" store for a swap device. The data is stored into + "transcendent memory", memory that is not directly accessible or + addressable by the kernel and is of unknown and possibly + time-varying size. When space in transcendent memory is available, + a significant swap I/O reduction may be achieved. When none is + available, all frontswap calls are reduced to a single pointer- + compare-against-NULL resulting in a negligible performance hit + and swap data is stored as normal on the matching swap device. + + If unsure, say Y to enable frontswap. + config MEMORY_HOLE_CARVEOUT bool help @@ -410,3 +427,27 @@ config USE_USER_ACCESSIBLE_TIMERS architecture-specific code that will need to be enabled separately. +config ZSMALLOC + bool "Memory allocator for compressed pages" + depends on MMU + default n + help + zsmalloc is a slab-based memory allocator designed to store + compressed RAM pages. zsmalloc uses virtual memory mapping + in order to reduce fragmentation. However, this results in a + non-standard allocator interface where a handle, not a pointer, is + returned by an alloc(). This handle must be mapped in order to + access the allocated space. + +config PGTABLE_MAPPING + bool "Use page table mapping to access object in zsmalloc" + depends on ZSMALLOC + help + By default, zsmalloc uses a copy-based object mapping method to + access allocations that span two pages. However, if a particular + architecture (ex, ARM) performs VM mapping faster than copying, + then you should select this. This causes zsmalloc to use page table + mapping rather than copying for object mapping. + + You can check speed with zsmalloc benchmark[1]. + [1] https://github.com/spartacus06/zsmalloc diff --git a/mm/Makefile b/mm/Makefile index 8aada89e..3ee79b0b 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o obj-$(CONFIG_HAS_DMA) += dmapool.o +obj-$(CONFIG_FRONTSWAP) += frontswap.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_SPARSEMEM) += sparse.o @@ -50,3 +51,4 @@ obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o obj-$(CONFIG_CLEANCACHE) += cleancache.o +obj-$(CONFIG_ZSMALLOC) += zsmalloc.o diff --git a/mm/frontswap.c b/mm/frontswap.c new file mode 100644 index 00000000..2890e67d --- /dev/null +++ b/mm/frontswap.c @@ -0,0 +1,370 @@ +/* + * Frontswap frontend + * + * This code provides the generic "frontend" layer to call a matching + * "backend" driver implementation of frontswap. See + * Documentation/vm/frontswap.txt for more information. + * + * Copyright (C) 2009-2012 Oracle Corp. All rights reserved. + * Author: Dan Magenheimer + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * frontswap_ops is set by frontswap_register_ops to contain the pointers + * to the frontswap "backend" implementation functions. + */ +static struct frontswap_ops frontswap_ops __read_mostly; + +/* + * This global enablement flag reduces overhead on systems where frontswap_ops + * has not been registered, so is preferred to the slower alternative: a + * function call that checks a non-global. + */ +bool frontswap_enabled __read_mostly; +EXPORT_SYMBOL(frontswap_enabled); + +/* + * If enabled, frontswap_store will return failure even on success. As + * a result, the swap subsystem will always write the page to swap, in + * effect converting frontswap into a writethrough cache. In this mode, + * there is no direct reduction in swap writes, but a frontswap backend + * can unilaterally "reclaim" any pages in use with no data loss, thus + * providing increases control over maximum memory usage due to frontswap. + */ +static bool frontswap_writethrough_enabled __read_mostly; + +/* + * If enabled, the underlying tmem implementation is capable of doing + * exclusive gets, so frontswap_load, on a successful tmem_get must + * mark the page as no longer in frontswap AND mark it dirty. + */ +static bool frontswap_tmem_exclusive_gets_enabled __read_mostly; + +#ifdef CONFIG_DEBUG_FS +/* + * Counters available via /sys/kernel/debug/frontswap (if debugfs is + * properly configured). These are for information only so are not protected + * against increment races. + */ +static u64 frontswap_loads; +static u64 frontswap_succ_stores; +static u64 frontswap_failed_stores; +static u64 frontswap_invalidates; + +static inline void inc_frontswap_loads(void) { + frontswap_loads++; +} +static inline void inc_frontswap_succ_stores(void) { + frontswap_succ_stores++; +} +static inline void inc_frontswap_failed_stores(void) { + frontswap_failed_stores++; +} +static inline void inc_frontswap_invalidates(void) { + frontswap_invalidates++; +} +#else +static inline void inc_frontswap_loads(void) { } +static inline void inc_frontswap_succ_stores(void) { } +static inline void inc_frontswap_failed_stores(void) { } +static inline void inc_frontswap_invalidates(void) { } +#endif +/* + * Register operations for frontswap, returning previous thus allowing + * detection of multiple backends and possible nesting. + */ +struct frontswap_ops frontswap_register_ops(struct frontswap_ops *ops) +{ + struct frontswap_ops old = frontswap_ops; + + frontswap_ops = *ops; + frontswap_enabled = true; + return old; +} +EXPORT_SYMBOL(frontswap_register_ops); + +/* + * Enable/disable frontswap writethrough (see above). + */ +void frontswap_writethrough(bool enable) +{ + frontswap_writethrough_enabled = enable; +} +EXPORT_SYMBOL(frontswap_writethrough); + +/* + * Enable/disable frontswap exclusive gets (see above). + */ +void frontswap_tmem_exclusive_gets(bool enable) +{ + frontswap_tmem_exclusive_gets_enabled = enable; +} +EXPORT_SYMBOL(frontswap_tmem_exclusive_gets); + +/* + * Called when a swap device is swapon'd. + */ +void __frontswap_init(unsigned type) +{ + struct swap_info_struct *sis = swap_info[type]; + + BUG_ON(sis == NULL); + if (sis->frontswap_map == NULL) + return; + frontswap_ops.init(type); +} +EXPORT_SYMBOL(__frontswap_init); + +static inline void __frontswap_clear(struct swap_info_struct *sis, pgoff_t offset) +{ + frontswap_clear(sis, offset); + atomic_dec(&sis->frontswap_pages); +} + +/* + * "Store" data from a page to frontswap and associate it with the page's + * swaptype and offset. Page must be locked and in the swap cache. + * If frontswap already contains a page with matching swaptype and + * offset, the frontswap implementation may either overwrite the data and + * return success or invalidate the page from frontswap and return failure. + */ +int __frontswap_store(struct page *page) +{ + int ret = -1, dup = 0; + swp_entry_t entry = { .val = page_private(page), }; + int type = swp_type(entry); + struct swap_info_struct *sis = swap_info[type]; + pgoff_t offset = swp_offset(entry); + + BUG_ON(!PageLocked(page)); + BUG_ON(sis == NULL); + if (frontswap_test(sis, offset)) + dup = 1; + ret = frontswap_ops.store(type, offset, page); + if (ret == 0) { + frontswap_set(sis, offset); + inc_frontswap_succ_stores(); + if (!dup) + atomic_inc(&sis->frontswap_pages); + } else { + /* + failed dup always results in automatic invalidate of + the (older) page from frontswap + */ + inc_frontswap_failed_stores(); + if (dup) + __frontswap_clear(sis, offset); + } + if (frontswap_writethrough_enabled) + /* report failure so swap also writes to swap device */ + ret = -1; + return ret; +} +EXPORT_SYMBOL(__frontswap_store); + +/* + * "Get" data from frontswap associated with swaptype and offset that were + * specified when the data was put to frontswap and use it to fill the + * specified page with data. Page must be locked and in the swap cache. + */ +int __frontswap_load(struct page *page) +{ + int ret = -1; + swp_entry_t entry = { .val = page_private(page), }; + int type = swp_type(entry); + struct swap_info_struct *sis = swap_info[type]; + pgoff_t offset = swp_offset(entry); + + BUG_ON(!PageLocked(page)); + BUG_ON(sis == NULL); + if (frontswap_test(sis, offset)) + ret = frontswap_ops.load(type, offset, page); + if (ret == 0) { + inc_frontswap_loads(); + if (frontswap_tmem_exclusive_gets_enabled) { + SetPageDirty(page); + frontswap_clear(sis, offset); + } + } + return ret; +} +EXPORT_SYMBOL(__frontswap_load); + +/* + * Invalidate any data from frontswap associated with the specified swaptype + * and offset so that a subsequent "get" will fail. + */ +void __frontswap_invalidate_page(unsigned type, pgoff_t offset) +{ + struct swap_info_struct *sis = swap_info[type]; + + BUG_ON(sis == NULL); + if (frontswap_test(sis, offset)) { + frontswap_ops.invalidate_page(type, offset); + __frontswap_clear(sis, offset); + inc_frontswap_invalidates(); + } +} +EXPORT_SYMBOL(__frontswap_invalidate_page); + +/* + * Invalidate all data from frontswap associated with all offsets for the + * specified swaptype. + */ +void __frontswap_invalidate_area(unsigned type) +{ + struct swap_info_struct *sis = swap_info[type]; + + BUG_ON(sis == NULL); + if (sis->frontswap_map == NULL) + return; + frontswap_ops.invalidate_area(type); + atomic_set(&sis->frontswap_pages, 0); + memset(sis->frontswap_map, 0, sis->max / sizeof(long)); +} +EXPORT_SYMBOL(__frontswap_invalidate_area); + +static unsigned long __frontswap_curr_pages(void) +{ + int type; + unsigned long totalpages = 0; + struct swap_info_struct *si = NULL; + + assert_spin_locked(&swap_lock); + for (type = swap_list.head; type >= 0; type = si->next) { + si = swap_info[type]; + totalpages += atomic_read(&si->frontswap_pages); + } + return totalpages; +} + +static int __frontswap_unuse_pages(unsigned long total, unsigned long *unused, + int *swapid) +{ + int ret = -EINVAL; + struct swap_info_struct *si = NULL; + int si_frontswap_pages; + unsigned long total_pages_to_unuse = total; + unsigned long pages = 0, pages_to_unuse = 0; + int type; + + assert_spin_locked(&swap_lock); + for (type = swap_list.head; type >= 0; type = si->next) { + si = swap_info[type]; + si_frontswap_pages = atomic_read(&si->frontswap_pages); + if (total_pages_to_unuse < si_frontswap_pages) { + pages = pages_to_unuse = total_pages_to_unuse; + } else { + pages = si_frontswap_pages; + pages_to_unuse = 0; /* unuse all */ + } + /* ensure there is enough RAM to fetch pages from frontswap */ + if (security_vm_enough_memory_mm(current->mm, pages)) { + ret = -ENOMEM; + continue; + } + vm_unacct_memory(pages); + *unused = pages_to_unuse; + *swapid = type; + ret = 0; + break; + } + + return ret; +} + +/* + * Used to check if it's necessory and feasible to unuse pages. + * Return 1 when nothing to do, 0 when need to shink pages, + * error code when there is an error. + */ +static int __frontswap_shrink(unsigned long target_pages, + unsigned long *pages_to_unuse, + int *type) +{ + unsigned long total_pages = 0, total_pages_to_unuse; + + assert_spin_locked(&swap_lock); + + total_pages = __frontswap_curr_pages(); + if (total_pages <= target_pages) { + /* Nothing to do */ + *pages_to_unuse = 0; + return 1; + } + total_pages_to_unuse = total_pages - target_pages; + return __frontswap_unuse_pages(total_pages_to_unuse, pages_to_unuse, type); +} + +/* + * Frontswap, like a true swap device, may unnecessarily retain pages + * under certain circumstances; "shrink" frontswap is essentially a + * "partial swapoff" and works by calling try_to_unuse to attempt to + * unuse enough frontswap pages to attempt to -- subject to memory + * constraints -- reduce the number of pages in frontswap to the + * number given in the parameter target_pages. + */ +void frontswap_shrink(unsigned long target_pages) +{ + unsigned long pages_to_unuse = 0; + int uninitialized_var(type), ret; + + /* + * we don't want to hold swap_lock while doing a very + * lengthy try_to_unuse, but swap_list may change + * so restart scan from swap_list.head each time + */ + spin_lock(&swap_lock); + ret = __frontswap_shrink(target_pages, &pages_to_unuse, &type); + spin_unlock(&swap_lock); + if (ret == 0) + try_to_unuse(type, true, pages_to_unuse); + return; +} +EXPORT_SYMBOL(frontswap_shrink); + +/* + * Count and return the number of frontswap pages across all + * swap devices. This is exported so that backend drivers can + * determine current usage without reading debugfs. + */ +unsigned long frontswap_curr_pages(void) +{ + unsigned long totalpages = 0; + + spin_lock(&swap_lock); + totalpages = __frontswap_curr_pages(); + spin_unlock(&swap_lock); + + return totalpages; +} +EXPORT_SYMBOL(frontswap_curr_pages); + +static int __init init_frontswap(void) +{ +#ifdef CONFIG_DEBUG_FS + struct dentry *root = debugfs_create_dir("frontswap", NULL); + if (root == NULL) + return -ENXIO; + debugfs_create_u64("loads", S_IRUGO, root, &frontswap_loads); + debugfs_create_u64("succ_stores", S_IRUGO, root, &frontswap_succ_stores); + debugfs_create_u64("failed_stores", S_IRUGO, root, + &frontswap_failed_stores); + debugfs_create_u64("invalidates", S_IRUGO, + root, &frontswap_invalidates); +#endif + return 0; +} + +module_init(init_frontswap); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index a33f2a0f..26adea8c 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -35,9 +35,6 @@ #include /* __set_page_dirty_buffers */ #include #include -#ifdef CONFIG_DYNAMIC_PAGE_WRITEBACK -#include -#endif /* * Sleep at most 200ms at a time in balance_dirty_pages(). @@ -93,37 +90,12 @@ int vm_dirty_ratio = 20; */ unsigned long vm_dirty_bytes; -/* - * The default intervals between `kupdate'-style writebacks - */ -#define DEFAULT_DIRTY_WRITEBACK_INTERVAL 5 * 100 /* centiseconds */ -#define HIGH_DIRTY_WRITEBACK_INTERVAL 15 * 100 /* centiseconds */ - /* * The interval between `kupdate'-style writebacks */ -unsigned int dirty_writeback_interval = DEFAULT_DIRTY_WRITEBACK_INTERVAL; /* centiseconds */ -EXPORT_SYMBOL_GPL(dirty_writeback_interval); - -#ifdef CONFIG_DYNAMIC_PAGE_WRITEBACK -/* - * The dynamic writeback activation status - */ -int dyn_dirty_writeback_enabled = 1; -EXPORT_SYMBOL_GPL(dyn_dirty_writeback_enabled); +unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */ -/* - * The interval between `kupdate'-style writebacks when the system is active - */ -unsigned int dirty_writeback_active_interval = HIGH_DIRTY_WRITEBACK_INTERVAL; /* centiseconds */ -EXPORT_SYMBOL_GPL(dirty_writeback_active_interval); - -/* - * The interval between `kupdate'-style writebacks when the system is suspended - */ -unsigned int dirty_writeback_suspend_interval = DEFAULT_DIRTY_WRITEBACK_INTERVAL; /* centiseconds */ -EXPORT_SYMBOL_GPL(dirty_writeback_suspend_interval); -#endif +EXPORT_SYMBOL_GPL(dirty_writeback_interval); /* * The longest time for which data is allowed to remain dirty @@ -214,18 +186,6 @@ static unsigned long highmem_dirtyable_memory(unsigned long total) x += zone_page_state(z, NR_FREE_PAGES) + zone_reclaimable_pages(z) - z->dirty_balance_reserve; } - /* - * Unreclaimable memory (kernel memory or anonymous memory - * without swap) can bring down the dirtyable pages below - * the zone's dirty balance reserve and the above calculation - * will underflow. However we still want to add in nodes - * which are below threshold (negative values) to get a more - * accurate calculation but make sure that the total never - * underflows. - */ - if ((long)x < 0) - x = 0; - /* * Make sure that the number of highmem pages is never larger * than the number of the total dirtyable memory. This can only @@ -248,8 +208,8 @@ unsigned long global_dirtyable_memory(void) { unsigned long x; - x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages(); - x -= min(x, dirty_balance_reserve); + x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages() - + dirty_balance_reserve; if (!vm_highmem_is_dirtyable) x -= highmem_dirtyable_memory(x); @@ -316,12 +276,9 @@ static unsigned long zone_dirtyable_memory(struct zone *zone) * highmem zone can hold its share of dirty pages, so we don't * care about vm_highmem_is_dirtyable here. */ - unsigned long nr_pages = zone_page_state(zone, NR_FREE_PAGES) + - zone_reclaimable_pages(zone); - - /* don't allow this to underflow */ - nr_pages -= min(nr_pages, zone->dirty_balance_reserve); - return nr_pages; + return zone_page_state(zone, NR_FREE_PAGES) + + zone_reclaimable_pages(zone) - + zone->dirty_balance_reserve; } /** @@ -1100,11 +1057,11 @@ static unsigned long dirty_poll_interval(unsigned long dirty, return 1; } -static unsigned long bdi_max_pause(struct backing_dev_info *bdi, - unsigned long bdi_dirty) +static long bdi_max_pause(struct backing_dev_info *bdi, + unsigned long bdi_dirty) { - unsigned long bw = bdi->avg_write_bandwidth; - unsigned long t; + long bw = bdi->avg_write_bandwidth; + long t; /* * Limit pause time for small memory systems. If sleeping for too long @@ -1116,7 +1073,7 @@ static unsigned long bdi_max_pause(struct backing_dev_info *bdi, t = bdi_dirty / (1 + bw / roundup_pow_of_two(1 + HZ / 8)); t++; - return min_t(unsigned long, t, MAX_PAUSE); + return min_t(long, t, MAX_PAUSE); } static long bdi_min_pause(struct backing_dev_info *bdi, @@ -1551,68 +1508,6 @@ int dirty_writeback_centisecs_handler(ctl_table *table, int write, return 0; } -#ifdef CONFIG_DYNAMIC_PAGE_WRITEBACK -/* - * Manages the dirty page writebacks activation status - */ -static void set_dirty_writeback_status(bool active) { - /* Change the current dirty writeback interval according to the - * status provided */ - dirty_writeback_interval = (active) ? - dirty_writeback_active_interval : - dirty_writeback_suspend_interval; - - /* Update the timer related to dirty writebacks interval */ - bdi_arm_supers_timer(); - - /* Print debug info */ - pr_debug("%s: Set dirty_writeback_interval = %d centisecs\n", - __func__, dirty_writeback_interval); -} - -/* - * sysctl handler for /proc/sys/vm/dyn_dirty_writeback_enabled - */ -int dynamic_dirty_writeback_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int ret; - int old_status = dyn_dirty_writeback_enabled; - - /* Get and store the new status */ - ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - - /* If the dynamic writeback has been enabled then set the active - * dirty writebacks interval, otherwise if the feature has been - * disabled, set the suspend interval (the default interval) - * to restore the standard functionality */ - if (ret == 0 && write && dyn_dirty_writeback_enabled != old_status) - set_dirty_writeback_status(!!dyn_dirty_writeback_enabled); - - return ret; -} - -/* - * sysctl handler for /proc/sys/vm/dirty_writeback_active_centisecs - */ -int dirty_writeback_active_centisecs_handler(ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - proc_dointvec_minmax(table, write, buffer, length, ppos); - return 0; -} - -/* - * sysctl handler for /proc/sys/vm/dirty_writeback_suspend_centisecs - */ -int dirty_writeback_suspend_centisecs_handler(ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - proc_dointvec_minmax(table, write, buffer, length, ppos); - return 0; -} -#endif - #ifdef CONFIG_BLOCK void laptop_mode_timer_fn(unsigned long data) { @@ -1678,46 +1573,18 @@ void writeback_set_ratelimit(void) ratelimit_pages = 16; } -static int +static int __cpuinit ratelimit_handler(struct notifier_block *self, unsigned long u, void *v) { writeback_set_ratelimit(); return NOTIFY_DONE; } -static struct notifier_block ratelimit_nb = { +static struct notifier_block __cpuinitdata ratelimit_nb = { .notifier_call = ratelimit_handler, .next = NULL, }; -#ifdef CONFIG_DYNAMIC_PAGE_WRITEBACK -/* - * Sets the dirty page writebacks interval for suspended system - */ -static void dirty_writeback_early_suspend(struct early_suspend *handler) -{ - if (dyn_dirty_writeback_enabled) - set_dirty_writeback_status(false); -} - -/* - * Sets the dirty page writebacks interval for active system - */ -static void dirty_writeback_late_resume(struct early_suspend *handler) -{ - if (dyn_dirty_writeback_enabled) - set_dirty_writeback_status(true); -} - -/* - * Struct for the dirty page writeback management during suspend/resume - */ -static struct early_suspend dirty_writeback_suspend = { - .suspend = dirty_writeback_early_suspend, - .resume = dirty_writeback_late_resume, -}; -#endif - /* * Called early on to tune the page writeback dirty limits. * @@ -1740,11 +1607,6 @@ void __init page_writeback_init(void) { int shift; -#ifdef CONFIG_DYNAMIC_PAGE_WRITEBACK - /* Register the dirty page writeback management during suspend/resume */ - register_early_suspend(&dirty_writeback_suspend); -#endif - writeback_set_ratelimit(); register_cpu_notifier(&ratelimit_nb); @@ -2116,12 +1978,11 @@ int __set_page_dirty_nobuffers(struct page *page) if (!TestSetPageDirty(page)) { struct address_space *mapping = page_mapping(page); struct address_space *mapping2; - unsigned long flags; if (!mapping) return 1; - spin_lock_irqsave(&mapping->tree_lock, flags); + spin_lock_irq(&mapping->tree_lock); mapping2 = page_mapping(page); if (mapping2) { /* Race with truncate? */ BUG_ON(mapping2 != mapping); @@ -2130,7 +1991,7 @@ int __set_page_dirty_nobuffers(struct page *page) radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } - spin_unlock_irqrestore(&mapping->tree_lock, flags); + spin_unlock_irq(&mapping->tree_lock); if (mapping->host) { /* !PageAnon && !swapper_space */ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); diff --git a/mm/swapfile.c b/mm/swapfile.c index 7fc4c406..3913f025 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include #include @@ -42,7 +45,7 @@ static bool swap_count_continued(struct swap_info_struct *, pgoff_t, static void free_swap_count_continuations(struct swap_info_struct *); static sector_t map_swap_entry(swp_entry_t, struct block_device**); -static DEFINE_SPINLOCK(swap_lock); +DEFINE_SPINLOCK(swap_lock); static unsigned int nr_swapfiles; long nr_swap_pages; long total_swap_pages; @@ -53,9 +56,9 @@ static const char Unused_file[] = "Unused swap file entry "; static const char Bad_offset[] = "Bad swap offset entry "; static const char Unused_offset[] = "Unused swap offset entry "; -static struct swap_list_t swap_list = {-1, -1}; +struct swap_list_t swap_list = {-1, -1}; -static struct swap_info_struct *swap_info[MAX_SWAPFILES]; +struct swap_info_struct *swap_info[MAX_SWAPFILES]; static DEFINE_MUTEX(swapon_mutex); @@ -288,7 +291,7 @@ static unsigned long scan_swap_map(struct swap_info_struct *si, scan_base = offset = si->lowest_bit; /* reuse swap entry of cache-only swap if not busy. */ - if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + if (si->swap_map[offset] == SWAP_HAS_CACHE) { int swap_was_freed; spin_unlock(&swap_lock); swap_was_freed = __try_to_reclaim_swap(si, offset); @@ -377,7 +380,7 @@ static unsigned long scan_swap_map(struct swap_info_struct *si, spin_lock(&swap_lock); goto checks; } - if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + if (si->swap_map[offset] == SWAP_HAS_CACHE) { spin_lock(&swap_lock); goto checks; } @@ -392,7 +395,7 @@ static unsigned long scan_swap_map(struct swap_info_struct *si, spin_lock(&swap_lock); goto checks; } - if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + if (si->swap_map[offset] == SWAP_HAS_CACHE) { spin_lock(&swap_lock); goto checks; } @@ -556,6 +559,7 @@ static unsigned char swap_entry_free(struct swap_info_struct *p, swap_list.next = p->type; nr_swap_pages++; p->inuse_pages--; + frontswap_invalidate_page(p->type, offset); if ((p->flags & SWP_BLKDEV) && disk->fops->swap_slot_free_notify) disk->fops->swap_slot_free_notify(p->bdev, offset); @@ -601,7 +605,7 @@ void swapcache_free(swp_entry_t entry, struct page *page) * This does not give an exact answer when swap count is continued, * but does include the high COUNT_CONTINUED flag to allow for that. */ -static inline int page_swapcount(struct page *page) +int page_swapcount(struct page *page) { int count = 0; struct swap_info_struct *p; @@ -706,8 +710,7 @@ int free_swap_and_cache(swp_entry_t entry) * Not mapped elsewhere, or swap space full? Free it! * Also recheck PageSwapCache now page is locked (above). */ - if (PageSwapCache(page) && !PageWriteback(page) && - (!page_mapped(page) || vm_swap_full())) { + if (PageSwapCache(page) && !PageWriteback(page)) { delete_from_swap_cache(page); SetPageDirty(page); } @@ -1016,11 +1019,12 @@ static int unuse_mm(struct mm_struct *mm, } /* - * Scan swap_map from current position to next entry still in use. + * Scan swap_map (or frontswap_map if frontswap parameter is true) + * from current position to next entry still in use. * Recycle to start on reaching the end, returning 0 when empty. */ static unsigned int find_next_to_unuse(struct swap_info_struct *si, - unsigned int prev) + unsigned int prev, bool frontswap) { unsigned int max = si->max; unsigned int i = prev; @@ -1046,6 +1050,12 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si, prev = 0; i = 1; } + if (frontswap) { + if (frontswap_test(si, i)) + break; + else + continue; + } count = si->swap_map[i]; if (count && swap_count(count) != SWAP_MAP_BAD) break; @@ -1057,8 +1067,12 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si, * We completely avoid races by reading each swap page in advance, * and then search for the process using it. All the necessary * page table adjustments can then be made atomically. + * + * if the boolean frontswap is true, only unuse pages_to_unuse pages; + * pages_to_unuse==0 means all pages; ignored if frontswap is false */ -static int try_to_unuse(unsigned int type) +int try_to_unuse(unsigned int type, bool frontswap, + unsigned long pages_to_unuse) { struct swap_info_struct *si = swap_info[type]; struct mm_struct *start_mm; @@ -1091,7 +1105,7 @@ static int try_to_unuse(unsigned int type) * one pass through swap_map is enough, but not necessarily: * there are races when an instance of an entry might be missed. */ - while ((i = find_next_to_unuse(si, i)) != 0) { + while ((i = find_next_to_unuse(si, i, frontswap)) != 0) { if (signal_pending(current)) { retval = -EINTR; break; @@ -1258,6 +1272,10 @@ static int try_to_unuse(unsigned int type) * interactive performance. */ cond_resched(); + if (frontswap && pages_to_unuse > 0) { + if (!--pages_to_unuse) + break; + } } mmput(start_mm); @@ -1517,7 +1535,8 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span) } static void enable_swap_info(struct swap_info_struct *p, int prio, - unsigned char *swap_map) + unsigned char *swap_map, + unsigned long *frontswap_map) { int i, prev; @@ -1527,6 +1546,7 @@ static void enable_swap_info(struct swap_info_struct *p, int prio, else p->prio = --least_priority; p->swap_map = swap_map; + frontswap_map_set(p, frontswap_map); p->flags |= SWP_WRITEOK; nr_swap_pages += p->pages; total_swap_pages += p->pages; @@ -1543,6 +1563,7 @@ static void enable_swap_info(struct swap_info_struct *p, int prio, swap_list.head = swap_list.next = p->type; else swap_info[prev]->next = p->type; + frontswap_init(p->type); spin_unlock(&swap_lock); } @@ -1616,7 +1637,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) spin_unlock(&swap_lock); oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX); - err = try_to_unuse(type); + err = try_to_unuse(type, false, 0); /* force all pages to be unused */ compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, oom_score_adj); if (err) { @@ -1627,7 +1648,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) * sys_swapoff for this swap_info_struct at this point. */ /* re-insert swap space back into swap_list */ - enable_swap_info(p, p->prio, p->swap_map); + enable_swap_info(p, p->prio, p->swap_map, frontswap_map_get(p)); goto out_dput; } @@ -1654,8 +1675,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) p->swap_map = NULL; p->flags = 0; spin_unlock(&swap_lock); + frontswap_invalidate_area(type); mutex_unlock(&swapon_mutex); vfree(swap_map); + vfree(frontswap_map_get(p)); /* Destroy swap account informatin */ swap_cgroup_swapoff(type); @@ -2015,6 +2038,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) sector_t span; unsigned long maxpages; unsigned char *swap_map = NULL; + unsigned long *frontswap_map = NULL; struct page *page = NULL; struct inode *inode = NULL; @@ -2098,6 +2122,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = nr_extents; goto bad_swap; } + /* frontswap enabled? set up bit-per-page map for frontswap */ + if (frontswap_enabled) + frontswap_map = vzalloc(maxpages / sizeof(long)); if (p->bdev) { if (blk_queue_nonrot(bdev_get_queue(p->bdev))) { @@ -2113,14 +2140,15 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (swap_flags & SWAP_FLAG_PREFER) prio = (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; - enable_swap_info(p, prio, swap_map); + enable_swap_info(p, prio, swap_map, frontswap_map); printk(KERN_INFO "Adding %uk swap on %s. " - "Priority:%d extents:%d across:%lluk %s%s\n", + "Priority:%d extents:%d across:%lluk %s%s%s\n", p->pages<<(PAGE_SHIFT-10), name, p->prio, nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), (p->flags & SWP_SOLIDSTATE) ? "SS" : "", - (p->flags & SWP_DISCARDABLE) ? "D" : ""); + (p->flags & SWP_DISCARDABLE) ? "D" : "", + (frontswap_map) ? "FS" : ""); mutex_unlock(&swapon_mutex); atomic_inc(&proc_poll_event); @@ -2295,6 +2323,24 @@ struct swap_info_struct *page_swap_info(struct page *page) return swap_info[swp_type(swap)]; } +/* + * out-of-line __page_file_ methods to avoid include hell. + */ +struct address_space *__page_file_mapping(struct page *page) +{ + VM_BUG_ON(!PageSwapCache(page)); + return page_swap_info(page)->swap_file->f_mapping; +} +EXPORT_SYMBOL_GPL(__page_file_mapping); + +pgoff_t __page_file_index(struct page *page) +{ + swp_entry_t swap = { .val = page_private(page) }; + VM_BUG_ON(!PageSwapCache(page)); + return swp_offset(swap); +} +EXPORT_SYMBOL_GPL(__page_file_index); + /* * add_swap_count_continuation - called when a swap count is duplicated * beyond SWAP_MAP_MAX, it allocates a new page and links that to the entry's diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/mm/zsmalloc.c similarity index 88% rename from drivers/staging/zsmalloc/zsmalloc-main.c rename to mm/zsmalloc.c index 41a68032..9b6f696d 100644 --- a/drivers/staging/zsmalloc/zsmalloc-main.c +++ b/mm/zsmalloc.c @@ -2,6 +2,7 @@ * zsmalloc memory allocator * * Copyright (C) 2011 Nitin Gupta + * Copyright (C) 2012, 2013 Minchan Kim * * This code is released using a dual license strategy: BSD/GPL * You can choose the license that better fits your requirements. @@ -10,16 +11,14 @@ * Released under the terms of GNU General Public License Version 2.0 */ - /* - * This allocator is designed for use with zcache and zram. Thus, the - * allocator is supposed to work well under low memory conditions. In - * particular, it never attempts higher order page allocation which is - * very likely to fail under memory pressure. On the other hand, if we - * just use single (0-order) pages, it would suffer from very high - * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy - * an entire page. This was one of the major issues with its predecessor - * (xvmalloc). + * This allocator is designed for use with zram. Thus, the allocator is + * supposed to work well under low memory conditions. In particular, it + * never attempts higher order page allocation which is very likely to + * fail under memory pressure. On the other hand, if we just use single + * (0-order) pages, it would suffer from very high fragmentation -- + * any object of size PAGE_SIZE/2 or larger would occupy an entire page. + * This was one of the major issues with its predecessor (xvmalloc). * * To overcome these issues, zsmalloc allocates a bunch of 0-order pages * and links them together using various 'struct page' fields. These linked @@ -27,6 +26,21 @@ * page boundaries. The code refers to these linked pages as a single entity * called zspage. * + * For simplicity, zsmalloc can only allocate objects of size up to PAGE_SIZE + * since this satisfies the requirements of all its current users (in the + * worst case, page is incompressible and is thus stored "as-is" i.e. in + * uncompressed form). For allocation requests larger than this size, failure + * is returned (see zs_malloc). + * + * Additionally, zs_malloc() does not return a dereferenceable pointer. + * Instead, it returns an opaque handle (unsigned long) which encodes actual + * location of the allocated object. The reason for this indirection is that + * zsmalloc does not keep zspages permanently mapped since that would cause + * issues on 32-bit systems where the VA region for kernel space mappings + * is very small. So, before using the allocating memory, the object has to + * be mapped using zs_map_object() to get a usable pointer and subsequently + * unmapped using zs_unmap_object(). + * * Following is how we use various fields and flags of underlying * struct page(s) to form a zspage. * @@ -67,7 +81,6 @@ #include #include #include -#include #include #include #include @@ -78,8 +91,7 @@ #include #include #include - -#include "zsmalloc.h" +#include /* * This must be power of 2 and greater than of equal to sizeof(link_free). @@ -98,7 +110,7 @@ /* * Object location (, ) is encoded as - * as single (void *) handle value. + * as single (unsigned long) handle value. * * Note that object index is relative to system * page it is stored in, so for each sub-page belonging @@ -218,19 +230,8 @@ struct zs_pool { #define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1) #define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1) -/* - * By default, zsmalloc uses a copy-based object mapping method to access - * allocations that span two pages. However, if a particular architecture - * performs VM mapping faster than copying, then it should be added here - * so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use - * page table mapping rather than copying for object mapping. - */ -#if defined(CONFIG_ARM) && !defined(MODULE) -#define USE_PGTABLE_MAPPING -#endif - struct mapping_area { -#ifdef USE_PGTABLE_MAPPING +#ifdef CONFIG_PGTABLE_MAPPING struct vm_struct *vm; /* vm area for mapping object that span pages */ #else char *vm_buf; /* copy buffer for objects that span pages */ @@ -275,6 +276,13 @@ static void set_zspage_mapping(struct page *page, unsigned int class_idx, page->mapping = (struct address_space *)m; } +/* + * zsmalloc divides the pool into various size classes where each + * class maintains a list of zspages where each zspage is divided + * into equal sized chunks. Each allocation falls into one of these + * classes depending on its size. This function returns index of the + * size class which has chunk size big enough to hold the give size. + */ static int get_size_class_index(int size) { int idx = 0; @@ -286,6 +294,13 @@ static int get_size_class_index(int size) return idx; } +/* + * For each size class, zspages are divided into different groups + * depending on how "full" they are. This was done so that we could + * easily find empty or nearly empty zspages when we try to shrink + * the pool (not yet implemented). This function returns fullness + * status of the given page. + */ static enum fullness_group get_fullness_group(struct page *page) { int inuse, max_objects; @@ -307,6 +322,12 @@ static enum fullness_group get_fullness_group(struct page *page) return fg; } +/* + * Each size class maintains various freelists and zspages are assigned + * to one of these freelists based on the number of live objects they + * have. This functions inserts the given zspage into the freelist + * identified by . + */ static void insert_zspage(struct page *page, struct size_class *class, enum fullness_group fullness) { @@ -324,6 +345,10 @@ static void insert_zspage(struct page *page, struct size_class *class, *head = page; } +/* + * This function removes the given zspage from the freelist identified + * by . + */ static void remove_zspage(struct page *page, struct size_class *class, enum fullness_group fullness) { @@ -345,6 +370,15 @@ static void remove_zspage(struct page *page, struct size_class *class, list_del_init(&page->lru); } +/* + * Each size class maintains zspages in different fullness groups depending + * on the number of live objects they contain. When allocating or freeing + * objects, the fullness status of the page can change, say, from ALMOST_FULL + * to ALMOST_EMPTY when freeing an object. This function checks if such + * a status change has occurred for the given page and accordingly moves the + * page from the freelist of the old fullness group to that of the new + * fullness group. + */ static enum fullness_group fix_fullness_group(struct zs_pool *pool, struct page *page) { @@ -631,7 +665,7 @@ static struct page *find_get_zspage(struct size_class *class) return page; } -#ifdef USE_PGTABLE_MAPPING +#ifdef CONFIG_PGTABLE_MAPPING static inline int __zs_cpu_up(struct mapping_area *area) { /* @@ -669,7 +703,7 @@ static inline void __zs_unmap_object(struct mapping_area *area, unmap_kernel_range(addr, PAGE_SIZE * 2); } -#else /* USE_PGTABLE_MAPPING */ +#else /* CONFIG_PGTABLE_MAPPING */ static inline int __zs_cpu_up(struct mapping_area *area) { @@ -747,7 +781,7 @@ static void __zs_unmap_object(struct mapping_area *area, pagefault_enable(); } -#endif /* USE_PGTABLE_MAPPING */ +#endif /* CONFIG_PGTABLE_MAPPING */ static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, void *pcpu) @@ -780,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(); diff --git a/net/Makefile b/net/Makefile index 6865dab6..eee6577c 100644 --- a/net/Makefile +++ b/net/Makefile @@ -48,7 +48,7 @@ endif obj-$(CONFIG_IP_DCCP) += dccp/ obj-$(CONFIG_IP_SCTP) += sctp/ obj-$(CONFIG_RDS) += rds/ -obj-$(CONFIG_WIRELESS) += wireless/ +obj-$(CONFIG_WIRELESS) += wireless_ath/ obj-$(CONFIG_MAC80211) += mac80211/ obj-$(CONFIG_TIPC) += tipc/ obj-$(CONFIG_NETLABEL) += netlabel/ diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c old mode 100644 new mode 100755 index 30b1ec03..984f9f6b --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Technologies, Inc. + Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky @@ -290,8 +290,6 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, return err; } - msg->msg_namelen = 0; - copied = skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; @@ -349,8 +347,6 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (flags & MSG_OOB) return -EOPNOTSUPP; - msg->msg_namelen = 0; - BT_DBG("sk %p size %zu", sk, size); lock_sock(sk); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index c19be91e..ed3bff83 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2010-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 @@ -10,6 +10,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ +// rollback to original BlueZ #include #include @@ -88,15 +89,15 @@ static struct amp_mgr *get_amp_mgr_sk(struct sock *sk) return found; } -static struct amp_mgr *get_create_amp_mgr(struct hci_conn *hcon, +static struct amp_mgr *get_create_amp_mgr(struct l2cap_conn *conn, struct sk_buff *skb) { struct amp_mgr *mgr; write_lock(&_mgr_list_lock); list_for_each_entry(mgr, &_mgr_list, list) { - if (mgr->l2cap_conn == hcon->l2cap_data) { - BT_DBG("found %p", mgr); + if (mgr->l2cap_conn == conn) { + BT_DBG("conn %p found %p", conn, mgr); write_unlock(&_mgr_list_lock); goto gc_finished; } @@ -107,13 +108,13 @@ static struct amp_mgr *get_create_amp_mgr(struct hci_conn *hcon, if (!mgr) return NULL; - mgr->l2cap_conn = hcon->l2cap_data; + mgr->l2cap_conn = conn; mgr->next_ident = 1; INIT_LIST_HEAD(&mgr->ctx_list); rwlock_init(&mgr->ctx_list_lock); mgr->skb = skb; - BT_DBG("hcon %p mgr %p", hcon, mgr); - mgr->a2mp_sock = open_fixed_channel(&hcon->hdev->bdaddr, &hcon->dst); + BT_DBG("conn %p mgr %p", conn, mgr); + mgr->a2mp_sock = open_fixed_channel(conn->src, conn->dst); if (!mgr->a2mp_sock) { kfree(mgr); return NULL; @@ -375,11 +376,13 @@ static void send_a2mp_change_notify(void) { struct amp_mgr *mgr; + read_lock(&_mgr_list_lock); list_for_each_entry(mgr, &_mgr_list, list) { if (mgr->discovered) send_a2mp_cl(mgr, next_ident(mgr), A2MP_CHANGE_NOTIFY, 0, NULL); } + read_unlock(&_mgr_list_lock); } static inline int discover_req(struct amp_mgr *mgr, struct sk_buff *skb) @@ -483,7 +486,7 @@ static void create_physical(struct l2cap_conn *conn, struct sock *sk) struct amp_ctx *ctx = NULL; BT_DBG("conn %p", conn); - mgr = get_create_amp_mgr(conn->hcon, NULL); + mgr = get_create_amp_mgr(conn, NULL); if (!mgr) goto cp_finished; BT_DBG("mgr %p", mgr); @@ -513,7 +516,7 @@ static void accept_physical(struct l2cap_conn *lcon, u8 id, struct sock *sk) if (!hdev) goto ap_finished; BT_DBG("hdev %p", hdev); - mgr = get_create_amp_mgr(lcon->hcon, NULL); + mgr = get_create_amp_mgr(lcon, NULL); if (!mgr) goto ap_finished; BT_DBG("mgr %p", mgr); @@ -1157,7 +1160,6 @@ static u8 createphyslink_handler(struct amp_ctx *ctx, u8 evt_type, void *data) if (skb->len < sizeof(*grsp)) goto cpl_finished; grsp = (struct a2mp_getinfo_rsp *) skb_pull(skb, sizeof(*hdr)); - skb_pull(skb, sizeof(*grsp)); if (grsp->status) goto cpl_finished; if (grsp->id != ctx->d.cpl.remote_id) @@ -1171,6 +1173,7 @@ static u8 createphyslink_handler(struct amp_ctx *ctx, u8 evt_type, void *data) ctrl->min_latency = le32_to_cpu(grsp->min_latency); ctrl->pal_cap = le16_to_cpu(grsp->pal_cap); ctrl->max_assoc_size = le16_to_cpu(grsp->assoc_size); + skb_pull(skb, sizeof(*grsp)); ctx->d.cpl.max_len = ctrl->max_assoc_size; @@ -1190,6 +1193,8 @@ static u8 createphyslink_handler(struct amp_ctx *ctx, u8 evt_type, void *data) goto cpl_finished; hdr = (void *) skb->data; arsp = (void *) skb_pull(skb, sizeof(*hdr)); + if (arsp->id != ctx->d.cpl.remote_id) + goto cpl_finished; if (arsp->status != 0) goto cpl_finished; @@ -1197,12 +1202,12 @@ static u8 createphyslink_handler(struct amp_ctx *ctx, u8 evt_type, void *data) assoc = (u8 *) skb_pull(skb, sizeof(*arsp)); ctx->d.cpl.len_so_far = 0; ctx->d.cpl.rem_len = hdr->len - sizeof(*arsp); - skb_pull(skb, ctx->d.cpl.rem_len); rassoc = kmalloc(ctx->d.cpl.rem_len, GFP_ATOMIC); if (!rassoc) goto cpl_finished; memcpy(rassoc, assoc, ctx->d.cpl.rem_len); ctx->d.cpl.remote_assoc = rassoc; + skb_pull(skb, ctx->d.cpl.rem_len); /* set up CPL command */ ctx->d.cpl.phy_handle = physlink_handle(ctx->hdev); @@ -1772,13 +1777,12 @@ static struct socket *open_fixed_channel(bdaddr_t *src, bdaddr_t *dst) static void conn_ind_worker(struct work_struct *w) { struct amp_work_conn_ind *work = (struct amp_work_conn_ind *) w; - struct hci_conn *hcon = work->hcon; + struct l2cap_conn *conn = work->conn; struct sk_buff *skb = work->skb; struct amp_mgr *mgr; - mgr = get_create_amp_mgr(hcon, skb); + mgr = get_create_amp_mgr(conn, skb); BT_DBG("mgr %p", mgr); - hci_conn_put(hcon); kfree(work); } @@ -1804,20 +1808,17 @@ static void accept_physical_worker(struct work_struct *w) /* L2CAP Fixed Channel interface */ -void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb) +void amp_conn_ind(struct l2cap_conn *conn, struct sk_buff *skb) { struct amp_work_conn_ind *work; - BT_DBG("hcon %p, skb %p", hcon, skb); + BT_DBG("conn %p, skb %p", conn, skb); work = kmalloc(sizeof(*work), GFP_ATOMIC); if (work) { INIT_WORK((struct work_struct *) work, conn_ind_worker); - hci_conn_hold(hcon); - work->hcon = hcon; + work->conn = conn; work->skb = skb; - if (!queue_work(amp_workqueue, (struct work_struct *) work)) { - hci_conn_put(hcon); + if (queue_work(amp_workqueue, (struct work_struct *) work) == 0) kfree(work); - } } } diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 5ac5c52a..f5049219 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -56,9 +56,6 @@ #include "bnep.h" #define VERSION "1.3" -/* As this feature is dummy for BNEP net device -** disabling support */ -#undef CONFIG_BT_BNEP_MC_FILTER static bool compress_src = 1; static bool compress_dst = 1; diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index a8e54493..155ff740 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -44,9 +44,6 @@ #include "bnep.h" #define BNEP_TX_QUEUE_LEN 20 -/* As this feature is dummy for BNEP net device -** disabling support */ -#undef CONFIG_BT_BNEP_MC_FILTER static int bnep_net_open(struct net_device *dev) { diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 91dd3f90..dbc6378a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -23,6 +23,7 @@ */ /* Bluetooth HCI connection handling. */ +// rollback to original BlueZ #include @@ -44,90 +45,39 @@ #include #include -#include -struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type, - bdaddr_t *dst, __u8 sec_level, __u8 auth_type, - struct bt_le_params *le_params) +static void hci_le_connect(struct hci_conn *conn) { - struct hci_conn *le; + struct hci_dev *hdev = conn->hdev; struct hci_cp_le_create_conn cp; - struct adv_entry *entry; - struct link_key *key; - - BT_DBG("%p", hdev); - - le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); - if (le) { - hci_conn_hold(le); - return le; - } - - key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK); - if (!key) { - entry = hci_find_adv_entry(hdev, dst); - if (entry) - le = hci_le_conn_add(hdev, dst, - entry->bdaddr_type); - else - le = hci_le_conn_add(hdev, dst, 0); - } else { - le = hci_le_conn_add(hdev, dst, key->addr_type); - } - - if (!le) - return ERR_PTR(-ENOMEM); - hci_conn_hold(le); + BT_DBG("%p", conn); - le->state = BT_CONNECT; - le->out = 1; - le->link_mode |= HCI_LM_MASTER; - le->sec_level = BT_SECURITY_LOW; - le->type = LE_LINK; + conn->state = BT_CONNECT; + conn->out = 1; + conn->link_mode |= HCI_LM_MASTER; + conn->sec_level = BT_SECURITY_LOW; + conn->type = LE_LINK; memset(&cp, 0, sizeof(cp)); - if (l2cap_sock_le_params_valid(le_params)) { - cp.supervision_timeout = - cpu_to_le16(le_params->supervision_timeout); - cp.scan_interval = cpu_to_le16(le_params->scan_interval); - cp.scan_window = cpu_to_le16(le_params->scan_window); - cp.conn_interval_min = cpu_to_le16(le_params->interval_min); - cp.conn_interval_max = cpu_to_le16(le_params->interval_max); - cp.conn_latency = cpu_to_le16(le_params->latency); - cp.min_ce_len = cpu_to_le16(le_params->min_ce_len); - cp.max_ce_len = cpu_to_le16(le_params->max_ce_len); - le->conn_timeout = le_params->conn_timeout; - } else { - cp.supervision_timeout = cpu_to_le16(BT_LE_SUP_TO_DEFAULT); - cp.scan_interval = cpu_to_le16(BT_LE_SCAN_INTERVAL_DEF); - cp.scan_window = cpu_to_le16(BT_LE_SCAN_WINDOW_DEF); - cp.conn_interval_min = cpu_to_le16(BT_LE_CONN_INTERVAL_MIN_DEF); - cp.conn_interval_max = cpu_to_le16(BT_LE_CONN_INTERVAL_MAX_DEF); - cp.conn_latency = cpu_to_le16(BT_LE_LATENCY_DEF); - le->conn_timeout = 5; - } - bacpy(&cp.peer_addr, &le->dst); - cp.peer_addr_type = le->dst_type; + cp.scan_interval = cpu_to_le16(0x0004); + cp.scan_window = cpu_to_le16(0x0004); + bacpy(&cp.peer_addr, &conn->dst); + cp.peer_addr_type = conn->dst_type; + cp.conn_interval_min = cpu_to_le16(0x0008); + cp.conn_interval_max = cpu_to_le16(0x0100); + cp.supervision_timeout = cpu_to_le16(0x0064); + cp.min_ce_len = cpu_to_le16(0x0001); + cp.max_ce_len = cpu_to_le16(0x0001); hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); - - return le; } -EXPORT_SYMBOL(hci_le_connect); static void hci_le_connect_cancel(struct hci_conn *conn) { hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); } -static inline bool is_role_switch_possible(struct hci_dev *hdev) -{ - if (hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECTED)) - return false; - return true; -} - void hci_acl_connect(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; @@ -163,8 +113,7 @@ void hci_acl_connect(struct hci_conn *conn) } cp.pkt_type = cpu_to_le16(conn->pkt_type); - if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER) - && is_role_switch_possible(hdev)) + if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) cp.role_switch = 0x01; else cp.role_switch = 0x00; @@ -277,18 +226,6 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, } EXPORT_SYMBOL(hci_le_conn_update); -void hci_read_rssi(struct hci_conn *conn) -{ - struct hci_cp_read_rssi cp; - struct hci_dev *hdev = conn->hdev; - - memset(&cp, 0, sizeof(cp)); - cp.handle = cpu_to_le16(conn->handle); - - hci_send_cmd(hdev, HCI_OP_READ_RSSI, sizeof(cp), &cp); -} -EXPORT_SYMBOL(hci_read_rssi); - void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]) { @@ -385,37 +322,9 @@ static void hci_conn_idle(unsigned long arg) BT_DBG("conn %p mode %d", conn, conn->mode); + hci_dev_lock(conn->hdev); hci_conn_enter_sniff_mode(conn); -} - -static void hci_conn_rssi_update(struct work_struct *work) -{ - struct delayed_work *delayed = - container_of(work, struct delayed_work, work); - struct hci_conn *conn = - container_of(delayed, struct hci_conn, rssi_update_work); - - BT_DBG("conn %p mode %d", conn, conn->mode); - - hci_read_rssi(conn); -} - -static void encryption_disabled_timeout(unsigned long userdata) -{ - struct hci_conn *conn = (struct hci_conn *)userdata; - BT_INFO("conn %p Grace Prd Exp ", conn); - - hci_encrypt_cfm(conn, 0, 0); - - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { - struct hci_cp_set_conn_encrypt cp; - BT_INFO("HCI_CONN_ENCRYPT_PEND is set"); - cp.handle = cpu_to_le16(conn->handle); - cp.encrypt = 1; - hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, - sizeof(cp), &cp); - } - + hci_dev_unlock(conn->hdev); } struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, @@ -440,14 +349,10 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, conn->power_save = 1; conn->disc_timeout = HCI_DISCONN_TIMEOUT; - conn->conn_valid = true; - spin_lock_init(&conn->lock); - wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle"); switch (type) { case ACL_LINK: conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; - conn->link_policy = hdev->link_policy; break; case SCO_LINK: if (!pkt_type) @@ -473,9 +378,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); - INIT_DELAYED_WORK(&conn->rssi_update_work, hci_conn_rssi_update); - setup_timer(&conn->encrypt_pause_timer, encryption_disabled_timeout, - (unsigned long)conn); atomic_set(&conn->refcnt, 0); @@ -514,17 +416,9 @@ int hci_conn_del(struct hci_conn *conn) BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); - spin_lock_bh(&conn->lock); - conn->conn_valid = false; /* conn data is being released */ - spin_unlock_bh(&conn->lock); - - /* Make sure no timers are running */ del_timer(&conn->idle_timer); - wake_lock_destroy(&conn->idle_lock); + del_timer(&conn->disc_timer); - del_timer(&conn->smp_timer); - __cancel_delayed_work(&conn->rssi_update_work); - del_timer(&conn->encrypt_pause_timer); if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; @@ -552,8 +446,6 @@ int hci_conn_del(struct hci_conn *conn) if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); - tasklet_schedule(&hdev->tx_task); - tasklet_enable(&hdev->tx_task); skb_queue_purge(&conn->data_q); @@ -585,7 +477,6 @@ struct hci_chan *hci_chan_add(struct hci_dev *hdev) return chan; } -EXPORT_SYMBOL(hci_chan_add); int hci_chan_del(struct hci_chan *chan) { @@ -604,24 +495,18 @@ int hci_chan_del(struct hci_chan *chan) int hci_chan_put(struct hci_chan *chan) { struct hci_cp_disconn_logical_link cp; - struct hci_conn *hcon; - u16 ll_handle; BT_DBG("chan %p refcnt %d", chan, atomic_read(&chan->refcnt)); if (!atomic_dec_and_test(&chan->refcnt)) return 0; - hcon = chan->conn; - ll_handle = chan->ll_handle; - - hci_chan_del(chan); - - BT_DBG("chan->conn->state %d", hcon->state); - if (hcon->state == BT_CONNECTED) { - cp.log_handle = cpu_to_le16(ll_handle); - hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, + BT_DBG("chan->conn->state %d", chan->conn->state); + if (chan->conn->state == BT_CONNECTED) { + cp.log_handle = cpu_to_le16(chan->ll_handle); + hci_send_cmd(chan->conn->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp); - } + } else + hci_chan_del(chan); return 1; } @@ -729,12 +614,41 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, { struct hci_conn *acl; struct hci_conn *sco; + struct hci_conn *le; BT_DBG("%s dst %s", hdev->name, batostr(dst)); - if (type == LE_LINK) - return hci_le_connect(hdev, pkt_type, dst, sec_level, - auth_type, NULL); + if (type == LE_LINK) { + struct adv_entry *entry; + struct link_key *key; + + le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); + if (le) { + hci_conn_hold(le); + return le; + } + + key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK); + if (!key) { + entry = hci_find_adv_entry(hdev, dst); + if (entry) + le = hci_le_conn_add(hdev, dst, + entry->bdaddr_type); + else + le = hci_le_conn_add(hdev, dst, 0); + } else { + le = hci_le_conn_add(hdev, dst, key->addr_type); + } + + if (!le) + return ERR_PTR(-ENOMEM); + + hci_le_connect(le); + + hci_conn_hold(le); + + return le; + } acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { @@ -791,7 +705,7 @@ void hci_disconnect(struct hci_conn *conn, __u8 reason) { BT_DBG("conn %p", conn); - hci_proto_disconn_cfm(conn, reason, 0); + hci_proto_disconn_cfm(conn, reason); } EXPORT_SYMBOL(hci_disconnect); @@ -850,10 +764,6 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; - - /* encrypt must be pending if auth is also pending */ - set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); - cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); @@ -884,16 +794,12 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) return 0; } else if (conn->link_mode & HCI_LM_ENCRYPT) { return hci_conn_auth(conn, sec_level, auth_type); - } else if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + } else if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { return 0; } if (hci_conn_auth(conn, sec_level, auth_type)) { struct hci_cp_set_conn_encrypt cp; - if (timer_pending(&conn->encrypt_pause_timer)) { - BT_INFO("encrypt_pause_timer is pending"); - return 0; - } cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 1; hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, @@ -965,52 +871,9 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) } timer: - if (hdev->idle_timeout > 0) { - spin_lock_bh(&conn->lock); - if (conn->conn_valid) { - mod_timer(&conn->idle_timer, - jiffies + msecs_to_jiffies(hdev->idle_timeout)); - wake_lock(&conn->idle_lock); - } - spin_unlock_bh(&conn->lock); - } -} - -static inline void hci_conn_stop_rssi_timer(struct hci_conn *conn) -{ - BT_DBG("conn %p", conn); - cancel_delayed_work(&conn->rssi_update_work); -} - -static inline void hci_conn_start_rssi_timer(struct hci_conn *conn, - u16 interval) -{ - struct hci_dev *hdev = conn->hdev; - BT_DBG("conn %p, pending %d", conn, - delayed_work_pending(&conn->rssi_update_work)); - if (!delayed_work_pending(&conn->rssi_update_work)) { - queue_delayed_work(hdev->workqueue, &conn->rssi_update_work, - msecs_to_jiffies(interval)); - } -} - -void hci_conn_set_rssi_reporter(struct hci_conn *conn, - s8 rssi_threshold, u16 interval, u8 updateOnThreshExceed) -{ - if (conn) { - conn->rssi_threshold = rssi_threshold; - conn->rssi_update_interval = interval; - conn->rssi_update_thresh_exceed = updateOnThreshExceed; - hci_conn_start_rssi_timer(conn, interval); - } -} - -void hci_conn_unset_rssi_reporter(struct hci_conn *conn) -{ - if (conn) { - BT_DBG("Deleting the rssi_update_timer"); - hci_conn_stop_rssi_timer(conn); - } + if (hdev->idle_timeout > 0) + mod_timer(&conn->idle_timer, + jiffies + msecs_to_jiffies(hdev->idle_timeout)); } /* Enter sniff mode */ @@ -1029,9 +892,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn) if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) return; - if (conn->mode != HCI_CM_ACTIVE || - !(conn->link_policy & HCI_LP_SNIFF) || - (hci_find_link_key(hdev, &conn->dst) == NULL)) + if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF)) return; if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { @@ -1054,12 +915,18 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn) } } -struct hci_chan *hci_chan_create(struct hci_chan *chan, +struct hci_chan *hci_chan_accept(struct hci_conn *conn, struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs) { + struct hci_chan *chan; struct hci_cp_create_logical_link cp; + chan = hci_chan_add(conn->hdev); + if (!chan) + return NULL; + chan->state = BT_CONNECT; + chan->conn = conn; chan->tx_fs = *tx_fs; chan->rx_fs = *rx_fs; cp.phy_handle = chan->conn->handle; @@ -1076,12 +943,40 @@ struct hci_chan *hci_chan_create(struct hci_chan *chan, cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency); cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to); hci_conn_hold(chan->conn); - if (chan->conn->out) - hci_send_cmd(chan->conn->hdev, HCI_OP_CREATE_LOGICAL_LINK, - sizeof(cp), &cp); - else - hci_send_cmd(chan->conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK, - sizeof(cp), &cp); + hci_send_cmd(conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), &cp); + return chan; +} +EXPORT_SYMBOL(hci_chan_accept); + +struct hci_chan *hci_chan_create(struct hci_conn *conn, + struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs) +{ + struct hci_chan *chan; + struct hci_cp_create_logical_link cp; + + chan = hci_chan_add(conn->hdev); + if (!chan) + return NULL; + + chan->state = BT_CONNECT; + chan->conn = conn; + chan->tx_fs = *tx_fs; + chan->rx_fs = *rx_fs; + cp.phy_handle = chan->conn->handle; + cp.tx_fs.id = chan->tx_fs.id; + cp.tx_fs.type = chan->tx_fs.type; + cp.tx_fs.max_sdu = cpu_to_le16(chan->tx_fs.max_sdu); + cp.tx_fs.sdu_arr_time = cpu_to_le32(chan->tx_fs.sdu_arr_time); + cp.tx_fs.acc_latency = cpu_to_le32(chan->tx_fs.acc_latency); + cp.tx_fs.flush_to = cpu_to_le32(chan->tx_fs.flush_to); + cp.rx_fs.id = chan->rx_fs.id; + cp.rx_fs.type = chan->rx_fs.type; + cp.rx_fs.max_sdu = cpu_to_le16(chan->rx_fs.max_sdu); + cp.rx_fs.sdu_arr_time = cpu_to_le32(chan->rx_fs.sdu_arr_time); + cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency); + cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to); + hci_conn_hold(chan->conn); + hci_send_cmd(conn->hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), &cp); return chan; } EXPORT_SYMBOL(hci_chan_create); @@ -1113,7 +1008,7 @@ void hci_chan_modify(struct hci_chan *chan, EXPORT_SYMBOL(hci_chan_modify); /* Drop all connection on the device */ -void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process) +void hci_conn_hash_flush(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; struct list_head *p; @@ -1129,7 +1024,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process) c->state = BT_CLOSED; - hci_proto_disconn_cfm(c, 0x16, is_process); + hci_proto_disconn_cfm(c, 0x16); hci_conn_del(c); } } @@ -1306,3 +1201,4 @@ int hci_set_auth_info(struct hci_dev *hdev, void __user *arg) return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0; } + diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c old mode 100644 new mode 100755 index 1928f431..cbde45b3 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -23,6 +23,7 @@ */ /* Bluetooth HCI core. */ +// rollback to original BlueZ #include #include @@ -561,19 +562,6 @@ int hci_dev_open(__u16 dev) goto done; } - if (!skb_queue_empty(&hdev->cmd_q)) { - BT_ERR("command queue is not empty, purging"); - skb_queue_purge(&hdev->cmd_q); - } - if (!skb_queue_empty(&hdev->rx_q)) { - BT_ERR("rx queue is not empty, purging"); - skb_queue_purge(&hdev->rx_q); - } - if (!skb_queue_empty(&hdev->raw_q)) { - BT_ERR("raw queue is not empty, purging"); - skb_queue_purge(&hdev->raw_q); - } - if (!test_bit(HCI_RAW, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); set_bit(HCI_INIT, &hdev->flags); @@ -626,7 +614,7 @@ int hci_dev_open(__u16 dev) return ret; } -static int hci_dev_do_close(struct hci_dev *hdev, u8 is_process) +static int hci_dev_do_close(struct hci_dev *hdev) { unsigned long keepflags = 0; @@ -647,17 +635,11 @@ static int hci_dev_do_close(struct hci_dev *hdev, u8 is_process) hci_dev_lock_bh(hdev); inquiry_cache_flush(hdev); - hci_conn_hash_flush(hdev, is_process); + hci_conn_hash_flush(hdev); hci_dev_unlock_bh(hdev); hci_notify(hdev, HCI_DEV_DOWN); - if (hdev->dev_type == HCI_BREDR) { - hci_dev_lock_bh(hdev); - mgmt_powered(hdev->id, 0); - hci_dev_unlock_bh(hdev); - } - if (hdev->flush) hdev->flush(hdev); @@ -690,6 +672,12 @@ static int hci_dev_do_close(struct hci_dev *hdev, u8 is_process) * and no tasks are scheduled. */ hdev->close(hdev); + if (hdev->dev_type == HCI_BREDR) { + hci_dev_lock_bh(hdev); + mgmt_powered(hdev->id, 0); + hci_dev_unlock_bh(hdev); + } + /* Clear only non-persistent flags */ if (test_bit(HCI_MGMT, &hdev->flags)) set_bit(HCI_MGMT, &keepflags); @@ -714,7 +702,7 @@ int hci_dev_close(__u16 dev) hdev = hci_dev_get(dev); if (!hdev) return -ENODEV; - err = hci_dev_do_close(hdev, 1); + err = hci_dev_do_close(hdev); hci_dev_put(hdev); return err; } @@ -740,7 +728,7 @@ int hci_dev_reset(__u16 dev) hci_dev_lock_bh(hdev); inquiry_cache_flush(hdev); - hci_conn_hash_flush(hdev, 0); + hci_conn_hash_flush(hdev); hci_dev_unlock_bh(hdev); if (hdev->flush) @@ -953,7 +941,7 @@ static int hci_rfkill_set_block(void *data, bool blocked) if (!blocked) return 0; - hci_dev_do_close(hdev, 0); + hci_dev_do_close(hdev); return 0; } @@ -1468,10 +1456,16 @@ int hci_register_dev(struct hci_dev *hdev) hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; + tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); + tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); + tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); + skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); skb_queue_head_init(&hdev->raw_q); + setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); + for (i = 0; i < NUM_REASSEMBLY; i++) hdev->reassembly[i] = NULL; @@ -1493,27 +1487,16 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->adv_entries); rwlock_init(&hdev->adv_entries_lock); + setup_timer(&hdev->adv_timer, hci_adv_clear, (unsigned long) hdev); INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->power_off, hci_power_off); + setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); atomic_set(&hdev->promisc, 0); - //initial the task in case someone want to schedule it before other global variables init ready. - tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); - tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); - tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); - - setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); - setup_timer(&hdev->disco_timer, mgmt_disco_timeout, - (unsigned long) hdev); - setup_timer(&hdev->disco_le_timer, mgmt_disco_le_timeout, - (unsigned long) hdev); - setup_timer(&hdev->adv_timer, hci_adv_clear, (unsigned long) hdev); - setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); - write_unlock_bh(&hci_dev_list_lock); hdev->workqueue = create_singlethread_workqueue(hdev->name); @@ -1564,11 +1547,15 @@ int hci_unregister_dev(struct hci_dev *hdev) list_del(&hdev->list); write_unlock_bh(&hci_dev_list_lock); - hci_dev_do_close(hdev, hdev->bus == HCI_SMD); + hci_dev_do_close(hdev); for (i = 0; i < NUM_REASSEMBLY; i++) kfree_skb(hdev->reassembly[i]); + cancel_work_sync(&hdev->power_on); + + cancel_work_sync(&hdev->power_on); + if (!test_bit(HCI_INIT, &hdev->flags) && !test_bit(HCI_SETUP, &hdev->flags) && hdev->dev_type == HCI_BREDR) { @@ -1589,12 +1576,8 @@ int hci_unregister_dev(struct hci_dev *hdev) hci_unregister_sysfs(hdev); - /* Disable all timers */ hci_del_off_timer(hdev); del_timer(&hdev->adv_timer); - del_timer(&hdev->cmd_timer); - del_timer(&hdev->disco_timer); - del_timer(&hdev->disco_le_timer); destroy_workqueue(hdev->workqueue); @@ -2136,9 +2119,6 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int /* We don't have to lock device here. Connections are always * added and removed with TX task disabled. */ - - BUG_ON(!h); - list_for_each(p, &h->list) { struct hci_conn *c; c = list_entry(p, struct hci_conn, list); @@ -2238,6 +2218,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev) if (count > hdev->acl_cnt) return; + hci_dev_lock(hdev); hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active); hci_send_frame(skb); @@ -2247,6 +2228,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev) quote -= count; conn->sent += count; + hci_dev_unlock(hdev); } } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index df1f4a86..40bfed84 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011, Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -23,6 +23,7 @@ */ /* Bluetooth HCI event handling. */ +// rollback to original BlueZ #include @@ -940,21 +941,6 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, hci_dev_unlock(hdev); } -static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct hci_conn *conn; - struct hci_rp_read_rssi *rp = (void *) skb->data; - - BT_DBG("%s status 0x%x", hdev->name, rp->status); - - BT_DBG("%s rssi : %d handle : %d", hdev->name, rp->rssi, rp->handle); - - conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); - if (conn) - mgmt_read_rssi_complete(hdev->id, rp->rssi, &conn->dst, - __le16_to_cpu(rp->handle), rp->status); -} - static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, struct sk_buff *skb) { @@ -1121,25 +1107,9 @@ static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - if (status) { - mgmt_auth_failed(hdev->id, &conn->dst, status); - clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); - - if (conn->state == BT_CONFIG) { - conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, status); - hci_conn_put(conn); - } else { - hci_auth_cfm(conn, status); - hci_conn_hold(conn); - conn->disc_timeout = HCI_DISCONN_TIMEOUT; - hci_conn_put(conn); - } - - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); - hci_encrypt_cfm(conn, status, 0x00); - } + if (status && conn->state == BT_CONFIG) { + hci_proto_connect_cfm(conn, status); + hci_conn_put(conn); } conn->auth_initiator = 1; } @@ -1357,6 +1327,12 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) if (conn) { clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + // when exit sniffer mode cmd failed error code equal 12 means command diallowed, we don't setup sco link. + if (12 == status) { + hci_dev_unlock(hdev); + return; + } + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) hci_sco_setup(conn, status); } @@ -1368,7 +1344,6 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) { struct hci_cp_le_create_conn *cp; struct hci_conn *conn; - unsigned long exp = msecs_to_jiffies(5000); BT_DBG("%s status 0x%x", hdev->name, status); @@ -1397,11 +1372,11 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) conn->out = 1; else BT_ERR("No memory for new connection"); - } else - exp = msecs_to_jiffies(conn->conn_timeout * 1000); + } - if (conn && exp) - mod_timer(&conn->disc_timer, jiffies + exp); + if (conn) + mod_timer(&conn->disc_timer, + jiffies + msecs_to_jiffies(5000)); } hci_dev_unlock(hdev); @@ -1428,10 +1403,10 @@ static void hci_cs_accept_logical_link(struct hci_dev *hdev, __u8 status) if (chan && chan->state == BT_CONNECT) { chan->state = BT_CLOSED; hci_proto_create_cfm(chan, status); + hci_chan_del(chan); } - } else if (chan) { - chan->state = BT_CONNECT2; - } + } else if (chan) + chan->state = BT_CONNECT2; hci_dev_unlock(hdev); } @@ -1457,6 +1432,7 @@ static void hci_cs_create_logical_link(struct hci_dev *hdev, __u8 status) if (chan && chan->state == BT_CONNECT) { chan->state = BT_CLOSED; hci_proto_create_cfm(chan, status); + hci_chan_del(chan); } } else if (chan) chan->state = BT_CONNECT2; @@ -1549,7 +1525,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s status %d", hdev->name, status); - if (!hdev->disco_state) + if (!lmp_le_capable(hdev)) clear_bit(HCI_INQUIRY, &hdev->flags); hci_req_complete(hdev, HCI_OP_INQUIRY, status); @@ -1638,12 +1614,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (test_bit(HCI_ENCRYPT, &hdev->flags)) conn->link_mode |= HCI_LM_ENCRYPT; - /* Get remote version */ + /* Get remote features */ if (conn->type == ACL_LINK) { - struct hci_cp_read_remote_version cp; + struct hci_cp_read_remote_features cp; cp.handle = ev->handle; - hci_send_cmd(hdev, HCI_OP_READ_REMOTE_VERSION, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, + sizeof(cp), &cp); } /* Set packet type for incoming connection */ @@ -1654,6 +1630,9 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp); } + + + } else { conn->state = BT_CLOSED; if (conn->type == ACL_LINK || conn->type == LE_LINK) @@ -1675,15 +1654,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s hci_conn_check_pending(hdev); } -static inline bool is_sco_active(struct hci_dev *hdev) -{ - if (hci_conn_hash_lookup_state(hdev, SCO_LINK, BT_CONNECTED) || - (hci_conn_hash_lookup_state(hdev, ESCO_LINK, - BT_CONNECTED))) - return true; - return false; -} - static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; @@ -1718,8 +1688,6 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk } memcpy(conn->dev_class, ev->dev_class, 3); - /* For incoming connection update remote class to userspace */ - mgmt_remote_class(hdev->id, &ev->bdaddr, ev->dev_class); conn->state = BT_CONNECT; hci_dev_unlock(hdev); @@ -1729,8 +1697,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk bacpy(&cp.bdaddr, &ev->bdaddr); - if (lmp_rswitch_capable(hdev) && ((mask & HCI_LM_MASTER) - || is_sco_active(hdev))) + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) cp.role = 0x00; /* Become master */ else cp.role = 0x01; /* Remain slave */ @@ -1790,7 +1757,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (conn->type == LE_LINK) del_timer(&conn->smp_timer); - hci_proto_disconn_cfm(conn, ev->reason, 0); + hci_proto_disconn_cfm(conn, ev->reason); hci_conn_del(conn); unlock: @@ -1811,24 +1778,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (ev->status == 0x06 && hdev->ssp_mode > 0 && conn->ssp_mode > 0) { struct hci_cp_auth_requested cp; - struct link_key *key; - key = hci_find_link_key(hdev, &conn->dst); - if (key && key->key_type == 0x05) { - BT_INFO("Previous key was authenticated, " - "updating the auth type for outgoing connection"); - conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM; - } hci_remove_link_key(hdev, &conn->dst); cp.handle = cpu_to_le16(conn->handle); - /*Initiates dedicated bonding as pin or key is missing - on remote device*/ - /*In case if remote device is ssp supported, - reduce the security level to MEDIUM if it is HIGH*/ - if (conn->ssp_mode && conn->auth_initiator && - conn->io_capability != 0x03) { - conn->pending_sec_level = BT_SECURITY_HIGH; - conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM; - } hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); hci_dev_unlock(hdev); @@ -1869,29 +1820,11 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { if (!ev->status) { - if (conn->link_mode & HCI_LM_ENCRYPT) { - /* Encryption implies authentication */ - conn->link_mode |= HCI_LM_AUTH; - conn->link_mode |= HCI_LM_ENCRYPT; - conn->sec_level = - conn->pending_sec_level; - clear_bit(HCI_CONN_ENCRYPT_PEND, - &conn->pend); - hci_encrypt_cfm(conn, ev->status, 1); - - if (test_bit(HCI_MGMT, &hdev->flags)) - mgmt_encrypt_change(hdev->id, - &conn->dst, - ev->status); - - } else { - struct hci_cp_set_conn_encrypt cp; - cp.handle = ev->handle; - cp.encrypt = 0x01; - hci_send_cmd(hdev, - HCI_OP_SET_CONN_ENCRYPT, - sizeof(cp), &cp); - } + struct hci_cp_set_conn_encrypt cp; + cp.handle = ev->handle; + cp.encrypt = 0x01; + hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, + sizeof(cp), &cp); } else { clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); hci_encrypt_cfm(conn, ev->status, 0x00); @@ -1955,25 +1888,8 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * hci_proto_connect_cfm(conn, ev->status); hci_conn_put(conn); - } else { - /* - * If the remote device does not support - * Pause Encryption, usually during the - * roleSwitch we see Encryption disable - * for short duration. Allow remote device - * to disable encryption - * for short duration in this case. - */ - if ((ev->encrypt == 0) && (ev->status == 0) && - ((conn->features[5] & LMP_PAUSE_ENC) == 0)) { - mod_timer(&conn->encrypt_pause_timer, - jiffies + msecs_to_jiffies(500)); - BT_INFO("enc pause timer, enc_pend_flag set"); - } else { - del_timer(&conn->encrypt_pause_timer); - hci_encrypt_cfm(conn, ev->status, ev->encrypt); - } - } + } else + hci_encrypt_cfm(conn, ev->status, ev->encrypt); if (test_bit(HCI_MGMT, &hdev->flags)) mgmt_encrypt_change(hdev->id, &conn->dst, ev->status); @@ -2017,10 +1933,8 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff if (!conn) goto unlock; - if (!ev->status) { + if (!ev->status) memcpy(conn->features, ev->features, 8); - mgmt_remote_features(hdev->id, &conn->dst, ev->features); - } if (conn->state != BT_CONFIG) goto unlock; @@ -2032,9 +1946,8 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES, sizeof(cp), &cp); goto unlock; - } else if (!(lmp_ssp_capable(conn)) && conn->auth_initiator && - (conn->pending_sec_level == BT_SECURITY_HIGH)) { - conn->pending_sec_level = BT_SECURITY_MEDIUM; + + } if (!ev->status) { @@ -2057,24 +1970,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_remote_version *ev = (void *) skb->data; - struct hci_cp_read_remote_features cp; - struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); - - hci_dev_lock(hdev); - cp.handle = ev->handle; - hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, - sizeof(cp), &cp); - - conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); - if (!conn) - goto unlock; - if (!ev->status) - mgmt_remote_version(hdev->id, &conn->dst, ev->lmp_ver, - ev->manufacturer, ev->lmp_subver); -unlock: - hci_dev_unlock(hdev); + BT_DBG("%s", hdev->name); } static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) @@ -2086,14 +1982,12 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk { struct hci_ev_cmd_complete *ev = (void *) skb->data; __u16 opcode; + extern unsigned char fm_command_pending; skb_pull(skb, sizeof(*ev)); opcode = __le16_to_cpu(ev->opcode); - if (test_bit(HCI_RESET, &hdev->flags) && (opcode != HCI_OP_RESET)) - return; - switch (opcode) { case HCI_OP_INQUIRY_CANCEL: hci_cc_inquiry_cancel(hdev, skb); @@ -2260,10 +2154,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_le_read_buffer_size(hdev, skb); break; - case HCI_OP_READ_RSSI: - hci_cc_read_rssi(hdev, skb); - break; - case HCI_OP_USER_CONFIRM_REPLY: hci_cc_user_confirm_reply(hdev, skb); break; @@ -2286,13 +2176,18 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk default: BT_DBG("%s opcode 0x%x", hdev->name, opcode); + //delete + if (opcode == 0xfc15) //0xfc15 means fm cmd + { + fm_command_pending = 0; + } break; } if (ev->opcode != HCI_OP_NOP) del_timer(&hdev->cmd_timer); - if (ev->ncmd) { + if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) tasklet_schedule(&hdev->cmd_task); @@ -2420,7 +2315,8 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb if (ev->role) conn->link_mode &= ~HCI_LM_MASTER; else - conn->link_mode |= HCI_LM_MASTER; + conn->link_mode |= HCI_LM_MASTER; + } clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend); @@ -2575,9 +2471,6 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb else conn->power_save = 0; } - if (conn->mode == HCI_CM_SNIFF) - if (wake_lock_active(&conn->idle_lock)) - wake_unlock(&conn->idle_lock); if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) hci_sco_setup(conn, ev->status); @@ -2600,7 +2493,6 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff hci_conn_hold(conn); conn->disc_timeout = HCI_PAIRING_TIMEOUT; hci_conn_put(conn); - hci_conn_enter_active_mode(conn, 0); } if (!test_bit(HCI_PAIRABLE, &hdev->flags)) @@ -2648,6 +2540,12 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("Conn pending sec level is %d, ssp is %d, key len is %d", conn->pending_sec_level, conn->ssp_mode, key->pin_len); } + if (conn && (conn->ssp_mode == 0) && + (conn->pending_sec_level == BT_SECURITY_HIGH) && + (key->pin_len != 16)) { + BT_DBG("Security is high ignoring this key"); + goto not_found; + } if (key->key_type == 0x04 && conn && conn->auth_type != 0xff && (conn->auth_type & 0x01)) { @@ -2688,10 +2586,8 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff conn->key_type = ev->key_type; hci_disconnect_amp(conn, 0x06); - conn->link_mode &= ~HCI_LM_ENCRYPT; pin_len = conn->pin_length; hci_conn_put(conn); - hci_conn_enter_active_mode(conn, 0); } if (test_bit(HCI_LINK_KEYS, &hdev->flags)) @@ -2833,15 +2729,9 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b conn->ssp_mode = (ev->features[0] & 0x01); /*In case if remote device ssp supported/2.0 device reduce the security level to MEDIUM if it is HIGH*/ - if (!conn->ssp_mode && conn->auth_initiator && + if (!conn->ssp_mode && (conn->pending_sec_level == BT_SECURITY_HIGH)) conn->pending_sec_level = BT_SECURITY_MEDIUM; - - if (conn->ssp_mode && conn->auth_initiator && - conn->io_capability != 0x03) { - conn->pending_sec_level = BT_SECURITY_HIGH; - conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM; - } } if (conn->state != BT_CONFIG) @@ -3375,15 +3265,19 @@ static inline void hci_log_link_complete(struct hci_dev *hdev, chan = hci_chan_list_lookup_id(hdev, ev->phy_handle); - if (chan) { - if (ev->status == 0) { + if (ev->status == 0) { + if (chan) { chan->ll_handle = __le16_to_cpu(ev->log_handle); chan->state = BT_CONNECTED; - } else { + hci_proto_create_cfm(chan, ev->status); + hci_chan_hold(chan); + } + } else { + if (chan) { chan->state = BT_CLOSED; + hci_proto_create_cfm(chan, ev->status); + hci_chan_del(chan); } - - hci_proto_create_cfm(chan, ev->status); } hci_dev_unlock(hdev); @@ -3422,8 +3316,10 @@ static inline void hci_disconn_log_link_complete_evt(struct hci_dev *hdev, hci_dev_lock(hdev); chan = hci_chan_list_lookup_handle(hdev, __le16_to_cpu(ev->log_handle)); - if (chan) + if (chan) { hci_proto_destroy_cfm(chan, ev->reason); + hci_chan_del(chan); + } hci_dev_unlock(hdev); } @@ -3445,7 +3341,7 @@ static inline void hci_disconn_phy_link_complete_evt(struct hci_dev *hdev, if (conn) { conn->state = BT_CLOSED; - hci_proto_disconn_cfm(conn, ev->reason, 0); + hci_proto_disconn_cfm(conn, ev->reason); hci_conn_del(conn); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c old mode 100644 new mode 100755 index 550f6019..b2f7e0c6 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2011, The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2011, Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -24,6 +24,8 @@ /* Bluetooth HCI sockets. */ +// rollback to original BlueZ + #include #include @@ -49,6 +51,8 @@ #include #include +//#define BT_DBG(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) +unsigned char fm_command_pending = 0; static bool enable_mgmt = 1; /* ----- HCI socket interface ----- */ @@ -440,6 +444,7 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add *addr_len = sizeof(*haddr); haddr->hci_family = AF_BLUETOOTH; haddr->hci_dev = hdev->id; + haddr->hci_channel= 0; release_sock(sk); return 0; @@ -499,8 +504,6 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (!skb) return err; - msg->msg_namelen = 0; - copied = skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; @@ -523,7 +526,6 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct sock *sk = sock->sk; struct hci_dev *hdev; struct sk_buff *skb; - int reserve = 0; int err; BT_DBG("sock %p sk %p", sock, sk); @@ -561,18 +563,10 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, goto done; } - /* Allocate extra headroom for Qualcomm PAL */ - if (hdev->dev_type == HCI_AMP && hdev->manufacturer == 0x001d) - reserve = BT_SKB_RESERVE_80211; - - skb = bt_skb_send_alloc(sk, len + reserve, - msg->msg_flags & MSG_DONTWAIT, &err); + skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) goto done; - if (reserve) - skb_reserve(skb, reserve); - if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; goto drop; @@ -587,6 +581,16 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, u16 ogf = hci_opcode_ogf(opcode); u16 ocf = hci_opcode_ocf(opcode); + /* 4329 FM VSC checking, 0xfc15 means fm cmd */ + if (opcode == 0xfc15) { + while (fm_command_pending == 1) + { + BT_DBG("fm command is pending."); + msleep(2); + } + fm_command_pending = 1; + } + if (((ogf > HCI_SFLT_MAX_OGF) || !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) && !capable(CAP_NET_RAW)) { @@ -661,6 +665,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char { struct hci_filter *f = &hci_pi(sk)->filter; + memset(&uf, 0, sizeof(uf)); uf.type_mask = f->type_mask; uf.opcode = f->opcode; uf.event_mask[0] = *((u32 *) f->event_mask + 0); @@ -732,6 +737,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char { struct hci_filter *f = &hci_pi(sk)->filter; + memset(&uf, 0, sizeof(uf)); uf.type_mask = f->type_mask; uf.opcode = f->opcode; uf.event_mask[0] = *((u32 *) f->event_mask + 0); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index ba09f4a8..45496848 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -1,7 +1,7 @@ /* HIDP implementation for Linux Bluetooth stack (BlueZ). Copyright (C) 2003-2004 Marcel Holtmann - Copyright (c) 2012 The Linux Foundation. All rights reserved. + Copyright (c) 2012 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 as @@ -93,15 +93,40 @@ static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr) return NULL; } +static struct device *hidp_get_device(struct hidp_session *session) +{ + bdaddr_t *dst = &session->bdaddr; + + struct device *device = NULL; + struct hci_dev *hdev; + + hdev = hci_get_route(dst, BDADDR_ANY); + if (!hdev) + return NULL; + + session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); + if (session->conn) + device = &session->conn->dev; + + hci_dev_put(hdev); + + return device; +} + static void __hidp_link_session(struct hidp_session *session) { __module_get(THIS_MODULE); list_add(&session->list, &hidp_session_list); + + hci_conn_hold_device(session->conn); } static void __hidp_unlink_session(struct hidp_session *session) { - if (session->conn) + struct device *dev; + + dev = hidp_get_device(session); + if (dev) hci_conn_put_device(session->conn); list_del(&session->list); @@ -635,28 +660,6 @@ static int hidp_session(void *arg) return 0; } -static struct hci_conn *hidp_get_connection(struct hidp_session *session) -{ - bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src; - bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst; - struct hci_conn *conn; - struct hci_dev *hdev; - - hdev = hci_get_route(dst, src); - if (!hdev) - return NULL; - - hci_dev_lock_bh(hdev); - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); - if (conn) - hci_conn_hold_device(conn); - hci_dev_unlock_bh(hdev); - - hci_dev_put(hdev); - - return conn; -} - static int hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req) { @@ -704,7 +707,7 @@ static int hidp_setup_input(struct hidp_session *session, input->relbit[0] |= BIT_MASK(REL_WHEEL); } - input->dev.parent = &session->conn->dev; + input->dev.parent = hidp_get_device(session); input->event = hidp_input_event; @@ -801,11 +804,11 @@ static int hidp_setup_hid(struct hidp_session *session, hid->version = req->version; hid->country = req->country; - strncpy(hid->name, req->name, 128); + strncpy(hid->name, req->name, sizeof(req->name) - 1); strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64); strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64); - hid->dev.parent = &session->conn->dev; + hid->dev.parent = hidp_get_device(session); hid->ll_driver = &hidp_hid_driver; hid->hid_output_raw_report = hidp_output_raw_report; @@ -863,12 +866,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, session->intr_sock = intr_sock; session->state = BT_CONNECTED; - session->conn = hidp_get_connection(session); - if (!session->conn) { - err = -ENOTCONN; - goto failed; - } - setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session); skb_queue_head_init(&session->ctrl_transmit); @@ -877,8 +874,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); session->idle_to = req->idle_to; - __hidp_link_session(session); - if (req->rd_size > 0) { err = hidp_setup_hid(session, req); if (err && err != -ENODEV) @@ -891,6 +886,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, goto purge; } + __hidp_link_session(session); + hidp_set_timer(session); err = kernel_thread(hidp_session, session, CLONE_KERNEL); @@ -912,6 +909,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, unlink: hidp_del_timer(session); + __hidp_unlink_session(session); + if (session->input) { input_unregister_device(session->input); session->input = NULL; @@ -926,8 +925,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, session->rd_data = NULL; purge: - __hidp_unlink_session(session); - skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c new file mode 100644 index 00000000..79650957 --- /dev/null +++ b/net/bluetooth/l2cap.c @@ -0,0 +1,4747 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + 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; + + 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 OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* Bluetooth L2CAP core and sockets. */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define VERSION "2.14" + +#ifdef CONFIG_BT_L2CAP_EXT_FEATURES +static bool enable_ertm = 1; +#else +static bool enable_ertm = 0; +#endif +static uint max_transmit = L2CAP_DEFAULT_MAX_TX; +static uint tx_window = L2CAP_DEFAULT_TX_WINDOW; + +static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; +static u8 l2cap_fixed_chan[8] = { 0x02, }; + +static const struct proto_ops l2cap_sock_ops; + +static struct workqueue_struct *_busy_wq; + +static struct bt_sock_list l2cap_sk_list = { + .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) +}; + +static void l2cap_busy_work(struct work_struct *work); + +static void __l2cap_sock_close(struct sock *sk, int reason); +static void l2cap_sock_close(struct sock *sk); +static void l2cap_sock_kill(struct sock *sk); + +static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, + u8 code, u8 ident, u16 dlen, void *data); + +/* ---- L2CAP timers ---- */ +static void l2cap_sock_timeout(unsigned long arg) +{ + struct sock *sk = (struct sock *) arg; + int reason; + + BT_DBG("sock %p state %d", sk, sk->sk_state); + + bh_lock_sock(sk); + + if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) + reason = ECONNREFUSED; + else if (sk->sk_state == BT_CONNECT && + l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) + reason = ECONNREFUSED; + else + reason = ETIMEDOUT; + + __l2cap_sock_close(sk, reason); + + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); + sock_put(sk); +} + +static void l2cap_sock_set_timer(struct sock *sk, long timeout) +{ + BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); + sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); +} + +static void l2cap_sock_clear_timer(struct sock *sk) +{ + BT_DBG("sock %p state %d", sk, sk->sk_state); + sk_stop_timer(sk, &sk->sk_timer); +} + +/* ---- L2CAP channels ---- */ +static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) +{ + struct sock *s; + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->dcid == cid) + break; + } + return s; +} + +static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +{ + struct sock *s; + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->scid == cid) + break; + } + return s; +} + +/* Find channel with given SCID. + * Returns locked socket */ +static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +{ + struct sock *s; + read_lock(&l->lock); + s = __l2cap_get_chan_by_scid(l, cid); + if (s) + bh_lock_sock(s); + read_unlock(&l->lock); + return s; +} + +static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +{ + struct sock *s; + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->ident == ident) + break; + } + return s; +} + +static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +{ + struct sock *s; + read_lock(&l->lock); + s = __l2cap_get_chan_by_ident(l, ident); + if (s) + bh_lock_sock(s); + read_unlock(&l->lock); + return s; +} + +static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) +{ + u16 cid = L2CAP_CID_DYN_START; + + for (; cid < L2CAP_CID_DYN_END; cid++) { + if (!__l2cap_get_chan_by_scid(l, cid)) + return cid; + } + + return 0; +} + +static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) +{ + sock_hold(sk); + + if (l->head) + l2cap_pi(l->head)->prev_c = sk; + + l2cap_pi(sk)->next_c = l->head; + l2cap_pi(sk)->prev_c = NULL; + l->head = sk; +} + +static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) +{ + struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; + + write_lock_bh(&l->lock); + if (sk == l->head) + l->head = next; + + if (next) + l2cap_pi(next)->prev_c = prev; + if (prev) + l2cap_pi(prev)->next_c = next; + write_unlock_bh(&l->lock); + + __sock_put(sk); +} + +static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +{ + struct l2cap_chan_list *l = &conn->chan_list; + + BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, + l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + + conn->disc_reason = 0x13; + + l2cap_pi(sk)->conn = conn; + + if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { + /* Alloc CID for connection-oriented socket */ + l2cap_pi(sk)->scid = l2cap_alloc_cid(l); + } else if (sk->sk_type == SOCK_DGRAM) { + /* Connectionless socket */ + l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; + l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; + l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + } else { + /* Raw socket can send/recv signalling messages only */ + l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; + l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; + l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + } + + __l2cap_chan_link(l, sk); + + if (parent) + bt_accept_enqueue(parent, sk); +} + +/* Delete channel. + * Must be called on the locked socket. */ +static void l2cap_chan_del(struct sock *sk, int err) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sock *parent = bt_sk(sk)->parent; + + l2cap_sock_clear_timer(sk); + + BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + if (sock_owned_by_user(sk)){ + printk("L2CAP ERROR: unlink owned sk!\n"); + } + /* Unlink from channel list */ + l2cap_chan_unlink(&conn->chan_list, sk); + l2cap_pi(sk)->conn = NULL; + hci_conn_put(conn->hcon); + } + + sk->sk_state = BT_CLOSED; + sock_set_flag(sk, SOCK_ZAPPED); + + if (err) + sk->sk_err = err; + + if (parent) { + bt_accept_unlink(sk); + parent->sk_data_ready(parent, 0); + } else + sk->sk_state_change(sk); +} + +/* Service level security */ +static inline int l2cap_check_security(struct sock *sk) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + __u8 auth_type; + + if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { + if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + auth_type = HCI_AT_NO_BONDING_MITM; + else + auth_type = HCI_AT_NO_BONDING; + + if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) + l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + } else { + switch (l2cap_pi(sk)->sec_level) { + case BT_SECURITY_HIGH: + auth_type = HCI_AT_GENERAL_BONDING_MITM; + break; + case BT_SECURITY_MEDIUM: + auth_type = HCI_AT_GENERAL_BONDING; + break; + default: + auth_type = HCI_AT_NO_BONDING; + break; + } + } + + return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level, + auth_type); +} + +static inline u8 l2cap_get_ident(struct l2cap_conn *conn) +{ + u8 id; + + /* Get next available identificator. + * 1 - 128 are used by kernel. + * 129 - 199 are reserved. + * 200 - 254 are used by utilities like l2ping, etc. + */ + + spin_lock_bh(&conn->lock); + + if (++conn->tx_ident > 128) + conn->tx_ident = 1; + + id = conn->tx_ident; + + spin_unlock_bh(&conn->lock); + + return id; +} + +static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data) +{ + struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); + u8 flags; + + BT_DBG("code 0x%2.2x", code); + + if (!skb) + return; + + if (lmp_no_flush_capable(conn->hcon->hdev)) + flags = ACL_START_NO_FLUSH; + else + flags = ACL_START; + + hci_send_acl(conn->hcon, skb, flags); +} + +static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) +{ + struct sk_buff *skb; + struct l2cap_hdr *lh; + struct l2cap_conn *conn = pi->conn; + int count, hlen = L2CAP_HDR_SIZE + 2; + + if (pi->fcs == L2CAP_FCS_CRC16) + hlen += 2; + + BT_DBG("pi %p, control 0x%2.2x", pi, control); + + count = min_t(unsigned int, conn->mtu, hlen); + control |= L2CAP_CTRL_FRAME_TYPE; + + if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; + pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + + if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { + control |= L2CAP_CTRL_POLL; + pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; + } + + skb = bt_skb_alloc(count, GFP_ATOMIC); + if (!skb) + return; + + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(pi->dcid); + put_unaligned_le16(control, skb_put(skb, 2)); + + if (pi->fcs == L2CAP_FCS_CRC16) { + u16 fcs = crc16(0, (u8 *)lh, count - 2); + put_unaligned_le16(fcs, skb_put(skb, 2)); + } + + hci_send_acl(pi->conn->hcon, skb, 0); +} + +static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) +{ + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + control |= L2CAP_SUPER_RCV_NOT_READY; + pi->conn_state |= L2CAP_CONN_RNR_SENT; + } else + control |= L2CAP_SUPER_RCV_READY; + + control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + + l2cap_send_sframe(pi, control); +} + +static inline int __l2cap_no_conn_pending(struct sock *sk) +{ + return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND); +} + +static void l2cap_do_start(struct sock *sk) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { + if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) + return; + + if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) { + struct l2cap_conn_req req; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + + l2cap_pi(sk)->ident = l2cap_get_ident(conn); + l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_REQ, sizeof(req), &req); + } + } else { + struct l2cap_info_req req; + req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; + conn->info_ident = l2cap_get_ident(conn); + + mod_timer(&conn->info_timer, jiffies + + msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + + l2cap_send_cmd(conn, conn->info_ident, + L2CAP_INFO_REQ, sizeof(req), &req); + } +} + +static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk) +{ + struct l2cap_disconn_req req; + + req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_DISCONN_REQ, sizeof(req), &req); +} + +/* ---- L2CAP connections ---- */ +static void l2cap_conn_start(struct l2cap_conn *conn) +{ + struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk; + + BT_DBG("conn %p", conn); + + read_lock(&l->lock); + + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (sk->sk_type != SOCK_SEQPACKET && + sk->sk_type != SOCK_STREAM) { + bh_unlock_sock(sk); + continue; + } + + if (sk->sk_state == BT_CONNECT) { + if (l2cap_check_security(sk) && + __l2cap_no_conn_pending(sk)) { + struct l2cap_conn_req req; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + + l2cap_pi(sk)->ident = l2cap_get_ident(conn); + l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_REQ, sizeof(req), &req); + } + } else if (sk->sk_state == BT_CONNECT2) { + struct l2cap_conn_rsp rsp; + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + + if (l2cap_check_security(sk)) { + if (bt_sk(sk)->defer_setup) { + struct sock *parent = bt_sk(sk)->parent; + rsp.result = cpu_to_le16(L2CAP_CR_PEND); + rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); + if (parent) + parent->sk_data_ready(parent, 0); + + } else { + sk->sk_state = BT_CONFIG; + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + } + } else { + rsp.result = cpu_to_le16(L2CAP_CR_PEND); + rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); + } + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + } + + bh_unlock_sock(sk); + } + + read_unlock(&l->lock); +} + +static void l2cap_conn_ready(struct l2cap_conn *conn) +{ + struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk; + + BT_DBG("conn %p", conn); + + read_lock(&l->lock); + + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (sk->sk_type != SOCK_SEQPACKET && + sk->sk_type != SOCK_STREAM) { + l2cap_sock_clear_timer(sk); + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); + } else if (sk->sk_state == BT_CONNECT) + l2cap_do_start(sk); + + bh_unlock_sock(sk); + } + + read_unlock(&l->lock); +} + +/* Notify sockets that we cannot guaranty reliability anymore */ +static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) +{ + struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk; + + BT_DBG("conn %p", conn); + + read_lock(&l->lock); + + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + if (l2cap_pi(sk)->force_reliable) + sk->sk_err = err; + } + + read_unlock(&l->lock); +} + +static void l2cap_info_timeout(unsigned long arg) +{ + struct l2cap_conn *conn = (void *) arg; + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + conn->info_ident = 0; + + l2cap_conn_start(conn); +} + +static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + + if (conn || status) + return conn; + + conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC); + if (!conn) + return NULL; + + hcon->l2cap_data = conn; + conn->hcon = hcon; + + BT_DBG("hcon %p conn %p", hcon, conn); + + conn->mtu = hcon->hdev->acl_mtu; + conn->src = &hcon->hdev->bdaddr; + conn->dst = &hcon->dst; + + conn->feat_mask = 0; + + spin_lock_init(&conn->lock); + rwlock_init(&conn->chan_list.lock); + + setup_timer(&conn->info_timer, l2cap_info_timeout, + (unsigned long) conn); + + conn->disc_reason = 0x13; + + return conn; +} + +static void l2cap_conn_del(struct hci_conn *hcon, int err) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + struct sock *sk; + + if (!conn) + return; + + BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); + + kfree_skb(conn->rx_skb); + + /* Kill channels */ + while ((sk = conn->chan_list.head)) { + bh_lock_sock(sk); + l2cap_chan_del(sk, err); + bh_unlock_sock(sk); + l2cap_sock_kill(sk); + } + + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) + del_timer_sync(&conn->info_timer); + + hcon->l2cap_data = NULL; + kfree(conn); +} + +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +{ + struct l2cap_chan_list *l = &conn->chan_list; + write_lock_bh(&l->lock); + __l2cap_chan_add(conn, sk, parent); + write_unlock_bh(&l->lock); +} + +/* ---- Socket interface ---- */ +static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) +{ + struct sock *sk; + struct hlist_node *node; + sk_for_each(sk, node, &l2cap_sk_list.head) + if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + goto found; + sk = NULL; +found: + return sk; +} + +/* Find socket with psm and source bdaddr. + * Returns closest match. + */ +static struct sock *__l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) +{ + struct sock *sk = NULL, *sk1 = NULL; + struct hlist_node *node; + + sk_for_each(sk, node, &l2cap_sk_list.head) { + if (state && sk->sk_state != state) + continue; + + if (l2cap_pi(sk)->psm == psm) { + /* Exact match. */ + if (!bacmp(&bt_sk(sk)->src, src)) + break; + + /* Closest match */ + if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) + sk1 = sk; + } + } + return node ? sk : sk1; +} + +/* Find socket with given address (psm, src). + * Returns locked socket */ +static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) +{ + struct sock *s; + read_lock(&l2cap_sk_list.lock); + s = __l2cap_get_sock_by_psm(state, psm, src); + if (s) + bh_lock_sock(s); + read_unlock(&l2cap_sk_list.lock); + return s; +} + +static void l2cap_sock_destruct(struct sock *sk) +{ + BT_DBG("sk %p", sk); + + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); +} + +static void l2cap_sock_cleanup_listen(struct sock *parent) +{ + struct sock *sk; + + BT_DBG("parent %p", parent); + + /* Close not yet accepted channels */ + while ((sk = bt_accept_dequeue(parent, NULL))) + l2cap_sock_close(sk); + + parent->sk_state = BT_CLOSED; + sock_set_flag(parent, SOCK_ZAPPED); +} + +/* Kill socket (only if zapped and orphan) + * Must be called on unlocked socket. + */ +static void l2cap_sock_kill(struct sock *sk) +{ + if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) + return; + + BT_DBG("sk %p state %d", sk, sk->sk_state); + + /* Kill poor orphan */ + bt_sock_unlink(&l2cap_sk_list, sk); + sock_set_flag(sk, SOCK_DEAD); + sock_put(sk); +} + +static void __l2cap_sock_close(struct sock *sk, int reason) +{ + BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); + + switch (sk->sk_state) { + case BT_LISTEN: + l2cap_sock_cleanup_listen(sk); + break; + + case BT_CONNECTED: + case BT_CONFIG: + if (sk->sk_type == SOCK_SEQPACKET || + sk->sk_type == SOCK_STREAM) { + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + + sk->sk_state = BT_DISCONN; + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); + l2cap_send_disconn_req(conn, sk); + } else + l2cap_chan_del(sk, reason); + break; + + case BT_CONNECT2: + if (sk->sk_type == SOCK_SEQPACKET || + sk->sk_type == SOCK_STREAM) { + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn_rsp rsp; + __u16 result; + + if (bt_sk(sk)->defer_setup) + result = L2CAP_CR_SEC_BLOCK; + else + result = L2CAP_CR_BAD_PSM; + + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = cpu_to_le16(result); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + } else + l2cap_chan_del(sk, reason); + break; + + case BT_CONNECT: + case BT_DISCONN: + l2cap_chan_del(sk, reason); + break; + + default: + sock_set_flag(sk, SOCK_ZAPPED); + break; + } +} + +/* Must be called on unlocked socket. */ +static void l2cap_sock_close(struct sock *sk) +{ + l2cap_sock_clear_timer(sk); + lock_sock(sk); + __l2cap_sock_close(sk, ECONNRESET); + release_sock(sk); + l2cap_sock_kill(sk); +} + +static void l2cap_sock_init(struct sock *sk, struct sock *parent) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + + BT_DBG("sk %p", sk); + + if (parent) { + sk->sk_type = parent->sk_type; + bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; + + pi->imtu = l2cap_pi(parent)->imtu; + pi->omtu = l2cap_pi(parent)->omtu; + pi->mode = l2cap_pi(parent)->mode; + pi->fcs = l2cap_pi(parent)->fcs; + pi->max_tx = l2cap_pi(parent)->max_tx; + pi->tx_win = l2cap_pi(parent)->tx_win; + pi->sec_level = l2cap_pi(parent)->sec_level; + pi->role_switch = l2cap_pi(parent)->role_switch; + pi->force_reliable = l2cap_pi(parent)->force_reliable; + pi->flushable = l2cap_pi(parent)->flushable; + } else { + pi->imtu = L2CAP_DEFAULT_MTU; + pi->omtu = 0; + if (enable_ertm && sk->sk_type == SOCK_STREAM) + pi->mode = L2CAP_MODE_ERTM; + else + pi->mode = L2CAP_MODE_BASIC; + pi->max_tx = max_transmit; + pi->fcs = L2CAP_FCS_CRC16; + pi->tx_win = tx_window; + pi->sec_level = BT_SECURITY_LOW; + pi->role_switch = 0; + pi->force_reliable = 0; + pi->flushable = 0; + } + + /* Default config options */ + pi->conf_len = 0; + pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; + skb_queue_head_init(TX_QUEUE(sk)); + skb_queue_head_init(SREJ_QUEUE(sk)); + skb_queue_head_init(BUSY_QUEUE(sk)); + INIT_LIST_HEAD(SREJ_LIST(sk)); +} + +static struct proto l2cap_proto = { + .name = "L2CAP", + .owner = THIS_MODULE, + .obj_size = sizeof(struct l2cap_pinfo) +}; + +static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) +{ + struct sock *sk; + + sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto); + if (!sk) + return NULL; + + sock_init_data(sock, sk); + INIT_LIST_HEAD(&bt_sk(sk)->accept_q); + + sk->sk_destruct = l2cap_sock_destruct; + sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); + + sock_reset_flag(sk, SOCK_ZAPPED); + + sk->sk_protocol = proto; + sk->sk_state = BT_OPEN; + + setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); + + bt_sock_link(&l2cap_sk_list, sk); + return sk; +} + +static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) +{ + struct sock *sk; + + BT_DBG("sock %p", sock); + + sock->state = SS_UNCONNECTED; + + if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && + sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) + return -EPERM; + + sock->ops = &l2cap_sock_ops; + + sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); + if (!sk) + return -ENOMEM; + + l2cap_sock_init(sk, NULL); + return 0; +} + +static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) +{ + struct sock *sk = sock->sk; + struct sockaddr_l2 la; + int len, err = 0; + + BT_DBG("sk %p", sk); + + if (!addr || addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + + memset(&la, 0, sizeof(la)); + len = min_t(unsigned int, sizeof(la), alen); + memcpy(&la, addr, len); + + if (la.l2_cid) + return -EINVAL; + + lock_sock(sk); + + if (sk->sk_state != BT_OPEN) { + err = -EBADFD; + goto done; + } + + if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 && + !capable(CAP_NET_BIND_SERVICE)) { + err = -EACCES; + goto done; + } + + write_lock_bh(&l2cap_sk_list.lock); + + if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) { + err = -EADDRINUSE; + } else { + /* Save source address */ + bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); + l2cap_pi(sk)->psm = la.l2_psm; + l2cap_pi(sk)->sport = la.l2_psm; + sk->sk_state = BT_BOUND; + + if (__le16_to_cpu(la.l2_psm) == 0x0001 || + __le16_to_cpu(la.l2_psm) == 0x0003) + l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + } + + write_unlock_bh(&l2cap_sk_list.lock); + +done: + release_sock(sk); + return err; +} + +static int l2cap_do_connect(struct sock *sk) +{ + bdaddr_t *src = &bt_sk(sk)->src; + bdaddr_t *dst = &bt_sk(sk)->dst; + struct l2cap_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + __u8 auth_type; + int err; + + BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), + l2cap_pi(sk)->psm); + + hdev = hci_get_route(dst, src); + if (!hdev) + return -EHOSTUNREACH; + + hci_dev_lock_bh(hdev); + + err = -ENOMEM; + + if (sk->sk_type == SOCK_RAW) { + switch (l2cap_pi(sk)->sec_level) { + case BT_SECURITY_HIGH: + auth_type = HCI_AT_DEDICATED_BONDING_MITM; + break; + case BT_SECURITY_MEDIUM: + auth_type = HCI_AT_DEDICATED_BONDING; + break; + default: + auth_type = HCI_AT_NO_BONDING; + break; + } + } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { + if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + auth_type = HCI_AT_NO_BONDING_MITM; + else + auth_type = HCI_AT_NO_BONDING; + + if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) + l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + } else { + switch (l2cap_pi(sk)->sec_level) { + case BT_SECURITY_HIGH: + auth_type = HCI_AT_GENERAL_BONDING_MITM; + break; + case BT_SECURITY_MEDIUM: + auth_type = HCI_AT_GENERAL_BONDING; + break; + default: + auth_type = HCI_AT_NO_BONDING; + break; + } + } + + hcon = hci_connect(hdev, ACL_LINK, 0, dst, + l2cap_pi(sk)->sec_level, auth_type); + if (!hcon) + goto done; + + conn = l2cap_conn_add(hcon, 0); + if (!conn) { + hci_conn_put(hcon); + goto done; + } + + err = 0; + + /* Update source addr of the socket */ + bacpy(src, conn->src); + + l2cap_chan_add(conn, sk, NULL); + + sk->sk_state = BT_CONNECT; + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); + + if (hcon->state == BT_CONNECTED) { + if (sk->sk_type != SOCK_SEQPACKET && + sk->sk_type != SOCK_STREAM) { + l2cap_sock_clear_timer(sk); + sk->sk_state = BT_CONNECTED; + } else + l2cap_do_start(sk); + } + +done: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + return err; +} + +static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_l2 la; + int len, err = 0; + + BT_DBG("sk %p", sk); + + if (!addr || alen < sizeof(addr->sa_family) || + addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + + memset(&la, 0, sizeof(la)); + len = min_t(unsigned int, sizeof(la), alen); + memcpy(&la, addr, len); + + if (la.l2_cid) + return -EINVAL; + + lock_sock(sk); + + if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) + && !la.l2_psm) { + err = -EINVAL; + goto done; + } + + switch (l2cap_pi(sk)->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (enable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + + switch (sk->sk_state) { + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + /* Already connecting */ + goto wait; + + case BT_CONNECTED: + /* Already connected */ + goto done; + + case BT_OPEN: + case BT_BOUND: + /* Can connect */ + break; + + default: + err = -EBADFD; + goto done; + } + + /* Set destination address and psm */ + bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); + l2cap_pi(sk)->psm = la.l2_psm; + + err = l2cap_do_connect(sk); + if (err) + goto done; + +wait: + err = bt_sock_wait_state(sk, BT_CONNECTED, + sock_sndtimeo(sk, flags & O_NONBLOCK)); +done: + release_sock(sk); + return err; +} + +static int l2cap_sock_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sk %p backlog %d", sk, backlog); + + lock_sock(sk); + + if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) + || sk->sk_state != BT_BOUND) { + err = -EBADFD; + goto done; + } + + switch (l2cap_pi(sk)->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (enable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + + if (!l2cap_pi(sk)->psm) { + bdaddr_t *src = &bt_sk(sk)->src; + u16 psm; + + err = -EINVAL; + + write_lock_bh(&l2cap_sk_list.lock); + + for (psm = 0x1001; psm < 0x1100; psm += 2) + if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { + l2cap_pi(sk)->psm = cpu_to_le16(psm); + l2cap_pi(sk)->sport = cpu_to_le16(psm); + err = 0; + break; + } + + write_unlock_bh(&l2cap_sk_list.lock); + + if (err < 0) + goto done; + } + + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + sk->sk_state = BT_LISTEN; + +done: + release_sock(sk); + return err; +} + +static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) +{ + DECLARE_WAITQUEUE(wait, current); + struct sock *sk = sock->sk, *nsk; + long timeo; + int err = 0; + + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); + + if (sk->sk_state != BT_LISTEN) { + err = -EBADFD; + goto done; + } + + timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + + BT_DBG("sk %p timeo %ld", sk, timeo); + + /* Wait for an incoming connection. (wake-one). */ + add_wait_queue_exclusive(sk_sleep(sk), &wait); + while (!(nsk = bt_accept_dequeue(sk, newsock))) { + set_current_state(TASK_INTERRUPTIBLE); + if (!timeo) { + err = -EAGAIN; + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); + + if (sk->sk_state != BT_LISTEN) { + err = -EBADFD; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk_sleep(sk), &wait); + + if (err) + goto done; + + newsock->state = SS_CONNECTED; + + BT_DBG("new socket %p", nsk); + +done: + release_sock(sk); + return err; +} + +static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) +{ + struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; + struct sock *sk = sock->sk; + + BT_DBG("sock %p, sk %p", sock, sk); + + addr->sa_family = AF_BLUETOOTH; + *len = sizeof(struct sockaddr_l2); + + if (peer) { + la->l2_psm = l2cap_pi(sk)->psm; + bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); + } else { + la->l2_psm = l2cap_pi(sk)->sport; + bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); + } + + return 0; +} + +static int __l2cap_wait_ack(struct sock *sk) +{ + DECLARE_WAITQUEUE(wait, current); + int err = 0; + int timeo = HZ/5; + + add_wait_queue(sk_sleep(sk), &wait); + while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + set_current_state(TASK_INTERRUPTIBLE); + + if (!timeo) + timeo = HZ/5; + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + err = sock_error(sk); + if (err) + break; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk_sleep(sk), &wait); + return err; +} + +static void l2cap_monitor_timeout(unsigned long arg) +{ + struct sock *sk = (void *) arg; + + bh_lock_sock(sk); + if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { + l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk); + bh_unlock_sock(sk); + return; + } + + l2cap_pi(sk)->retry_count++; + __mod_monitor_timer(); + + l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); + bh_unlock_sock(sk); +} + +static void l2cap_retrans_timeout(unsigned long arg) +{ + struct sock *sk = (void *) arg; + + bh_lock_sock(sk); + l2cap_pi(sk)->retry_count = 1; + __mod_monitor_timer(); + + l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + + l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); + bh_unlock_sock(sk); +} + +static void l2cap_drop_acked_frames(struct sock *sk) +{ + struct sk_buff *skb; + + while ((skb = skb_peek(TX_QUEUE(sk))) && + l2cap_pi(sk)->unacked_frames) { + if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq) + break; + + skb = skb_dequeue(TX_QUEUE(sk)); + kfree_skb(skb); + + l2cap_pi(sk)->unacked_frames--; + } + + if (!l2cap_pi(sk)->unacked_frames) + del_timer(&l2cap_pi(sk)->retrans_timer); +} + +static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct hci_conn *hcon = pi->conn->hcon; + u16 flags; + + BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); + + if (lmp_no_flush_capable(hcon->hdev) && !l2cap_pi(sk)->flushable) + flags = ACL_START_NO_FLUSH; + else + flags = ACL_START; + + hci_send_acl(hcon, skb, flags); +} + +static int l2cap_streaming_send(struct sock *sk) +{ + struct sk_buff *skb, *tx_skb; + struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control, fcs; + + while ((skb = sk->sk_send_head)) { + tx_skb = skb_clone(skb, GFP_ATOMIC); + + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + + if (pi->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); + } + + l2cap_do_send(sk, tx_skb); + + pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + + if (skb_queue_is_last(TX_QUEUE(sk), skb)) + sk->sk_send_head = NULL; + else + sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); + + skb = skb_dequeue(TX_QUEUE(sk)); + kfree_skb(skb); + } + return 0; +} + +static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb, *tx_skb; + u16 control, fcs; + + skb = skb_peek(TX_QUEUE(sk)); + if (!skb) + return; + + do { + if (bt_cb(skb)->tx_seq == tx_seq) + break; + + if (skb_queue_is_last(TX_QUEUE(sk), skb)) + return; + + } while ((skb = skb_queue_next(TX_QUEUE(sk), skb))); + + if (pi->remote_max_tx && + bt_cb(skb)->retries == pi->remote_max_tx) { + l2cap_send_disconn_req(pi->conn, sk); + return; + } + + tx_skb = skb_clone(skb, GFP_ATOMIC); + bt_cb(skb)->retries++; + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) + | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + + if (pi->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); + } + + l2cap_do_send(sk, tx_skb); +} + +static int l2cap_ertm_send(struct sock *sk) +{ + struct sk_buff *skb, *tx_skb; + struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control, fcs; + int nsent = 0; + + if (pi->conn_state & L2CAP_CONN_WAIT_F) + return 0; + + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) && + !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) { + + if (pi->remote_max_tx && + bt_cb(skb)->retries == pi->remote_max_tx) { + l2cap_send_disconn_req(pi->conn, sk); + break; + } + + tx_skb = skb_clone(skb, GFP_ATOMIC); + + bt_cb(skb)->retries++; + + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; + pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) + | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + + + if (pi->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); + } + + l2cap_do_send(sk, tx_skb); + + __mod_retrans_timer(); + + bt_cb(skb)->tx_seq = pi->next_tx_seq; + pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + + pi->unacked_frames++; + pi->frames_sent++; + + if (skb_queue_is_last(TX_QUEUE(sk), skb)) + sk->sk_send_head = NULL; + else + sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); + + nsent++; + } + + return nsent; +} + +static int l2cap_retransmit_frames(struct sock *sk) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int ret; + + spin_lock_bh(&pi->send_lock); + + if (!skb_queue_empty(TX_QUEUE(sk))) + sk->sk_send_head = TX_QUEUE(sk)->next; + + pi->next_tx_seq = pi->expected_ack_seq; + ret = l2cap_ertm_send(sk); + + spin_unlock_bh(&pi->send_lock); + + return ret; +} + +static void l2cap_send_ack(struct l2cap_pinfo *pi) +{ + struct sock *sk = (struct sock *)pi; + u16 control = 0; + int nframes; + + control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + control |= L2CAP_SUPER_RCV_NOT_READY; + pi->conn_state |= L2CAP_CONN_RNR_SENT; + l2cap_send_sframe(pi, control); + return; + } + + spin_lock_bh(&pi->send_lock); + nframes = l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + + if (nframes > 0) + return; + + control |= L2CAP_SUPER_RCV_READY; + l2cap_send_sframe(pi, control); +} + +static void l2cap_send_srejtail(struct sock *sk) +{ + struct srej_list *tail; + u16 control; + + control = L2CAP_SUPER_SELECT_REJECT; + control |= L2CAP_CTRL_FINAL; + + tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list); + control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + + l2cap_send_sframe(l2cap_pi(sk), control); +} + +static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff **frag; + int err, sent = 0; + + if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) + return -EFAULT; + + sent += count; + len -= count; + + /* Continuation fragments (no L2CAP header) */ + frag = &skb_shinfo(skb)->frag_list; + while (len) { + count = min_t(unsigned int, conn->mtu, len); + + *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); + if (!*frag) + return -EFAULT; + if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) + return -EFAULT; + + sent += count; + len -= count; + + frag = &(*frag)->next; + } + + return sent; +} + +static struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE + 2; + struct l2cap_hdr *lh; + + BT_DBG("sk %p len %d", sk, (int)len); + + count = min_t(unsigned int, (conn->mtu - hlen), len); + skb = bt_skb_send_alloc(sk, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + return ERR_PTR(-ENOMEM); + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + if (unlikely(err < 0)) { + kfree_skb(skb); + return ERR_PTR(err); + } + return skb; +} + +static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE; + struct l2cap_hdr *lh; + + BT_DBG("sk %p len %d", sk, (int)len); + + count = min_t(unsigned int, (conn->mtu - hlen), len); + skb = bt_skb_send_alloc(sk, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + return ERR_PTR(-ENOMEM); + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + if (unlikely(err < 0)) { + kfree_skb(skb); + return ERR_PTR(err); + } + return skb; +} + +static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE + 2; + struct l2cap_hdr *lh; + + BT_DBG("sk %p len %d", sk, (int)len); + + if (!conn) + return ERR_PTR(-ENOTCONN); + + if (sdulen) + hlen += 2; + + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + hlen += 2; + + count = min_t(unsigned int, (conn->mtu - hlen), len); + skb = bt_skb_send_alloc(sk, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + return ERR_PTR(-ENOMEM); + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + put_unaligned_le16(control, skb_put(skb, 2)); + if (sdulen) + put_unaligned_le16(sdulen, skb_put(skb, 2)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + if (unlikely(err < 0)) { + kfree_skb(skb); + return ERR_PTR(err); + } + + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + put_unaligned_le16(0, skb_put(skb, 2)); + + bt_cb(skb)->retries = 0; + return skb; +} + +static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb; + struct sk_buff_head sar_queue; + u16 control; + size_t size = 0; + + skb_queue_head_init(&sar_queue); + control = L2CAP_SDU_START; + skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + __skb_queue_tail(&sar_queue, skb); + len -= pi->remote_mps; + size += pi->remote_mps; + + while (len > 0) { + size_t buflen; + + if (len > pi->remote_mps) { + control = L2CAP_SDU_CONTINUE; + buflen = pi->remote_mps; + } else { + control = L2CAP_SDU_END; + buflen = len; + } + + skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0); + if (IS_ERR(skb)) { + skb_queue_purge(&sar_queue); + return PTR_ERR(skb); + } + + __skb_queue_tail(&sar_queue, skb); + len -= buflen; + size += buflen; + } + skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); + spin_lock_bh(&pi->send_lock); + if (sk->sk_send_head == NULL) + sk->sk_send_head = sar_queue.next; + spin_unlock_bh(&pi->send_lock); + + return size; +} + +static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb; + u16 control; + int err; + + BT_DBG("sock %p, sk %p", sock, sk); + + err = sock_error(sk); + if (err) + return err; + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + lock_sock(sk); + + if (sk->sk_state != BT_CONNECTED) { + err = -ENOTCONN; + goto done; + } + + /* Connectionless channel */ + if (sk->sk_type == SOCK_DGRAM) { + skb = l2cap_create_connless_pdu(sk, msg, len); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + } else { + l2cap_do_send(sk, skb); + err = len; + } + goto done; + } + + switch (pi->mode) { + case L2CAP_MODE_BASIC: + /* Check outgoing MTU */ + if (len > pi->omtu) { + err = -EINVAL; + goto done; + } + + /* Create a basic PDU */ + skb = l2cap_create_basic_pdu(sk, msg, len); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto done; + } + + l2cap_do_send(sk, skb); + err = len; + break; + + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + /* Entire SDU fits into one PDU */ + if (len <= pi->remote_mps) { + control = L2CAP_SDU_UNSEGMENTED; + skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto done; + } + __skb_queue_tail(TX_QUEUE(sk), skb); + + if (pi->mode == L2CAP_MODE_ERTM) + spin_lock_bh(&pi->send_lock); + + if (sk->sk_send_head == NULL) + sk->sk_send_head = skb; + + if (pi->mode == L2CAP_MODE_ERTM) + spin_unlock_bh(&pi->send_lock); + } else { + /* Segment SDU into multiples PDUs */ + err = l2cap_sar_segment_sdu(sk, msg, len); + if (err < 0) + goto done; + } + + if (pi->mode == L2CAP_MODE_STREAMING) { + err = l2cap_streaming_send(sk); + } else { + spin_lock_bh(&pi->send_lock); + err = l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + } + + if (err >= 0) + err = len; + break; + + default: + BT_DBG("bad state %1.1x", pi->mode); + err = -EINVAL; + } + +done: + release_sock(sk); + return err; +} + +static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags) +{ + struct sock *sk = sock->sk; + + lock_sock(sk); + + if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { + struct l2cap_conn_rsp rsp; + + sk->sk_state = BT_CONFIG; + + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + + release_sock(sk); + return 0; + } + + release_sock(sk); + + return bt_sock_recvmsg(iocb, sock, msg, len, flags); +} + +static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) +{ + struct sock *sk = sock->sk; + struct l2cap_options opts; + int len, err = 0; + u32 opt; + + BT_DBG("sk %p", sk); + + lock_sock(sk); + + switch (optname) { + case L2CAP_OPTIONS: + opts.imtu = l2cap_pi(sk)->imtu; + opts.omtu = l2cap_pi(sk)->omtu; + opts.flush_to = l2cap_pi(sk)->flush_to; + opts.mode = l2cap_pi(sk)->mode; + opts.fcs = l2cap_pi(sk)->fcs; + opts.max_tx = l2cap_pi(sk)->max_tx; + opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + + len = min_t(unsigned int, sizeof(opts), optlen); + if (copy_from_user((char *) &opts, optval, len)) { + err = -EFAULT; + break; + } + + l2cap_pi(sk)->mode = opts.mode; + switch (l2cap_pi(sk)->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (enable_ertm) + break; + /* fall through */ + default: + err = -EINVAL; + break; + } + + l2cap_pi(sk)->imtu = opts.imtu; + l2cap_pi(sk)->omtu = opts.omtu; + l2cap_pi(sk)->fcs = opts.fcs; + l2cap_pi(sk)->max_tx = opts.max_tx; + l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; + break; + + case L2CAP_LM: + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + if (opt & L2CAP_LM_AUTH) + l2cap_pi(sk)->sec_level = BT_SECURITY_LOW; + if (opt & L2CAP_LM_ENCRYPT) + l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM; + if (opt & L2CAP_LM_SECURE) + l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH; + + l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); + l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); + l2cap_pi(sk)->flushable = (opt & L2CAP_LM_FLUSHABLE); + break; + + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; +} + +static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) +{ + struct sock *sk = sock->sk; + struct bt_security sec; + int len, err = 0; + u32 opt; + + BT_DBG("sk %p", sk); + + if (level == SOL_L2CAP) + return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); + + if (level != SOL_BLUETOOTH) + return -ENOPROTOOPT; + + lock_sock(sk); + + switch (optname) { + case BT_SECURITY: + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { + err = -EINVAL; + break; + } + + sec.level = BT_SECURITY_LOW; + + len = min_t(unsigned int, sizeof(sec), optlen); + if (copy_from_user((char *) &sec, optval, len)) { + err = -EFAULT; + break; + } + + if (sec.level < BT_SECURITY_LOW || + sec.level > BT_SECURITY_HIGH) { + err = -EINVAL; + break; + } + + l2cap_pi(sk)->sec_level = sec.level; + break; + + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + bt_sk(sk)->defer_setup = opt; + break; + + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; +} + +static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) +{ + struct sock *sk = sock->sk; + struct l2cap_options opts; + struct l2cap_conninfo cinfo; + int len, err = 0; + u32 opt; + + BT_DBG("sk %p", sk); + + if (get_user(len, optlen)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + case L2CAP_OPTIONS: + opts.imtu = l2cap_pi(sk)->imtu; + opts.omtu = l2cap_pi(sk)->omtu; + opts.flush_to = l2cap_pi(sk)->flush_to; + opts.mode = l2cap_pi(sk)->mode; + opts.fcs = l2cap_pi(sk)->fcs; + opts.max_tx = l2cap_pi(sk)->max_tx; + opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + + len = min_t(unsigned int, len, sizeof(opts)); + if (copy_to_user(optval, (char *) &opts, len)) + err = -EFAULT; + + break; + + case L2CAP_LM: + switch (l2cap_pi(sk)->sec_level) { + case BT_SECURITY_LOW: + opt = L2CAP_LM_AUTH; + break; + case BT_SECURITY_MEDIUM: + opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT; + break; + case BT_SECURITY_HIGH: + opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | + L2CAP_LM_SECURE; + break; + default: + opt = 0; + break; + } + + if (l2cap_pi(sk)->role_switch) + opt |= L2CAP_LM_MASTER; + + if (l2cap_pi(sk)->force_reliable) + opt |= L2CAP_LM_RELIABLE; + + if (l2cap_pi(sk)->flushable) + opt |= L2CAP_LM_FLUSHABLE; + + if (put_user(opt, (u32 __user *) optval)) + err = -EFAULT; + break; + + case L2CAP_CONNINFO: + if (sk->sk_state != BT_CONNECTED && + !(sk->sk_state == BT_CONNECT2 && + bt_sk(sk)->defer_setup)) { + err = -ENOTCONN; + break; + } + + cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; + memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3); + + len = min_t(unsigned int, len, sizeof(cinfo)); + if (copy_to_user(optval, (char *) &cinfo, len)) + err = -EFAULT; + + break; + + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; +} + +static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) +{ + struct sock *sk = sock->sk; + struct bt_security sec; + int len, err = 0; + + BT_DBG("sk %p", sk); + + if (level == SOL_L2CAP) + return l2cap_sock_getsockopt_old(sock, optname, optval, optlen); + + if (level != SOL_BLUETOOTH) + return -ENOPROTOOPT; + + if (get_user(len, optlen)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + case BT_SECURITY: + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { + err = -EINVAL; + break; + } + + sec.level = l2cap_pi(sk)->sec_level; + + len = min_t(unsigned int, len, sizeof(sec)); + if (copy_to_user(optval, (char *) &sec, len)) + err = -EFAULT; + + break; + + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) + err = -EFAULT; + + break; + + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; +} + +static int l2cap_sock_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + lock_sock(sk); + if (!sk->sk_shutdown) { + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + err = __l2cap_wait_ack(sk); + + sk->sk_shutdown = SHUTDOWN_MASK; + l2cap_sock_clear_timer(sk); + __l2cap_sock_close(sk, 0); + + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + err = bt_sock_wait_state(sk, BT_CLOSED, + sk->sk_lingertime); + } + release_sock(sk); + return err; +} + +static int l2cap_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + int err; + + BT_DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + err = l2cap_sock_shutdown(sock, 2); + + sock_orphan(sk); + l2cap_sock_kill(sk); + return err; +} + +static void l2cap_chan_ready(struct sock *sk) +{ + struct sock *parent = bt_sk(sk)->parent; + + BT_DBG("sk %p, parent %p", sk, parent); + + l2cap_pi(sk)->conf_state = 0; + l2cap_sock_clear_timer(sk); + + if (!parent) { + /* Outgoing channel. + * Wake up socket sleeping on connect. + */ + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); + } else { + /* Incoming channel. + * Wake up socket sleeping on accept. + */ + parent->sk_data_ready(parent, 0); + } +} + +/* Copy frame to all raw sockets on that connection */ +static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) +{ + struct l2cap_chan_list *l = &conn->chan_list; + struct sk_buff *nskb; + struct sock *sk; + + BT_DBG("conn %p", conn); + + read_lock(&l->lock); + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + if (sk->sk_type != SOCK_RAW) + continue; + + /* Don't send frame to the socket it came from */ + if (skb->sk == sk) + continue; + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + read_unlock(&l->lock); +} + +/* ---- L2CAP signalling commands ---- */ +static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, + u8 code, u8 ident, u16 dlen, void *data) +{ + struct sk_buff *skb, **frag; + struct l2cap_cmd_hdr *cmd; + struct l2cap_hdr *lh; + int len, count; + + BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", + conn, code, ident, dlen); + + len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; + count = min_t(unsigned int, conn->mtu, len); + + skb = bt_skb_alloc(count, GFP_ATOMIC); + if (!skb) + return NULL; + + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); + lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); + + cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); + cmd->code = code; + cmd->ident = ident; + cmd->len = cpu_to_le16(dlen); + + if (dlen) { + count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE; + memcpy(skb_put(skb, count), data, count); + data += count; + } + + len -= skb->len; + + /* Continuation fragments (no L2CAP header) */ + frag = &skb_shinfo(skb)->frag_list; + while (len) { + count = min_t(unsigned int, conn->mtu, len); + + *frag = bt_skb_alloc(count, GFP_ATOMIC); + if (!*frag) + goto fail; + + memcpy(skb_put(*frag, count), data, count); + + len -= count; + data += count; + + frag = &(*frag)->next; + } + + return skb; + +fail: + kfree_skb(skb); + return NULL; +} + +static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val) +{ + struct l2cap_conf_opt *opt = *ptr; + int len; + + len = L2CAP_CONF_OPT_SIZE + opt->len; + *ptr += len; + + *type = opt->type; + *olen = opt->len; + + switch (opt->len) { + case 1: + *val = *((u8 *) opt->val); + break; + + case 2: + *val = __le16_to_cpu(*((__le16 *) opt->val)); + break; + + case 4: + *val = __le32_to_cpu(*((__le32 *) opt->val)); + break; + + default: + *val = (unsigned long) opt->val; + break; + } + + BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val); + return len; +} + +static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) +{ + struct l2cap_conf_opt *opt = *ptr; + + BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val); + + opt->type = type; + opt->len = len; + + switch (len) { + case 1: + *((u8 *) opt->val) = val; + break; + + case 2: + *((__le16 *) opt->val) = cpu_to_le16(val); + break; + + case 4: + *((__le32 *) opt->val) = cpu_to_le32(val); + break; + + default: + memcpy(opt->val, (void *) val, len); + break; + } + + *ptr += L2CAP_CONF_OPT_SIZE + len; +} + +static void l2cap_ack_timeout(unsigned long arg) +{ + struct sock *sk = (void *) arg; + + bh_lock_sock(sk); + l2cap_send_ack(l2cap_pi(sk)); + bh_unlock_sock(sk); +} + +static inline void l2cap_ertm_init(struct sock *sk) +{ + l2cap_pi(sk)->expected_ack_seq = 0; + l2cap_pi(sk)->unacked_frames = 0; + l2cap_pi(sk)->buffer_seq = 0; + l2cap_pi(sk)->num_acked = 0; + l2cap_pi(sk)->frames_sent = 0; + + setup_timer(&l2cap_pi(sk)->retrans_timer, + l2cap_retrans_timeout, (unsigned long) sk); + setup_timer(&l2cap_pi(sk)->monitor_timer, + l2cap_monitor_timeout, (unsigned long) sk); + setup_timer(&l2cap_pi(sk)->ack_timer, + l2cap_ack_timeout, (unsigned long) sk); + + __skb_queue_head_init(SREJ_QUEUE(sk)); + __skb_queue_head_init(BUSY_QUEUE(sk)); + spin_lock_init(&l2cap_pi(sk)->send_lock); + + INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); +} + +static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) +{ + u32 local_feat_mask = l2cap_feat_mask; + if (enable_ertm) + local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; + + switch (mode) { + case L2CAP_MODE_ERTM: + return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask; + case L2CAP_MODE_STREAMING: + return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask; + default: + return 0x00; + } +} + +static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) +{ + switch (mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: + if (l2cap_mode_supported(mode, remote_feat_mask)) + return mode; + /* fall through */ + default: + return L2CAP_MODE_BASIC; + } +} + +static int l2cap_build_conf_req(struct sock *sk, void *data) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_conf_req *req = data; + struct l2cap_conf_rfc rfc = { .mode = pi->mode }; + void *ptr = req->data; + + BT_DBG("sk %p", sk); + + if (pi->num_conf_req || pi->num_conf_rsp) + goto done; + + switch (pi->mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: + pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) + l2cap_send_disconn_req(pi->conn, sk); + break; + default: + pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + break; + } + +done: + switch (pi->mode) { + case L2CAP_MODE_BASIC: + if (pi->imtu != L2CAP_DEFAULT_MTU) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + break; + + case L2CAP_MODE_ERTM: + rfc.mode = L2CAP_MODE_ERTM; + rfc.txwin_size = pi->tx_win; + rfc.max_transmit = pi->max_tx; + rfc.retrans_timeout = 0; + rfc.monitor_timeout = 0; + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + + if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + break; + + if (pi->fcs == L2CAP_FCS_NONE || + pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + pi->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + } + break; + + case L2CAP_MODE_STREAMING: + rfc.mode = L2CAP_MODE_STREAMING; + rfc.txwin_size = 0; + rfc.max_transmit = 0; + rfc.retrans_timeout = 0; + rfc.monitor_timeout = 0; + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + + if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + break; + + if (pi->fcs == L2CAP_FCS_NONE || + pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + pi->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + } + break; + } + + /* FIXME: Need actual value of the flush timeout */ + //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) + // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); + + req->dcid = cpu_to_le16(pi->dcid); + req->flags = cpu_to_le16(0); + + return ptr - data; +} + +static int l2cap_parse_conf_req(struct sock *sk, void *data) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_conf_rsp *rsp = data; + void *ptr = rsp->data; + void *req = pi->conf_req; + int len = pi->conf_len; + int type, hint, olen; + unsigned long val; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; + u16 mtu = L2CAP_DEFAULT_MTU; + u16 result = L2CAP_CONF_SUCCESS; + + BT_DBG("sk %p", sk); + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&req, &type, &olen, &val); + + hint = type & L2CAP_CONF_HINT; + type &= L2CAP_CONF_MASK; + + switch (type) { + case L2CAP_CONF_MTU: + mtu = val; + break; + + case L2CAP_CONF_FLUSH_TO: + pi->flush_to = val; + break; + + case L2CAP_CONF_QOS: + break; + + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *) val, olen); + break; + + case L2CAP_CONF_FCS: + if (val == L2CAP_FCS_NONE) + pi->conf_state |= L2CAP_CONF_NO_FCS_RECV; + + break; + + default: + if (hint) + break; + + result = L2CAP_CONF_UNKNOWN; + *((u8 *) ptr++) = type; + break; + } + } + + if (pi->num_conf_rsp || pi->num_conf_req) + goto done; + + switch (pi->mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: + pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) + return -ECONNREFUSED; + break; + default: + pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + break; + } + +done: + if (pi->mode != rfc.mode) { + result = L2CAP_CONF_UNACCEPT; + rfc.mode = pi->mode; + + if (pi->num_conf_rsp == 1) + return -ECONNREFUSED; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + } + + + if (result == L2CAP_CONF_SUCCESS) { + /* Configure output options and let the other side know + * which ones we don't like. */ + + if (mtu < L2CAP_DEFAULT_MIN_MTU) + result = L2CAP_CONF_UNACCEPT; + else { + pi->omtu = mtu; + pi->conf_state |= L2CAP_CONF_MTU_DONE; + } + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); + + switch (rfc.mode) { + case L2CAP_MODE_BASIC: + pi->fcs = L2CAP_FCS_NONE; + pi->conf_state |= L2CAP_CONF_MODE_DONE; + break; + + case L2CAP_MODE_ERTM: + pi->remote_tx_win = rfc.txwin_size; + pi->remote_max_tx = rfc.max_transmit; + if (rfc.max_pdu_size > pi->conn->mtu - 10) + rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10); + + pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); + + rfc.retrans_timeout = + le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = + le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); + + pi->conf_state |= L2CAP_CONF_MODE_DONE; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + + break; + + case L2CAP_MODE_STREAMING: + if (rfc.max_pdu_size > pi->conn->mtu - 10) + rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10); + + pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); + + pi->conf_state |= L2CAP_CONF_MODE_DONE; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + + break; + + default: + result = L2CAP_CONF_UNACCEPT; + + memset(&rfc, 0, sizeof(rfc)); + rfc.mode = pi->mode; + } + + if (result == L2CAP_CONF_SUCCESS) + pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; + } + rsp->scid = cpu_to_le16(pi->dcid); + rsp->result = cpu_to_le16(result); + rsp->flags = cpu_to_le16(0x0000); + + return ptr - data; +} + +static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, u16 *result) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_conf_req *req = data; + void *ptr = req->data; + int type, olen; + unsigned long val; + struct l2cap_conf_rfc rfc; + + BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data); + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); + + switch (type) { + case L2CAP_CONF_MTU: + if (val < L2CAP_DEFAULT_MIN_MTU) { + *result = L2CAP_CONF_UNACCEPT; + pi->omtu = L2CAP_DEFAULT_MIN_MTU; + } else + pi->omtu = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); + break; + + case L2CAP_CONF_FLUSH_TO: + pi->flush_to = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, + 2, pi->flush_to); + break; + + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *)val, olen); + + if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) && + rfc.mode != pi->mode) + return -ECONNREFUSED; + + pi->mode = rfc.mode; + pi->fcs = 0; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + break; + } + } + + if (*result == L2CAP_CONF_SUCCESS) { + switch (rfc.mode) { + case L2CAP_MODE_ERTM: + pi->remote_tx_win = rfc.txwin_size; + pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); + pi->mps = le16_to_cpu(rfc.max_pdu_size); + break; + case L2CAP_MODE_STREAMING: + pi->mps = le16_to_cpu(rfc.max_pdu_size); + } + } + + req->dcid = cpu_to_le16(pi->dcid); + req->flags = cpu_to_le16(0x0000); + + return ptr - data; +} + +static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) +{ + struct l2cap_conf_rsp *rsp = data; + void *ptr = rsp->data; + + BT_DBG("sk %p", sk); + + rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp->result = cpu_to_le16(result); + rsp->flags = cpu_to_le16(flags); + + return ptr - data; +} + +static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int type, olen; + unsigned long val; + struct l2cap_conf_rfc rfc; + + BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); + + if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) + return; + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); + + switch (type) { + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *)val, olen); + goto done; + } + } + +done: + switch (rfc.mode) { + case L2CAP_MODE_ERTM: + pi->remote_tx_win = rfc.txwin_size; + pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); + pi->mps = le16_to_cpu(rfc.max_pdu_size); + break; + case L2CAP_MODE_STREAMING: + pi->mps = le16_to_cpu(rfc.max_pdu_size); + } +} + +static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data; + + if (rej->reason != 0x0000) + return 0; + + if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && + cmd->ident == conn->info_ident) { + del_timer(&conn->info_timer); + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + conn->info_ident = 0; + + l2cap_conn_start(conn); + } + + return 0; +} + +static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_chan_list *list = &conn->chan_list; + struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; + struct l2cap_conn_rsp rsp; + struct sock *sk, *parent; + int result, status = L2CAP_CS_NO_INFO; + + u16 dcid = 0, scid = __le16_to_cpu(req->scid); + __le16 psm = req->psm; + + BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); + + /* Check if we have socket listening on psm */ + parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src); + if (!parent) { + result = L2CAP_CR_BAD_PSM; + goto sendresp; + } + + /* Check if the ACL is secure enough (if not SDP) */ + if (psm != cpu_to_le16(0x0001) && + !hci_conn_check_link_mode(conn->hcon)) { + conn->disc_reason = 0x05; + result = L2CAP_CR_SEC_BLOCK; + goto response; + } + + result = L2CAP_CR_NO_MEM; + + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); + goto response; + } + + sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC); + if (!sk) + goto response; + + write_lock_bh(&list->lock); + + /* Check if we already have channel with that dcid */ + if (__l2cap_get_chan_by_dcid(list, scid)) { + write_unlock_bh(&list->lock); + sock_set_flag(sk, SOCK_ZAPPED); + l2cap_sock_kill(sk); + goto response; + } + + hci_conn_hold(conn->hcon); + + l2cap_sock_init(sk, parent); + bacpy(&bt_sk(sk)->src, conn->src); + bacpy(&bt_sk(sk)->dst, conn->dst); + l2cap_pi(sk)->psm = psm; + l2cap_pi(sk)->dcid = scid; + + __l2cap_chan_add(conn, sk, parent); + dcid = l2cap_pi(sk)->scid; + + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); + + l2cap_pi(sk)->ident = cmd->ident; + + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { + if (l2cap_check_security(sk)) { + if (bt_sk(sk)->defer_setup) { + sk->sk_state = BT_CONNECT2; + result = L2CAP_CR_PEND; + status = L2CAP_CS_AUTHOR_PEND; + parent->sk_data_ready(parent, 0); + } else { + sk->sk_state = BT_CONFIG; + result = L2CAP_CR_SUCCESS; + status = L2CAP_CS_NO_INFO; + } + } else { + sk->sk_state = BT_CONNECT2; + result = L2CAP_CR_PEND; + status = L2CAP_CS_AUTHEN_PEND; + } + } else { + sk->sk_state = BT_CONNECT2; + result = L2CAP_CR_PEND; + status = L2CAP_CS_NO_INFO; + } + + write_unlock_bh(&list->lock); + +response: + bh_unlock_sock(parent); + +sendresp: + rsp.scid = cpu_to_le16(scid); + rsp.dcid = cpu_to_le16(dcid); + rsp.result = cpu_to_le16(result); + rsp.status = cpu_to_le16(status); + l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); + + if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) { + struct l2cap_info_req info; + info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; + conn->info_ident = l2cap_get_ident(conn); + + mod_timer(&conn->info_timer, jiffies + + msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + + l2cap_send_cmd(conn, conn->info_ident, + L2CAP_INFO_REQ, sizeof(info), &info); + } + + return 0; +} + +static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; + u16 scid, dcid, result, status; + struct sock *sk; + u8 req[128]; + + scid = __le16_to_cpu(rsp->scid); + dcid = __le16_to_cpu(rsp->dcid); + result = __le16_to_cpu(rsp->result); + status = __le16_to_cpu(rsp->status); + + BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + + if (scid) { + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) + return 0; + } else { + sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + if (!sk) + return 0; + } + + switch (result) { + case L2CAP_CR_SUCCESS: + sk->sk_state = BT_CONFIG; + l2cap_pi(sk)->ident = 0; + l2cap_pi(sk)->dcid = dcid; + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; + + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, + l2cap_build_conf_req(sk, req), req); + l2cap_pi(sk)->num_conf_req++; + break; + + case L2CAP_CR_PEND: + l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + break; + + default: + /* sync kernel.org patch. commit a49184c229535ebedbb659214db2d4d1d77b7c07 */ + /* don't delete l2cap channel if sk is owned by user */ + if (sock_owned_by_user(sk)) { + sk->sk_state = BT_DISCONN; + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ / 5); + break; + } + + l2cap_chan_del(sk, ECONNREFUSED); + break; + } + + bh_unlock_sock(sk); + return 0; +} + +static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) +{ + struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; + u16 dcid, flags; + u8 rsp[64]; + struct sock *sk; + int len; + + dcid = __le16_to_cpu(req->dcid); + flags = __le16_to_cpu(req->flags); + + BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); + + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) + return -ENOENT; + + if (sk->sk_state == BT_DISCONN) + goto unlock; + + /* Reject if config buffer is too small. */ + len = cmd_len - sizeof(*req); + if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) { + l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, + l2cap_build_conf_rsp(sk, rsp, + L2CAP_CONF_REJECT, flags), rsp); + goto unlock; + } + + /* Store config. */ + memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len); + l2cap_pi(sk)->conf_len += len; + + if (flags & 0x0001) { + /* Incomplete config. Send empty response. */ + l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, + l2cap_build_conf_rsp(sk, rsp, + L2CAP_CONF_SUCCESS, 0x0001), rsp); + goto unlock; + } + + /* Complete config. */ + len = l2cap_parse_conf_req(sk, rsp); + if (len < 0) { + l2cap_send_disconn_req(conn, sk); + goto unlock; + } + + l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); + l2cap_pi(sk)->num_conf_rsp++; + + /* Reset config buffer. */ + l2cap_pi(sk)->conf_len = 0; + + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE)) + goto unlock; + + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) || + l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) + l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; + + sk->sk_state = BT_CONNECTED; + + l2cap_pi(sk)->next_tx_seq = 0; + l2cap_pi(sk)->expected_tx_seq = 0; + __skb_queue_head_init(TX_QUEUE(sk)); + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + l2cap_ertm_init(sk); + + l2cap_chan_ready(sk); + goto unlock; + } + + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { + u8 buf[64]; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, + l2cap_build_conf_req(sk, buf), buf); + l2cap_pi(sk)->num_conf_req++; + } + +unlock: + bh_unlock_sock(sk); + return 0; +} + +static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; + u16 scid, flags, result; + struct sock *sk; + int len = cmd->len - sizeof(*rsp); + + scid = __le16_to_cpu(rsp->scid); + flags = __le16_to_cpu(rsp->flags); + result = __le16_to_cpu(rsp->result); + + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", + scid, flags, result); + + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) + return 0; + + switch (result) { + case L2CAP_CONF_SUCCESS: + l2cap_conf_rfc_get(sk, rsp->data, len); + break; + + case L2CAP_CONF_UNACCEPT: + if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { + char req[64]; + + if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { + l2cap_send_disconn_req(conn, sk); + goto done; + } + + /* throw out any old stored conf requests */ + result = L2CAP_CONF_SUCCESS; + len = l2cap_parse_conf_rsp(sk, rsp->data, + len, req, &result); + if (len < 0) { + l2cap_send_disconn_req(conn, sk); + goto done; + } + + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_CONF_REQ, len, req); + l2cap_pi(sk)->num_conf_req++; + if (result != L2CAP_CONF_SUCCESS) + goto done; + break; + } + + default: + sk->sk_state = BT_DISCONN; + sk->sk_err = ECONNRESET; + l2cap_sock_set_timer(sk, HZ * 5); + l2cap_send_disconn_req(conn, sk); + goto done; + } + + if (flags & 0x01) + goto done; + + l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; + + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) || + l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) + l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; + + sk->sk_state = BT_CONNECTED; + l2cap_pi(sk)->next_tx_seq = 0; + l2cap_pi(sk)->expected_tx_seq = 0; + __skb_queue_head_init(TX_QUEUE(sk)); + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + l2cap_ertm_init(sk); + + l2cap_chan_ready(sk); + } + +done: + bh_unlock_sock(sk); + return 0; +} + +static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data; + struct l2cap_disconn_rsp rsp; + u16 dcid, scid; + struct sock *sk; + + scid = __le16_to_cpu(req->scid); + dcid = __le16_to_cpu(req->dcid); + + BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); + + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) + return 0; + + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); + + sk->sk_shutdown = SHUTDOWN_MASK; + + skb_queue_purge(TX_QUEUE(sk)); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + skb_queue_purge(SREJ_QUEUE(sk)); + skb_queue_purge(BUSY_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + del_timer(&l2cap_pi(sk)->ack_timer); + } + + /* sync kernel.org patch. commit a49184c229535ebedbb659214db2d4d1d77b7c07 */ + /* don't delete l2cap channel if sk is owned by user */ + if (sock_owned_by_user(sk)) { + sk->sk_state = BT_DISCONN; + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ / 5); + bh_unlock_sock(sk); + return 0; + } + + l2cap_chan_del(sk, ECONNRESET); + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); + return 0; +} + +static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; + u16 dcid, scid; + struct sock *sk; + + scid = __le16_to_cpu(rsp->scid); + dcid = __le16_to_cpu(rsp->dcid); + + BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); + + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) + return 0; + + skb_queue_purge(TX_QUEUE(sk)); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + skb_queue_purge(SREJ_QUEUE(sk)); + skb_queue_purge(BUSY_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + del_timer(&l2cap_pi(sk)->ack_timer); + } + + /* sync kernel.org patch. commit a49184c229535ebedbb659214db2d4d1d77b7c07 */ + /* don't delete l2cap channel if sk is owned by user */ + if (sock_owned_by_user(sk)) { + sk->sk_state = BT_DISCONN; + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ / 5); + bh_unlock_sock(sk); + return 0; + } + l2cap_chan_del(sk, 0); + bh_unlock_sock(sk); + + l2cap_sock_kill(sk); + return 0; +} + +static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_info_req *req = (struct l2cap_info_req *) data; + u16 type; + + type = __le16_to_cpu(req->type); + + BT_DBG("type 0x%4.4x", type); + + if (type == L2CAP_IT_FEAT_MASK) { + u8 buf[8]; + u32 feat_mask = l2cap_feat_mask; + struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; + rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); + if (enable_ertm) + feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING + | L2CAP_FEAT_FCS; + put_unaligned_le32(feat_mask, rsp->data); + l2cap_send_cmd(conn, cmd->ident, + L2CAP_INFO_RSP, sizeof(buf), buf); + } else if (type == L2CAP_IT_FIXED_CHAN) { + u8 buf[12]; + struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; + rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); + rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); + memcpy(buf + 4, l2cap_fixed_chan, 8); + l2cap_send_cmd(conn, cmd->ident, + L2CAP_INFO_RSP, sizeof(buf), buf); + } else { + struct l2cap_info_rsp rsp; + rsp.type = cpu_to_le16(type); + rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP); + l2cap_send_cmd(conn, cmd->ident, + L2CAP_INFO_RSP, sizeof(rsp), &rsp); + } + + return 0; +} + +static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; + u16 type, result; + + type = __le16_to_cpu(rsp->type); + result = __le16_to_cpu(rsp->result); + + BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); + + del_timer(&conn->info_timer); + + if (type == L2CAP_IT_FEAT_MASK) { + conn->feat_mask = get_unaligned_le32(rsp->data); + + if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { + struct l2cap_info_req req; + req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); + + conn->info_ident = l2cap_get_ident(conn); + + l2cap_send_cmd(conn, conn->info_ident, + L2CAP_INFO_REQ, sizeof(req), &req); + } else { + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + conn->info_ident = 0; + + l2cap_conn_start(conn); + } + } else if (type == L2CAP_IT_FIXED_CHAN) { + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + conn->info_ident = 0; + + l2cap_conn_start(conn); + } + + return 0; +} + +static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) +{ + u8 *data = skb->data; + int len = skb->len; + struct l2cap_cmd_hdr cmd; + int err = 0; + + l2cap_raw_recv(conn, skb); + + while (len >= L2CAP_CMD_HDR_SIZE) { + u16 cmd_len; + memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); + data += L2CAP_CMD_HDR_SIZE; + len -= L2CAP_CMD_HDR_SIZE; + + cmd_len = le16_to_cpu(cmd.len); + + BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident); + + if (cmd_len > len || !cmd.ident) { + BT_DBG("corrupted command"); + break; + } + + switch (cmd.code) { + case L2CAP_COMMAND_REJ: + l2cap_command_rej(conn, &cmd, data); + break; + + case L2CAP_CONN_REQ: + err = l2cap_connect_req(conn, &cmd, data); + break; + + case L2CAP_CONN_RSP: + err = l2cap_connect_rsp(conn, &cmd, data); + break; + + case L2CAP_CONF_REQ: + err = l2cap_config_req(conn, &cmd, cmd_len, data); + break; + + case L2CAP_CONF_RSP: + err = l2cap_config_rsp(conn, &cmd, data); + break; + + case L2CAP_DISCONN_REQ: + err = l2cap_disconnect_req(conn, &cmd, data); + break; + + case L2CAP_DISCONN_RSP: + err = l2cap_disconnect_rsp(conn, &cmd, data); + break; + + case L2CAP_ECHO_REQ: + l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd_len, data); + break; + + case L2CAP_ECHO_RSP: + break; + + case L2CAP_INFO_REQ: + err = l2cap_information_req(conn, &cmd, data); + break; + + case L2CAP_INFO_RSP: + err = l2cap_information_rsp(conn, &cmd, data); + break; + + default: + BT_ERR("Unknown signaling command 0x%2.2x", cmd.code); + err = -EINVAL; + break; + } + + if (err) { + struct l2cap_cmd_rej rej; + BT_DBG("error %d", err); + + /* FIXME: Map err to a valid reason */ + rej.reason = cpu_to_le16(0); + l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); + } + + data += cmd_len; + len -= cmd_len; + } + + kfree_skb(skb); +} + +static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) +{ + u16 our_fcs, rcv_fcs; + int hdr_size = L2CAP_HDR_SIZE + 2; + + if (pi->fcs == L2CAP_FCS_CRC16) { + skb_trim(skb, skb->len - 2); + rcv_fcs = get_unaligned_le16(skb->data + skb->len); + our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); + + if (our_fcs != rcv_fcs) + return -EINVAL; + } + return 0; +} + +static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control = 0; + + pi->frames_sent = 0; + pi->conn_state |= L2CAP_CONN_SEND_FBIT; + + control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL; + l2cap_send_sframe(pi, control); + pi->conn_state |= L2CAP_CONN_RNR_SENT; + pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + + if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0) + __mod_retrans_timer(); + + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + + spin_lock_bh(&pi->send_lock); + l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + + if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && + pi->frames_sent == 0) { + control |= L2CAP_SUPER_RCV_READY; + l2cap_send_sframe(pi, control); + } +} + +static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) +{ + struct sk_buff *next_skb; + + bt_cb(skb)->tx_seq = tx_seq; + bt_cb(skb)->sar = sar; + + next_skb = skb_peek(SREJ_QUEUE(sk)); + if (!next_skb) { + __skb_queue_tail(SREJ_QUEUE(sk), skb); + return 0; + } + + do { + if (bt_cb(next_skb)->tx_seq == tx_seq) + return -EINVAL; + + if (bt_cb(next_skb)->tx_seq > tx_seq) { + __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); + return 0; + } + + if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) + break; + + } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); + + __skb_queue_tail(SREJ_QUEUE(sk), skb); + + return 0; +} + +static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *_skb; + int err; + + switch (control & L2CAP_CTRL_SAR) { + case L2CAP_SDU_UNSEGMENTED: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) + goto drop; + + err = sock_queue_rcv_skb(sk, skb); + if (!err) + return err; + + break; + + case L2CAP_SDU_START: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) + goto drop; + + pi->sdu_len = get_unaligned_le16(skb->data); + + if (pi->sdu_len > pi->imtu) + goto disconnect; + + pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); + if (!pi->sdu) + return -ENOMEM; + + /* pull sdu_len bytes only after alloc, because of Local Busy + * condition we have to be sure that this will be executed + * only once, i.e., when alloc does not fail */ + skb_pull(skb, 2); + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->conn_state |= L2CAP_CONN_SAR_SDU; + pi->partial_sdu_len = skb->len; + break; + + case L2CAP_SDU_CONTINUE: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + goto disconnect; + + if (!pi->sdu) + goto disconnect; + + pi->partial_sdu_len += skb->len; + if (pi->partial_sdu_len > pi->sdu_len) + goto drop; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + break; + + case L2CAP_SDU_END: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + goto disconnect; + + if (!pi->sdu) + goto disconnect; + + if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) { + pi->partial_sdu_len += skb->len; + + if (pi->partial_sdu_len > pi->imtu) + goto drop; + + if (pi->partial_sdu_len != pi->sdu_len) + goto drop; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + } + + _skb = skb_clone(pi->sdu, GFP_ATOMIC); + if (!_skb) { + pi->conn_state |= L2CAP_CONN_SAR_RETRY; + return -ENOMEM; + } + + err = sock_queue_rcv_skb(sk, _skb); + if (err < 0) { + kfree_skb(_skb); + pi->conn_state |= L2CAP_CONN_SAR_RETRY; + return err; + } + + pi->conn_state &= ~L2CAP_CONN_SAR_RETRY; + pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + + kfree_skb(pi->sdu); + break; + } + + kfree_skb(skb); + return 0; + +drop: + kfree_skb(pi->sdu); + pi->sdu = NULL; + +disconnect: + l2cap_send_disconn_req(pi->conn, sk); + kfree_skb(skb); + return 0; +} + +static void l2cap_busy_work(struct work_struct *work) +{ + DECLARE_WAITQUEUE(wait, current); + struct l2cap_pinfo *pi = + container_of(work, struct l2cap_pinfo, busy_work); + struct sock *sk = (struct sock *)pi; + int n_tries = 0, timeo = HZ/5, err; + struct sk_buff *skb; + u16 control; + + lock_sock(sk); + + add_wait_queue(sk_sleep(sk), &wait); + while ((skb = skb_peek(BUSY_QUEUE(sk)))) { + set_current_state(TASK_INTERRUPTIBLE); + + if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { + err = -EBUSY; + l2cap_send_disconn_req(pi->conn, sk); + goto done; + } + + if (!timeo) + timeo = HZ/5; + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + goto done; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + err = sock_error(sk); + if (err) + goto done; + + while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { + control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; + err = l2cap_ertm_reassembly_sdu(sk, skb, control); + if (err < 0) { + skb_queue_head(BUSY_QUEUE(sk), skb); + break; + } + + pi->buffer_seq = (pi->buffer_seq + 1) % 64; + } + + if (!skb) + break; + } + + if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) + goto done; + + control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; + l2cap_send_sframe(pi, control); + l2cap_pi(sk)->retry_count = 1; + + del_timer(&pi->retrans_timer); + __mod_monitor_timer(); + + l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + +done: + pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; + pi->conn_state &= ~L2CAP_CONN_RNR_SENT; + + set_current_state(TASK_RUNNING); + remove_wait_queue(sk_sleep(sk), &wait); + + release_sock(sk); +} + +static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int sctrl, err; + + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; + __skb_queue_tail(BUSY_QUEUE(sk), skb); + return -EBUSY; + } + + err = l2cap_ertm_reassembly_sdu(sk, skb, control); + if (err >= 0) { + pi->buffer_seq = (pi->buffer_seq + 1) % 64; + return err; + } + + /* Busy Condition */ + pi->conn_state |= L2CAP_CONN_LOCAL_BUSY; + bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; + __skb_queue_tail(BUSY_QUEUE(sk), skb); + + sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + sctrl |= L2CAP_SUPER_RCV_NOT_READY; + l2cap_send_sframe(pi, sctrl); + + pi->conn_state |= L2CAP_CONN_RNR_SENT; + + queue_work(_busy_wq, &pi->busy_work); + + return err; +} + +static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *_skb; + int err = -EINVAL; + + /* + * TODO: We have to notify the userland if some data is lost with the + * Streaming Mode. + */ + + switch (control & L2CAP_CTRL_SAR) { + case L2CAP_SDU_UNSEGMENTED: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + kfree_skb(pi->sdu); + break; + } + + err = sock_queue_rcv_skb(sk, skb); + if (!err) + return 0; + + break; + + case L2CAP_SDU_START: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + kfree_skb(pi->sdu); + break; + } + + pi->sdu_len = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + + if (pi->sdu_len > pi->imtu) { + err = -EMSGSIZE; + break; + } + + pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); + if (!pi->sdu) { + err = -ENOMEM; + break; + } + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->conn_state |= L2CAP_CONN_SAR_SDU; + pi->partial_sdu_len = skb->len; + err = 0; + break; + + case L2CAP_SDU_CONTINUE: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + break; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->partial_sdu_len += skb->len; + if (pi->partial_sdu_len > pi->sdu_len) + kfree_skb(pi->sdu); + else + err = 0; + + break; + + case L2CAP_SDU_END: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + break; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + pi->partial_sdu_len += skb->len; + + if (pi->partial_sdu_len > pi->imtu) + goto drop; + + if (pi->partial_sdu_len == pi->sdu_len) { + _skb = skb_clone(pi->sdu, GFP_ATOMIC); + err = sock_queue_rcv_skb(sk, _skb); + if (err < 0) + kfree_skb(_skb); + } + err = 0; + +drop: + kfree_skb(pi->sdu); + break; + } + + kfree_skb(skb); + return err; +} + +static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) +{ + struct sk_buff *skb; + u16 control; + + while ((skb = skb_peek(SREJ_QUEUE(sk)))) { + if (bt_cb(skb)->tx_seq != tx_seq) + break; + + skb = skb_dequeue(SREJ_QUEUE(sk)); + control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; + l2cap_ertm_reassembly_sdu(sk, skb, control); + l2cap_pi(sk)->buffer_seq_srej = + (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; + tx_seq++; + } +} + +static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct srej_list *l, *tmp; + u16 control; + + list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { + if (l->tx_seq == tx_seq) { + list_del(&l->list); + kfree(l); + return; + } + control = L2CAP_SUPER_SELECT_REJECT; + control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + l2cap_send_sframe(pi, control); + list_del(&l->list); + list_add_tail(&l->list, SREJ_LIST(sk)); + } +} + +static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct srej_list *new; + u16 control; + + while (tx_seq != pi->expected_tx_seq) { + control = L2CAP_SUPER_SELECT_REJECT; + control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + l2cap_send_sframe(pi, control); + + new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); + new->tx_seq = pi->expected_tx_seq++; + list_add_tail(&new->list, SREJ_LIST(sk)); + } + pi->expected_tx_seq++; +} + +static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_txseq(rx_control); + u8 req_seq = __get_reqseq(rx_control); + u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; + u8 tx_seq_offset, expected_tx_seq_offset; + int num_to_ack = (pi->tx_win/6) + 1; + int err = 0; + + BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + + if (L2CAP_CTRL_FINAL & rx_control && + l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { + del_timer(&pi->monitor_timer); + if (pi->unacked_frames > 0) + __mod_retrans_timer(); + pi->conn_state &= ~L2CAP_CONN_WAIT_F; + } + + pi->expected_ack_seq = req_seq; + l2cap_drop_acked_frames(sk); + + if (tx_seq == pi->expected_tx_seq) + goto expected; + + tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; + if (tx_seq_offset < 0) + tx_seq_offset += 64; + + /* invalid tx_seq */ + if (tx_seq_offset >= pi->tx_win) { + l2cap_send_disconn_req(pi->conn, sk); + goto drop; + } + + if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY) + goto drop; + + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + struct srej_list *first; + + first = list_first_entry(SREJ_LIST(sk), + struct srej_list, list); + if (tx_seq == first->tx_seq) { + l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + l2cap_check_srej_gap(sk, tx_seq); + + list_del(&first->list); + kfree(first); + + if (list_empty(SREJ_LIST(sk))) { + pi->buffer_seq = pi->buffer_seq_srej; + pi->conn_state &= ~L2CAP_CONN_SREJ_SENT; + l2cap_send_ack(pi); + } + } else { + struct srej_list *l; + + /* duplicated tx_seq */ + if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0) + goto drop; + + list_for_each_entry(l, SREJ_LIST(sk), list) { + if (l->tx_seq == tx_seq) { + l2cap_resend_srejframe(sk, tx_seq); + return 0; + } + } + l2cap_send_srejframe(sk, tx_seq); + } + } else { + expected_tx_seq_offset = + (pi->expected_tx_seq - pi->buffer_seq) % 64; + if (expected_tx_seq_offset < 0) + expected_tx_seq_offset += 64; + + /* duplicated tx_seq */ + if (tx_seq_offset < expected_tx_seq_offset) + goto drop; + + pi->conn_state |= L2CAP_CONN_SREJ_SENT; + + INIT_LIST_HEAD(SREJ_LIST(sk)); + pi->buffer_seq_srej = pi->buffer_seq; + + __skb_queue_head_init(SREJ_QUEUE(sk)); + __skb_queue_head_init(BUSY_QUEUE(sk)); + l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + + pi->conn_state |= L2CAP_CONN_SEND_PBIT; + + l2cap_send_srejframe(sk, tx_seq); + } + return 0; + +expected: + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + bt_cb(skb)->tx_seq = tx_seq; + bt_cb(skb)->sar = sar; + __skb_queue_tail(SREJ_QUEUE(sk), skb); + return 0; + } + + if (rx_control & L2CAP_CTRL_FINAL) { + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else + l2cap_retransmit_frames(sk); + } + + err = l2cap_push_rx_skb(sk, skb, rx_control); + if (err < 0) + return 0; + + __mod_ack_timer(); + + pi->num_acked = (pi->num_acked + 1) % num_to_ack; + if (pi->num_acked == num_to_ack - 1) + l2cap_send_ack(pi); + + return 0; + +drop: + kfree_skb(skb); + return 0; +} + +static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + + pi->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(sk); + + if (rx_control & L2CAP_CTRL_POLL) { + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (pi->unacked_frames > 0)) + __mod_retrans_timer(); + + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + l2cap_send_srejtail(sk); + } else { + l2cap_send_i_or_rr_or_rnr(sk); + } + + } else if (rx_control & L2CAP_CTRL_FINAL) { + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else + l2cap_retransmit_frames(sk); + + } else { + if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (pi->unacked_frames > 0)) + __mod_retrans_timer(); + + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + l2cap_send_ack(pi); + } else { + spin_lock_bh(&pi->send_lock); + l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + } + } +} + +static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_reqseq(rx_control); + + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); + + if (rx_control & L2CAP_CTRL_FINAL) { + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else + l2cap_retransmit_frames(sk); + } else { + l2cap_retransmit_frames(sk); + + if (pi->conn_state & L2CAP_CONN_WAIT_F) + pi->conn_state |= L2CAP_CONN_REJ_ACT; + } +} +static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_reqseq(rx_control); + + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + + if (rx_control & L2CAP_CTRL_POLL) { + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); + l2cap_retransmit_one_frame(sk, tx_seq); + + spin_lock_bh(&pi->send_lock); + l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_SREJ_ACT; + } + } else if (rx_control & L2CAP_CTRL_FINAL) { + if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && + pi->srej_save_reqseq == tx_seq) + pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; + else + l2cap_retransmit_one_frame(sk, tx_seq); + } else { + l2cap_retransmit_one_frame(sk, tx_seq); + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_SREJ_ACT; + } + } +} + +static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_reqseq(rx_control); + + pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); + + if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) { + del_timer(&pi->retrans_timer); + if (rx_control & L2CAP_CTRL_POLL) + l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL); + return; + } + + if (rx_control & L2CAP_CTRL_POLL) + l2cap_send_srejtail(sk); + else + l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY); +} + +static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +{ + BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + + if (L2CAP_CTRL_FINAL & rx_control && + l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { + del_timer(&l2cap_pi(sk)->monitor_timer); + if (l2cap_pi(sk)->unacked_frames > 0) + __mod_retrans_timer(); + l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F; + } + + switch (rx_control & L2CAP_CTRL_SUPERVISE) { + case L2CAP_SUPER_RCV_READY: + l2cap_data_channel_rrframe(sk, rx_control); + break; + + case L2CAP_SUPER_REJECT: + l2cap_data_channel_rejframe(sk, rx_control); + break; + + case L2CAP_SUPER_SELECT_REJECT: + l2cap_data_channel_srejframe(sk, rx_control); + break; + + case L2CAP_SUPER_RCV_NOT_READY: + l2cap_data_channel_rnrframe(sk, rx_control); + break; + } + + kfree_skb(skb); + return 0; +} + +static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) +{ + struct sock *sk; + struct l2cap_pinfo *pi; + u16 control, len; + u8 tx_seq, req_seq, next_tx_seq_offset, req_seq_offset; + + sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); + if (!sk) { + BT_DBG("unknown cid 0x%4.4x", cid); + goto drop; + } + + pi = l2cap_pi(sk); + + BT_DBG("sk %p, len %d", sk, skb->len); + + if (sk->sk_state != BT_CONNECTED) + goto drop; + + switch (pi->mode) { + case L2CAP_MODE_BASIC: + /* If socket recv buffers overflows we drop data here + * which is *bad* because L2CAP has to be reliable. + * But we don't have any other choice. L2CAP doesn't + * provide flow control mechanism. */ + + if (pi->imtu < skb->len) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) + goto done; + break; + + case L2CAP_MODE_ERTM: + control = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + len = skb->len; + + if (__is_sar_start(control)) + len -= 2; + + if (pi->fcs == L2CAP_FCS_CRC16) + len -= 2; + + /* + * We can just drop the corrupted I-frame here. + * Receiver will miss it and start proper recovery + * procedures and ask retransmission. + */ + if (len > pi->mps) { + l2cap_send_disconn_req(pi->conn, sk); + goto drop; + } + + if (l2cap_check_fcs(pi, skb)) + goto drop; + + req_seq = __get_reqseq(control); + req_seq_offset = (req_seq - pi->expected_ack_seq) % 64; + if (req_seq_offset < 0) + req_seq_offset += 64; + + next_tx_seq_offset = + (pi->next_tx_seq - pi->expected_ack_seq) % 64; + if (next_tx_seq_offset < 0) + next_tx_seq_offset += 64; + + /* check for invalid req-seq */ + if (req_seq_offset > next_tx_seq_offset) { + l2cap_send_disconn_req(pi->conn, sk); + goto drop; + } + + if (__is_iframe(control)) { + if (len < 4) { + l2cap_send_disconn_req(pi->conn, sk); + goto drop; + } + + l2cap_data_channel_iframe(sk, control, skb); + } else { + if (len != 0) { + l2cap_send_disconn_req(pi->conn, sk); + goto drop; + } + + l2cap_data_channel_sframe(sk, control, skb); + } + + goto done; + + case L2CAP_MODE_STREAMING: + control = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + len = skb->len; + + if (__is_sar_start(control)) + len -= 2; + + if (pi->fcs == L2CAP_FCS_CRC16) + len -= 2; + + if (len > pi->mps || len < 4 || __is_sframe(control)) + goto drop; + + if (l2cap_check_fcs(pi, skb)) + goto drop; + + tx_seq = __get_txseq(control); + + if (pi->expected_tx_seq == tx_seq) + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + else + pi->expected_tx_seq = (tx_seq + 1) % 64; + + l2cap_streaming_reassembly_sdu(sk, skb, control); + + goto done; + + default: + BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode); + break; + } + +drop: + kfree_skb(skb); + +done: + if (sk) + bh_unlock_sock(sk); + + return 0; +} + +static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) +{ + struct sock *sk; + + sk = l2cap_get_sock_by_psm(0, psm, conn->src); + if (!sk) + goto drop; + + BT_DBG("sk %p, len %d", sk, skb->len); + + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) + goto drop; + + if (l2cap_pi(sk)->imtu < skb->len) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) + goto done; + +drop: + kfree_skb(skb); + +done: + if (sk) + bh_unlock_sock(sk); + return 0; +} + +static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) +{ + struct l2cap_hdr *lh = (void *) skb->data; + u16 cid, len; + __le16 psm; + + skb_pull(skb, L2CAP_HDR_SIZE); + cid = __le16_to_cpu(lh->cid); + len = __le16_to_cpu(lh->len); + + if (len != skb->len) { + kfree_skb(skb); + return; + } + + BT_DBG("len %d, cid 0x%4.4x", len, cid); + + switch (cid) { + case L2CAP_CID_SIGNALING: + l2cap_sig_channel(conn, skb); + break; + + case L2CAP_CID_CONN_LESS: + psm = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + l2cap_conless_channel(conn, psm, skb); + break; + + default: + l2cap_data_channel(conn, cid, skb); + break; + } +} + +/* ---- L2CAP interface with lower layer (HCI) ---- */ + +static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) +{ + int exact = 0, lm1 = 0, lm2 = 0; + register struct sock *sk; + struct hlist_node *node; + + if (type != ACL_LINK) + return 0; + + BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); + + /* Find listening sockets and check their link_mode */ + read_lock(&l2cap_sk_list.lock); + sk_for_each(sk, node, &l2cap_sk_list.head) { + if (sk->sk_state != BT_LISTEN) + continue; + + if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { + lm1 |= HCI_LM_ACCEPT; + if (l2cap_pi(sk)->role_switch) + lm1 |= HCI_LM_MASTER; + exact++; + } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { + lm2 |= HCI_LM_ACCEPT; + if (l2cap_pi(sk)->role_switch) + lm2 |= HCI_LM_MASTER; + } + } + read_unlock(&l2cap_sk_list.lock); + + return exact ? lm1 : lm2; +} + +static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) +{ + struct l2cap_conn *conn; + + BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); + + if (hcon->type != ACL_LINK) + return 0; + + if (!status) { + conn = l2cap_conn_add(hcon, status); + if (conn) + l2cap_conn_ready(conn); + } else + l2cap_conn_del(hcon, bt_err(status)); + + return 0; +} + +static int l2cap_disconn_ind(struct hci_conn *hcon) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + + BT_DBG("hcon %p", hcon); + + if (hcon->type != ACL_LINK || !conn) + return 0x13; + + return conn->disc_reason; +} + +static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) +{ + BT_DBG("hcon %p reason %d", hcon, reason); + + if (hcon->type != ACL_LINK) + return 0; + + l2cap_conn_del(hcon, bt_err(reason)); + + return 0; +} + +static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) +{ + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) + return; + + if (encrypt == 0x00) { + if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) { + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ * 5); + } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + __l2cap_sock_close(sk, ECONNREFUSED); + } else { + if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) + l2cap_sock_clear_timer(sk); + } +} + +static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) +{ + struct l2cap_chan_list *l; + struct l2cap_conn *conn = hcon->l2cap_data; + struct sock *sk; + + if (!conn) + return 0; + + l = &conn->chan_list; + + BT_DBG("conn %p", conn); + + read_lock(&l->lock); + + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + bh_lock_sock(sk); + + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { + bh_unlock_sock(sk); + continue; + } + + if (!status && (sk->sk_state == BT_CONNECTED || + sk->sk_state == BT_CONFIG)) { + l2cap_check_encryption(sk, encrypt); + bh_unlock_sock(sk); + continue; + } + + if (sk->sk_state == BT_CONNECT) { + if (!status) { + struct l2cap_conn_req req; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + + l2cap_pi(sk)->ident = l2cap_get_ident(conn); + l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_REQ, sizeof(req), &req); + } else { + l2cap_sock_clear_timer(sk); + l2cap_sock_set_timer(sk, HZ / 10); + } + } else if (sk->sk_state == BT_CONNECT2) { + struct l2cap_conn_rsp rsp; + __u16 result; + + if (!status) { + sk->sk_state = BT_CONFIG; + result = L2CAP_CR_SUCCESS; + } else { + sk->sk_state = BT_DISCONN; + l2cap_sock_set_timer(sk, HZ / 10); + result = L2CAP_CR_SEC_BLOCK; + } + + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = cpu_to_le16(result); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + } + + bh_unlock_sock(sk); + } + + read_unlock(&l->lock); + + return 0; +} + +static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + + if (!conn && !(conn = l2cap_conn_add(hcon, 0))) + goto drop; + + BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); + + if (!(flags & ACL_CONT)) { + struct l2cap_hdr *hdr; + int len; + + if (conn->rx_len) { + BT_ERR("Unexpected start frame (len %d)", skb->len); + kfree_skb(conn->rx_skb); + conn->rx_skb = NULL; + conn->rx_len = 0; + l2cap_conn_unreliable(conn, ECOMM); + } + + if (skb->len < 2) { + BT_ERR("Frame is too short (len %d)", skb->len); + l2cap_conn_unreliable(conn, ECOMM); + goto drop; + } + + hdr = (struct l2cap_hdr *) skb->data; + len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; + + if (len == skb->len) { + /* Complete frame received */ + l2cap_recv_frame(conn, skb); + return 0; + } + + BT_DBG("Start: total len %d, frag len %d", len, skb->len); + + if (skb->len > len) { + BT_ERR("Frame is too long (len %d, expected len %d)", + skb->len, len); + l2cap_conn_unreliable(conn, ECOMM); + goto drop; + } + + /* Allocate skb for the complete frame (with header) */ + conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!conn->rx_skb) + goto drop; + + skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), + skb->len); + conn->rx_len = len - skb->len; + } else { + BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); + + if (!conn->rx_len) { + BT_ERR("Unexpected continuation frame (len %d)", skb->len); + l2cap_conn_unreliable(conn, ECOMM); + goto drop; + } + + if (skb->len > conn->rx_len) { + BT_ERR("Fragment is too long (len %d, expected %d)", + skb->len, conn->rx_len); + kfree_skb(conn->rx_skb); + conn->rx_skb = NULL; + conn->rx_len = 0; + l2cap_conn_unreliable(conn, ECOMM); + goto drop; + } + + skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), + skb->len); + conn->rx_len -= skb->len; + + if (!conn->rx_len) { + /* Complete frame received */ + l2cap_recv_frame(conn, conn->rx_skb); + conn->rx_skb = NULL; + } + } + +drop: + kfree_skb(skb); + return 0; +} + +static int l2cap_debugfs_show(struct seq_file *f, void *p) +{ + struct sock *sk; + struct hlist_node *node; + + read_lock_bh(&l2cap_sk_list.lock); + + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_pinfo *pi = l2cap_pi(sk); + + seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", + batostr(&bt_sk(sk)->src), + batostr(&bt_sk(sk)->dst), + sk->sk_state, __le16_to_cpu(pi->psm), + pi->scid, pi->dcid, + pi->imtu, pi->omtu, pi->sec_level); + } + + read_unlock_bh(&l2cap_sk_list.lock); + + return 0; +} + +static int l2cap_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, l2cap_debugfs_show, inode->i_private); +} + +static const struct file_operations l2cap_debugfs_fops = { + .open = l2cap_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *l2cap_debugfs; + +static const struct proto_ops l2cap_sock_ops = { + .family = PF_BLUETOOTH, + .owner = THIS_MODULE, + .release = l2cap_sock_release, + .bind = l2cap_sock_bind, + .connect = l2cap_sock_connect, + .listen = l2cap_sock_listen, + .accept = l2cap_sock_accept, + .getname = l2cap_sock_getname, + .sendmsg = l2cap_sock_sendmsg, + .recvmsg = l2cap_sock_recvmsg, + .poll = bt_sock_poll, + .ioctl = bt_sock_ioctl, + .mmap = sock_no_mmap, + .socketpair = sock_no_socketpair, + .shutdown = l2cap_sock_shutdown, + .setsockopt = l2cap_sock_setsockopt, + .getsockopt = l2cap_sock_getsockopt +}; + +static const struct net_proto_family l2cap_sock_family_ops = { + .family = PF_BLUETOOTH, + .owner = THIS_MODULE, + .create = l2cap_sock_create, +}; + +static struct hci_proto l2cap_hci_proto = { + .name = "L2CAP", + .id = HCI_PROTO_L2CAP, + .connect_ind = l2cap_connect_ind, + .connect_cfm = l2cap_connect_cfm, + .disconn_ind = l2cap_disconn_ind, + .disconn_cfm = l2cap_disconn_cfm, + .security_cfm = l2cap_security_cfm, + .recv_acldata = l2cap_recv_acldata +}; + +static int __init l2cap_init(void) +{ + int err; + + err = proto_register(&l2cap_proto, 0); + if (err < 0) + return err; + + _busy_wq = create_singlethread_workqueue("l2cap"); + if (!_busy_wq) + goto error; + + err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); + if (err < 0) { + BT_ERR("L2CAP socket registration failed"); + goto error; + } + + err = hci_register_proto(&l2cap_hci_proto); + if (err < 0) { + BT_ERR("L2CAP protocol registration failed"); + bt_sock_unregister(BTPROTO_L2CAP); + goto error; + } + + if (bt_debugfs) { + l2cap_debugfs = debugfs_create_file("l2cap", 0444, + bt_debugfs, NULL, &l2cap_debugfs_fops); + if (!l2cap_debugfs) + BT_ERR("Failed to create L2CAP debug file"); + } + + BT_INFO("L2CAP ver %s", VERSION); + BT_INFO("L2CAP socket layer initialized"); + + return 0; + +error: + proto_unregister(&l2cap_proto); + return err; +} + +static void __exit l2cap_exit(void) +{ + debugfs_remove(l2cap_debugfs); + + flush_workqueue(_busy_wq); + destroy_workqueue(_busy_wq); + + if (bt_sock_unregister(BTPROTO_L2CAP) < 0) + BT_ERR("L2CAP socket unregistration failed"); + + if (hci_unregister_proto(&l2cap_hci_proto) < 0) + BT_ERR("L2CAP protocol unregistration failed"); + + proto_unregister(&l2cap_proto); +} + +void l2cap_load(void) +{ + /* Dummy function to trigger automatic L2CAP module loading by + * other modules that use L2CAP sockets but don't use any other + * symbols from it. */ +} +EXPORT_SYMBOL(l2cap_load); + +module_init(l2cap_init); +module_exit(l2cap_exit); + +module_param(enable_ertm, bool, 0644); +MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode"); + +module_param(max_transmit, uint, 0644); +MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)"); + +module_param(tx_window, uint, 0644); +MODULE_PARM_DESC(tx_window, "Transmission window size value (default = 63)"); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("bt-proto-0"); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9b1c7dc6..37c485b7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved. + Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved. Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. @@ -25,6 +25,7 @@ */ /* Bluetooth L2CAP core. */ +// rollback to original BlueZ #include @@ -59,11 +60,10 @@ #include bool disable_ertm; -bool enable_hs; bool enable_reconfig; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; -static u8 l2cap_fc_mask = L2CAP_FC_L2CAP; +static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_A2MP, }; struct workqueue_struct *_l2cap_wq; @@ -90,9 +90,7 @@ static int l2cap_answer_move_poll(struct sock *sk); static int l2cap_create_cfm(struct hci_chan *chan, u8 status); static int l2cap_deaggregate(struct hci_chan *chan, struct l2cap_pinfo *pi); static void l2cap_chan_ready(struct sock *sk); -static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process); -static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l); -static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to); +static void l2cap_conn_del(struct hci_conn *hcon, int err); /* ---- L2CAP channels ---- */ static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) @@ -522,11 +520,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } - - if (l2cap_get_smallest_flushto(l) > l2cap_pi(sk)->flush_to) { - /*if flush timeout of the channel is lesser than existing */ - l2cap_set_acl_flushto(conn->hcon, l2cap_pi(sk)->flush_to); - } /* Otherwise, do not set scid/dcid/omtu. These will be set up * by l2cap_fixed_channel_config() */ @@ -546,30 +539,23 @@ void l2cap_chan_del(struct sock *sk, int err) BT_DBG("sk %p, conn %p, err %d", sk, conn, err); if (conn) { - struct l2cap_chan_list *l = &conn->chan_list; /* Unlink from channel list */ - l2cap_chan_unlink(l, sk); + l2cap_chan_unlink(&conn->chan_list, sk); l2cap_pi(sk)->conn = NULL; if (!l2cap_pi(sk)->fixed_channel) hci_conn_put(conn->hcon); - - read_lock(&l->lock); - if (l2cap_pi(sk)->flush_to < l2cap_get_smallest_flushto(l)) - l2cap_set_acl_flushto(conn->hcon, - l2cap_get_smallest_flushto(l)); - read_unlock(&l->lock); } - if (l2cap_pi(sk)->ampchan) { - struct hci_chan *ampchan = l2cap_pi(sk)->ampchan; - struct hci_conn *ampcon = l2cap_pi(sk)->ampcon; - l2cap_pi(sk)->ampchan = NULL; + if (l2cap_pi(sk)->ampcon) { + l2cap_pi(sk)->ampcon->l2cap_data = NULL; l2cap_pi(sk)->ampcon = NULL; + if (l2cap_pi(sk)->ampchan) { + if (!hci_chan_put(l2cap_pi(sk)->ampchan)) + l2cap_deaggregate(l2cap_pi(sk)->ampchan, + l2cap_pi(sk)); + } + l2cap_pi(sk)->ampchan = NULL; l2cap_pi(sk)->amp_id = 0; - if (hci_chan_put(ampchan)) - ampcon->l2cap_data = NULL; - else - l2cap_deaggregate(ampchan, l2cap_pi(sk)); } sk->sk_state = BT_CLOSED; @@ -584,7 +570,6 @@ void l2cap_chan_del(struct sock *sk, int err) } else sk->sk_state_change(sk); - sk->sk_send_head = NULL; skb_queue_purge(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { @@ -755,7 +740,6 @@ static void l2cap_do_start(struct sock *sk) if (l2cap_pi(sk)->amp_pref == BT_AMP_POLICY_PREFER_AMP && - enable_hs && conn->fc_mask & L2CAP_FC_A2MP) amp_create_physical(conn, sk); else @@ -799,7 +783,6 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) if (!conn) return; - sk->sk_send_head = NULL; skb_queue_purge(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { @@ -864,7 +847,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (l2cap_pi(sk)->amp_pref == BT_AMP_POLICY_PREFER_AMP && - enable_hs && conn->fc_mask & L2CAP_FC_A2MP) amp_create_physical(conn, sk); else @@ -932,24 +914,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } /* Find socket with fixed cid with given source and destination bdaddrs. - * Direction of the req/rsp must match. + * Returns closest match, locked. */ -struct sock *l2cap_find_sock_by_fixed_cid_and_dir(__le16 cid, bdaddr_t *src, - bdaddr_t *dst, int incoming) +static struct sock *l2cap_get_sock_by_fixed_scid(int state, + __le16 cid, bdaddr_t *src, bdaddr_t *dst) { struct sock *sk = NULL, *sk1 = NULL; struct hlist_node *node; - BT_DBG(" %d", incoming); - read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { - - if (incoming && !l2cap_pi(sk)->incoming) - continue; - - if (!incoming && l2cap_pi(sk)->incoming) + if (state && sk->sk_state != state) continue; if (l2cap_pi(sk)->scid == cid && !bacmp(&bt_sk(sk)->dst, dst)) { @@ -1030,12 +1006,13 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) l2cap_sock_init(sk, parent); bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - l2cap_pi(sk)->incoming = 1; bt_accept_enqueue(parent, sk); __l2cap_chan_add(conn, sk); + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); + sk->sk_state = BT_CONNECTED; parent->sk_data_ready(parent, 0); @@ -1068,10 +1045,10 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (pending_sec > sec_level) sec_level = pending_sec; - if (smp_conn_security(conn, sec_level)) + if (smp_conn_security(conn, sec_level)) { l2cap_chan_ready(sk); - - hci_conn_put(conn->hcon); + hci_conn_put(conn->hcon); + } } else if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { @@ -1088,9 +1065,6 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) } read_unlock(&l->lock); - - if (conn->hcon->out && conn->hcon->type == LE_LINK) - l2cap_le_conn_ready(conn); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -1162,7 +1136,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) return conn; } -static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process) +static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; struct sock *sk; @@ -1183,15 +1157,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process) BT_DBG("ampcon %p", l2cap_pi(sk)->ampcon); if ((conn->hcon == hcon) || (l2cap_pi(sk)->ampcon == hcon)) { next = l2cap_pi(sk)->next_c; - if (is_process) - lock_sock(sk); - else - bh_lock_sock(sk); + bh_lock_sock(sk); l2cap_chan_del(sk, err); - if (is_process) - release_sock(sk); - else - bh_unlock_sock(sk); + bh_unlock_sock(sk); l2cap_sock_kill(sk); sk = next; } else @@ -1256,7 +1224,7 @@ int l2cap_do_connect(struct sock *sk) struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; - int err; + int err = 0; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); @@ -1280,9 +1248,8 @@ int l2cap_do_connect(struct sock *sk) conn = hcon->l2cap_data; } else { if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) - hcon = hci_le_connect(hdev, 0, dst, - l2cap_pi(sk)->sec_level, auth_type, - &bt_sk(sk)->le_params); + hcon = hci_connect(hdev, LE_LINK, 0, dst, + l2cap_pi(sk)->sec_level, auth_type); else hcon = hci_connect(hdev, ACL_LINK, 0, dst, l2cap_pi(sk)->sec_level, auth_type); @@ -1312,17 +1279,7 @@ int l2cap_do_connect(struct sock *sk) sk->sk_state_change(sk); } else { sk->sk_state = BT_CONNECT; - /* If we have valid LE Params, let timeout override default */ - if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA && - l2cap_sock_le_params_valid(&bt_sk(sk)->le_params)) { - u16 timeout = bt_sk(sk)->le_params.conn_timeout; - - if (timeout) - l2cap_sock_set_timer(sk, - msecs_to_jiffies(timeout*1000)); - } else - l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); sk->sk_state_change(sk); if (hcon->state == BT_CONNECTED) { @@ -1423,11 +1380,6 @@ void l2cap_do_send(struct sock *sk, struct sk_buff *skb) } else { u16 flags; - if (!(pi->conn)) { - kfree_skb(skb); - return; - } - bt_cb(skb)->force_active = pi->force_active; BT_DBG("Sending on BR/EDR connection %p", pi->conn->hcon); @@ -1501,6 +1453,10 @@ int l2cap_ertm_send(struct sock *sk) tx_skb->destructor = l2cap_skb_destructor; atomic_inc(&pi->ertm_queued); + l2cap_do_send(sk, tx_skb); + + BT_DBG("Sent txseq %d", (int)control->txseq); + l2cap_ertm_start_retrans_timer(pi); pi->next_tx_seq = __next_seq(pi->next_tx_seq, pi); @@ -1512,9 +1468,6 @@ int l2cap_ertm_send(struct sock *sk) sk->sk_send_head = NULL; else sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); - - l2cap_do_send(sk, tx_skb); - BT_DBG("Sent txseq %d", (int)control->txseq); } BT_DBG("Sent %d, %d unacked, %d in ERTM queue, %d in HCI queue", sent, @@ -1606,7 +1559,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff **frag; struct sk_buff *final; - int err, sent = 0; + int err = 0, sent = 0; BT_DBG("sk %p, msg %p, len %d, count %d, skb %p", sk, msg, (int)len, (int)count, skb); @@ -1708,7 +1661,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; - int err, count, hlen = L2CAP_HDR_SIZE + 2; + int err = 0, count = 0, hlen = L2CAP_HDR_SIZE + 2; struct l2cap_hdr *lh; BT_DBG("sk %p len %d", sk, (int)len); @@ -1737,7 +1690,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; - int err, count, hlen = L2CAP_HDR_SIZE; + int err = 0, count = 0, hlen = L2CAP_HDR_SIZE; struct l2cap_hdr *lh; BT_DBG("sk %p len %d", sk, (int)len); @@ -1766,7 +1719,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, u16 sdulen, int reseg) { struct sk_buff *skb; - int err, count, hlen; + int err = 0, count = 0, hlen = 0; int reserve = 0; struct l2cap_hdr *lh; u8 fcs = l2cap_pi(sk)->fcs; @@ -1998,10 +1951,10 @@ static void l2cap_ertm_send_ack(struct sock *sk) frames_to_ack = 0; } - /* Ack now if the window is 3/4ths full. + /* Ack now if the tx window is 3/4ths full. * Calculate without mul or div */ - threshold = pi->ack_win; + threshold = pi->tx_win; threshold += threshold << 1; threshold >>= 2; @@ -2731,7 +2684,7 @@ void l2cap_amp_move_init(struct sock *sk) if (!l2cap_pi(sk)->conn) return; - if (!(l2cap_pi(sk)->conn->fc_mask & L2CAP_FC_A2MP) || !enable_hs) + if (!(l2cap_pi(sk)->conn->fc_mask & L2CAP_FC_A2MP)) return; if (l2cap_pi(sk)->amp_id == 0) { @@ -3067,8 +3020,7 @@ void l2cap_ertm_recv_done(struct sock *sk) { lock_sock(sk); - if (l2cap_pi(sk)->mode != L2CAP_MODE_ERTM || - sk->sk_state != BT_CONNECTED) { + if (l2cap_pi(sk)->mode != L2CAP_MODE_ERTM) { release_sock(sk); return; } @@ -3110,7 +3062,6 @@ static void l2cap_setup_txwin(struct l2cap_pinfo *pi) pi->tx_win_max = L2CAP_TX_WIN_MAX_ENHANCED; pi->extended_control = 0; } - pi->ack_win = pi->tx_win; } static void l2cap_aggregate_fs(struct hci_ext_fs *cur, @@ -3206,9 +3157,8 @@ static int l2cap_deaggregate(struct hci_chan *chan, struct l2cap_pinfo *pi) return 1; } -static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct sock *sk) +static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct l2cap_pinfo *pi) { - struct l2cap_pinfo *pi = l2cap_pi(sk); struct hci_dev *hdev; struct hci_conn *hcon; struct hci_chan *chan; @@ -3228,67 +3178,26 @@ static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct sock *sk) chan = hci_chan_list_lookup_id(hdev, hcon->handle); if (chan) { l2cap_aggregate(chan, pi); - sock_hold(sk); - chan->l2cap_sk = sk; hci_chan_hold(chan); - pi->ampchan = chan; goto done; } - chan = hci_chan_add(hdev); - if (chan) { - chan->conn = hcon; - sock_hold(sk); - chan->l2cap_sk = sk; - hci_chan_hold(chan); - pi->ampchan = chan; - hci_chan_create(chan, - (struct hci_ext_fs *) &pi->local_fs, - (struct hci_ext_fs *) &pi->remote_fs); + if (bt_sk(pi)->parent) { + /* Incoming connection */ + chan = hci_chan_accept(hcon, + (struct hci_ext_fs *) &pi->local_fs, + (struct hci_ext_fs *) &pi->remote_fs); + } else { + /* Outgoing connection */ + chan = hci_chan_create(hcon, + (struct hci_ext_fs *) &pi->local_fs, + (struct hci_ext_fs *) &pi->remote_fs); } done: hci_dev_put(hdev); return chan; } -static void l2cap_get_ertm_timeouts(struct l2cap_conf_rfc *rfc, - struct l2cap_pinfo *pi) -{ - if (pi->amp_id && pi->ampcon) { - u64 ertm_to = pi->ampcon->hdev->amp_be_flush_to; - - /* Class 1 devices have must have ERTM timeouts - * exceeding the Link Supervision Timeout. The - * default Link Supervision Timeout for AMP - * controllers is 10 seconds. - * - * Class 1 devices use 0xffffffff for their - * best-effort flush timeout, so the clamping logic - * will result in a timeout that meets the above - * requirement. ERTM timeouts are 16-bit values, so - * the maximum timeout is 65.535 seconds. - */ - - /* Convert timeout to milliseconds and round */ - ertm_to = div_u64(ertm_to + 999, 1000); - - /* This is the recommended formula for class 2 devices - * that start ERTM timers when packets are sent to the - * controller. - */ - ertm_to = 3 * ertm_to + 500; - - if (ertm_to > 0xffff) - ertm_to = 0xffff; - - rfc->retrans_timeout = cpu_to_le16((u16) ertm_to); - rfc->monitor_timeout = rfc->retrans_timeout; - } else { - rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); - rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); - } -} - int l2cap_build_conf_req(struct sock *sk, void *data) { struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -3296,7 +3205,7 @@ int l2cap_build_conf_req(struct sock *sk, void *data) struct l2cap_conf_rfc rfc = { .mode = pi->mode }; void *ptr = req->data; - BT_DBG("sk %p mode %d", sk, pi->mode); + BT_DBG("sk %p", sk); if (pi->num_conf_req || pi->num_conf_rsp) goto done; @@ -3322,6 +3231,7 @@ int l2cap_build_conf_req(struct sock *sk, void *data) if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) && !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING)) break; + rfc.txwin_size = 0; rfc.max_transmit = 0; rfc.retrans_timeout = 0; @@ -3338,10 +3248,10 @@ int l2cap_build_conf_req(struct sock *sk, void *data) rfc.txwin_size = L2CAP_TX_WIN_MAX_ENHANCED; else rfc.txwin_size = pi->tx_win; - rfc.max_transmit = pi->max_tx; - rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); - l2cap_get_ertm_timeouts(&rfc, pi); - + rfc.max_transmit = pi->max_tx; + rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->imtu) rfc.max_pdu_size = cpu_to_le16(pi->imtu); @@ -3373,7 +3283,6 @@ int l2cap_build_conf_req(struct sock *sk, void *data) break; case L2CAP_MODE_STREAMING: - l2cap_setup_txwin(pi); rfc.txwin_size = 0; rfc.max_transmit = 0; rfc.retrans_timeout = 0; @@ -3414,16 +3323,30 @@ static int l2cap_build_amp_reconf_req(struct sock *sk, void *data) struct l2cap_conf_req *req = data; struct l2cap_conf_rfc rfc = { .mode = pi->mode }; void *ptr = req->data; + u32 be_flush_to; BT_DBG("sk %p", sk); + /* convert to milliseconds, round up */ + be_flush_to = (pi->conn->hcon->hdev->amp_be_flush_to + 999) / 1000; + switch (pi->mode) { case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; rfc.txwin_size = pi->tx_win; rfc.max_transmit = pi->max_tx; + if (pi->amp_move_id) { + rfc.retrans_timeout = + cpu_to_le16((3 * be_flush_to) + 500); + rfc.monitor_timeout = + cpu_to_le16((3 * be_flush_to) + 500); + } else { + rfc.retrans_timeout = + cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = + cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + } rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); - l2cap_get_ertm_timeouts(&rfc, pi); if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->imtu) rfc.max_pdu_size = cpu_to_le16(pi->imtu); @@ -3437,16 +3360,17 @@ static int l2cap_build_amp_reconf_req(struct sock *sk, void *data) (unsigned long) &rfc); if (pi->conn->feat_mask & L2CAP_FEAT_FCS) { + /* TODO assign fcs for br/edr based on socket config option */ - /* FCS is not used with AMP because it is redundant - lower - * layers already include a checksum. */ - if (pi->amp_id) + if (pi->amp_move_id) pi->local_conf.fcs = L2CAP_FCS_NONE; else pi->local_conf.fcs = L2CAP_FCS_CRC16; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->local_conf.fcs); - pi->fcs = pi->local_conf.fcs | pi->remote_conf.fcs; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, + pi->local_conf.fcs); + + pi->fcs = pi->local_conf.fcs | pi->remote_conf.fcs; } req->dcid = cpu_to_le16(pi->dcid); @@ -3471,9 +3395,6 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) BT_DBG("sk %p", sk); - if (pi->omtu > mtu) - mtu = pi->omtu; - while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); @@ -3575,8 +3496,6 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) if (pi->mode != rfc.mode) { result = L2CAP_CONF_UNACCEPT; rfc.mode = pi->mode; - if (mtu > L2CAP_DEFAULT_MTU) - pi->omtu = mtu; if (pi->num_conf_rsp == 1) return -ECONNREFUSED; @@ -3613,9 +3532,15 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) case L2CAP_MODE_ERTM: if (!(pi->conf_state & L2CAP_CONF_EXT_WIN_RECV)) pi->remote_tx_win = rfc.txwin_size; + pi->remote_max_tx = rfc.max_transmit; + pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); - l2cap_get_ertm_timeouts(&rfc, pi); + + rfc.retrans_timeout = + cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = + cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); pi->conf_state |= L2CAP_CONF_MODE_DONE; @@ -3655,10 +3580,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) struct hci_chan *chan; /* Trigger logical link creation only on AMP */ - chan = l2cap_chan_admit(pi->amp_id, sk); + chan = l2cap_chan_admit(pi->amp_id, pi); if (!chan) return -ECONNREFUSED; + chan->l2cap_sk = sk; if (chan->state == BT_CONNECTED) l2cap_create_cfm(chan, 0); } @@ -3717,6 +3643,9 @@ static int l2cap_parse_amp_move_reconf_req(struct sock *sk, void *data) case L2CAP_CONF_RFC: if (olen == sizeof(rfc)) memcpy(&rfc, (void *) val, olen); + if (pi->mode != rfc.mode || + rfc.mode == L2CAP_MODE_BASIC) + result = L2CAP_CONF_UNACCEPT; break; case L2CAP_CONF_FCS: @@ -3752,9 +3681,6 @@ static int l2cap_parse_amp_move_reconf_req(struct sock *sk, void *data) BT_DBG("result 0x%2.2x cur mode 0x%2.2x req mode 0x%2.2x", result, pi->mode, rfc.mode); - if (pi->mode != rfc.mode || rfc.mode == L2CAP_MODE_BASIC) - result = L2CAP_CONF_UNACCEPT; - if (result == L2CAP_CONF_SUCCESS) { /* Configure output options and let the other side know * which ones we don't like. */ @@ -3774,26 +3700,38 @@ static int l2cap_parse_amp_move_reconf_req(struct sock *sk, void *data) pi->remote_tx_win); } - pi->remote_mps = rfc.max_pdu_size; - if (rfc.mode == L2CAP_MODE_ERTM) { - l2cap_get_ertm_timeouts(&rfc, pi); - } else { - rfc.retrans_timeout = 0; - rfc.monitor_timeout = 0; - } + pi->remote_conf.retrans_timeout = + le16_to_cpu(rfc.retrans_timeout); + pi->remote_conf.monitor_timeout = + le16_to_cpu(rfc.monitor_timeout); - l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + BT_DBG("remote conf monitor timeout %d", + pi->remote_conf.monitor_timeout); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); + } + } if (result != L2CAP_CONF_SUCCESS) goto done; - pi->fcs = pi->remote_conf.fcs | pi->local_conf.fcs; + pi->fcs = pi->remote_conf.fcs | pi->local_conf.fcs ; - if (pi->rx_state == L2CAP_ERTM_RX_STATE_WAIT_F_FLAG) + if (pi->rx_state == L2CAP_ERTM_RX_STATE_WAIT_F_FLAG) { pi->flush_to = pi->remote_conf.flush_to; + pi->retrans_timeout = pi->remote_conf.retrans_timeout; + + if (pi->amp_move_id) + pi->monitor_timeout = pi->remote_conf.monitor_timeout; + else + pi->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; + BT_DBG("mode %d monitor timeout %d", + pi->mode, pi->monitor_timeout); + + } done: rsp->scid = cpu_to_le16(pi->dcid); @@ -3854,7 +3792,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, break; case L2CAP_CONF_EXT_WINDOW: - pi->ack_win = min_t(u16, val, pi->ack_win); + pi->tx_win = val; + + if (pi->tx_win > L2CAP_TX_WIN_MAX_ENHANCED) + pi->tx_win = L2CAP_TX_WIN_MAX_ENHANCED; l2cap_add_conf_opt(&ptr, L2CAP_CONF_EXT_WINDOW, 2, pi->tx_win); @@ -3876,10 +3817,6 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); pi->mps = le16_to_cpu(rfc.max_pdu_size); - if (!pi->extended_control) { - pi->ack_win = min_t(u16, pi->ack_win, - rfc.txwin_size); - } break; case L2CAP_MODE_STREAMING: pi->mps = le16_to_cpu(rfc.max_pdu_size); @@ -3912,7 +3849,6 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; - u16 txwin_ext = pi->ack_win; BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); @@ -3921,7 +3857,6 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); - rfc.txwin_size = min_t(u16, pi->ack_win, L2CAP_DEFAULT_TX_WINDOW); if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) return; @@ -3933,22 +3868,16 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) case L2CAP_CONF_RFC: if (olen == sizeof(rfc)) memcpy(&rfc, (void *)val, olen); - break; - case L2CAP_CONF_EXT_WINDOW: - txwin_ext = val; - break; + goto done; } } +done: switch (rfc.mode) { case L2CAP_MODE_ERTM: pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); pi->mps = le16_to_cpu(rfc.max_pdu_size); - if (pi->extended_control) - pi->ack_win = min_t(u16, pi->ack_win, txwin_ext); - else - pi->ack_win = min_t(u16, pi->ack_win, rfc.txwin_size); break; case L2CAP_MODE_STREAMING: pi->mps = le16_to_cpu(rfc.max_pdu_size); @@ -4026,41 +3955,34 @@ static int l2cap_amp_move_reconf_rsp(struct sock *sk, void *rsp, int len, if (type == L2CAP_CONF_RFC) { if (olen == sizeof(rfc)) memcpy(&rfc, (void *)val, olen); - - if (rfc.mode != pi->mode) { - l2cap_send_disconn_req(pi->conn, sk, - ECONNRESET); - return -ECONNRESET; + if (rfc.mode != pi->mode && + rfc.mode != L2CAP_MODE_ERTM) { + err = -ECONNREFUSED; + goto done; } - - goto done; + break; } } } - BT_ERR("Expected RFC option was missing, using existing values"); - - rfc.mode = pi->mode; - rfc.retrans_timeout = cpu_to_le16(pi->retrans_timeout); - rfc.monitor_timeout = cpu_to_le16(pi->monitor_timeout); - done: l2cap_ertm_stop_ack_timer(pi); l2cap_ertm_stop_retrans_timer(pi); l2cap_ertm_stop_monitor_timer(pi); - pi->mps = le16_to_cpu(rfc.max_pdu_size); - if (pi->mode == L2CAP_MODE_ERTM) { - pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); - pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - } - if (l2cap_pi(sk)->reconf_state == L2CAP_RECONF_ACC) { l2cap_pi(sk)->reconf_state = L2CAP_RECONF_NONE; /* Respond to poll */ err = l2cap_answer_move_poll(sk); + } else if (l2cap_pi(sk)->reconf_state == L2CAP_RECONF_INT) { + + /* If moving to BR/EDR, use default timeout defined by + * the spec */ + if (pi->amp_move_id == 0) + pi->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; + if (pi->mode == L2CAP_MODE_ERTM) { l2cap_ertm_tx(sk, NULL, NULL, L2CAP_ERTM_EVENT_EXPLICIT_POLL); @@ -4501,13 +4423,14 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Already sent a 'pending' response, so set up * the logical link now */ - chan = l2cap_chan_admit(pi->amp_id, sk); + chan = l2cap_chan_admit(pi->amp_id, pi); if (!chan) { l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); goto done; } + chan->l2cap_sk = sk; if (chan->state == BT_CONNECTED) l2cap_create_cfm(chan, 0); } @@ -4593,7 +4516,6 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd if (sk->sk_state != BT_DISCONN) { sk->sk_shutdown = SHUTDOWN_MASK; - sk->sk_send_head = NULL; skb_queue_purge(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { @@ -4676,14 +4598,10 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm L2CAP_INFO_RSP, sizeof(buf), buf); } else if (type == L2CAP_IT_FIXED_CHAN) { u8 buf[12]; - u8 fc_mask = l2cap_fc_mask; struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); - if (enable_hs) - fc_mask |= L2CAP_FC_A2MP; - memset(rsp->data, 0, 8); - rsp->data[0] = fc_mask; + memcpy(buf + 4, l2cap_fixed_chan, 8); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), buf); } else { @@ -5002,16 +4920,15 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, */ pi->amp_move_state = L2CAP_AMP_STATE_WAIT_LOGICAL_CONFIRM; - } else if (pi->amp_move_state == + } else if (result == L2CAP_MOVE_CHAN_SUCCESS && + pi->amp_move_state == L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS) { - if (result == L2CAP_MOVE_CHAN_PENDING) { - break; - } else if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + /* Logical link is up or moving to BR/EDR, + * proceed with move */ + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { pi->amp_move_state = L2CAP_AMP_STATE_WAIT_LOCAL_BUSY; } else { - /* Logical link is up or moving to BR/EDR, - * proceed with move */ pi->amp_move_state = L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP; l2cap_send_move_chan_cfm(conn, pi, pi->scid, @@ -5039,16 +4956,16 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, } pi->remote_fs = default_fs; pi->local_fs = default_fs; - chan = l2cap_chan_admit(pi->amp_move_id, sk); + chan = l2cap_chan_admit(pi->amp_move_id, pi); if (!chan) { /* Logical link not available */ l2cap_send_move_chan_cfm(conn, pi, pi->scid, L2CAP_MOVE_CHAN_UNCONFIRMED); break; } - if (chan->state == BT_CONNECTED) { /* Logical link is already ready to go */ + pi->ampchan = chan; pi->ampcon = chan->conn; pi->ampcon->l2cap_data = pi->conn; if (result == L2CAP_MOVE_CHAN_SUCCESS) { @@ -5063,15 +4980,10 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, pi->amp_move_state = L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS; } - - l2cap_create_cfm(chan, 0); - } + } else + chan->l2cap_sk = sk; } else { /* Any other amp move state means the move failed. */ - pi->amp_move_id = pi->amp_id; - pi->amp_move_state = L2CAP_AMP_STATE_STABLE; - l2cap_amp_move_revert(sk); - pi->amp_move_role = L2CAP_AMP_MOVE_NONE; l2cap_send_move_chan_cfm(conn, pi, pi->scid, L2CAP_MOVE_CHAN_UNCONFIRMED); l2cap_sock_set_timer(sk, L2CAP_MOVE_TIMEOUT); @@ -5124,7 +5036,6 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, { struct l2cap_move_chan_cfm *cfm = (struct l2cap_move_chan_cfm *) data; struct sock *sk; - struct l2cap_pinfo *pi; u16 icid, result; icid = le16_to_cpu(cfm->icid); @@ -5142,32 +5053,29 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, } lock_sock(sk); - pi = l2cap_pi(sk); - if (pi->amp_move_state == L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM) { - pi->amp_move_state = L2CAP_AMP_STATE_STABLE; + if (l2cap_pi(sk)->amp_move_state == L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM) { + l2cap_pi(sk)->amp_move_state = L2CAP_AMP_STATE_STABLE; if (result == L2CAP_MOVE_CHAN_CONFIRMED) { - pi->amp_id = pi->amp_move_id; - if (!pi->amp_id && pi->ampchan) { - struct hci_chan *ampchan = pi->ampchan; - struct hci_conn *ampcon = pi->ampcon; + l2cap_pi(sk)->amp_id = l2cap_pi(sk)->amp_move_id; + if ((!l2cap_pi(sk)->amp_id) && + (l2cap_pi(sk)->ampchan)) { /* Have moved off of AMP, free the channel */ - pi->ampchan = NULL; - pi->ampcon = NULL; - if (hci_chan_put(ampchan)) - ampcon->l2cap_data = NULL; - else - l2cap_deaggregate(ampchan, pi); + if (!hci_chan_put(l2cap_pi(sk)->ampchan)) + l2cap_deaggregate(l2cap_pi(sk)->ampchan, + l2cap_pi(sk)); + l2cap_pi(sk)->ampchan = NULL; + l2cap_pi(sk)->ampcon = NULL; } l2cap_amp_move_success(sk); } else { - pi->amp_move_id = pi->amp_id; + l2cap_pi(sk)->amp_move_id = l2cap_pi(sk)->amp_id; l2cap_amp_move_revert(sk); } - pi->amp_move_role = L2CAP_AMP_MOVE_NONE; - } else if (pi->amp_move_state == + l2cap_pi(sk)->amp_move_role = L2CAP_AMP_MOVE_NONE; + } else if (l2cap_pi(sk)->amp_move_state == L2CAP_AMP_STATE_WAIT_LOGICAL_CONFIRM) { - BT_DBG("Bad AMP_MOVE_STATE (%d)", pi->amp_move_state); + BT_DBG("Bad AMP_MOVE_STATE (%d)", l2cap_pi(sk)->amp_move_state); } send_move_confirm_response: @@ -5185,8 +5093,6 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, struct l2cap_move_chan_cfm_rsp *rsp = (struct l2cap_move_chan_cfm_rsp *) data; struct sock *sk; - struct l2cap_pinfo *pi; - u16 icid; icid = le16_to_cpu(rsp->icid); @@ -5201,30 +5107,28 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, return 0; lock_sock(sk); - pi = l2cap_pi(sk); l2cap_sock_clear_timer(sk); - if (pi->amp_move_state == + if (l2cap_pi(sk)->amp_move_state == L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP) { - pi->amp_move_state = L2CAP_AMP_STATE_STABLE; - pi->amp_id = pi->amp_move_id; + l2cap_pi(sk)->amp_move_state = L2CAP_AMP_STATE_STABLE; + l2cap_pi(sk)->amp_id = l2cap_pi(sk)->amp_move_id; - if (!pi->amp_id && pi->ampchan) { - struct hci_chan *ampchan = pi->ampchan; - struct hci_conn *ampcon = pi->ampcon; + if (!l2cap_pi(sk)->amp_id) { /* Have moved off of AMP, free the channel */ - pi->ampchan = NULL; - pi->ampcon = NULL; - if (hci_chan_put(ampchan)) - ampcon->l2cap_data = NULL; - else - l2cap_deaggregate(ampchan, pi); + l2cap_pi(sk)->ampcon = NULL; + if (l2cap_pi(sk)->ampchan) { + if (!hci_chan_put(l2cap_pi(sk)->ampchan)) + l2cap_deaggregate(l2cap_pi(sk)->ampchan, + l2cap_pi(sk)); + } + l2cap_pi(sk)->ampchan = NULL; } l2cap_amp_move_success(sk); - pi->amp_move_role = L2CAP_AMP_MOVE_NONE; + l2cap_pi(sk)->amp_move_role = L2CAP_AMP_MOVE_NONE; } release_sock(sk); @@ -5354,10 +5258,11 @@ void l2cap_amp_physical_complete(int result, u8 local_id, u8 remote_id, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; pi->remote_fs = default_fs; pi->local_fs = default_fs; - chan = l2cap_chan_admit(local_id, sk); + chan = l2cap_chan_admit(local_id, pi); if (chan) { if (chan->state == BT_CONNECTED) { /* Logical link is ready to go */ + pi->ampchan = chan; pi->ampcon = chan->conn; pi->ampcon->l2cap_data = pi->conn; pi->amp_move_state = @@ -5365,10 +5270,9 @@ void l2cap_amp_physical_complete(int result, u8 local_id, u8 remote_id, l2cap_send_move_chan_rsp(pi->conn, pi->amp_move_cmd_ident, pi->dcid, L2CAP_MOVE_CHAN_SUCCESS); - - l2cap_create_cfm(chan, 0); } else { /* Wait for logical link to be ready */ + chan->l2cap_sk = sk; pi->amp_move_state = L2CAP_AMP_STATE_WAIT_LOGICAL_CONFIRM; } @@ -5409,17 +5313,14 @@ void l2cap_amp_physical_complete(int result, u8 local_id, u8 remote_id, release_sock(sk); } -static void l2cap_logical_link_complete(struct hci_chan *chan, u8 status) +int l2cap_logical_link_complete(struct hci_chan *chan, u8 status) { struct l2cap_pinfo *pi; struct sock *sk; - struct hci_chan *ampchan; - struct hci_conn *ampcon; BT_DBG("status %d, chan %p, conn %p", (int) status, chan, chan->conn); sk = chan->l2cap_sk; - chan->l2cap_sk = NULL; BT_DBG("sk %p", sk); @@ -5427,17 +5328,16 @@ static void l2cap_logical_link_complete(struct hci_chan *chan, u8 status) if (sk->sk_state != BT_CONNECTED && !l2cap_pi(sk)->amp_id) { release_sock(sk); - return; + return 0; } pi = l2cap_pi(sk); if ((!status) && (chan != NULL)) { + pi->ampchan = chan; pi->ampcon = chan->conn; pi->ampcon->l2cap_data = pi->conn; - BT_DBG("amp_move_state %d", pi->amp_move_state); - if (sk->sk_state != BT_CONNECTED) { struct l2cap_conf_rsp rsp; @@ -5489,24 +5389,13 @@ static void l2cap_logical_link_complete(struct hci_chan *chan, u8 status) pi->amp_move_cmd_ident, pi->dcid, L2CAP_MOVE_CHAN_SUCCESS); } - } else if ((pi->amp_move_state != - L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS) && - (pi->amp_move_state != - L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM) && - (pi->amp_move_state != - L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP)) { - /* Move was not in expected state, free the channel */ - ampchan = pi->ampchan; - ampcon = pi->ampcon; - pi->ampchan = NULL; + } else { + /* Move was not in expected state, free the + * logical link + */ + hci_chan_put(pi->ampchan); pi->ampcon = NULL; - if (ampchan) { - if (hci_chan_put(ampchan)) - ampcon->l2cap_data = NULL; - else - l2cap_deaggregate(ampchan, pi); - } - pi->amp_move_state = L2CAP_AMP_STATE_STABLE; + pi->ampchan = NULL; } } else { /* Logical link setup failed. */ @@ -5541,33 +5430,21 @@ static void l2cap_logical_link_complete(struct hci_chan *chan, u8 status) L2CAP_MOVE_CHAN_UNCONFIRMED); l2cap_sock_set_timer(sk, L2CAP_MOVE_TIMEOUT); } - ampchan = pi->ampchan; - ampcon = pi->ampcon; - pi->ampchan = NULL; + pi->ampcon = NULL; - if (ampchan) { - if (hci_chan_put(ampchan)) - ampcon->l2cap_data = NULL; - else - l2cap_deaggregate(ampchan, pi); - } + pi->ampchan = NULL; } release_sock(sk); + return 0; } static void l2cap_logical_link_worker(struct work_struct *work) { struct l2cap_logical_link_work *log_link_work = container_of(work, struct l2cap_logical_link_work, work); - struct sock *sk = log_link_work->chan->l2cap_sk; - if (sk) { - l2cap_logical_link_complete(log_link_work->chan, - log_link_work->status); - sock_put(sk); - } - hci_chan_put(log_link_work->chan); + l2cap_logical_link_complete(log_link_work->chan, log_link_work->status); kfree(log_link_work); } @@ -5575,27 +5452,15 @@ static int l2cap_create_cfm(struct hci_chan *chan, u8 status) { struct l2cap_logical_link_work *amp_work; - if (!chan->l2cap_sk) { - BT_ERR("Expected l2cap_sk to point to connecting socket"); - return -EFAULT; - } - amp_work = kzalloc(sizeof(*amp_work), GFP_ATOMIC); - if (!amp_work) { - sock_put(chan->l2cap_sk); + if (!amp_work) return -ENOMEM; - } INIT_WORK(&_work->work, l2cap_logical_link_worker); amp_work->chan = chan; amp_work->status = status; - - hci_chan_hold(chan); - if (!queue_work(_l2cap_wq, &_work->work)) { kfree(amp_work); - sock_put(chan->l2cap_sk); - hci_chan_put(chan); return -ENOMEM; } @@ -5631,14 +5496,8 @@ int l2cap_destroy_cfm(struct hci_chan *chan, u8 reason) bh_lock_sock(sk); /* TODO MM/PK - What to do if connection is LOCAL_BUSY? */ if (l2cap_pi(sk)->ampchan == chan) { - struct hci_conn *ampcon = l2cap_pi(sk)->ampcon; l2cap_pi(sk)->ampchan = NULL; l2cap_pi(sk)->ampcon = NULL; - if (hci_chan_put(chan)) - ampcon->l2cap_data = NULL; - else - l2cap_deaggregate(chan, l2cap_pi(sk)); - l2cap_amp_move_init(sk); } bh_unlock_sock(sk); @@ -5706,8 +5565,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, struct hci_conn *hcon = conn->hcon; struct l2cap_conn_param_update_req *req; struct l2cap_conn_param_update_rsp rsp; - struct sock *sk; - u16 min, max, latency, timeout, cmd_len; + u16 min, max, latency, to_multiplier, cmd_len; int err; if (!(hcon->link_mode & HCI_LM_MASTER)) @@ -5717,32 +5575,28 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) return -EPROTO; - memset(&rsp, 0, sizeof(rsp)); - rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); + req = (struct l2cap_conn_param_update_req *) data; + min = __le16_to_cpu(req->min); + max = __le16_to_cpu(req->max); + latency = __le16_to_cpu(req->latency); + to_multiplier = __le16_to_cpu(req->to_multiplier); - sk = l2cap_find_sock_by_fixed_cid_and_dir(4, conn->src, conn->dst, 0); + BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x", + min, max, latency, to_multiplier); - if (sk && !bt_sk(sk)->le_params.prohibit_remote_chg) { - req = (struct l2cap_conn_param_update_req *) data; - min = __le16_to_cpu(req->min); - max = __le16_to_cpu(req->max); - latency = __le16_to_cpu(req->latency); - timeout = __le16_to_cpu(req->to_multiplier); + memset(&rsp, 0, sizeof(rsp)); - err = l2cap_check_conn_param(min, max, latency, timeout); - if (!err) { - rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED); - hci_le_conn_update(hcon, min, max, latency, timeout); - bt_sk(sk)->le_params.interval_min = min; - bt_sk(sk)->le_params.interval_max = max; - bt_sk(sk)->le_params.latency = latency; - bt_sk(sk)->le_params.supervision_timeout = timeout; - } - } + err = l2cap_check_conn_param(min, max, latency, to_multiplier); + if (err) + rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); + else + rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED); l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP, sizeof(rsp), &rsp); + if (!err) + hci_le_conn_update(hcon, min, max, latency, to_multiplier); return 0; } @@ -7265,41 +7119,15 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str return 0; } -static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, - struct sk_buff *skb) +static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) { - struct sock *sk = NULL; + struct sock *sk; struct sk_buff *skb_rsp; struct l2cap_hdr *lh; - int dir; u8 err_rsp[] = {L2CAP_ATT_ERROR, 0x00, 0x00, 0x00, L2CAP_ATT_NOT_SUPPORTED}; - if (skb->data[0] == L2CAP_ATT_MTU_REQ) { - u8 mtu_rsp[] = {L2CAP_ATT_MTU_RSP, 23, 0}; - - skb_rsp = bt_skb_alloc(sizeof(mtu_rsp) + L2CAP_HDR_SIZE, - GFP_ATOMIC); - if (!skb_rsp) - goto drop; - - lh = (struct l2cap_hdr *) skb_put(skb_rsp, L2CAP_HDR_SIZE); - lh->len = cpu_to_le16(sizeof(mtu_rsp)); - lh->cid = cpu_to_le16(L2CAP_CID_LE_DATA); - memcpy(skb_put(skb_rsp, sizeof(mtu_rsp)), mtu_rsp, - sizeof(mtu_rsp)); - hci_send_acl(conn->hcon, NULL, skb_rsp, 0); - - goto free_skb; - } - - dir = (skb->data[0] & L2CAP_ATT_RESPONSE_BIT) ? 0 : 1; - - sk = l2cap_find_sock_by_fixed_cid_and_dir(cid, conn->src, - conn->dst, dir); - - BT_DBG("sk %p, dir:%d", sk, dir); - + sk = l2cap_get_sock_by_fixed_scid(0, cid, conn->src, conn->dst); if (!sk) goto drop; @@ -7317,26 +7145,8 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, goto done; drop: - if (skb->data[0] != L2CAP_ATT_INDICATE) - goto not_indicate; - - /* If this is an incoming Indication, we are required to confirm */ - - skb_rsp = bt_skb_alloc(sizeof(u8) + L2CAP_HDR_SIZE, GFP_ATOMIC); - if (!skb_rsp) - goto free_skb; - - lh = (struct l2cap_hdr *) skb_put(skb_rsp, L2CAP_HDR_SIZE); - lh->len = cpu_to_le16(sizeof(u8)); - lh->cid = cpu_to_le16(L2CAP_CID_LE_DATA); - err_rsp[0] = L2CAP_ATT_CONFIRM; - memcpy(skb_put(skb_rsp, sizeof(u8)), err_rsp, sizeof(u8)); - hci_send_acl(conn->hcon, NULL, skb_rsp, 0); - goto free_skb; - -not_indicate: - if (skb->data[0] & L2CAP_ATT_RESPONSE_BIT || - skb->data[0] == L2CAP_ATT_CONFIRM) + if (skb->data[0] & L2CAP_ATT_RESPONSE_BIT && + skb->data[0] != L2CAP_ATT_INDICATE) goto free_skb; /* If this is an incoming PDU that requires a response, respond with @@ -7398,7 +7208,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) case L2CAP_CID_SMP: if (smp_sig_channel(conn, skb)) - l2cap_conn_del(conn->hcon, EACCES, 0); + l2cap_conn_del(conn->hcon, EACCES); break; default: @@ -7412,9 +7222,9 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_data_channel(sk, skb); bh_unlock_sock(sk); - } else if ((cid == L2CAP_CID_A2MP) && enable_hs) { + } else if (cid == L2CAP_CID_A2MP) { BT_DBG("A2MP"); - amp_conn_ind(conn->hcon, skb); + amp_conn_ind(conn, skb); } else { BT_DBG("unknown cid 0x%4.4x", cid); kfree_skb(skb); @@ -7433,7 +7243,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) struct hlist_node *node; if (type != ACL_LINK) - return 0; + return -EINVAL; BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); @@ -7473,7 +7283,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) if (conn) l2cap_conn_ready(conn); } else - l2cap_conn_del(hcon, bt_err(status), 0); + l2cap_conn_del(hcon, bt_err(status)); return 0; } @@ -7490,14 +7300,14 @@ static int l2cap_disconn_ind(struct hci_conn *hcon) return conn->disc_reason; } -static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason, u8 is_process) +static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) { BT_DBG("hcon %p reason %d", hcon, reason); if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK)) return -EINVAL; - l2cap_conn_del(hcon, bt_err(reason), is_process); + l2cap_conn_del(hcon, bt_err(reason)); return 0; } @@ -7524,7 +7334,6 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) struct l2cap_chan_list *l; struct l2cap_conn *conn = hcon->l2cap_data; struct sock *sk; - int smp = 0; if (!conn) return 0; @@ -7541,12 +7350,13 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("sk->scid %d", l2cap_pi(sk)->scid); if (l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) { - if (!status && encrypt) { + if (!status && encrypt) l2cap_pi(sk)->sec_level = hcon->sec_level; - l2cap_chan_ready(sk); - } - smp = 1; + del_timer(&hcon->smp_timer); + l2cap_chan_ready(sk); + smp_link_encrypt_cmplt(conn, status, encrypt); + bh_unlock_sock(sk); continue; } @@ -7567,9 +7377,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status) { l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; - if ((l2cap_pi(sk)->amp_pref == - BT_AMP_POLICY_PREFER_AMP) && - enable_hs) { + if (l2cap_pi(sk)->amp_pref == + BT_AMP_POLICY_PREFER_AMP) { amp_create_physical(l2cap_pi(sk)->conn, sk); } else @@ -7604,17 +7413,6 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && - result == L2CAP_CR_SUCCESS) { - char buf[128]; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; - l2cap_send_cmd(conn, l2cap_get_ident(conn), - L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), - buf); - l2cap_pi(sk)->num_conf_req++; - } } bh_unlock_sock(sk); @@ -7622,11 +7420,6 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) read_unlock(&l->lock); - if (smp) { - del_timer(&hcon->smp_timer); - smp_link_encrypt_cmplt(conn, status, encrypt); - } - return 0; } @@ -7733,33 +7526,6 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl return 0; } -static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to) -{ - struct hci_cp_write_automatic_flush_timeout flush_tm; - if (hcon && hcon->hdev) { - flush_tm.handle = hcon->handle; - if (flush_to == L2CAP_DEFAULT_FLUSH_TO) - flush_to = 0; - flush_tm.timeout = (flush_to < L2CAP_MAX_FLUSH_TO) ? - flush_to : L2CAP_MAX_FLUSH_TO; - hci_send_cmd(hcon->hdev, - HCI_OP_WRITE_AUTOMATIC_FLUSH_TIMEOUT, - 4, &(flush_tm)); - } -} - -static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l) -{ - int ret_flush_to = L2CAP_DEFAULT_FLUSH_TO; - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->flush_to > 0 && - l2cap_pi(s)->flush_to < ret_flush_to) - ret_flush_to = l2cap_pi(s)->flush_to; - } - return ret_flush_to; -} - static int l2cap_debugfs_show(struct seq_file *f, void *p) { struct sock *sk; @@ -7871,8 +7637,5 @@ void l2cap_exit(void) module_param(disable_ertm, bool, 0644); MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode"); -module_param(enable_hs, bool, 0644); -MODULE_PARM_DESC(enable_hs, "Enable A2MP protocol"); - module_param(enable_reconfig, bool, 0644); MODULE_PARM_DESC(enable_reconfig, "Enable reconfig after initiating AMP move"); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 4557ddad..11e46ba0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (c) 2000-2001, 2011-2012 The Linux Foundation. All rights reserved. + Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. @@ -25,8 +25,7 @@ */ /* Bluetooth L2CAP sockets. */ - -#include +// rollback to original BlueZ #include #include @@ -81,23 +80,6 @@ void l2cap_sock_clear_timer(struct sock *sk) sk_stop_timer(sk, &sk->sk_timer); } -int l2cap_sock_le_params_valid(struct bt_le_params *le_params) -{ - if (!le_params || le_params->latency > BT_LE_LATENCY_MAX || - le_params->scan_window > BT_LE_SCAN_WINDOW_MAX || - le_params->scan_interval < BT_LE_SCAN_INTERVAL_MIN || - le_params->scan_window > le_params->scan_interval || - le_params->interval_min < BT_LE_CONN_INTERVAL_MIN || - le_params->interval_max > BT_LE_CONN_INTERVAL_MAX || - le_params->interval_min > le_params->interval_max || - le_params->supervision_timeout < BT_LE_SUP_TO_MIN || - le_params->supervision_timeout > BT_LE_SUP_TO_MAX) { - return 0; - } - - return 1; -} - static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) { struct sock *sk; @@ -390,6 +372,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l BT_DBG("sock %p, sk %p", sock, sk); + memset(la, 0, sizeof(struct sockaddr_l2)); addr->sa_family = AF_BLUETOOTH; *len = sizeof(struct sockaddr_l2); @@ -525,10 +508,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch memset(&sec, 0, sizeof(sec)); sec.level = l2cap_pi(sk)->sec_level; - if (sk->sk_state == BT_CONNECTED) { + if (sk->sk_state == BT_CONNECTED) sec.key_size = l2cap_pi(sk)->conn->hcon->enc_key_size; - sec.level = l2cap_pi(sk)->conn->hcon->sec_level; - } len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) @@ -567,17 +548,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch err = -EFAULT; break; - case BT_LE_PARAMS: - if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { - err = -EINVAL; - break; - } - - if (copy_to_user(optval, (char *) &bt_sk(sk)->le_params, - sizeof(bt_sk(sk)->le_params))) - err = -EFAULT; - break; - default: err = -ENOPROTOOPT; break; @@ -644,16 +614,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us case L2CAP_MODE_BASIC: l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; - case L2CAP_MODE_STREAMING: - if (!disable_ertm) { - /* No fallback to ERTM or Basic mode */ - l2cap_pi(sk)->conf_state |= - L2CAP_CONF_STATE2_DEVICE; - break; - } - err = -EINVAL; - break; case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: if (!disable_ertm) break; /* fall through */ @@ -667,7 +629,6 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->fcs = opts.fcs; l2cap_pi(sk)->max_tx = opts.max_tx; l2cap_pi(sk)->tx_win = opts.txwin_size; - l2cap_pi(sk)->flush_to = opts.flush_to; break; case L2CAP_LM: @@ -702,7 +663,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch struct sock *sk = sock->sk; struct bt_security sec; struct bt_power pwr; - struct bt_le_params le_params; struct l2cap_conn *conn; int len, err = 0; u32 opt; @@ -809,50 +769,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; - case BT_FLUSHABLE: - if (get_user(opt, (u32 __user *) optval)) { - err = -EFAULT; - break; - } - l2cap_pi(sk)->flushable = opt; - - break; - - case BT_LE_PARAMS: - if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { - err = -EINVAL; - break; - } - - if (copy_from_user((char *) &le_params, optval, - sizeof(struct bt_le_params))) { - err = -EFAULT; - break; - } - - conn = l2cap_pi(sk)->conn; - if (!conn || !conn->hcon || - l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { - memcpy(&bt_sk(sk)->le_params, &le_params, - sizeof(le_params)); - break; - } - - if (!conn->hcon->out || - !l2cap_sock_le_params_valid(&le_params)) { - err = -EINVAL; - break; - } - - memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params)); - - hci_le_conn_update(conn->hcon, - le_params.interval_min, - le_params.interval_max, - le_params.latency, - le_params.supervision_timeout); - break; - default: err = -ENOPROTOOPT; break; @@ -1034,8 +950,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms else err = bt_sock_recvmsg(iocb, sock, msg, len, flags); - if (err >= 0) - l2cap_ertm_recv_done(sk); + l2cap_ertm_recv_done(sk); return err; } @@ -1174,7 +1089,6 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) static int l2cap_sock_release(struct socket *sock) { struct sock *sk = sock->sk; - struct sock *sk2 = NULL; int err; BT_DBG("sock %p, sk %p", sock, sk); @@ -1182,17 +1096,6 @@ static int l2cap_sock_release(struct socket *sock) if (!sk) return 0; - /* If this is an ATT socket, find it's matching server/client */ - if (l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) - sk2 = l2cap_find_sock_by_fixed_cid_and_dir(L2CAP_CID_LE_DATA, - &bt_sk(sk)->src, &bt_sk(sk)->dst, - l2cap_pi(sk)->incoming ? 0 : 1); - - /* If matching socket found, request tear down */ - BT_DBG("sock:%p companion:%p", sk, sk2); - if (sk2) - l2cap_sock_set_timer(sk2, 1); - err = l2cap_sock_shutdown(sock, 2); sock_orphan(sk); @@ -1213,6 +1116,8 @@ static void l2cap_sock_destruct(struct sock *sk) static void set_default_config(struct l2cap_conf_prm *conf_prm) { conf_prm->fcs = L2CAP_FCS_CRC16; + conf_prm->retrans_timeout = 0; + conf_prm->monitor_timeout = 0; conf_prm->flush_to = L2CAP_DEFAULT_FLUSH_TO; } @@ -1271,10 +1176,17 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->scid = 0; pi->dcid = 0; pi->tx_win_max = L2CAP_TX_WIN_MAX_ENHANCED; - pi->ack_win = pi->tx_win; pi->extended_control = 0; pi->local_conf.fcs = pi->fcs; + if (pi->mode == L2CAP_MODE_BASIC) { + pi->local_conf.retrans_timeout = 0; + pi->local_conf.monitor_timeout = 0; + } else { + pi->local_conf.retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; + pi->local_conf.monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; + } + pi->local_conf.flush_to = pi->flush_to; set_default_config(&pi->remote_conf); diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 177e64f2..b826d1bf 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -1,6 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Technologies, Inc. + Copyright (C) 2000-2001 Qualcomm Incorporated Written 2000,2001 by Maxim Krasnyansky diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1c9d6d9a..28a5d9b2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1,7 +1,6 @@ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2010 Nokia Corporation - Copyright (c) 2011-2012 The Linux Foundation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as @@ -22,6 +21,7 @@ */ /* Bluetooth HCI Management interface */ +// rollback to original BlueZ #include #include @@ -37,9 +37,18 @@ #define MGMT_VERSION 0 #define MGMT_REVISION 1 -#define SCAN_IDLE 0x00 -#define SCAN_LE 0x01 -#define SCAN_BR 0x02 +enum scan_mode { + SCAN_IDLE, + SCAN_LE, + SCAN_BR +}; + +struct disco_interleave { + u16 index; + enum scan_mode mode; + int int_phase; + int int_count; +}; struct pending_cmd { struct list_head list; @@ -310,7 +319,7 @@ static void mgmt_pending_foreach(u16 opcode, int index, cmd = list_entry(p, struct pending_cmd, list); - if (opcode > 0 && cmd->opcode != opcode) + if (cmd->opcode != opcode) continue; if (index >= 0 && cmd->index != index) @@ -418,7 +427,6 @@ static u8 get_service_classes(struct hci_dev *hdev) static int update_class(struct hci_dev *hdev) { u8 cod[3]; - int err = 0; BT_DBG("%s", hdev->name); @@ -432,12 +440,7 @@ static int update_class(struct hci_dev *hdev) if (memcmp(cod, hdev->dev_class, 3) == 0) return 0; - err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); - - if (err == 0) - memcpy(hdev->dev_class, cod, 3); - - return err; + return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); } static int set_limited_discoverable(struct sock *sk, u16 index, @@ -770,7 +773,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) struct list_head *p; size_t name_len; - name_len = strnlen(hdev->dev_name, HCI_MAX_EIR_LENGTH); + name_len = strlen(hdev->dev_name); if (name_len > 0) { /* EIR Data type */ @@ -898,17 +901,13 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) list_add(&uuid->list, &hdev->uuids); - if (test_bit(HCI_UP, &hdev->flags)) { - - err = update_class(hdev); - if (err < 0) - goto failed; + err = update_class(hdev); + if (err < 0) + goto failed; - err = update_eir(hdev); - if (err < 0) - goto failed; - } else - err = 0; + err = update_eir(hdev); + if (err < 0) + goto failed; err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); @@ -962,16 +961,13 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) goto unlock; } - if (test_bit(HCI_UP, &hdev->flags)) { - err = update_class(hdev); - if (err < 0) - goto unlock; + err = update_class(hdev); + if (err < 0) + goto unlock; - err = update_eir(hdev); - if (err < 0) - goto unlock; - } else - err = 0; + err = update_eir(hdev); + if (err < 0) + goto unlock; err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); @@ -1006,12 +1002,9 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, hdev->major_class |= cp->major & MGMT_MAJOR_CLASS_MASK; hdev->minor_class = cp->minor; - if (test_bit(HCI_UP, &hdev->flags)) { - err = update_class(hdev); - if (err == 0) - err = cmd_complete(sk, index, - MGMT_OP_SET_DEV_CLASS, hdev->dev_class, sizeof(u8)*3); - } else + err = update_class(hdev); + + if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); hci_dev_unlock_bh(hdev); @@ -1045,12 +1038,9 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, err = 0; } else { clear_bit(HCI_SERVICE_CACHE, &hdev->flags); - if (test_bit(HCI_UP, &hdev->flags)) { - err = update_class(hdev); - if (err == 0) - err = update_eir(hdev); - } else - err = 0; + err = update_class(hdev); + if (err == 0) + err = update_eir(hdev); } if (err == 0) @@ -1361,23 +1351,20 @@ static int encrypt_link(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENETDOWN); - goto done; + goto failed; } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); - if (!conn) { - err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN); - goto done; - } + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + &cp->bdaddr); + if (!conn) + return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, ENOTCONN); - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { - err = cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS); - goto done; - } + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + return cmd_status(sk, index, MGMT_OP_ENCRYPT_LINK, EINPROGRESS); if (conn->link_mode & HCI_LM_AUTH) { enc.handle = cpu_to_le16(conn->handle); @@ -1394,8 +1381,8 @@ static int encrypt_link(struct sock *sk, u16 index, unsigned char *data, } } -done: - hci_dev_unlock_bh(hdev); +failed: + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1538,7 +1525,6 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) } pairing_complete(cmd, status); - hci_conn_put(conn); } static void pairing_security_complete_cb(struct hci_conn *conn, u8 status) @@ -1588,8 +1574,8 @@ static void discovery_terminated(struct pending_cmd *cmd, void *data) if (!hdev) goto not_found; - del_timer(&hdev->disco_le_timer); - del_timer(&hdev->disco_timer); + del_timer_sync(&hdev->disc_le_timer); + del_timer_sync(&hdev->disc_timer); hci_dev_put(hdev); not_found: @@ -1624,22 +1610,26 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) hci_dev_lock_bh(hdev); + BT_DBG("SSP Cap is %d", cp->ssp_cap); io_cap = cp->io_cap; - - sec_level = BT_SECURITY_MEDIUM; - auth_type = HCI_AT_DEDICATED_BONDING; + if ((cp->ssp_cap == 0) || (io_cap == 0x03)) { + sec_level = BT_SECURITY_MEDIUM; + auth_type = HCI_AT_DEDICATED_BONDING; + } else { + sec_level = BT_SECURITY_HIGH; + auth_type = HCI_AT_DEDICATED_BONDING_MITM; + } entry = hci_find_adv_entry(hdev, &cp->bdaddr); if (entry && entry->flags & 0x04) { - conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level, - auth_type, NULL); + conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level, + auth_type); } else { /* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */ if (io_cap == 0x04) io_cap = 0x01; conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level, auth_type); - conn->auth_initiator = 1; } if (IS_ERR(conn)) { @@ -1817,81 +1807,6 @@ static int set_connection_params(struct sock *sk, u16 index, return err; } -static int set_rssi_reporter(struct sock *sk, u16 index, - unsigned char *data, u16 len) -{ - struct mgmt_cp_set_rssi_reporter *cp = (void *) data; - struct hci_dev *hdev; - struct hci_conn *conn; - int err = 0; - - if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER, - EINVAL); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER, - ENODEV); - - hci_dev_lock_bh(hdev); - - conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); - - if (!conn) { - err = cmd_status(sk, index, MGMT_OP_SET_RSSI_REPORTER, - ENOTCONN); - goto failed; - } - - BT_DBG("updateOnThreshExceed %d ", cp->updateOnThreshExceed); - hci_conn_set_rssi_reporter(conn, cp->rssi_threshold, - __le16_to_cpu(cp->interval), cp->updateOnThreshExceed); - -failed: - hci_dev_unlock_bh(hdev); - hci_dev_put(hdev); - - return err; -} - -static int unset_rssi_reporter(struct sock *sk, u16 index, - unsigned char *data, u16 len) -{ - struct mgmt_cp_unset_rssi_reporter *cp = (void *) data; - struct hci_dev *hdev; - struct hci_conn *conn; - int err = 0; - - if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER, - EINVAL); - - hdev = hci_dev_get(index); - - if (!hdev) - return cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER, - ENODEV); - - hci_dev_lock_bh(hdev); - - conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); - - if (!conn) { - err = cmd_status(sk, index, MGMT_OP_UNSET_RSSI_REPORTER, - ENOTCONN); - goto failed; - } - - hci_conn_unset_rssi_reporter(conn); - -failed: - hci_dev_unlock_bh(hdev); - hci_dev_put(hdev); - - return err; -} - static int set_local_name(struct sock *sk, u16 index, unsigned char *data, u16 len) { @@ -1946,8 +1861,8 @@ static void discovery_rsp(struct pending_cmd *cmd, void *data) if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) { struct hci_dev *hdev = hci_dev_get(cmd->index); if (hdev) { - del_timer(&hdev->disco_le_timer); - del_timer(&hdev->disco_timer); + del_timer_sync(&hdev->disc_le_timer); + del_timer_sync(&hdev->disc_timer); hci_dev_put(hdev); } } @@ -1971,7 +1886,7 @@ void mgmt_inquiry_complete_evt(u16 index, u8 status) { struct hci_dev *hdev; struct hci_cp_le_set_scan_enable le_cp = {1, 0}; - struct mgmt_mode cp = {0}; + struct pending_cmd *cmd; int err = -1; BT_DBG(""); @@ -1979,6 +1894,7 @@ void mgmt_inquiry_complete_evt(u16 index, u8 status) hdev = hci_dev_get(index); if (!hdev || !lmp_le_capable(hdev)) { + struct mgmt_mode cp = {0}; mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index, discovery_terminated, NULL); @@ -1991,20 +1907,20 @@ void mgmt_inquiry_complete_evt(u16 index, u8 status) return; } - if (hdev->disco_state != SCAN_IDLE) { + cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index); + if (cmd && cmd->param) { + struct disco_interleave *ilp = cmd->param; + err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(le_cp), &le_cp); - if (err >= 0) { - mod_timer(&hdev->disco_le_timer, jiffies + - msecs_to_jiffies(hdev->disco_int_phase * 1000)); - hdev->disco_state = SCAN_LE; + if (err >= 0 && hdev) { + mod_timer(&hdev->disc_le_timer, jiffies + + msecs_to_jiffies(ilp->int_phase * 1000)); + ilp->mode = SCAN_LE; } else - hdev->disco_state = SCAN_IDLE; + ilp->mode = SCAN_IDLE; } - if (hdev->disco_state == SCAN_IDLE) - mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL); - if (err < 0) mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index, discovery_terminated, NULL); @@ -2013,78 +1929,82 @@ void mgmt_inquiry_complete_evt(u16 index, u8 status) hci_dev_put(hdev); } -void mgmt_disco_timeout(unsigned long data) +static void disco_to(unsigned long data) { - struct hci_dev *hdev = (void *) data; + struct disco_interleave *ilp = (void *)data; + struct hci_dev *hdev; struct pending_cmd *cmd; - struct mgmt_mode cp = {0}; - BT_DBG("hci%d", hdev->id); + BT_DBG("hci%d", ilp->index); - hdev = hci_dev_get(hdev->id); + hdev = hci_dev_get(ilp->index); - if (!hdev) - return; + if (hdev) { + hci_dev_lock_bh(hdev); + del_timer_sync(&hdev->disc_le_timer); - hci_dev_lock_bh(hdev); - del_timer(&hdev->disco_le_timer); + cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index); - if (hdev->disco_state != SCAN_IDLE) { - struct hci_cp_le_set_scan_enable le_cp = {0, 0}; + if (ilp->mode != SCAN_IDLE) { + struct hci_cp_le_set_scan_enable le_cp = {0, 0}; - if (test_bit(HCI_UP, &hdev->flags)) { - if (hdev->disco_state == SCAN_LE) + if (ilp->mode == SCAN_LE) hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(le_cp), &le_cp); else - hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, - NULL); + hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, + 0, NULL); + + ilp->mode = SCAN_IDLE; } - hdev->disco_state = SCAN_IDLE; - } - mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL); + if (cmd) { + struct mgmt_mode cp = {0}; - cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id); - if (cmd) - mgmt_pending_remove(cmd); + mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp, + sizeof(cp), NULL); + mgmt_pending_remove(cmd); + } - hci_dev_unlock_bh(hdev); - hci_dev_put(hdev); + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + } } -void mgmt_disco_le_timeout(unsigned long data) +static void disco_le_to(unsigned long data) { - struct hci_dev *hdev = (void *)data; + struct disco_interleave *ilp = (void *)data; + struct hci_dev *hdev; + struct pending_cmd *cmd; struct hci_cp_le_set_scan_enable le_cp = {0, 0}; - BT_DBG("hci%d", hdev->id); + BT_DBG("hci%d", ilp->index); - hdev = hci_dev_get(hdev->id); + hdev = hci_dev_get(ilp->index); - if (!hdev) - return; + if (hdev) { + hci_dev_lock_bh(hdev); - hci_dev_lock_bh(hdev); + cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index); - if (test_bit(HCI_UP, &hdev->flags)) { - if (hdev->disco_state == SCAN_LE) + if (ilp->mode == SCAN_LE) hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, - sizeof(le_cp), &le_cp); + sizeof(le_cp), &le_cp); - /* re-start BR scan */ - if (hdev->disco_state != SCAN_IDLE) { + /* re-start BR scan */ + if (cmd) { struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0}; - hdev->disco_int_phase *= 2; - hdev->disco_int_count = 0; - cp.num_rsp = (u8) hdev->disco_int_phase; + ilp->int_phase *= 2; + ilp->int_count = 0; + cp.num_rsp = (u8) ilp->int_phase; hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); - hdev->disco_state = SCAN_BR; - } - } + ilp->mode = SCAN_BR; + } else + ilp->mode = SCAN_IDLE; - hci_dev_unlock_bh(hdev); - hci_dev_put(hdev); + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + } } static int start_discovery(struct sock *sk, u16 index) @@ -2102,11 +2022,6 @@ static int start_discovery(struct sock *sk, u16 index) hci_dev_lock_bh(hdev); - if (hdev->disco_state && timer_pending(&hdev->disco_timer)) { - err = -EBUSY; - goto failed; - } - cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0); if (!cmd) { err = -ENOMEM; @@ -2137,31 +2052,33 @@ static int start_discovery(struct sock *sk, u16 index) err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); - if (err < 0) { + if (err < 0) mgmt_pending_remove(cmd); - hdev->disco_state = SCAN_IDLE; - } else if (lmp_le_capable(hdev)) { + else if (lmp_le_capable(hdev)) { + struct disco_interleave il, *ilp; + + il.int_phase = 1; + il.int_count = 0; + il.index = index; + il.mode = SCAN_BR; + mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il, + sizeof(struct disco_interleave)); cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index); - if (!cmd) - mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, - NULL, 0); - hdev->disco_int_phase = 1; - hdev->disco_int_count = 0; - hdev->disco_state = SCAN_BR; - del_timer(&hdev->disco_le_timer); - del_timer(&hdev->disco_timer); - mod_timer(&hdev->disco_timer, - jiffies + msecs_to_jiffies(20000)); - } else - hdev->disco_state = SCAN_BR; + if (cmd) { + ilp = cmd->param; + setup_timer(&hdev->disc_le_timer, disco_le_to, + (unsigned long) ilp); + setup_timer(&hdev->disc_timer, disco_to, + (unsigned long) ilp); + mod_timer(&hdev->disc_timer, + jiffies + msecs_to_jiffies(20000)); + } + } failed: hci_dev_unlock_bh(hdev); hci_dev_put(hdev); - if (err < 0) - return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err); - return err; } @@ -2169,10 +2086,10 @@ static int stop_discovery(struct sock *sk, u16 index) { struct hci_cp_le_set_scan_enable le_cp = {0, 0}; struct mgmt_mode mode_cp = {0}; + struct disco_interleave *ilp = NULL; struct hci_dev *hdev; struct pending_cmd *cmd = NULL; int err = -EPERM; - u8 state; BT_DBG(""); @@ -2182,30 +2099,38 @@ static int stop_discovery(struct sock *sk, u16 index) hci_dev_lock_bh(hdev); - state = hdev->disco_state; - hdev->disco_state = SCAN_IDLE; - del_timer(&hdev->disco_le_timer); - del_timer(&hdev->disco_timer); + if (lmp_le_capable(hdev)) { + cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + ilp = cmd->param; + } - if (state == SCAN_LE) { + if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE)) err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(le_cp), &le_cp); - if (err >= 0) { - mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index, - discovery_terminated, NULL); - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, - NULL, 0); - } - } else if (state == SCAN_BR) - err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); + if (err < 0) { + if (!ilp || (ilp->mode == SCAN_BR)) + err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, + 0, NULL); + } + + if (ilp) { + ilp->mode = SCAN_IDLE; + del_timer_sync(&hdev->disc_le_timer); + del_timer_sync(&hdev->disc_timer); + } - cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index); if (err < 0 && cmd) mgmt_pending_remove(cmd); mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL); +failed: hci_dev_unlock_bh(hdev); hci_dev_put(hdev); @@ -2447,12 +2372,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_CONNECTION_PARAMS: err = set_connection_params(sk, index, buf + sizeof(*hdr), len); break; - case MGMT_OP_SET_RSSI_REPORTER: - err = set_rssi_reporter(sk, index, buf + sizeof(*hdr), len); - break; - case MGMT_OP_UNSET_RSSI_REPORTER: - err = unset_rssi_reporter(sk, index, buf + sizeof(*hdr), len); - break; case MGMT_OP_READ_LOCAL_OOB_DATA: err = read_local_oob_data(sk, index); break; @@ -2483,14 +2402,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) return err; } -static void cmd_status_rsp(struct pending_cmd *cmd, void *data) -{ - u8 *status = data; - - cmd_status(cmd->sk, cmd->index, cmd->opcode, *status); - mgmt_pending_remove(cmd); -} - int mgmt_index_added(u16 index) { BT_DBG("%d", index); @@ -2499,12 +2410,7 @@ int mgmt_index_added(u16 index) int mgmt_index_removed(u16 index) { - u8 status = ENODEV; - BT_DBG("%d", index); - - mgmt_pending_foreach(0, index, cmd_status_rsp, &status); - return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL); } @@ -2543,11 +2449,6 @@ int mgmt_powered(u16 index, u8 powered) mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match); - if (!powered) { - u8 status = ENETDOWN; - mgmt_pending_foreach(0, index, cmd_status_rsp, &status); - } - ev.val = powered; ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk); @@ -2792,11 +2693,8 @@ int mgmt_user_confirm_request(u16 index, u8 event, if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) && conn->auth_initiator && rem_cap == 0x03) ev.auto_confirm = 1; - else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) { - if (!loc_mitm && !rem_mitm) - value = 0; + else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) goto no_auto_confirm; - } if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03)) @@ -2937,62 +2835,11 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, return err; } -void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr, - u16 handle, u8 status) -{ - struct mgmt_ev_rssi_update ev; - struct hci_conn *conn; - struct hci_dev *hdev; - - if (status) - return; - - hdev = hci_dev_get(index); - conn = hci_conn_hash_lookup_handle(hdev, handle); - - if (!conn) - return; - - BT_DBG("rssi_update_thresh_exceed : %d ", - conn->rssi_update_thresh_exceed); - BT_DBG("RSSI Threshold : %d , recvd RSSI : %d ", - conn->rssi_threshold, rssi); - - if (conn->rssi_update_thresh_exceed == 1) { - BT_DBG("rssi_update_thresh_exceed == 1"); - if (rssi > conn->rssi_threshold) { - memset(&ev, 0, sizeof(ev)); - bacpy(&ev.bdaddr, bdaddr); - ev.rssi = rssi; - mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev, - sizeof(ev), NULL); - } else { - hci_conn_set_rssi_reporter(conn, conn->rssi_threshold, - conn->rssi_update_interval, - conn->rssi_update_thresh_exceed); - } - } else { - BT_DBG("rssi_update_thresh_exceed == 0"); - if (rssi < conn->rssi_threshold) { - memset(&ev, 0, sizeof(ev)); - bacpy(&ev.bdaddr, bdaddr); - ev.rssi = rssi; - mgmt_event(MGMT_EV_RSSI_UPDATE, index, &ev, - sizeof(ev), NULL); - } else { - hci_conn_set_rssi_reporter(conn, conn->rssi_threshold, - conn->rssi_update_interval, - conn->rssi_update_thresh_exceed); - } - } -} - - int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le, u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir) { struct mgmt_ev_device_found ev; - struct hci_dev *hdev; + struct pending_cmd *cmd; int err; BT_DBG("le: %d", le); @@ -3015,38 +2862,36 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 type, u8 le, if (err < 0) return err; - hdev = hci_dev_get(index); - - if (!hdev) - return 0; - - if (hdev->disco_state == SCAN_IDLE) - goto done; - - hdev->disco_int_count++; + cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index); + if (cmd) { + struct disco_interleave *ilp = cmd->param; + struct hci_dev *hdev = hci_dev_get(index); - if (hdev->disco_int_count >= hdev->disco_int_phase) { - /* Inquiry scan for General Discovery LAP */ - struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0}; - struct hci_cp_le_set_scan_enable le_cp = {0, 0}; + ilp->int_count++; + if (hdev && ilp->int_count >= ilp->int_phase) { + /* Inquiry scan for General Discovery LAP */ + struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0}; + struct hci_cp_le_set_scan_enable le_cp = {0, 0}; - hdev->disco_int_phase *= 2; - hdev->disco_int_count = 0; - if (hdev->disco_state == SCAN_LE) { - /* cancel LE scan */ - hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, - sizeof(le_cp), &le_cp); - /* start BR scan */ - cp.num_rsp = (u8) hdev->disco_int_phase; - hci_send_cmd(hdev, HCI_OP_INQUIRY, - sizeof(cp), &cp); - hdev->disco_state = SCAN_BR; - del_timer_sync(&hdev->disco_le_timer); + ilp->int_phase *= 2; + ilp->int_count = 0; + if (ilp->mode == SCAN_LE) { + /* cancel LE scan */ + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, + sizeof(le_cp), &le_cp); + /* start BR scan */ + cp.num_rsp = (u8) ilp->int_phase; + hci_send_cmd(hdev, HCI_OP_INQUIRY, + sizeof(cp), &cp); + ilp->mode = SCAN_BR; + del_timer_sync(&hdev->disc_le_timer); + } } + + if (hdev) + hci_dev_put(hdev); } -done: - hci_dev_put(hdev); return 0; } @@ -3077,42 +2922,3 @@ int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status) NULL); } -int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3]) -{ - struct mgmt_ev_remote_class ev; - - memset(&ev, 0, sizeof(ev)); - - bacpy(&ev.bdaddr, bdaddr); - memcpy(ev.dev_class, dev_class, 3); - - return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL); -} - -int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf, - u16 sub_ver) -{ - struct mgmt_ev_remote_version ev; - - memset(&ev, 0, sizeof(ev)); - - bacpy(&ev.bdaddr, bdaddr); - ev.lmp_ver = ver; - ev.manufacturer = mnf; - ev.lmp_subver = sub_ver; - - return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL); -} - -int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8]) -{ - struct mgmt_ev_remote_features ev; - - memset(&ev, 0, sizeof(ev)); - - bacpy(&ev.bdaddr, bdaddr); - memcpy(ev.features, features, sizeof(ev.features)); - - return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev), - NULL); -} diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c old mode 100644 new mode 100755 index 66cc1f0c..459fc0f9 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -544,6 +544,7 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int * BT_DBG("sock %p, sk %p", sock, sk); + memset(sa, 0, sizeof(*sa)); sa->rc_family = AF_BLUETOOTH; sa->rc_channel = rfcomm_pi(sk)->channel; if (peer) @@ -832,6 +833,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c } sec.level = rfcomm_pi(sk)->sec_level; + sec.key_size = 0; len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index e18781ce..435af03a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -472,7 +472,7 @@ static int rfcomm_get_dev_list(void __user *arg) size = sizeof(*dl) + dev_num * sizeof(*di); - dl = kmalloc(size, GFP_KERNEL); + dl = kzalloc(size, GFP_KERNEL); if (!dl) return -ENOMEM; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 5a4303d2..7990b4cd 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -1,7 +1,7 @@ /* BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Technologies, Inc. - Copyright (c) 2011, The Linux Foundation. All rights reserved. + Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (c) 2011, Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky @@ -24,6 +24,7 @@ */ /* Bluetooth SCO sockets. */ +// rollback to original BlueZ #include #include @@ -63,7 +64,7 @@ static struct bt_sock_list sco_sk_list = { static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); -static int sco_conn_del(struct hci_conn *conn, int err, u8 is_process); +static int sco_conn_del(struct hci_conn *conn, int err); static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); @@ -136,7 +137,7 @@ static inline struct sock *sco_chan_get(struct sco_conn *conn) return sk; } -static int sco_conn_del(struct hci_conn *hcon, int err, u8 is_process) +static int sco_conn_del(struct hci_conn *hcon, int err) { struct sco_conn *conn = hcon->sco_data; struct sock *sk; @@ -149,16 +150,10 @@ static int sco_conn_del(struct hci_conn *hcon, int err, u8 is_process) /* Kill socket */ sk = sco_chan_get(conn); if (sk) { - if (is_process) - lock_sock(sk); - else - bh_lock_sock(sk); + bh_lock_sock(sk); sco_sock_clear_timer(sk); sco_chan_del(sk, err); - if (is_process) - release_sock(sk); - else - bh_unlock_sock(sk); + bh_unlock_sock(sk); sco_sock_kill(sk); } @@ -403,6 +398,7 @@ static void __sco_sock_close(struct sock *sk) sco_chan_del(sk, ECONNRESET); break; + case BT_CONNECT2: case BT_CONNECT: case BT_DISCONN: sco_chan_del(sk, ECONNRESET); @@ -935,7 +931,7 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) int lm = 0; if (type != SCO_LINK && type != ESCO_LINK) - return 0; + return -EINVAL; BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); @@ -970,19 +966,19 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) if (conn) sco_conn_ready(conn); } else - sco_conn_del(hcon, bt_err(status), 0); + sco_conn_del(hcon, bt_err(status)); return 0; } -static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason, __u8 is_process) +static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) { BT_DBG("hcon %p reason %d", hcon, reason); if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) return -EINVAL; - sco_conn_del(hcon, bt_err(reason), is_process); + sco_conn_del(hcon, bt_err(reason)); return 0; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 276ff715..f881b5b6 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -19,6 +19,7 @@ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ +// rollback to original BlueZ #include #include @@ -655,7 +656,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) static int smp_encrypt_link(struct hci_conn *hcon, struct link_key *key) { struct key_master_id *master; - u8 sec_level; u8 zerobuf[8]; if (!hcon || !key || !key->data) @@ -670,17 +670,6 @@ static int smp_encrypt_link(struct hci_conn *hcon, struct link_key *key) hcon->enc_key_size = key->pin_len; hcon->sec_req = TRUE; - sec_level = authreq_to_seclevel(key->auth); - - BT_DBG("cur %d, req: %d", hcon->sec_level, sec_level); - - if (sec_level > hcon->sec_level) - hcon->pending_sec_level = sec_level; - - - if (!(hcon->link_mode & HCI_LM_ENCRYPT)) - hci_conn_hold(hcon); - hci_le_start_enc(hcon, master->ediv, master->rand, key->val); return 0; @@ -705,6 +694,11 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (smp_encrypt_link(hcon, key) < 0) goto invalid_key; + hcon->sec_level = authreq_to_seclevel(key->auth); + + if (!(hcon->link_mode & HCI_LM_ENCRYPT)) + hci_conn_hold(hcon); + return 0; } @@ -716,7 +710,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); - hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); @@ -736,26 +729,33 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) struct hci_conn *hcon = conn->hcon; __u8 authreq; - BT_DBG("conn %p hcon %p %d req: %d", - conn, hcon, hcon->sec_level, sec_level); + BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); - if (IS_ERR(hcon->hdev->tfm)) + if (IS_ERR(hcon->hdev->tfm)) { + BT_DBG("IS_ERR"); return 1; + } - if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) { + BT_DBG("HCI_CONN_ENCRYPT_PEND"); return -EINPROGRESS; + } - if (sec_level == BT_SECURITY_LOW) + if (sec_level == BT_SECURITY_LOW) { + BT_DBG("BT_SECURITY_LOW"); return 1; + } - - if (hcon->sec_level >= sec_level) + if (hcon->sec_level > sec_level) { + BT_DBG("hcon->sec_level > sec_level"); return 1; + } authreq = seclevel_to_authreq(sec_level); + BT_ERR("conn = %p, sec: %d", conn, sec_level); hcon->smp_conn = conn; - hcon->pending_sec_level = sec_level; + hcon->sec_level = sec_level; if ((hcon->link_mode & HCI_LM_MASTER) && !hcon->sec_req) { struct link_key *key; @@ -780,7 +780,6 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); - hci_conn_hold(hcon); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; @@ -788,6 +787,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) } done: + hcon->pending_sec_level = sec_level; set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; @@ -1040,17 +1040,15 @@ int smp_link_encrypt_cmplt(struct l2cap_conn *conn, u8 status, u8 encrypt) clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); - if (!status && encrypt && hcon->sec_level < hcon->pending_sec_level) - hcon->sec_level = hcon->pending_sec_level; - if (!status && encrypt && !hcon->sec_req) - return smp_distribute_keys(conn, 0); + smp_distribute_keys(conn, 0); /* Fall back to Pairing request if failed a Link Security request */ else if (hcon->sec_req && (status || !encrypt)) - smp_conn_security(conn, hcon->pending_sec_level); + smp_conn_security(conn, hcon->sec_level); - hci_conn_put(hcon); + else + hci_conn_put(hcon); return 0; } diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 6af54f2d..02208f49 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -17,6 +17,12 @@ #include #include +#define INVALID_UID ((uid_t) -1) +#define uid_valid(uid) ((uid) != -1) +#define uid_lte(a, b) ((a) <= (b)) +#define uid_eq(a, b) ((a) == (b)) +#define uid_gte(a, b) ((a) >= (b)) + int fib_default_rule_add(struct fib_rules_ops *ops, u32 pref, u32 table, u32 flags) { @@ -31,6 +37,8 @@ int fib_default_rule_add(struct fib_rules_ops *ops, r->pref = pref; r->table = table; r->flags = flags; + r->uid_start = INVALID_UID; + r->uid_end = INVALID_UID; r->fr_net = hold_net(ops->fro_net); /* The lock is not required here, the list in unreacheable @@ -177,6 +185,23 @@ void fib_rules_unregister(struct fib_rules_ops *ops) } EXPORT_SYMBOL_GPL(fib_rules_unregister); +static inline uid_t fib_nl_uid(struct nlattr *nla) +{ + return nla_get_u32(nla); +} + +static int nla_put_uid(struct sk_buff *skb, int idx, uid_t uid) +{ + return nla_put_u32(skb, idx, uid); +} + +static int fib_uid_range_match(struct flowi *fl, struct fib_rule *rule) +{ + return (!uid_valid(rule->uid_start) && !uid_valid(rule->uid_end)) || + (uid_gte(fl->flowi_uid, rule->uid_start) && + uid_lte(fl->flowi_uid, rule->uid_end)); +} + static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, struct flowi *fl, int flags) { @@ -191,6 +216,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask) goto out; + if (!fib_uid_range_match(fl, rule)) + goto out; + ret = ops->match(rule, fl, flags); out: return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; @@ -361,6 +389,19 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) } else if (rule->action == FR_ACT_GOTO) goto errout_free; + /* UID start and end must either both be valid or both unspecified. */ + rule->uid_start = rule->uid_end = INVALID_UID; + if (tb[FRA_UID_START] || tb[FRA_UID_END]) { + if (tb[FRA_UID_START] && tb[FRA_UID_END]) { + rule->uid_start = fib_nl_uid(tb[FRA_UID_START]); + rule->uid_end = fib_nl_uid(tb[FRA_UID_END]); + } + if (!uid_valid(rule->uid_start) || + !uid_valid(rule->uid_end) || + !uid_lte(rule->uid_start, rule->uid_end)) + goto errout_free; + } + err = ops->configure(rule, skb, frh, tb); if (err < 0) goto errout_free; @@ -467,6 +508,14 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK]))) continue; + if (tb[FRA_UID_START] && + !uid_eq(rule->uid_start, fib_nl_uid(tb[FRA_UID_START]))) + continue; + + if (tb[FRA_UID_END] && + !uid_eq(rule->uid_end, fib_nl_uid(tb[FRA_UID_END]))) + continue; + if (!ops->compare(rule, frh, tb)) continue; @@ -521,7 +570,9 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, + nla_total_size(4) /* FRA_PRIORITY */ + nla_total_size(4) /* FRA_TABLE */ + nla_total_size(4) /* FRA_FWMARK */ - + nla_total_size(4); /* FRA_FWMASK */ + + nla_total_size(4) /* FRA_FWMASK */ + + nla_total_size(4) /* FRA_UID_START */ + + nla_total_size(4); /* FRA_UID_END */ if (ops->nlmsg_payload) payload += ops->nlmsg_payload(rule); @@ -579,6 +630,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, if (rule->target) NLA_PUT_U32(skb, FRA_GOTO, rule->target); + if (uid_valid(rule->uid_start)) + nla_put_uid(skb, FRA_UID_START, rule->uid_start); + + if (uid_valid(rule->uid_end)) + nla_put_uid(skb, FRA_UID_END, rule->uid_end); + if (ops->fill(rule, skb, frh) < 0) goto nla_put_failure; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index cbe3a685..0a24199f 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -481,6 +481,7 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = { [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, [RTA_FLOW] = { .type = NLA_U32 }, + [RTA_UID] = { .type = NLA_U32 }, }; static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 3f404325..c4784c32 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -365,7 +365,8 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, - ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport, + sock_i_uid(sk)); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) @@ -398,7 +399,8 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, - ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport, + sock_i_uid(sk)); security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 330be870..1a939d8b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1504,7 +1504,8 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, RT_SCOPE_UNIVERSE, sk->sk_protocol, ip_reply_arg_flowi_flags(arg), daddr, rt->rt_spec_dst, - tcp_hdr(skb)->source, tcp_hdr(skb)->dest); + tcp_hdr(skb)->source, tcp_hdr(skb)->dest, + arg->uid); security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(sock_net(sk), &fl4); if (IS_ERR(rt)) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 9f471c32..5e788f0f 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -568,7 +568,8 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, - inet_sk_flowi_flags(sk), faddr, saddr, 0, 0); + inet_sk_flowi_flags(sk), faddr, saddr, 0, 0, + sock_i_uid(sk)); security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index c1b3970c..a8f60180 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -568,8 +568,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, - inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP, - daddr, saddr, 0, 0); + FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0, + sock_i_uid(sk)); if (!inet->hdrincl) { err = raw_probe_proto_opt(&fl4, msg); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6c34bc98..5c774c14 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -743,6 +743,7 @@ static inline int compare_keys(struct rtable *rt1, struct rtable *rt2) (rt1->rt_mark ^ rt2->rt_mark) | (rt1->rt_key_tos ^ rt2->rt_key_tos) | (rt1->rt_route_iif ^ rt2->rt_route_iif) | + (rt1->rt_uid ^ rt2->rt_uid) | (rt1->rt_oif ^ rt2->rt_oif)) == 0; } @@ -1913,6 +1914,7 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt) fl4.flowi4_oif = rt->dst.dev->ifindex; fl4.flowi4_iif = skb->dev->ifindex; fl4.flowi4_mark = skb->mark; + fl4.flowi4_uid = skb->sk ? sock_i_uid(skb->sk) : 0; rcu_read_lock(); if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res) == 0) @@ -2096,6 +2098,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->rt_iif = dev->ifindex; rth->rt_oif = 0; rth->rt_mark = skb->mark; + rth->rt_uid = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->rt_peer_genid = 0; @@ -2225,6 +2228,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->rt_iif = in_dev->dev->ifindex; rth->rt_oif = 0; rth->rt_mark = skb->mark; + rth->rt_uid = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->rt_peer_genid = 0; @@ -2408,6 +2412,7 @@ out: return err; rth->rt_iif = dev->ifindex; rth->rt_oif = 0; rth->rt_mark = skb->mark; + rth->rt_uid = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->rt_peer_genid = 0; @@ -2612,6 +2617,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rth->rt_iif = orig_oif ? : dev_out->ifindex; rth->rt_oif = orig_oif; rth->rt_mark = fl4->flowi4_mark; + rth->rt_uid = fl4->flowi4_uid; rth->rt_gateway = fl4->daddr; rth->rt_spec_dst= fl4->saddr; rth->rt_peer_genid = 0; @@ -2863,6 +2869,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4) rt_is_output_route(rth) && rth->rt_oif == flp4->flowi4_oif && rth->rt_mark == flp4->flowi4_mark && + rth->rt_uid == flp4->flowi4_uid && !((rth->rt_key_tos ^ flp4->flowi4_tos) & (IPTOS_RT_MASK | RTO_ONLINK)) && net_eq(dev_net(rth->dst.dev), net) && @@ -2944,6 +2951,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or rt->rt_iif = ort->rt_iif; rt->rt_oif = ort->rt_oif; rt->rt_mark = ort->rt_mark; + rt->rt_uid = ort->rt_uid; rt->rt_genid = rt_genid(net); rt->rt_flags = ort->rt_flags; @@ -3039,6 +3047,9 @@ static int rt_fill_info(struct net *net, if (rt->rt_mark) NLA_PUT_BE32(skb, RTA_MARK, rt->rt_mark); + if (rt->rt_uid != (uid_t) -1) + NLA_PUT_BE32(skb, RTA_UID, rt->rt_uid); + error = rt->dst.error; if (peer) { inet_peer_refcheck(rt->peer); @@ -3157,6 +3168,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void .flowi4_tos = rtm->rtm_tos, .flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, .flowi4_mark = mark, + .flowi4_uid = tb[RTA_UID] ? nla_get_u32(tb[RTA_UID]) : current_uid(), }; rt = ip_route_output_key(net, &fl4); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 550aa2a9..50fc86fc 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -351,7 +351,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP, inet_sk_flowi_flags(sk), (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, - ireq->loc_addr, th->source, th->dest); + ireq->loc_addr, th->source, th->dest, + sock_i_uid(sk)) security_req_classify_flow(req, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(sock_net(sk), &fl4); if (IS_ERR(rt)) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5f8c20b6..cf5f672b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -932,7 +932,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, - faddr, saddr, dport, inet->inet_sport); + faddr, saddr, dport, inet->inet_sport, + sock_i_uid(sk)); security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index a0b4c5da..e8ee4279 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -86,6 +86,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, xdst->u.rt.rt_iif = fl4->flowi4_iif; xdst->u.rt.rt_oif = fl4->flowi4_oif; xdst->u.rt.rt_mark = fl4->flowi4_mark; + xdst->u.rt.rt_uid = fl4->flowi4_uid; xdst->u.dst.dev = dev; dev_hold(dev); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 29625e9a..1f7ab56f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -701,6 +701,7 @@ int inet6_sk_rebuild_header(struct sock *sk) fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); final_p = fl6_update_dst(&fl6, np->opt, &final); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 94e5258f..a21a2ecb 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -160,6 +160,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); if (!fl6.flowi6_oif && (addr_type&IPV6_ADDR_MULTICAST)) fl6.flowi6_oif = np->mcast_oif; diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 02dd203d..21ee0027 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -72,6 +72,7 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet_rsk(req)->rmt_port; fl6.fl6_sport = inet_rsk(req)->loc_port; + fl6.flowi6_uid = sock_i_uid(sk); security_req_classify_flow(req, flowi6_to_flowi(&fl6)); dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); @@ -223,6 +224,7 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused) fl6.flowi6_mark = sk->sk_mark; fl6.fl6_sport = inet->inet_sport; fl6.fl6_dport = inet->inet_dport; + fl6.flowi6_uid = sock_i_uid(sk); security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); final_p = fl6_update_dst(&fl6, np->opt, &final); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d6820d01..cf32b834 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -758,6 +758,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sock_i_uid(sk); if (sin6) { if (addr_len < SIN6_LEN_RFC2133) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 23b33048..cb1143d2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2298,6 +2298,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_IIF] = { .type = NLA_U32 }, [RTA_PRIORITY] = { .type = NLA_U32 }, [RTA_METRICS] = { .type = NLA_NESTED }, + [RTA_UID] = { .type = NLA_U32 }, }; static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2610,6 +2611,11 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (tb[RTA_OIF]) oif = nla_get_u32(tb[RTA_OIF]); + if (tb[RTA_UID]) + fl6.flowi6_uid = nla_get_u32(tb[RTA_UID]); + else + fl6.flowi6_uid = (iif ? (uid_t) -1 : current_uid()); + if (iif) { struct net_device *dev; int flags = 0; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 8e951d8d..83ee321c 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -244,6 +244,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet_rsk(req)->rmt_port; fl6.fl6_sport = inet_sk(sk)->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); security_req_classify_flow(req, flowi6_to_flowi(&fl6)); dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8dd4210a..8c756628 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -251,6 +251,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = usin->sin6_port; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); final_p = fl6_update_dst(&fl6, np->opt, &final); @@ -404,6 +405,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet->inet_dport; fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false); @@ -496,6 +498,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, fl6.flowi6_mark = sk->sk_mark; fl6.fl6_dport = inet_rsk(req)->rmt_port; fl6.fl6_sport = inet_rsk(req)->loc_port; + fl6.flowi6_uid = sock_i_uid(sk); security_req_classify_flow(req, flowi6_to_flowi(&fl6)); opt = np->opt; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 2f99b12b..dedfd528 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1087,6 +1087,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; fl6.flowi6_mark = sk->sk_mark; + fl6.flowi6_uid = sock_i_uid(sk); if (msg->msg_controllen) { opt = &opt_space; diff --git a/net/wireless_ath/Makefile b/net/wireless_ath/Makefile new file mode 100644 index 00000000..2af9470d --- /dev/null +++ b/net/wireless_ath/Makefile @@ -0,0 +1,23 @@ +NOSTDINC_FLAGS := -I$(srctree)/include/compat/ \ + -include $(srctree)/include/compat/linux/compat-2.6.h \ + $(CFLAGS) + +obj-$(CONFIG_CFG80211) += cfg80211.o + +obj-$(CONFIG_WEXT_CORE) += wext-core.o +obj-$(CONFIG_WEXT_PROC) += wext-proc.o +obj-$(CONFIG_WEXT_SPY) += wext-spy.o +obj-$(CONFIG_WEXT_PRIV) += wext-priv.o + +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o +cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o +cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o +cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o +cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o + +ccflags-y += -D__CHECK_ENDIAN__ + +$(obj)/regdb.c: $(srctree)/$(src)/db.txt $(srctree)/$(src)/genregdb.awk + @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@ + +clean-files := regdb.c \ No newline at end of file diff --git a/net/wireless_ath/Makefile.bk b/net/wireless_ath/Makefile.bk new file mode 100644 index 00000000..9b12455b --- /dev/null +++ b/net/wireless_ath/Makefile.bk @@ -0,0 +1,18 @@ +obj-$(CONFIG_CFG80211) += cfg80211.o +obj-$(CONFIG_LIB80211) += lib80211.o +obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o +obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o +obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o + +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o +cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o +cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o +cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o +cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o + +ccflags-y += -D__CHECK_ENDIAN__ + +$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk + @$(AWK) -f $(src)/genregdb.awk < $< > $@ + +clean-files := regdb.c diff --git a/net/wireless_ath/chan.c b/net/wireless_ath/chan.c new file mode 100644 index 00000000..17cd0c04 --- /dev/null +++ b/net/wireless_ath/chan.c @@ -0,0 +1,135 @@ +/* + * This file contains helper code to handle channel + * settings and keeping track of what is possible at + * any point in time. + * + * Copyright 2009 Johannes Berg + */ + +#include +#include "core.h" + +struct ieee80211_channel * +rdev_freq_to_chan(struct cfg80211_registered_device *rdev, + int freq, enum nl80211_channel_type channel_type) +{ + struct ieee80211_channel *chan; + struct ieee80211_sta_ht_cap *ht_cap; + + chan = ieee80211_get_channel(&rdev->wiphy, freq); + + /* Primary channel not allowed */ + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) + return NULL; + + if (channel_type == NL80211_CHAN_HT40MINUS && + chan->flags & IEEE80211_CHAN_NO_HT40MINUS) + return NULL; + else if (channel_type == NL80211_CHAN_HT40PLUS && + chan->flags & IEEE80211_CHAN_NO_HT40PLUS) + return NULL; + + ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; + + if (channel_type != NL80211_CHAN_NO_HT) { + if (!ht_cap->ht_supported) + return NULL; + + if (channel_type != NL80211_CHAN_HT20 && + (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || + ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) + return NULL; + } + + return chan; +} + +static bool can_beacon_sec_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ieee80211_channel *sec_chan; + int diff; + + switch (channel_type) { + case NL80211_CHAN_HT40PLUS: + diff = 20; + break; + case NL80211_CHAN_HT40MINUS: + diff = -20; + break; + default: + return false; + } + + sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); + if (!sec_chan) + return false; + + /* we'll need a DFS capability later */ + if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR)) + return false; + + return true; +} + +int cfg80211_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, int freq, + enum nl80211_channel_type channel_type) +{ + struct ieee80211_channel *chan; + int result; + + if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) + wdev = NULL; + + if (wdev) { + ASSERT_WDEV_LOCK(wdev); + + if (!netif_running(wdev->netdev)) + return -ENETDOWN; + } + + if (!rdev->ops->set_channel) + return -EOPNOTSUPP; + + chan = rdev_freq_to_chan(rdev, freq, channel_type); + if (!chan) + return -EINVAL; + + /* Both channels should be able to initiate communication */ + if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC || + wdev->iftype == NL80211_IFTYPE_AP || + wdev->iftype == NL80211_IFTYPE_AP_VLAN || + wdev->iftype == NL80211_IFTYPE_MESH_POINT || + wdev->iftype == NL80211_IFTYPE_P2P_GO)) { + switch (channel_type) { + case NL80211_CHAN_HT40PLUS: + case NL80211_CHAN_HT40MINUS: + if (!can_beacon_sec_chan(&rdev->wiphy, chan, + channel_type)) { + printk(KERN_DEBUG + "cfg80211: Secondary channel not " + "allowed to initiate communication\n"); + return -EINVAL; + } + break; + default: + break; + } + } + + result = rdev->ops->set_channel(&rdev->wiphy, + wdev ? wdev->netdev : NULL, + chan, channel_type); + if (result) + return result; + + if (wdev) + wdev->channel = chan; + + return 0; +} diff --git a/net/wireless_ath/core.c b/net/wireless_ath/core.c new file mode 100644 index 00000000..4e843bbd --- /dev/null +++ b/net/wireless_ath/core.c @@ -0,0 +1,1104 @@ +/* + * This is the linux wireless configuration interface. + * + * Copyright 2006-2010 Johannes Berg + */ + +//#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nl80211.h" +#include "core.h" +#include "sysfs.h" +#include "debugfs.h" +#include "wext-compat.h" +#include "ethtool.h" + +/* name for sysfs, %d is appended */ +#define PHY_NAME "phy" + +MODULE_AUTHOR("Johannes Berg"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("wireless configuration support"); + +/* RCU-protected (and cfg80211_mutex for writers) */ +LIST_HEAD(cfg80211_rdev_list); +int cfg80211_rdev_list_generation; + +DEFINE_MUTEX(cfg80211_mutex); + +/* for debugfs */ +static struct dentry *ieee80211_debugfs_dir; + +/* for the cleanup, scan and event works */ +struct workqueue_struct *cfg80211_wq; + +static bool cfg80211_disable_40mhz_24ghz; +module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); +MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, + "Disable 40MHz support in the 2.4GHz band"); + +/* requires cfg80211_mutex to be held! */ +struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) +{ + struct cfg80211_registered_device *result = NULL, *rdev; + + if (!wiphy_idx_valid(wiphy_idx)) + return NULL; + + assert_cfg80211_lock(); + + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (rdev->wiphy_idx == wiphy_idx) { + result = rdev; + break; + } + } + + return result; +} + +int get_wiphy_idx(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *rdev; + if (!wiphy) + return WIPHY_IDX_STALE; + rdev = wiphy_to_dev(wiphy); + return rdev->wiphy_idx; +} + +/* requires cfg80211_rdev_mutex to be held! */ +struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) +{ + struct cfg80211_registered_device *rdev; + + if (!wiphy_idx_valid(wiphy_idx)) + return NULL; + + assert_cfg80211_lock(); + + rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); + if (!rdev) + return NULL; + return &rdev->wiphy; +} + +/* requires cfg80211_mutex to be held! */ +struct cfg80211_registered_device * +__cfg80211_rdev_from_info(struct genl_info *info) +{ + int ifindex; + struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; + struct net_device *dev; + int err = -EINVAL; + + assert_cfg80211_lock(); + + if (info->attrs[NL80211_ATTR_WIPHY]) { + bywiphyidx = cfg80211_rdev_by_wiphy_idx( + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); + err = -ENODEV; + } + + if (info->attrs[NL80211_ATTR_IFINDEX]) { + ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); + dev = dev_get_by_index(genl_info_net(info), ifindex); + if (dev) { + if (dev->ieee80211_ptr) + byifidx = + wiphy_to_dev(dev->ieee80211_ptr->wiphy); + dev_put(dev); + } + err = -ENODEV; + } + + if (bywiphyidx && byifidx) { + if (bywiphyidx != byifidx) + return ERR_PTR(-EINVAL); + else + return bywiphyidx; /* == byifidx */ + } + if (bywiphyidx) + return bywiphyidx; + + if (byifidx) + return byifidx; + + return ERR_PTR(err); +} + +struct cfg80211_registered_device * +cfg80211_get_dev_from_info(struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + + mutex_lock(&cfg80211_mutex); + rdev = __cfg80211_rdev_from_info(info); + + /* if it is not an error we grab the lock on + * it to assure it won't be going away while + * we operate on it */ + if (!IS_ERR(rdev)) + mutex_lock(&rdev->mtx); + + mutex_unlock(&cfg80211_mutex); + + return rdev; +} + +struct cfg80211_registered_device * +cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) +{ + struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); + struct net_device *dev; + + mutex_lock(&cfg80211_mutex); + dev = dev_get_by_index(net, ifindex); + if (!dev) + goto out; + if (dev->ieee80211_ptr) { + rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); + mutex_lock(&rdev->mtx); + } else + rdev = ERR_PTR(-ENODEV); + dev_put(dev); + out: + mutex_unlock(&cfg80211_mutex); + return rdev; +} + +/* requires cfg80211_mutex to be held */ +int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, + char *newname) +{ + struct cfg80211_registered_device *rdev2; + int wiphy_idx, taken = -1, result, digits; + + assert_cfg80211_lock(); + + /* prohibit calling the thing phy%d when %d is not its number */ + sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); + if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { + /* count number of places needed to print wiphy_idx */ + digits = 1; + while (wiphy_idx /= 10) + digits++; + /* + * deny the name if it is phy where is printed + * without leading zeroes. taken == strlen(newname) here + */ + if (taken == strlen(PHY_NAME) + digits) + return -EINVAL; + } + + + /* Ignore nop renames */ + if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) + return 0; + + /* Ensure another device does not already have this name. */ + list_for_each_entry(rdev2, &cfg80211_rdev_list, list) + if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) + return -EINVAL; + + result = device_rename(&rdev->wiphy.dev, newname); + if (result) + return result; + + if (rdev->wiphy.debugfsdir && + !debugfs_rename(rdev->wiphy.debugfsdir->d_parent, + rdev->wiphy.debugfsdir, + rdev->wiphy.debugfsdir->d_parent, + newname)) + pr_err("failed to rename debugfs dir to %s!\n", newname); + + nl80211_notify_dev_rename(rdev); + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) +int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net) +{ + struct wireless_dev *wdev; + int err = 0; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) + return -EOPNOTSUPP; + + list_for_each_entry(wdev, &rdev->netdev_list, list) { + wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; + err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); + if (err) + break; + wdev->netdev->features |= NETIF_F_NETNS_LOCAL; + } + + if (err) { + /* failed -- clean up to old netns */ + net = wiphy_net(&rdev->wiphy); + + list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, + list) { + wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; + err = dev_change_net_namespace(wdev->netdev, net, + "wlan%d"); + WARN_ON(err); + wdev->netdev->features |= NETIF_F_NETNS_LOCAL; + } + + return err; + } + + wiphy_net_set(&rdev->wiphy, net); + + err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); + WARN_ON(err); + + return 0; +} +#endif + +static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) +{ + struct cfg80211_registered_device *rdev = data; + + rdev->ops->rfkill_poll(&rdev->wiphy); +} + +static int cfg80211_rfkill_set_block(void *data, bool blocked) +{ + struct cfg80211_registered_device *rdev = data; + struct wireless_dev *wdev; + + if (!blocked) + return 0; + + rtnl_lock(); + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->netdev_list, list) + dev_close(wdev->netdev); + + mutex_unlock(&rdev->devlist_mtx); + rtnl_unlock(); + + return 0; +} + +static void cfg80211_rfkill_sync_work(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync); + cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); +} + +static void cfg80211_event_work(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(work, struct cfg80211_registered_device, + event_work); + + rtnl_lock(); + cfg80211_lock_rdev(rdev); + + cfg80211_process_rdev_events(rdev); + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); +} + +/* exported functions */ + +struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) +{ + static int wiphy_counter; + + struct cfg80211_registered_device *rdev; + int alloc_size; + + /* + * Make sure the padding is >= the rest of the struct so that we + * always keep it large enough to pad out the entire original + * kernel's struct. We really only need to make sure it's larger + * than the kernel compat is compiled against, but since it'll + * only increase in size make sure it's larger than the current + * version of it. Subtract since it's included. + */ + BUILD_BUG_ON(WIPHY_COMPAT_PAD_SIZE < + sizeof(struct wiphy) - WIPHY_COMPAT_PAD_SIZE); + + WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); + WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); + WARN_ON(ops->connect && !ops->disconnect); + WARN_ON(ops->join_ibss && !ops->leave_ibss); + WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); + WARN_ON(ops->add_station && !ops->del_station); + WARN_ON(ops->add_mpath && !ops->del_mpath); + WARN_ON(ops->join_mesh && !ops->leave_mesh); + + alloc_size = sizeof(*rdev) + sizeof_priv; + + rdev = kzalloc(alloc_size, GFP_KERNEL); + if (!rdev) + return NULL; + + rdev->ops = ops; + + mutex_lock(&cfg80211_mutex); + + rdev->wiphy_idx = wiphy_counter++; + + if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { + wiphy_counter--; + mutex_unlock(&cfg80211_mutex); + /* ugh, wrapped! */ + kfree(rdev); + return NULL; + } + + mutex_unlock(&cfg80211_mutex); + + /* give it a proper name */ + dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); + + mutex_init(&rdev->mtx); + mutex_init(&rdev->devlist_mtx); + mutex_init(&rdev->sched_scan_mtx); + INIT_LIST_HEAD(&rdev->netdev_list); + spin_lock_init(&rdev->bss_lock); + INIT_LIST_HEAD(&rdev->bss_list); + INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); + INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); + device_initialize(&rdev->wiphy.dev); + rdev->wiphy.dev.class = &ieee80211_class; + rdev->wiphy.dev.platform_data = rdev; + +#ifdef CONFIG_CFG80211_DEFAULT_PS + rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + wiphy_net_set(&rdev->wiphy, &init_net); +#endif + + rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; + rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev), + &rdev->wiphy.dev, RFKILL_TYPE_WLAN, + &rdev->rfkill_ops, rdev); + + if (!rdev->rfkill) { + kfree(rdev); + return NULL; + } + + INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); + + init_waitqueue_head(&rdev->dev_wait); + + /* + * Initialize wiphy parameters to IEEE 802.11 MIB default values. + * Fragmentation and RTS threshold are disabled by default with the + * special -1 value. + */ + rdev->wiphy.retry_short = 7; + rdev->wiphy.retry_long = 4; + rdev->wiphy.frag_threshold = (u32) -1; + rdev->wiphy.rts_threshold = (u32) -1; + rdev->wiphy.coverage_class = 0; + + return &rdev->wiphy; +} +EXPORT_SYMBOL(wiphy_new); + +static int wiphy_verify_combinations(struct wiphy *wiphy) +{ + const struct ieee80211_iface_combination *c; + int i, j; + + /* If we have combinations enforce them */ + if (wiphy->n_iface_combinations) + wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS; + + for (i = 0; i < wiphy->n_iface_combinations; i++) { + u32 cnt = 0; + u16 all_iftypes = 0; + + c = &wiphy->iface_combinations[i]; + + /* Combinations with just one interface aren't real */ + if (WARN_ON(c->max_interfaces < 2)) + return -EINVAL; + + /* Need at least one channel */ + if (WARN_ON(!c->num_different_channels)) + return -EINVAL; + + if (WARN_ON(!c->n_limits)) + return -EINVAL; + + for (j = 0; j < c->n_limits; j++) { + u16 types = c->limits[j].types; + + /* + * interface types shouldn't overlap, this is + * used in cfg80211_can_change_interface() + */ + if (WARN_ON(types & all_iftypes)) + return -EINVAL; + all_iftypes |= types; + + if (WARN_ON(!c->limits[j].max)) + return -EINVAL; + + /* Shouldn't list software iftypes in combinations! */ + if (WARN_ON(wiphy->software_iftypes & types)) + return -EINVAL; + + cnt += c->limits[j].max; + /* + * Don't advertise an unsupported type + * in a combination. + */ + if (WARN_ON((wiphy->interface_modes & types) != types)) + return -EINVAL; + } + + /* You can't even choose that many! */ + if (WARN_ON(cnt < c->max_interfaces)) + return -EINVAL; + } + + return 0; +} + +int wiphy_register(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + int res; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + bool have_band = false; + int i; + u16 ifmodes = wiphy->interface_modes; + + if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && + !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) + return -EINVAL; + + if (WARN_ON(wiphy->ap_sme_capa && + !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) + return -EINVAL; + + if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) + return -EINVAL; + + if (WARN_ON(wiphy->addresses && + !is_zero_ether_addr(wiphy->perm_addr) && + memcmp(wiphy->perm_addr, wiphy->addresses[0].addr, + ETH_ALEN))) + return -EINVAL; + + if (wiphy->addresses) + memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); + + /* sanity check ifmodes */ + WARN_ON(!ifmodes); + ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1; + if (WARN_ON(ifmodes != wiphy->interface_modes)) + wiphy->interface_modes = ifmodes; + + res = wiphy_verify_combinations(wiphy); + if (res) + return res; + + /* sanity check supported bands/channels */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + + sband->band = band; + + if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) + return -EINVAL; + + /* + * Since cfg80211_disable_40mhz_24ghz is global, we can + * modify the sband's ht data even if the driver uses a + * global structure for that. + */ + if (cfg80211_disable_40mhz_24ghz && + band == IEEE80211_BAND_2GHZ && + sband->ht_cap.ht_supported) { + sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; + } + + /* + * Since we use a u32 for rate bitmaps in + * ieee80211_get_response_rate, we cannot + * have more than 32 legacy rates. + */ + if (WARN_ON(sband->n_bitrates > 32)) + return -EINVAL; + + for (i = 0; i < sband->n_channels; i++) { + sband->channels[i].orig_flags = + sband->channels[i].flags; + sband->channels[i].orig_mag = + sband->channels[i].max_antenna_gain; + sband->channels[i].orig_mpwr = + sband->channels[i].max_power; + sband->channels[i].band = band; + } + + have_band = true; + } + + if (!have_band) { + WARN_ON(1); + return -EINVAL; + } + + if (rdev->wiphy.wowlan.n_patterns) { + if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || + rdev->wiphy.wowlan.pattern_min_len > + rdev->wiphy.wowlan.pattern_max_len)) + return -EINVAL; + } + + /* check and set up bitrates */ + ieee80211_set_bitrate_flags(wiphy); + + mutex_lock(&cfg80211_mutex); + + res = device_add(&rdev->wiphy.dev); + if (res) { + mutex_unlock(&cfg80211_mutex); + return res; + } + + /* set up regulatory info */ + regulatory_update(wiphy, NL80211_REGDOM_SET_BY_CORE); + + list_add_rcu(&rdev->list, &cfg80211_rdev_list); + cfg80211_rdev_list_generation++; + + /* add to debugfs */ + rdev->wiphy.debugfsdir = + debugfs_create_dir(wiphy_name(&rdev->wiphy), + ieee80211_debugfs_dir); + if (IS_ERR(rdev->wiphy.debugfsdir)) + rdev->wiphy.debugfsdir = NULL; + + if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { + struct regulatory_request request; + + request.wiphy_idx = get_wiphy_idx(wiphy); + request.initiator = NL80211_REGDOM_SET_BY_DRIVER; + request.alpha2[0] = '9'; + request.alpha2[1] = '9'; + + nl80211_send_reg_change_event(&request); + } + + cfg80211_debugfs_rdev_add(rdev); + mutex_unlock(&cfg80211_mutex); + + /* + * due to a locking dependency this has to be outside of the + * cfg80211_mutex lock + */ + res = rfkill_register(rdev->rfkill); + if (res) + goto out_rm_dev; + + rtnl_lock(); + rdev->wiphy.registered = true; + rtnl_unlock(); + return 0; + +out_rm_dev: + device_del(&rdev->wiphy.dev); + return res; +} +EXPORT_SYMBOL(wiphy_register); + +void wiphy_rfkill_start_polling(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + if (!rdev->ops->rfkill_poll) + return; + rdev->rfkill_ops.poll = cfg80211_rfkill_poll; + rfkill_resume_polling(rdev->rfkill); +} +EXPORT_SYMBOL(wiphy_rfkill_start_polling); + +void wiphy_rfkill_stop_polling(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + rfkill_pause_polling(rdev->rfkill); +} +EXPORT_SYMBOL(wiphy_rfkill_stop_polling); + +void wiphy_unregister(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + rtnl_lock(); + rdev->wiphy.registered = false; + rtnl_unlock(); + + rfkill_unregister(rdev->rfkill); + + /* protect the device list */ + mutex_lock(&cfg80211_mutex); + + wait_event(rdev->dev_wait, ({ + int __count; + mutex_lock(&rdev->devlist_mtx); + __count = rdev->opencount; + mutex_unlock(&rdev->devlist_mtx); + __count == 0;})); + + mutex_lock(&rdev->devlist_mtx); + BUG_ON(!list_empty(&rdev->netdev_list)); + mutex_unlock(&rdev->devlist_mtx); + + /* + * First remove the hardware from everywhere, this makes + * it impossible to find from userspace. + */ + debugfs_remove_recursive(rdev->wiphy.debugfsdir); + list_del_rcu(&rdev->list); + synchronize_rcu(); + + /* + * Try to grab rdev->mtx. If a command is still in progress, + * hopefully the driver will refuse it since it's tearing + * down the device already. We wait for this command to complete + * before unlinking the item from the list. + * Note: as codified by the BUG_ON above we cannot get here if + * a virtual interface is still present. Hence, we can only get + * to lock contention here if userspace issues a command that + * identified the hardware by wiphy index. + */ + cfg80211_lock_rdev(rdev); + /* nothing */ + cfg80211_unlock_rdev(rdev); + + /* If this device got a regulatory hint tell core its + * free to listen now to a new shiny device regulatory hint */ + reg_device_remove(wiphy); + + cfg80211_rdev_list_generation++; + device_del(&rdev->wiphy.dev); + + mutex_unlock(&cfg80211_mutex); + + flush_work(&rdev->scan_done_wk); + cancel_work_sync(&rdev->conn_work); + flush_work(&rdev->event_work); +} +EXPORT_SYMBOL(wiphy_unregister); + +void cfg80211_dev_free(struct cfg80211_registered_device *rdev) +{ + struct cfg80211_internal_bss *scan, *tmp; + rfkill_destroy(rdev->rfkill); + mutex_destroy(&rdev->mtx); + mutex_destroy(&rdev->devlist_mtx); + mutex_destroy(&rdev->sched_scan_mtx); + list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) + cfg80211_put_bss(&scan->pub); + cfg80211_rdev_free_wowlan(rdev); + kfree(rdev); +} + +void wiphy_free(struct wiphy *wiphy) +{ + put_device(&wiphy->dev); +} +EXPORT_SYMBOL(wiphy_free); + +void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + if (rfkill_set_hw_state(rdev->rfkill, blocked)) + schedule_work(&rdev->rfkill_sync); +} +EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); + +static void wdev_cleanup_work(struct work_struct *work) +{ + struct wireless_dev *wdev; + struct cfg80211_registered_device *rdev; + + wdev = container_of(work, struct wireless_dev, cleanup_work); + rdev = wiphy_to_dev(wdev->wiphy); + + cfg80211_lock_rdev(rdev); + + if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev, true); + } + + cfg80211_unlock_rdev(rdev); + + mutex_lock(&rdev->sched_scan_mtx); + + if (WARN_ON(rdev->sched_scan_req && + rdev->sched_scan_req->dev == wdev->netdev)) { + __cfg80211_stop_sched_scan(rdev, false); + } + + mutex_unlock(&rdev->sched_scan_mtx); + + mutex_lock(&rdev->devlist_mtx); + rdev->opencount--; + mutex_unlock(&rdev->devlist_mtx); + wake_up(&rdev->dev_wait); + + dev_put(wdev->netdev); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) +static struct device_type wiphy_type = { + .name = "wlan", +}; +#endif + +static int cfg80211_netdev_notifier_call(struct notifier_block * nb, + unsigned long state, + void *ndev) +{ + struct net_device *dev = ndev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev; + int ret; + + if (!wdev) + return NOTIFY_DONE; + + rdev = wiphy_to_dev(wdev->wiphy); + + WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED); + + switch (state) { + case NETDEV_POST_INIT: + SET_NETDEV_DEVTYPE(dev, &wiphy_type); + break; + case NETDEV_REGISTER: + /* + * NB: cannot take rdev->mtx here because this may be + * called within code protected by it when interfaces + * are added with nl80211. + */ + mutex_init(&wdev->mtx); + INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); + INIT_LIST_HEAD(&wdev->event_list); + spin_lock_init(&wdev->event_lock); + INIT_LIST_HEAD(&wdev->mgmt_registrations); + spin_lock_init(&wdev->mgmt_registrations_lock); + + mutex_lock(&rdev->devlist_mtx); + list_add_rcu(&wdev->list, &rdev->netdev_list); + rdev->devlist_generation++; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + /* can only change netns with wiphy */ + dev->features |= NETIF_F_NETNS_LOCAL; +#endif + + if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, + "phy80211")) { + pr_err("failed to add phy80211 symlink to netdev!\n"); + } + wdev->netdev = dev; + wdev->sme_state = CFG80211_SME_IDLE; + mutex_unlock(&rdev->devlist_mtx); +#ifdef CONFIG_CFG80211_WEXT +#ifdef CONFIG_WIRELESS_EXT + if (!dev->wireless_handlers) + dev->wireless_handlers = &cfg80211_wext_handler; +#else + printk_once(KERN_WARNING "cfg80211: wext will not work because " + "kernel was compiled with CONFIG_WIRELESS_EXT=n. " + "Tools using wext interface, like iwconfig will " + "not work.\n"); +#endif + wdev->wext.default_key = -1; + wdev->wext.default_mgmt_key = -1; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; +#endif + + if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) + wdev->ps = true; + else + wdev->ps = false; + /* allow mac80211 to determine the timeout */ + wdev->ps_timeout = -1; + + if (!dev->ethtool_ops) + dev->ethtool_ops = &cfg80211_ethtool_ops; + + if ((wdev->iftype == NL80211_IFTYPE_STATION || + wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || + wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) + dev->priv_flags |= IFF_DONT_BRIDGE; + break; + case NETDEV_GOING_DOWN: + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + cfg80211_leave_ibss(rdev, dev, true); + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + mutex_lock(&rdev->sched_scan_mtx); + __cfg80211_stop_sched_scan(rdev, false); + mutex_unlock(&rdev->sched_scan_mtx); + + wdev_lock(wdev); +#ifdef CONFIG_CFG80211_WEXT + kfree(wdev->wext.ie); + wdev->wext.ie = NULL; + wdev->wext.ie_len = 0; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; +#endif + __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, true); + cfg80211_mlme_down(rdev, dev); + wdev_unlock(wdev); + break; + case NL80211_IFTYPE_MESH_POINT: + cfg80211_leave_mesh(rdev, dev); + break; + default: + break; + } + wdev->beacon_interval = 0; + break; + case NETDEV_DOWN: + dev_hold(dev); + queue_work(cfg80211_wq, &wdev->cleanup_work); + break; + case NETDEV_UP: + /* + * If we have a really quick DOWN/UP succession we may + * have this work still pending ... cancel it and see + * if it was pending, in which case we need to account + * for some of the work it would have done. + */ + if (cancel_work_sync(&wdev->cleanup_work)) { + mutex_lock(&rdev->devlist_mtx); + rdev->opencount--; + mutex_unlock(&rdev->devlist_mtx); + dev_put(dev); + } + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + switch (wdev->iftype) { +#ifdef CONFIG_CFG80211_WEXT + case NL80211_IFTYPE_ADHOC: + cfg80211_ibss_wext_join(rdev, wdev); + break; + case NL80211_IFTYPE_STATION: + cfg80211_mgd_wext_connect(rdev, wdev); + break; +#endif +#ifdef CONFIG_MAC80211_MESH + case NL80211_IFTYPE_MESH_POINT: + { + /* backward compat code... */ + struct mesh_setup setup; + memcpy(&setup, &default_mesh_setup, + sizeof(setup)); + /* back compat only needed for mesh_id */ + setup.mesh_id = wdev->ssid; + setup.mesh_id_len = wdev->mesh_id_up_len; + if (wdev->mesh_id_up_len) + __cfg80211_join_mesh(rdev, dev, + &setup, + &default_mesh_config); + break; + } +#endif + default: + break; + } + wdev_unlock(wdev); + rdev->opencount++; + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); + + /* + * Configure power management to the driver here so that its + * correctly set also after interface type changes etc. + */ + if ((wdev->iftype == NL80211_IFTYPE_STATION || + wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && + rdev->ops->set_power_mgmt) + if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, + wdev->ps, + wdev->ps_timeout)) { + /* assume this means it's off */ + wdev->ps = false; + } + break; + case NETDEV_UNREGISTER: + /* + * NB: cannot take rdev->mtx here because this may be + * called within code protected by it when interfaces + * are removed with nl80211. + */ + mutex_lock(&rdev->devlist_mtx); + /* + * It is possible to get NETDEV_UNREGISTER + * multiple times. To detect that, check + * that the interface is still on the list + * of registered interfaces, and only then + * remove and clean it up. + */ + if (!list_empty(&wdev->list)) { + sysfs_remove_link(&dev->dev.kobj, "phy80211"); + list_del_rcu(&wdev->list); + rdev->devlist_generation++; + cfg80211_mlme_purge_registrations(wdev); +#ifdef CONFIG_CFG80211_WEXT + kfree(wdev->wext.keys); +#endif + } + mutex_unlock(&rdev->devlist_mtx); + /* + * synchronise (so that we won't find this netdev + * from other code any more) and then clear the list + * head so that the above code can safely check for + * !list_empty() to avoid double-cleanup. + */ + synchronize_rcu(); + INIT_LIST_HEAD(&wdev->list); + break; + case NETDEV_PRE_UP: + if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) + return notifier_from_errno(-EOPNOTSUPP); + if (rfkill_blocked(rdev->rfkill)) + return notifier_from_errno(-ERFKILL); + ret = cfg80211_can_add_interface(rdev, wdev->iftype); + if (ret) + return notifier_from_errno(ret); + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block cfg80211_netdev_notifier = { + .notifier_call = cfg80211_netdev_notifier_call, +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) +static void __net_exit cfg80211_pernet_exit(struct net *net) +{ + struct cfg80211_registered_device *rdev; + + rtnl_lock(); + mutex_lock(&cfg80211_mutex); + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (net_eq(wiphy_net(&rdev->wiphy), net)) + WARN_ON(cfg80211_switch_netns(rdev, &init_net)); + } + mutex_unlock(&cfg80211_mutex); + rtnl_unlock(); +} + +static struct pernet_operations cfg80211_pernet_ops = { + .exit = cfg80211_pernet_exit, +}; +#endif + +static int __init cfg80211_init(void) +{ + int err; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + err = register_pernet_device(&cfg80211_pernet_ops); + if (err) + goto out_fail_pernet; +#endif + + err = wiphy_sysfs_init(); + if (err) + goto out_fail_sysfs; + + err = register_netdevice_notifier(&cfg80211_netdev_notifier); + if (err) + goto out_fail_notifier; + + err = nl80211_init(); + if (err) + goto out_fail_nl80211; + + ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); + + err = regulatory_init(); + if (err) + goto out_fail_reg; + + cfg80211_wq = create_singlethread_workqueue("cfg80211"); + if (!cfg80211_wq) + goto out_fail_wq; + + return 0; + +out_fail_wq: + regulatory_exit(); +out_fail_reg: + debugfs_remove(ieee80211_debugfs_dir); +out_fail_nl80211: + unregister_netdevice_notifier(&cfg80211_netdev_notifier); +out_fail_notifier: + wiphy_sysfs_exit(); +out_fail_sysfs: +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + unregister_pernet_device(&cfg80211_pernet_ops); +out_fail_pernet: +#endif + return err; +} +subsys_initcall(cfg80211_init); + +static void __exit cfg80211_exit(void) +{ + debugfs_remove(ieee80211_debugfs_dir); + nl80211_exit(); + unregister_netdevice_notifier(&cfg80211_netdev_notifier); + wiphy_sysfs_exit(); + regulatory_exit(); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + unregister_pernet_device(&cfg80211_pernet_ops); +#endif + destroy_workqueue(cfg80211_wq); +} +module_exit(cfg80211_exit); diff --git a/net/wireless_ath/core.h b/net/wireless_ath/core.h new file mode 100644 index 00000000..11ff6bbd --- /dev/null +++ b/net/wireless_ath/core.h @@ -0,0 +1,468 @@ +/* + * Wireless configuration interface internals. + * + * Copyright 2006-2010 Johannes Berg + */ +#ifndef __NET_WIRELESS_CORE_H +#define __NET_WIRELESS_CORE_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "reg.h" + +struct cfg80211_registered_device { + const struct cfg80211_ops *ops; + struct list_head list; + /* we hold this mutex during any call so that + * we cannot do multiple calls at once, and also + * to avoid the deregister call to proceed while + * any call is in progress */ + struct mutex mtx; + + /* rfkill support */ + struct rfkill_ops rfkill_ops; + struct rfkill *rfkill; + struct work_struct rfkill_sync; + + /* ISO / IEC 3166 alpha2 for which this device is receiving + * country IEs on, this can help disregard country IEs from APs + * on the same alpha2 quickly. The alpha2 may differ from + * cfg80211_regdomain's alpha2 when an intersection has occurred. + * If the AP is reconfigured this can also be used to tell us if + * the country on the country IE changed. */ + char country_ie_alpha2[2]; + + /* If a Country IE has been received this tells us the environment + * which its telling us its in. This defaults to ENVIRON_ANY */ + enum environment_cap env; + + /* wiphy index, internal only */ + int wiphy_idx; + + /* associate netdev list */ + struct mutex devlist_mtx; + /* protected by devlist_mtx or RCU */ + struct list_head netdev_list; + int devlist_generation; + int opencount; /* also protected by devlist_mtx */ + wait_queue_head_t dev_wait; + + u32 ap_beacons_nlpid; + + /* BSSes/scanning */ + spinlock_t bss_lock; + struct list_head bss_list; + struct rb_root bss_tree; + u32 bss_generation; + struct cfg80211_scan_request *scan_req; /* protected by RTNL */ + struct cfg80211_sched_scan_request *sched_scan_req; + unsigned long suspend_at; + struct work_struct scan_done_wk; + struct work_struct sched_scan_results_wk; + + struct mutex sched_scan_mtx; + +#ifdef CONFIG_NL80211_TESTMODE + struct genl_info *testmode_info; +#endif + + struct work_struct conn_work; + struct work_struct event_work; + + struct cfg80211_wowlan *wowlan; + + /* must be last because of the way we do wiphy_priv(), + * and it should at least be aligned to NETDEV_ALIGN */ + struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +static inline +struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) +{ + BUG_ON(!wiphy); + return container_of(wiphy, struct cfg80211_registered_device, wiphy); +} + +/* Note 0 is valid, hence phy0 */ +static inline +bool wiphy_idx_valid(int wiphy_idx) +{ + return wiphy_idx >= 0; +} + +static inline void +cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) +{ + int i; + + if (!rdev->wowlan) + return; + for (i = 0; i < rdev->wowlan->n_patterns; i++) + kfree(rdev->wowlan->patterns[i].mask); + kfree(rdev->wowlan->patterns); + kfree(rdev->wowlan); +} + +extern struct workqueue_struct *cfg80211_wq; +extern struct mutex cfg80211_mutex; +extern struct list_head cfg80211_rdev_list; +extern int cfg80211_rdev_list_generation; + +static inline void assert_cfg80211_lock(void) +{ + lockdep_assert_held(&cfg80211_mutex); +} + +/* + * You can use this to mark a wiphy_idx as not having an associated wiphy. + * It guarantees cfg80211_rdev_by_wiphy_idx(wiphy_idx) will return NULL + */ +#define WIPHY_IDX_STALE -1 + +struct cfg80211_internal_bss { + struct list_head list; + struct rb_node rbn; + unsigned long ts; + struct kref ref; + atomic_t hold; + bool beacon_ies_allocated; + bool proberesp_ies_allocated; + + /* must be last because of priv member */ + struct cfg80211_bss pub; +}; + +static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub) +{ + return container_of(pub, struct cfg80211_internal_bss, pub); +} + +static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss) +{ + kref_get(&bss->ref); +} + +static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) +{ + atomic_inc(&bss->hold); +} + +static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) +{ + int r = atomic_dec_return(&bss->hold); + WARN_ON(r < 0); +} + + +struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); +int get_wiphy_idx(struct wiphy *wiphy); + +struct cfg80211_registered_device * +__cfg80211_rdev_from_info(struct genl_info *info); + +/* + * This function returns a pointer to the driver + * that the genl_info item that is passed refers to. + * If successful, it returns non-NULL and also locks + * the driver's mutex! + * + * This means that you need to call cfg80211_unlock_rdev() + * before being allowed to acquire &cfg80211_mutex! + * + * This is necessary because we need to lock the global + * mutex to get an item off the list safely, and then + * we lock the rdev mutex so it doesn't go away under us. + * + * We don't want to keep cfg80211_mutex locked + * for all the time in order to allow requests on + * other interfaces to go through at the same time. + * + * The result of this can be a PTR_ERR and hence must + * be checked with IS_ERR() for errors. + */ +extern struct cfg80211_registered_device * +cfg80211_get_dev_from_info(struct genl_info *info); + +/* requires cfg80211_rdev_mutex to be held! */ +struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); + +/* identical to cfg80211_get_dev_from_info but only operate on ifindex */ +extern struct cfg80211_registered_device * +cfg80211_get_dev_from_ifindex(struct net *net, int ifindex); + +int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net); + +static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) +{ + mutex_lock(&rdev->mtx); +} + +static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *rdev) +{ + BUG_ON(IS_ERR(rdev) || !rdev); + mutex_unlock(&rdev->mtx); +} + +static inline void wdev_lock(struct wireless_dev *wdev) + __acquires(wdev) +{ + mutex_lock(&wdev->mtx); + __acquire(wdev->mtx); +} + +static inline void wdev_unlock(struct wireless_dev *wdev) + __releases(wdev) +{ + __release(wdev->mtx); + mutex_unlock(&wdev->mtx); +} + +#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) +#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) + +enum cfg80211_event_type { + EVENT_CONNECT_RESULT, + EVENT_ROAMED, + EVENT_DISCONNECTED, + EVENT_IBSS_JOINED, +}; + +struct cfg80211_event { + struct list_head list; + enum cfg80211_event_type type; + + union { + struct { + u8 bssid[ETH_ALEN]; + const u8 *req_ie; + const u8 *resp_ie; + size_t req_ie_len; + size_t resp_ie_len; + u16 status; + } cr; + struct { + const u8 *req_ie; + const u8 *resp_ie; + size_t req_ie_len; + size_t resp_ie_len; + struct cfg80211_bss *bss; + } rm; + struct { + const u8 *ie; + size_t ie_len; + u16 reason; + } dc; + struct { + u8 bssid[ETH_ALEN]; + } ij; + }; +}; + +struct cfg80211_cached_keys { + struct key_params params[6]; + u8 data[6][WLAN_MAX_KEY_LEN]; + int def, defmgmt; +}; + + +/* free object */ +extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); + +extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, + char *newname); + +void ieee80211_set_bitrate_flags(struct wiphy *wiphy); + +void cfg80211_bss_expire(struct cfg80211_registered_device *dev); +void cfg80211_bss_age(struct cfg80211_registered_device *dev, + unsigned long age_secs); + +/* IBSS */ +int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys); +int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys); +void cfg80211_clear_ibss(struct net_device *dev, bool nowext); +int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext); +int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext); +void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); +int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev); + +/* mesh */ +extern const struct mesh_config default_mesh_config; +extern const struct mesh_setup default_mesh_setup; +int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev, + const struct mesh_setup *setup, + const struct mesh_config *conf); +int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev, + const struct mesh_setup *setup, + const struct mesh_config *conf); +int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev); + +/* MLME */ +int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, + const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx, + bool local_state_change); +int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx, + bool local_state_change); +int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt); +int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt); +int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason, + bool local_state_change); +int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason, + bool local_state_change); +int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason, + bool local_state_change); +void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, + struct net_device *dev); +void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, bool wextev, + struct cfg80211_bss *bss); +int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, + u16 frame_type, const u8 *match_data, + int match_len); +void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); +void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); +int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie); + +/* SME */ +int __cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys, + const u8 *prev_bssid); +int cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys); +int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason, + bool wextev); +int cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason, + bool wextev); +void __cfg80211_roamed(struct wireless_dev *wdev, + struct cfg80211_bss *bss, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len); +int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev); + +void cfg80211_conn_work(struct work_struct *work); +void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); +bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); + +/* internal helpers */ +bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); +int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, + struct key_params *params, int key_idx, + bool pairwise, const u8 *mac_addr); +void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, + size_t ie_len, u16 reason, bool from_ap); +void cfg80211_sme_scan_done(struct net_device *dev); +void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_sme_disassoc(struct net_device *dev, int idx); +void __cfg80211_scan_done(struct work_struct *wk); +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); +void __cfg80211_sched_scan_results(struct work_struct *wk); +int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, + bool driver_initiated); +void cfg80211_upload_connect_keys(struct wireless_dev *wdev); +int cfg80211_change_iface(struct cfg80211_registered_device *rdev, + struct net_device *dev, enum nl80211_iftype ntype, + u32 *flags, struct vif_params *params); +void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); + +int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + enum nl80211_iftype iftype); + +static inline int +cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, + enum nl80211_iftype iftype) +{ + return cfg80211_can_change_interface(rdev, NULL, iftype); +} + +struct ieee80211_channel * +rdev_freq_to_chan(struct cfg80211_registered_device *rdev, + int freq, enum nl80211_channel_type channel_type); +int cfg80211_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, int freq, + enum nl80211_channel_type channel_type); + +u16 cfg80211_calculate_bitrate(struct rate_info *rate); + +int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, + const u8 *rates, unsigned int n_rates, + u32 *mask); + +int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, + u32 beacon_int); + +#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS +#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) +#else +/* + * Trick to enable using it as a condition, + * and also not give a warning when it's + * not used that way. + */ +#define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; }) +#endif + +#endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless_ath/db.txt b/net/wireless_ath/db.txt new file mode 100644 index 00000000..d0f56304 --- /dev/null +++ b/net/wireless_ath/db.txt @@ -0,0 +1,697 @@ +# This is the world regulatory domain +country 00: + (2402 - 2472 @ 40), (3, 20) + # Channel 12 - 13. No HT40 channel fits here + (2457 - 2482 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS + # Channel 14. Only JP enables this and for 802.11b only + (2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM + # Channel 36 - 48 + (5140 - 5360 @ 40), (0, 30), PASSIVE-SCAN, NO-IBSS + # NB: 5260 MHz - 5700 MHz requies DFS + # Channel 149 - 165 + (5460 - 5860 @ 40), (0, 30), PASSIVE-SCAN, NO-IBSS + + +country AE: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country AL: + (2402 - 2482 @ 20), (N/A, 20) + +country AM: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 18) + (5250 - 5330 @ 20), (N/A, 18), DFS + +country AN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country AR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country AT: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country AU: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 23) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country AW: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country AZ: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country BA: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country BB: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 23) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country BD: + (2402 - 2482 @ 40), (N/A, 20) + +country BE: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country BG: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 23) + (5250 - 5290 @ 40), (N/A, 23), DFS + (5490 - 5710 @ 40), (N/A, 30), DFS + +country BH: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + (5735 - 5835 @ 20), (N/A, 20) + +country BL: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country BN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5735 - 5835 @ 40), (N/A, 30) + +country BO: + (2402 - 2482 @ 40), (N/A, 30) + (5735 - 5835 @ 40), (N/A, 30) + +country BR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country BY: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country BZ: + (2402 - 2482 @ 40), (N/A, 30) + (5735 - 5835 @ 40), (N/A, 30) + +country CA: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country CH: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country CL: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5735 - 5835 @ 40), (N/A, 20) + +country CN: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country CO: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country CR: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (3, 17) + (5250 - 5330 @ 20), (3, 23), DFS + (5735 - 5835 @ 20), (3, 30) + +country CS: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country CY: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf +# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf +# Power at 5250 - 5350 MHz and 5470 - 5725 MHz can be doubled if TPC is +# implemented. +country CZ: DFS-ETSI + (2400 - 2483.5 @ 40), (N/A, 100 mW) + (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR + (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS + (5470 - 5725 @ 40), (N/A, 500 mW), DFS + +# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from +# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf +# For the 5GHz range also see +# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38216/publicationFile/6579/WLAN5GHzVfg7_2010_28042010pdf.pdf +# The values have been reduced by a factor of 2 (3db) for non TPC devices +# (in other words: devices with TPC can use twice the tx power of this table). +# Note that the docs do not require TPC for 5150--5250; the reduction to +# 100mW thus is not strictly required -- however the conservative 100mW +# limit is used here as the non-interference with radar and satellite +# apps relies on the attenuation by the building walls only in the +# absence of DFS; the neighbour countries have 100mW limit here as well. + +country DE: DFS-ETSI + # entries 279004 and 280006 + (2400 - 2483.5 @ 40), (N/A, 100 mW) + # entry 303005 + (5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR + # entries 304002 and 305002 + (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS + # entries 308002, 309001 and 310003 + (5470 - 5725 @ 40), (N/A, 500 mW), DFS + +country DK: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country DO: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country DZ: + (2402 - 2482 @ 40), (N/A, 20) + +country EC: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (3, 17) + (5250 - 5330 @ 20), (3, 23), DFS + (5735 - 5835 @ 20), (3, 30) + +country EE: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country EG: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + +country ES: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country FI: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country FR: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country GE: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country GB: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country GD: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country GR: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country GL: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + (5490 - 5710 @ 20), (N/A, 27), DFS + +country GT: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country GU: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 20), (3, 17) + (5250 - 5330 @ 20), (3, 23), DFS + (5735 - 5835 @ 20), (3, 30) + +country HN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country HK: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country HR: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country HT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country HU: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country ID: + (2402 - 2482 @ 40), (N/A, 20) + +country IE: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country IL: + (2402 - 2482 @ 40), (N/A, 20) + (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR + (5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS + +country IN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5735 - 5835 @ 40), (N/A, 20) + +country IS: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country IR: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country IT: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country JM: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country JP: + (2402 - 2472 @ 40), (N/A, 20) + (2457 - 2482 @ 20), (N/A, 20) + (2474 - 2494 @ 20), (N/A, 20), NO-OFDM + (4910 - 4930 @ 10), (N/A, 23) + (4910 - 4990 @ 40), (N/A, 23) + (4930 - 4950 @ 10), (N/A, 23) + (5030 - 5045 @ 10), (N/A, 23) + (5030 - 5090 @ 40), (N/A, 23) + (5050 - 5060 @ 10), (N/A, 23) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 23), DFS + +country JO: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + +country KE: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country KH: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country KP: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5330 @ 40), (3, 20) + (5160 - 5250 @ 40), (3, 20), DFS + (5490 - 5630 @ 40), (3, 30), DFS + (5735 - 5815 @ 40), (3, 30) + +country KR: + (2402 - 2482 @ 20), (N/A, 20) + (5170 - 5250 @ 20), (3, 20) + (5250 - 5330 @ 20), (3, 20), DFS + (5490 - 5630 @ 20), (3, 30), DFS + (5735 - 5815 @ 20), (3, 30) + +country KW: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + +country KZ: + (2402 - 2482 @ 40), (N/A, 20) + +country LB: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country LI: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country LK: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (3, 17) + (5250 - 5330 @ 20), (3, 20), DFS + (5490 - 5710 @ 20), (3, 20), DFS + (5735 - 5835 @ 20), (3, 30) + +country LT: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country LU: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country LV: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country MC: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 18) + (5250 - 5330 @ 40), (N/A, 18), DFS + +country MA: + (2402 - 2482 @ 40), (N/A, 20) + +country MO: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 23) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country MK: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country MT: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country MY: + (2402 - 2482 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 30), DFS + (5735 - 5835 @ 40), (N/A, 30) + +country MX: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country NL: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR + (5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country NO: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country NP: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country NZ: + (2402 - 2482 @ 40), (N/A, 30) + (5170 - 5250 @ 20), (3, 23) + (5250 - 5330 @ 20), (3, 23), DFS + (5735 - 5835 @ 20), (3, 30) + +country OM: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country PA: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country PE: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country PG: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country PH: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country PK: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country PL: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country PT: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country PR: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 23), DFS + (5735 - 5835 @ 40), (3, 30) + +country QA: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 40), (N/A, 30) + +country RO: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country RU: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5835 @ 20), (N/A, 30) + +country SA: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (3, 23) + (5250 - 5330 @ 20), (3, 23), DFS + (5735 - 5835 @ 20), (3, 30) + +country SE: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country SG: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5735 - 5835 @ 40), (N/A, 20) + +country SI: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country SK: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + (5490 - 5710 @ 40), (N/A, 27), DFS + +country SV: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (3, 17) + (5250 - 5330 @ 20), (3, 23), DFS + (5735 - 5835 @ 20), (3, 30) + +country SY: + (2402 - 2482 @ 40), (N/A, 20) + +country TW: + (2402 - 2472 @ 40), (3, 27) + (5270 - 5330 @ 40), (3, 17), DFS + (5735 - 5815 @ 40), (3, 30) + +country TH: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country TT: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country TN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + +country TR: DFS-ETSI + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 20), (N/A, 20) + (5250 - 5330 @ 20), (N/A, 20), DFS + +country UA: + (2402 - 2482 @ 40), (N/A, 20) + +country US: DFS-FCC + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5600 @ 40), (3, 20), DFS + (5650 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country UY: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country UZ: + (2402 - 2472 @ 40), (3, 27) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country VE: + (2402 - 2482 @ 40), (N/A, 20) + (5735 - 5815 @ 40), (N/A, 23) + +country VN: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (N/A, 20) + (5250 - 5330 @ 40), (N/A, 20), DFS + +country YE: + (2402 - 2482 @ 40), (N/A, 20) + +country ZA: + (2402 - 2482 @ 40), (N/A, 20) + (5170 - 5250 @ 40), (3, 17) + (5250 - 5330 @ 40), (3, 20), DFS + (5490 - 5710 @ 40), (3, 20), DFS + (5735 - 5835 @ 40), (3, 30) + +country ZW: + (2402 - 2482 @ 40), (N/A, 20) + diff --git a/net/wireless_ath/debugfs.c b/net/wireless_ath/debugfs.c new file mode 100644 index 00000000..39765bcf --- /dev/null +++ b/net/wireless_ath/debugfs.c @@ -0,0 +1,121 @@ +/* + * cfg80211 debugfs + * + * Copyright 2009 Luis R. Rodriguez + * Copyright 2007 Johannes Berg + * + * 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 +#include "core.h" +#include "debugfs.h" + +static int cfg80211_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wiphy *wiphy= file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = cfg80211_open_file_generic, \ + .llseek = generic_file_llseek, \ +}; + +DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", + wiphy->rts_threshold) +DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", + wiphy->frag_threshold); +DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", + wiphy->retry_short) +DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", + wiphy->retry_long); + +static int ht_print_chan(struct ieee80211_channel *chan, + char *buf, int buf_size, int offset) +{ + if (WARN_ON(offset > buf_size)) + return 0; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + return snprintf(buf + offset, + buf_size - offset, + "%d Disabled\n", + chan->center_freq); + + return snprintf(buf + offset, + buf_size - offset, + "%d HT40 %c%c\n", + chan->center_freq, + (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-', + (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? ' ' : '+'); +} + +static ssize_t ht40allow_map_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wiphy *wiphy = file->private_data; + char *buf; + unsigned int offset = 0, buf_size = PAGE_SIZE, i, r; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&cfg80211_mutex); + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + for (i = 0; i < sband->n_channels; i++) + offset += ht_print_chan(&sband->channels[i], + buf, buf_size, offset); + } + + mutex_unlock(&cfg80211_mutex); + + r = simple_read_from_buffer(user_buf, count, ppos, buf, offset); + + kfree(buf); + + return r; +} + +static const struct file_operations ht40allow_map_ops = { + .read = ht40allow_map_read, + .open = cfg80211_open_file_generic, + .llseek = default_llseek, +}; + +#define DEBUGFS_ADD(name) \ + debugfs_create_file(#name, S_IRUGO, phyd, &rdev->wiphy, &name## _ops); + +void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) +{ + struct dentry *phyd = rdev->wiphy.debugfsdir; + + DEBUGFS_ADD(rts_threshold); + DEBUGFS_ADD(fragmentation_threshold); + DEBUGFS_ADD(short_retry_limit); + DEBUGFS_ADD(long_retry_limit); + DEBUGFS_ADD(ht40allow_map); +} diff --git a/net/wireless_ath/debugfs.h b/net/wireless_ath/debugfs.h new file mode 100644 index 00000000..74fdd381 --- /dev/null +++ b/net/wireless_ath/debugfs.h @@ -0,0 +1,11 @@ +#ifndef __CFG80211_DEBUGFS_H +#define __CFG80211_DEBUGFS_H + +#ifdef CONFIG_CFG80211_DEBUGFS +void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev); +#else +static inline +void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {} +#endif + +#endif /* __CFG80211_DEBUGFS_H */ diff --git a/net/wireless_ath/ethtool.c b/net/wireless_ath/ethtool.c new file mode 100644 index 00000000..9bde4d1d --- /dev/null +++ b/net/wireless_ath/ethtool.c @@ -0,0 +1,78 @@ +#include +#include +#include "core.h" +#include "ethtool.h" + +static void cfg80211_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + strlcpy(info->driver, wiphy_dev(wdev->wiphy)->driver->name, + sizeof(info->driver)); + + strlcpy(info->version, init_utsname()->release, sizeof(info->version)); + + if (wdev->wiphy->fw_version[0]) + strncpy(info->fw_version, wdev->wiphy->fw_version, + sizeof(info->fw_version)); + else + strncpy(info->fw_version, "N/A", sizeof(info->fw_version)); + + strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), + sizeof(info->bus_info)); +} + +static int cfg80211_get_regs_len(struct net_device *dev) +{ + /* For now, return 0... */ + return 0; +} + +static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *data) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + regs->version = wdev->wiphy->hw_version; + regs->len = 0; +} + +static void cfg80211_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *rp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + + memset(rp, 0, sizeof(*rp)); + + if (rdev->ops->get_ringparam) + rdev->ops->get_ringparam(wdev->wiphy, + &rp->tx_pending, &rp->tx_max_pending, + &rp->rx_pending, &rp->rx_max_pending); +} + +static int cfg80211_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *rp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + + if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) + return -EINVAL; + + if (rdev->ops->set_ringparam) + return rdev->ops->set_ringparam(wdev->wiphy, + rp->tx_pending, rp->rx_pending); + + return -ENOTSUPP; +} + +const struct ethtool_ops cfg80211_ethtool_ops = { + .get_drvinfo = cfg80211_get_drvinfo, + .get_regs_len = cfg80211_get_regs_len, + .get_regs = cfg80211_get_regs, + .get_link = ethtool_op_get_link, + .get_ringparam = cfg80211_get_ringparam, + .set_ringparam = cfg80211_set_ringparam, +}; diff --git a/net/wireless_ath/ethtool.h b/net/wireless_ath/ethtool.h new file mode 100644 index 00000000..695ecad2 --- /dev/null +++ b/net/wireless_ath/ethtool.h @@ -0,0 +1,6 @@ +#ifndef __CFG80211_ETHTOOL__ +#define __CFG80211_ETHTOOL__ + +extern const struct ethtool_ops cfg80211_ethtool_ops; + +#endif /* __CFG80211_ETHTOOL__ */ diff --git a/net/wireless_ath/genregdb.awk b/net/wireless_ath/genregdb.awk new file mode 100644 index 00000000..53c143f5 --- /dev/null +++ b/net/wireless_ath/genregdb.awk @@ -0,0 +1,119 @@ +#!/usr/bin/awk -f +# +# genregdb.awk -- generate regdb.c from db.txt +# +# Actually, it reads from stdin (presumed to be db.txt) and writes +# to stdout (presumed to be regdb.c), but close enough... +# +# Copyright 2009 John W. Linville +# +# 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. +# + +BEGIN { + active = 0 + rules = 0; + print "/*" + print " * DO NOT EDIT -- file generated from data in db.txt" + print " */" + print "" + print "#include " + print "#include " + print "#include \"regdb.h\"" + print "" + regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" +} + +/^[ \t]*#/ { + # Ignore +} + +!active && /^[ \t]*$/ { + # Ignore +} + +!active && /country/ { + country=$2 + sub(/:/, "", country) + printf "static const struct ieee80211_regdomain regdom_%s = {\n", country + printf "\t.alpha2 = \"%s\",\n", country + printf "\t.reg_rules = {\n" + active = 1 + regdb = regdb "\t®dom_" country ",\n" +} + +active && /^[ \t]*\(/ { + start = $1 + sub(/\(/, "", start) + end = $3 + bw = $5 + sub(/\),/, "", bw) + gain = $6 + sub(/\(/, "", gain) + sub(/,/, "", gain) + power = $7 + sub(/\)/, "", power) + sub(/,/, "", power) + # power might be in mW... + units = $8 + sub(/\)/, "", units) + sub(/,/, "", units) + if (units == "mW") { + if (power == 100) { + power = 20 + } else if (power == 200) { + power = 23 + } else if (power == 500) { + power = 27 + } else if (power == 1000) { + power = 30 + } else { + print "Unknown power value in database!" + } + } + flagstr = "" + for (i=8; i<=NF; i++) + flagstr = flagstr $i + split(flagstr, flagarray, ",") + flags = "" + for (arg in flagarray) { + if (flagarray[arg] == "NO-OFDM") { + flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | " + } else if (flagarray[arg] == "NO-CCK") { + flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | " + } else if (flagarray[arg] == "NO-INDOOR") { + flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | " + } else if (flagarray[arg] == "NO-OUTDOOR") { + flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | " + } else if (flagarray[arg] == "DFS") { + flags = flags "\n\t\t\tNL80211_RRF_DFS | " + } else if (flagarray[arg] == "PTP-ONLY") { + flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | " + } else if (flagarray[arg] == "PTMP-ONLY") { + flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " + } else if (flagarray[arg] == "PASSIVE-SCAN") { + flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " + } else if (flagarray[arg] == "NO-IBSS") { + flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " + } + } + flags = flags "0" + printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags + rules++ +} + +active && /^[ \t]*$/ { + active = 0 + printf "\t},\n" + printf "\t.n_reg_rules = %d\n", rules + printf "};\n\n" + rules = 0; +} + +END { + print regdb "};" + print "" + print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" +} diff --git a/net/wireless_ath/ibss.c b/net/wireless_ath/ibss.c new file mode 100644 index 00000000..30f20fe4 --- /dev/null +++ b/net/wireless_ath/ibss.c @@ -0,0 +1,527 @@ +/* + * Some IBSS support code for cfg80211. + * + * Copyright 2009 Johannes Berg + */ + +#include +#include +#include +#include +#include +#include "wext-compat.h" +#include "nl80211.h" + + +void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_bss *bss; +#ifdef CONFIG_CFG80211_WEXT + union iwreq_data wrqu; +#endif + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return; + + if (!wdev->ssid_len) + return; + + bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); + + if (WARN_ON(!bss)) + return; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + } + + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); + + cfg80211_upload_connect_keys(wdev); + + nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, + GFP_KERNEL); +#ifdef CONFIG_CFG80211_WEXT + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} + +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + CFG80211_DEV_WARN_ON(!wdev->ssid_len); + + ev = kzalloc(sizeof(*ev), gfp); + if (!ev) + return; + + ev->type = EVENT_IBSS_JOINED; + memcpy(ev->cr.bssid, bssid, ETH_ALEN); + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + queue_work(cfg80211_wq, &rdev->event_work); +} +EXPORT_SYMBOL(cfg80211_ibss_joined); + +int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + ASSERT_WDEV_LOCK(wdev); + + if (wdev->ssid_len) + return -EALREADY; + + if (!params->basic_rates) { + /* + * If no rates were explicitly configured, + * use the mandatory rate set for 11b or + * 11a for maximum compatibility. + */ + struct ieee80211_supported_band *sband = + rdev->wiphy.bands[params->channel->band]; + int j; + u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? + IEEE80211_RATE_MANDATORY_A : + IEEE80211_RATE_MANDATORY_B; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].flags & flag) + params->basic_rates |= BIT(j); + } + } + + if (WARN_ON(wdev->connect_keys)) + kfree(wdev->connect_keys); + wdev->connect_keys = connkeys; + +#ifdef CONFIG_CFG80211_WEXT + wdev->wext.ibss.channel = params->channel; +#endif + err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); + if (err) { + wdev->connect_keys = NULL; + return err; + } + + memcpy(wdev->ssid, params->ssid, params->ssid_len); + wdev->ssid_len = params->ssid_len; + + return 0; +} + +int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + err = __cfg80211_join_ibss(rdev, dev, params, connkeys); + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + + return err; +} + +static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int i; + + ASSERT_WDEV_LOCK(wdev); + + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + + /* + * Delete all the keys ... pairwise keys can't really + * exist any more anyway, but default keys might. + */ + if (rdev->ops->del_key) + for (i = 0; i < 6; i++) + rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + } + + wdev->current_bss = NULL; + wdev->ssid_len = 0; +#ifdef CONFIG_CFG80211_WEXT + if (!nowext) + wdev->wext.ibss.ssid_len = 0; +#endif +} + +void cfg80211_clear_ibss(struct net_device *dev, bool nowext) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wdev_lock(wdev); + __cfg80211_clear_ibss(dev, nowext); + wdev_unlock(wdev); +} + +int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + ASSERT_WDEV_LOCK(wdev); + + if (!wdev->ssid_len) + return -ENOLINK; + + err = rdev->ops->leave_ibss(&rdev->wiphy, dev); + + if (err) + return err; + + __cfg80211_clear_ibss(dev, nowext); + + return 0; +} + +int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_leave_ibss(rdev, dev, nowext); + wdev_unlock(wdev); + + return err; +} + +#ifdef CONFIG_CFG80211_WEXT +int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + struct cfg80211_cached_keys *ck = NULL; + enum ieee80211_band band; + int i, err; + + ASSERT_WDEV_LOCK(wdev); + + if (!wdev->wext.ibss.beacon_interval) + wdev->wext.ibss.beacon_interval = 100; + + /* try to find an IBSS channel if none requested ... */ + if (!wdev->wext.ibss.channel) { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + + sband = rdev->wiphy.bands[band]; + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + continue; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + wdev->wext.ibss.channel = chan; + break; + } + + if (wdev->wext.ibss.channel) + break; + } + + if (!wdev->wext.ibss.channel) + return -EINVAL; + } + + /* don't join -- SSID is not there */ + if (!wdev->wext.ibss.ssid_len) + return 0; + + if (!netif_running(wdev->netdev)) + return 0; + + if (wdev->wext.keys) { + wdev->wext.keys->def = wdev->wext.default_key; + wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; + } + + wdev->wext.ibss.privacy = wdev->wext.default_key != -1; + + if (wdev->wext.keys) { + ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); + if (!ck) + return -ENOMEM; + for (i = 0; i < 6; i++) + ck->params[i].key = ck->data[i]; + } + err = __cfg80211_join_ibss(rdev, wdev->netdev, + &wdev->wext.ibss, ck); + if (err) + kfree(ck); + + return err; +} + +int cfg80211_ibss_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wextfreq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan = NULL; + int err, freq; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!rdev->ops->join_ibss) + return -EOPNOTSUPP; + + freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + if (freq < 0) + return freq; + + if (freq) { + chan = ieee80211_get_channel(wdev->wiphy, freq); + if (!chan) + return -EINVAL; + if (chan->flags & IEEE80211_CHAN_NO_IBSS || + chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + } + + if (wdev->wext.ibss.channel == chan) + return 0; + + wdev_lock(wdev); + err = 0; + if (wdev->ssid_len) + err = __cfg80211_leave_ibss(rdev, dev, true); + wdev_unlock(wdev); + + if (err) + return err; + + if (chan) { + wdev->wext.ibss.channel = chan; + wdev->wext.ibss.channel_fixed = true; + } else { + /* cfg80211_ibss_wext_join will pick one if needed */ + wdev->wext.ibss.channel_fixed = false; + } + + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + err = cfg80211_ibss_wext_join(rdev, wdev); + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + + return err; +} + +int cfg80211_ibss_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan = NULL; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + wdev_lock(wdev); + if (wdev->current_bss) + chan = wdev->current_bss->pub.channel; + else if (wdev->wext.ibss.channel) + chan = wdev->wext.ibss.channel; + wdev_unlock(wdev); + + if (chan) { + freq->m = chan->center_freq; + freq->e = 6; + return 0; + } + + /* no channel if not joining */ + return -EINVAL; +} + +int cfg80211_ibss_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + size_t len = data->length; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!rdev->ops->join_ibss) + return -EOPNOTSUPP; + + wdev_lock(wdev); + err = 0; + if (wdev->ssid_len) + err = __cfg80211_leave_ibss(rdev, dev, true); + wdev_unlock(wdev); + + if (err) + return err; + + /* iwconfig uses nul termination in SSID.. */ + if (len > 0 && ssid[len - 1] == '\0') + len--; + + wdev->wext.ibss.ssid = wdev->ssid; + memcpy(wdev->wext.ibss.ssid, ssid, len); + wdev->wext.ibss.ssid_len = len; + + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + err = cfg80211_ibss_wext_join(rdev, wdev); + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + + return err; +} + +int cfg80211_ibss_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + data->flags = 0; + + wdev_lock(wdev); + if (wdev->ssid_len) { + data->flags = 1; + data->length = wdev->ssid_len; + memcpy(ssid, wdev->ssid, data->length); + } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) { + data->flags = 1; + data->length = wdev->wext.ibss.ssid_len; + memcpy(ssid, wdev->wext.ibss.ssid, data->length); + } + wdev_unlock(wdev); + + return 0; +} + +int cfg80211_ibss_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u8 *bssid = ap_addr->sa_data; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!rdev->ops->join_ibss) + return -EOPNOTSUPP; + + if (ap_addr->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* automatic mode */ + if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) + bssid = NULL; + + /* both automatic */ + if (!bssid && !wdev->wext.ibss.bssid) + return 0; + + /* fixed already - and no change */ + if (wdev->wext.ibss.bssid && bssid && + compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) + return 0; + + wdev_lock(wdev); + err = 0; + if (wdev->ssid_len) + err = __cfg80211_leave_ibss(rdev, dev, true); + wdev_unlock(wdev); + + if (err) + return err; + + if (bssid) { + memcpy(wdev->wext.bssid, bssid, ETH_ALEN); + wdev->wext.ibss.bssid = wdev->wext.bssid; + } else + wdev->wext.ibss.bssid = NULL; + + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + err = cfg80211_ibss_wext_join(rdev, wdev); + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + + return err; +} + +int cfg80211_ibss_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + ap_addr->sa_family = ARPHRD_ETHER; + + wdev_lock(wdev); + if (wdev->current_bss) + memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); + else if (wdev->wext.ibss.bssid) + memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); + else + memset(ap_addr->sa_data, 0, ETH_ALEN); + + wdev_unlock(wdev); + + return 0; +} +#endif diff --git a/net/wireless_ath/lib80211.c b/net/wireless_ath/lib80211.c new file mode 100644 index 00000000..a55c27b7 --- /dev/null +++ b/net/wireless_ath/lib80211.c @@ -0,0 +1,289 @@ +/* + * lib80211 -- common bits for IEEE802.11 drivers + * + * Copyright(c) 2008 John W. Linville + * + * Portions copied from old ieee80211 component, w/ original copyright + * notices below: + * + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen + * Portions Copyright (C) 2004, Intel Corporation + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRV_NAME "lib80211" + +#define DRV_DESCRIPTION "common routines for IEEE802.11 drivers" + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR("John W. Linville "); +MODULE_LICENSE("GPL"); + +struct lib80211_crypto_alg { + struct list_head list; + struct lib80211_crypto_ops *ops; +}; + +static LIST_HEAD(lib80211_crypto_algs); +static DEFINE_SPINLOCK(lib80211_crypto_lock); + +static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, + int force); +static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info); +static void lib80211_crypt_deinit_handler(unsigned long data); + +const char *print_ssid(char *buf, const char *ssid, u8 ssid_len) +{ + const char *s = ssid; + char *d = buf; + + ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN); + while (ssid_len--) { + if (isprint(*s)) { + *d++ = *s++; + continue; + } + + *d++ = '\\'; + if (*s == '\0') + *d++ = '0'; + else if (*s == '\n') + *d++ = 'n'; + else if (*s == '\r') + *d++ = 'r'; + else if (*s == '\t') + *d++ = 't'; + else if (*s == '\\') + *d++ = '\\'; + else + d += snprintf(d, 3, "%03o", *s); + s++; + } + *d = '\0'; + return buf; +} +EXPORT_SYMBOL(print_ssid); + +int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name, + spinlock_t *lock) +{ + memset(info, 0, sizeof(*info)); + + info->name = name; + info->lock = lock; + + INIT_LIST_HEAD(&info->crypt_deinit_list); + setup_timer(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler, + (unsigned long)info); + + return 0; +} +EXPORT_SYMBOL(lib80211_crypt_info_init); + +void lib80211_crypt_info_free(struct lib80211_crypt_info *info) +{ + int i; + + lib80211_crypt_quiescing(info); + del_timer_sync(&info->crypt_deinit_timer); + lib80211_crypt_deinit_entries(info, 1); + + for (i = 0; i < NUM_WEP_KEYS; i++) { + struct lib80211_crypt_data *crypt = info->crypt[i]; + if (crypt) { + if (crypt->ops) { + crypt->ops->deinit(crypt->priv); + module_put(crypt->ops->owner); + } + kfree(crypt); + info->crypt[i] = NULL; + } + } +} +EXPORT_SYMBOL(lib80211_crypt_info_free); + +static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, + int force) +{ + struct lib80211_crypt_data *entry, *next; + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) { + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(&entry->list); + + if (entry->ops) { + entry->ops->deinit(entry->priv); + module_put(entry->ops->owner); + } + kfree(entry); + } + spin_unlock_irqrestore(info->lock, flags); +} + +/* After this, crypt_deinit_list won't accept new members */ +static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info) +{ + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + info->crypt_quiesced = 1; + spin_unlock_irqrestore(info->lock, flags); +} + +static void lib80211_crypt_deinit_handler(unsigned long data) +{ + struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data; + unsigned long flags; + + lib80211_crypt_deinit_entries(info, 0); + + spin_lock_irqsave(info->lock, flags); + if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) { + printk(KERN_DEBUG "%s: entries remaining in delayed crypt " + "deletion list\n", info->name); + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + spin_unlock_irqrestore(info->lock, flags); +} + +void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt) +{ + struct lib80211_crypt_data *tmp; + unsigned long flags; + + if (*crypt == NULL) + return; + + tmp = *crypt; + *crypt = NULL; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. */ + + spin_lock_irqsave(info->lock, flags); + if (!info->crypt_quiesced) { + list_add(&tmp->list, &info->crypt_deinit_list); + if (!timer_pending(&info->crypt_deinit_timer)) { + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + } + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(lib80211_crypt_delayed_deinit); + +int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops) +{ + unsigned long flags; + struct lib80211_crypto_alg *alg; + + alg = kzalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + alg->ops = ops; + + spin_lock_irqsave(&lib80211_crypto_lock, flags); + list_add(&alg->list, &lib80211_crypto_algs); + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + + printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} +EXPORT_SYMBOL(lib80211_register_crypto_ops); + +int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops) +{ + struct lib80211_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&lib80211_crypto_lock, flags); + list_for_each_entry(alg, &lib80211_crypto_algs, list) { + if (alg->ops == ops) + goto found; + } + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + return -EINVAL; + + found: + printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n", + ops->name); + list_del(&alg->list); + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + kfree(alg); + return 0; +} +EXPORT_SYMBOL(lib80211_unregister_crypto_ops); + +struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name) +{ + struct lib80211_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&lib80211_crypto_lock, flags); + list_for_each_entry(alg, &lib80211_crypto_algs, list) { + if (strcmp(alg->ops->name, name) == 0) + goto found; + } + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + return NULL; + + found: + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + return alg->ops; +} +EXPORT_SYMBOL(lib80211_get_crypto_ops); + +static void *lib80211_crypt_null_init(int keyidx) +{ + return (void *)1; +} + +static void lib80211_crypt_null_deinit(void *priv) +{ +} + +static struct lib80211_crypto_ops lib80211_crypt_null = { + .name = "NULL", + .init = lib80211_crypt_null_init, + .deinit = lib80211_crypt_null_deinit, + .owner = THIS_MODULE, +}; + +static int __init lib80211_init(void) +{ + pr_info(DRV_DESCRIPTION "\n"); + return lib80211_register_crypto_ops(&lib80211_crypt_null); +} + +static void __exit lib80211_exit(void) +{ + lib80211_unregister_crypto_ops(&lib80211_crypt_null); + BUG_ON(!list_empty(&lib80211_crypto_algs)); +} + +module_init(lib80211_init); +module_exit(lib80211_exit); diff --git a/net/wireless_ath/lib80211_crypt_ccmp.c b/net/wireless_ath/lib80211_crypt_ccmp.c new file mode 100644 index 00000000..755738d2 --- /dev/null +++ b/net/wireless_ath/lib80211_crypt_ccmp.c @@ -0,0 +1,491 @@ +/* + * lib80211 crypt: host-based CCMP encryption implementation for lib80211 + * + * Copyright (c) 2003-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville + * + * 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. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: CCMP"); +MODULE_LICENSE("GPL"); + +#define AES_BLOCK_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 + +struct lib80211_ccmp_data { + u8 key[CCMP_TK_LEN]; + int key_set; + + u8 tx_pn[CCMP_PN_LEN]; + u8 rx_pn[CCMP_PN_LEN]; + + u32 dot11RSNAStatsCCMPFormatErrors; + u32 dot11RSNAStatsCCMPReplays; + u32 dot11RSNAStatsCCMPDecryptErrors; + + int key_idx; + + struct crypto_cipher *tfm; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], + tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; + u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; +}; + +static inline void lib80211_ccmp_aes_encrypt(struct crypto_cipher *tfm, + const u8 pt[16], u8 ct[16]) +{ + crypto_cipher_encrypt_one(tfm, ct, pt); +} + +static void *lib80211_ccmp_init(int key_idx) +{ + struct lib80211_ccmp_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + priv->key_idx = key_idx; + + priv->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tfm)) { + priv->tfm = NULL; + goto fail; + } + + return priv; + + fail: + if (priv) { + if (priv->tfm) + crypto_free_cipher(priv->tfm); + kfree(priv); + } + + return NULL; +} + +static void lib80211_ccmp_deinit(void *priv) +{ + struct lib80211_ccmp_data *_priv = priv; + if (_priv && _priv->tfm) + crypto_free_cipher(_priv->tfm); + kfree(priv); +} + +static inline void xor_block(u8 * b, u8 * a, size_t len) +{ + int i; + for (i = 0; i < len; i++) + b[i] ^= a[i]; +} + +static void ccmp_init_blocks(struct crypto_cipher *tfm, + struct ieee80211_hdr *hdr, + u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0) +{ + u8 *pos, qc = 0; + size_t aad_len; + int a4_included, qc_included; + u8 aad[2 * AES_BLOCK_LEN]; + + a4_included = ieee80211_has_a4(hdr->frame_control); + qc_included = ieee80211_is_data_qos(hdr->frame_control); + + aad_len = 22; + if (a4_included) + aad_len += 6; + if (qc_included) { + pos = (u8 *) & hdr->addr4; + if (a4_included) + pos += 6; + qc = *pos & 0x0f; + aad_len += 2; + } + + /* CCM Initial Block: + * Flag (Include authentication header, M=3 (8-octet MIC), + * L=1 (2-octet Dlen)) + * Nonce: 0x00 | A2 | PN + * Dlen */ + b0[0] = 0x59; + b0[1] = qc; + memcpy(b0 + 2, hdr->addr2, ETH_ALEN); + memcpy(b0 + 8, pn, CCMP_PN_LEN); + b0[14] = (dlen >> 8) & 0xff; + b0[15] = dlen & 0xff; + + /* AAD: + * FC with bits 4..6 and 11..13 masked to zero; 14 is always one + * A1 | A2 | A3 + * SC with bits 4..15 (seq#) masked to zero + * A4 (if present) + * QC (if present) + */ + pos = (u8 *) hdr; + aad[0] = 0; /* aad_len >> 8 */ + aad[1] = aad_len & 0xff; + aad[2] = pos[0] & 0x8f; + aad[3] = pos[1] & 0xc7; + memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); + pos = (u8 *) & hdr->seq_ctrl; + aad[22] = pos[0] & 0x0f; + aad[23] = 0; /* all bits masked */ + memset(aad + 24, 0, 8); + if (a4_included) + memcpy(aad + 24, hdr->addr4, ETH_ALEN); + if (qc_included) { + aad[a4_included ? 30 : 24] = qc; + /* rest of QC masked */ + } + + /* Start with the first block and AAD */ + lib80211_ccmp_aes_encrypt(tfm, b0, auth); + xor_block(auth, aad, AES_BLOCK_LEN); + lib80211_ccmp_aes_encrypt(tfm, auth, auth); + xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); + lib80211_ccmp_aes_encrypt(tfm, auth, auth); + b0[0] &= 0x07; + b0[14] = b0[15] = 0; + lib80211_ccmp_aes_encrypt(tfm, b0, s0); +} + +static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, + u8 *aeskey, int keylen, void *priv) +{ + struct lib80211_ccmp_data *key = priv; + int i; + u8 *pos; + + if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len) + return -1; + + if (aeskey != NULL && keylen >= CCMP_TK_LEN) + memcpy(aeskey, key->key, CCMP_TK_LEN); + + pos = skb_push(skb, CCMP_HDR_LEN); + memmove(pos, pos + CCMP_HDR_LEN, hdr_len); + pos += hdr_len; + + i = CCMP_PN_LEN - 1; + while (i >= 0) { + key->tx_pn[i]++; + if (key->tx_pn[i] != 0) + break; + i--; + } + + *pos++ = key->tx_pn[5]; + *pos++ = key->tx_pn[4]; + *pos++ = 0; + *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ; + *pos++ = key->tx_pn[3]; + *pos++ = key->tx_pn[2]; + *pos++ = key->tx_pn[1]; + *pos++ = key->tx_pn[0]; + + return CCMP_HDR_LEN; +} + +static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct lib80211_ccmp_data *key = priv; + int data_len, i, blocks, last, len; + u8 *pos, *mic; + struct ieee80211_hdr *hdr; + u8 *b0 = key->tx_b0; + u8 *b = key->tx_b; + u8 *e = key->tx_e; + u8 *s0 = key->tx_s0; + + if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len) + return -1; + + data_len = skb->len - hdr_len; + len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv); + if (len < 0) + return -1; + + pos = skb->data + hdr_len + CCMP_HDR_LEN; + hdr = (struct ieee80211_hdr *)skb->data; + ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); + + blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Authentication */ + xor_block(b, pos, len); + lib80211_ccmp_aes_encrypt(key->tfm, b, b); + /* Encryption, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + lib80211_ccmp_aes_encrypt(key->tfm, b0, e); + xor_block(pos, e, len); + pos += len; + } + + mic = skb_put(skb, CCMP_MIC_LEN); + for (i = 0; i < CCMP_MIC_LEN; i++) + mic[i] = b[i] ^ s0[i]; + + return 0; +} + +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o) +{ + u32 iv32_n, iv16_n; + u32 iv32_o, iv16_o; + + iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3]; + iv16_n = (pn_n[4] << 8) | pn_n[5]; + + iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3]; + iv16_o = (pn_o[4] << 8) | pn_o[5]; + + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + +static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct lib80211_ccmp_data *key = priv; + u8 keyidx, *pos; + struct ieee80211_hdr *hdr; + u8 *b0 = key->rx_b0; + u8 *b = key->rx_b; + u8 *a = key->rx_a; + u8 pn[6]; + int i, blocks, last, len; + size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; + u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; + + if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { + key->dot11RSNAStatsCCMPFormatErrors++; + return -1; + } + + hdr = (struct ieee80211_hdr *)skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: received packet without ExtIV" + " flag from %pM\n", hdr->addr2); + } + key->dot11RSNAStatsCCMPFormatErrors++; + return -2; + } + keyidx >>= 6; + if (key->key_idx != keyidx) { + printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " + "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); + return -6; + } + if (!key->key_set) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: received packet from %pM" + " with keyid=%d that does not have a configured" + " key\n", hdr->addr2, keyidx); + } + return -3; + } + + pn[0] = pos[7]; + pn[1] = pos[6]; + pn[2] = pos[5]; + pn[3] = pos[4]; + pn[4] = pos[1]; + pn[5] = pos[0]; + pos += 8; + + if (ccmp_replay_check(pn, key->rx_pn)) { +#ifdef CONFIG_LIB80211_DEBUG + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: replay detected: STA=%pM " + "previous PN %02x%02x%02x%02x%02x%02x " + "received PN %02x%02x%02x%02x%02x%02x\n", + hdr->addr2, + key->rx_pn[0], key->rx_pn[1], key->rx_pn[2], + key->rx_pn[3], key->rx_pn[4], key->rx_pn[5], + pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); + } +#endif + key->dot11RSNAStatsCCMPReplays++; + return -4; + } + + ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); + xor_block(mic, b, CCMP_MIC_LEN); + + blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Decrypt, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + lib80211_ccmp_aes_encrypt(key->tfm, b0, b); + xor_block(pos, b, len); + /* Authentication */ + xor_block(a, pos, len); + lib80211_ccmp_aes_encrypt(key->tfm, a, a); + pos += len; + } + + if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: decrypt failed: STA=" + "%pM\n", hdr->addr2); + } + key->dot11RSNAStatsCCMPDecryptErrors++; + return -5; + } + + memcpy(key->rx_pn, pn, CCMP_PN_LEN); + + /* Remove hdr and MIC */ + memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, CCMP_HDR_LEN); + skb_trim(skb, skb->len - CCMP_MIC_LEN); + + return keyidx; +} + +static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct lib80211_ccmp_data *data = priv; + int keyidx; + struct crypto_cipher *tfm = data->tfm; + + keyidx = data->key_idx; + memset(data, 0, sizeof(*data)); + data->key_idx = keyidx; + data->tfm = tfm; + if (len == CCMP_TK_LEN) { + memcpy(data->key, key, CCMP_TK_LEN); + data->key_set = 1; + if (seq) { + data->rx_pn[0] = seq[5]; + data->rx_pn[1] = seq[4]; + data->rx_pn[2] = seq[3]; + data->rx_pn[3] = seq[2]; + data->rx_pn[4] = seq[1]; + data->rx_pn[5] = seq[0]; + } + crypto_cipher_setkey(data->tfm, data->key, CCMP_TK_LEN); + } else if (len == 0) + data->key_set = 0; + else + return -1; + + return 0; +} + +static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct lib80211_ccmp_data *data = priv; + + if (len < CCMP_TK_LEN) + return -1; + + if (!data->key_set) + return 0; + memcpy(key, data->key, CCMP_TK_LEN); + + if (seq) { + seq[0] = data->tx_pn[5]; + seq[1] = data->tx_pn[4]; + seq[2] = data->tx_pn[3]; + seq[3] = data->tx_pn[2]; + seq[4] = data->tx_pn[1]; + seq[5] = data->tx_pn[0]; + } + + return CCMP_TK_LEN; +} + +static char *lib80211_ccmp_print_stats(char *p, void *priv) +{ + struct lib80211_ccmp_data *ccmp = priv; + + p += sprintf(p, "key[%d] alg=CCMP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "format_errors=%d replays=%d decrypt_errors=%d\n", + ccmp->key_idx, ccmp->key_set, + ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2], + ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5], + ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2], + ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5], + ccmp->dot11RSNAStatsCCMPFormatErrors, + ccmp->dot11RSNAStatsCCMPReplays, + ccmp->dot11RSNAStatsCCMPDecryptErrors); + + return p; +} + +static struct lib80211_crypto_ops lib80211_crypt_ccmp = { + .name = "CCMP", + .init = lib80211_ccmp_init, + .deinit = lib80211_ccmp_deinit, + .encrypt_mpdu = lib80211_ccmp_encrypt, + .decrypt_mpdu = lib80211_ccmp_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = lib80211_ccmp_set_key, + .get_key = lib80211_ccmp_get_key, + .print_stats = lib80211_ccmp_print_stats, + .extra_mpdu_prefix_len = CCMP_HDR_LEN, + .extra_mpdu_postfix_len = CCMP_MIC_LEN, + .owner = THIS_MODULE, +}; + +static int __init lib80211_crypto_ccmp_init(void) +{ + return lib80211_register_crypto_ops(&lib80211_crypt_ccmp); +} + +static void __exit lib80211_crypto_ccmp_exit(void) +{ + lib80211_unregister_crypto_ops(&lib80211_crypt_ccmp); +} + +module_init(lib80211_crypto_ccmp_init); +module_exit(lib80211_crypto_ccmp_exit); diff --git a/net/wireless_ath/lib80211_crypt_tkip.c b/net/wireless_ath/lib80211_crypt_tkip.c new file mode 100644 index 00000000..38734846 --- /dev/null +++ b/net/wireless_ath/lib80211_crypt_tkip.c @@ -0,0 +1,780 @@ +/* + * lib80211 crypt: host-based TKIP encryption implementation for lib80211 + * + * Copyright (c) 2003-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville + * + * 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. See README and COPYING for + * more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("lib80211 crypt: TKIP"); +MODULE_LICENSE("GPL"); + +#define TKIP_HDR_LEN 8 + +struct lib80211_tkip_data { +#define TKIP_KEY_LEN 32 + u8 key[TKIP_KEY_LEN]; + int key_set; + + u32 tx_iv32; + u16 tx_iv16; + u16 tx_ttak[5]; + int tx_phase1_done; + + u32 rx_iv32; + u16 rx_iv16; + u16 rx_ttak[5]; + int rx_phase1_done; + u32 rx_iv32_new; + u16 rx_iv16_new; + + u32 dot11RSNAStatsTKIPReplays; + u32 dot11RSNAStatsTKIPICVErrors; + u32 dot11RSNAStatsTKIPLocalMICFailures; + + int key_idx; + + struct crypto_blkcipher *rx_tfm_arc4; + struct crypto_hash *rx_tfm_michael; + struct crypto_blkcipher *tx_tfm_arc4; + struct crypto_hash *tx_tfm_michael; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 rx_hdr[16], tx_hdr[16]; + + unsigned long flags; +}; + +static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv) +{ + struct lib80211_tkip_data *_priv = priv; + unsigned long old_flags = _priv->flags; + _priv->flags = flags; + return old_flags; +} + +static unsigned long lib80211_tkip_get_flags(void *priv) +{ + struct lib80211_tkip_data *_priv = priv; + return _priv->flags; +} + +static void *lib80211_tkip_init(int key_idx) +{ + struct lib80211_tkip_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + + priv->key_idx = key_idx; + + priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_arc4)) { + priv->tx_tfm_arc4 = NULL; + goto fail; + } + + priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_michael)) { + priv->tx_tfm_michael = NULL; + goto fail; + } + + priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_arc4)) { + priv->rx_tfm_arc4 = NULL; + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_michael)) { + priv->rx_tfm_michael = NULL; + goto fail; + } + + return priv; + + fail: + if (priv) { + if (priv->tx_tfm_michael) + crypto_free_hash(priv->tx_tfm_michael); + if (priv->tx_tfm_arc4) + crypto_free_blkcipher(priv->tx_tfm_arc4); + if (priv->rx_tfm_michael) + crypto_free_hash(priv->rx_tfm_michael); + if (priv->rx_tfm_arc4) + crypto_free_blkcipher(priv->rx_tfm_arc4); + kfree(priv); + } + + return NULL; +} + +static void lib80211_tkip_deinit(void *priv) +{ + struct lib80211_tkip_data *_priv = priv; + if (_priv) { + if (_priv->tx_tfm_michael) + crypto_free_hash(_priv->tx_tfm_michael); + if (_priv->tx_tfm_arc4) + crypto_free_blkcipher(_priv->tx_tfm_arc4); + if (_priv->rx_tfm_michael) + crypto_free_hash(_priv->rx_tfm_michael); + if (_priv->rx_tfm_arc4) + crypto_free_blkcipher(_priv->rx_tfm_arc4); + } + kfree(priv); +} + +static inline u16 RotR1(u16 val) +{ + return (val >> 1) | (val << 15); +} + +static inline u8 Lo8(u16 val) +{ + return val & 0xff; +} + +static inline u8 Hi8(u16 val) +{ + return val >> 8; +} + +static inline u16 Lo16(u32 val) +{ + return val & 0xffff; +} + +static inline u16 Hi16(u32 val) +{ + return val >> 16; +} + +static inline u16 Mk16(u8 hi, u8 lo) +{ + return lo | (((u16) hi) << 8); +} + +static inline u16 Mk16_le(__le16 * v) +{ + return le16_to_cpu(*v); +} + +static const u16 Sbox[256] = { + 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, +}; + +static inline u16 _S_(u16 v) +{ + u16 t = Sbox[Hi8(v)]; + return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); +} + +#define PHASE1_LOOP_COUNT 8 + +static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA, + u32 IV32) +{ + int i, j; + + /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ + TTAK[0] = Lo16(IV32); + TTAK[1] = Hi16(IV32); + TTAK[2] = Mk16(TA[1], TA[0]); + TTAK[3] = Mk16(TA[3], TA[2]); + TTAK[4] = Mk16(TA[5], TA[4]); + + for (i = 0; i < PHASE1_LOOP_COUNT; i++) { + j = 2 * (i & 1); + TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); + TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); + TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); + TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); + TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; + } +} + +static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, + u16 IV16) +{ + /* Make temporary area overlap WEP seed so that the final copy can be + * avoided on little endian hosts. */ + u16 *PPK = (u16 *) & WEPSeed[4]; + + /* Step 1 - make copy of TTAK and bring in TSC */ + PPK[0] = TTAK[0]; + PPK[1] = TTAK[1]; + PPK[2] = TTAK[2]; + PPK[3] = TTAK[3]; + PPK[4] = TTAK[4]; + PPK[5] = TTAK[4] + IV16; + + /* Step 2 - 96-bit bijective mixing using S-box */ + PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0])); + PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2])); + PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4])); + PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6])); + PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8])); + PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10])); + + PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12])); + PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14])); + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + + /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value + * WEPSeed[0..2] is transmitted as WEP IV */ + WEPSeed[0] = Hi8(IV16); + WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; + WEPSeed[2] = Lo8(IV16); + WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1); + +#ifdef __BIG_ENDIAN + { + int i; + for (i = 0; i < 6; i++) + PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); + } +#endif +} + +static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, + u8 * rc4key, int keylen, void *priv) +{ + struct lib80211_tkip_data *tkey = priv; + u8 *pos; + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len) + return -1; + + if (rc4key == NULL || keylen < 16) + return -1; + + if (!tkey->tx_phase1_done) { + tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, + tkey->tx_iv32); + tkey->tx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); + + pos = skb_push(skb, TKIP_HDR_LEN); + memmove(pos, pos + TKIP_HDR_LEN, hdr_len); + pos += hdr_len; + + *pos++ = *rc4key; + *pos++ = *(rc4key + 1); + *pos++ = *(rc4key + 2); + *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ; + *pos++ = tkey->tx_iv32 & 0xff; + *pos++ = (tkey->tx_iv32 >> 8) & 0xff; + *pos++ = (tkey->tx_iv32 >> 16) & 0xff; + *pos++ = (tkey->tx_iv32 >> 24) & 0xff; + + tkey->tx_iv16++; + if (tkey->tx_iv16 == 0) { + tkey->tx_phase1_done = 0; + tkey->tx_iv32++; + } + + return TKIP_HDR_LEN; +} + +static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct lib80211_tkip_data *tkey = priv; + struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 }; + int len; + u8 rc4key[16], *pos, *icv; + u32 crc; + struct scatterlist sg; + + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { + if (net_ratelimit()) { + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *)skb->data; + printk(KERN_DEBUG ": TKIP countermeasures: dropped " + "TX packet to %pM\n", hdr->addr1); + } + return -1; + } + + if (skb_tailroom(skb) < 4 || skb->len < hdr_len) + return -1; + + len = skb->len - hdr_len; + pos = skb->data + hdr_len; + + if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) + return -1; + + crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + sg_init_one(&sg, pos, len + 4); + return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); +} + +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, + u32 iv32_o, u16 iv16_o) +{ + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + +static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct lib80211_tkip_data *tkey = priv; + struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 }; + u8 rc4key[16]; + u8 keyidx, *pos; + u32 iv32; + u16 iv16; + struct ieee80211_hdr *hdr; + u8 icv[4]; + u32 crc; + struct scatterlist sg; + int plen; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { + if (net_ratelimit()) { + printk(KERN_DEBUG ": TKIP countermeasures: dropped " + "received packet from %pM\n", hdr->addr2); + } + return -1; + } + + if (skb->len < hdr_len + TKIP_HDR_LEN + 4) + return -1; + + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: received packet without ExtIV" + " flag from %pM\n", hdr->addr2); + } + return -2; + } + keyidx >>= 6; + if (tkey->key_idx != keyidx) { + printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " + "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); + return -6; + } + if (!tkey->key_set) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: received packet from %pM" + " with keyid=%d that does not have a configured" + " key\n", hdr->addr2, keyidx); + } + return -3; + } + iv16 = (pos[0] << 8) | pos[2]; + iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); + pos += TKIP_HDR_LEN; + + if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { +#ifdef CONFIG_LIB80211_DEBUG + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: replay detected: STA=%pM" + " previous TSC %08x%04x received TSC " + "%08x%04x\n", hdr->addr2, + tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); + } +#endif + tkey->dot11RSNAStatsTKIPReplays++; + return -4; + } + + if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { + tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); + tkey->rx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); + + plen = skb->len - hdr_len - 12; + + crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + sg_init_one(&sg, pos, plen + 4); + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { + if (net_ratelimit()) { + printk(KERN_DEBUG ": TKIP: failed to decrypt " + "received packet from %pM\n", + hdr->addr2); + } + return -7; + } + + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + if (iv32 != tkey->rx_iv32) { + /* Previously cached Phase1 result was already lost, so + * it needs to be recalculated for the next packet. */ + tkey->rx_phase1_done = 0; + } +#ifdef CONFIG_LIB80211_DEBUG + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: ICV error detected: STA=" + "%pM\n", hdr->addr2); + } +#endif + tkey->dot11RSNAStatsTKIPICVErrors++; + return -5; + } + + /* Update real counters only after Michael MIC verification has + * completed */ + tkey->rx_iv32_new = iv32; + tkey->rx_iv16_new = iv16; + + /* Remove IV and ICV */ + memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, TKIP_HDR_LEN); + skb_trim(skb, skb->len - 4); + + return keyidx; +} + +static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, + u8 * data, size_t data_len, u8 * mic) +{ + struct hash_desc desc; + struct scatterlist sg[2]; + + if (tfm_michael == NULL) { + pr_warn("%s(): tfm_michael == NULL\n", __func__); + return -1; + } + sg_init_table(sg, 2); + sg_set_buf(&sg[0], hdr, 16); + sg_set_buf(&sg[1], data, data_len); + + if (crypto_hash_setkey(tfm_michael, key, 8)) + return -1; + + desc.tfm = tfm_michael; + desc.flags = 0; + return crypto_hash_digest(&desc, sg, data_len + 16, mic); +} + +static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) +{ + struct ieee80211_hdr *hdr11; + + hdr11 = (struct ieee80211_hdr *)skb->data; + + switch (le16_to_cpu(hdr11->frame_control) & + (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ + break; + case 0: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + } + + if (ieee80211_is_data_qos(hdr11->frame_control)) { + hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11))) + & IEEE80211_QOS_CTL_TID_MASK; + } else + hdr[12] = 0; /* priority */ + + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + +static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len, + void *priv) +{ + struct lib80211_tkip_data *tkey = priv; + u8 *pos; + + if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { + printk(KERN_DEBUG "Invalid packet for Michael MIC add " + "(tailroom=%d hdr_len=%d skb->len=%d)\n", + skb_tailroom(skb), hdr_len, skb->len); + return -1; + } + + michael_mic_hdr(skb, tkey->tx_hdr); + pos = skb_put(skb, 8); + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) + return -1; + + return 0; +} + +static void lib80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + memset(&ev, 0, sizeof(ev)); + ev.flags = keyidx & IW_MICFAILURE_KEY_ID; + if (hdr->addr1[0] & 0x01) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); +} + +static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx, + int hdr_len, void *priv) +{ + struct lib80211_tkip_data *tkey = priv; + u8 mic[8]; + + if (!tkey->key_set) + return -1; + + michael_mic_hdr(skb, tkey->rx_hdr); + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) + return -1; + if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *)skb->data; + printk(KERN_DEBUG "%s: Michael MIC verification failed for " + "MSDU from %pM keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", hdr->addr2, + keyidx); + if (skb->dev) + lib80211_michael_mic_failure(skb->dev, hdr, keyidx); + tkey->dot11RSNAStatsTKIPLocalMICFailures++; + return -1; + } + + /* Update TSC counters for RX now that the packet verification has + * completed. */ + tkey->rx_iv32 = tkey->rx_iv32_new; + tkey->rx_iv16 = tkey->rx_iv16_new; + + skb_trim(skb, skb->len - 8); + + return 0; +} + +static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct lib80211_tkip_data *tkey = priv; + int keyidx; + struct crypto_hash *tfm = tkey->tx_tfm_michael; + struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_hash *tfm3 = tkey->rx_tfm_michael; + struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; + + keyidx = tkey->key_idx; + memset(tkey, 0, sizeof(*tkey)); + tkey->key_idx = keyidx; + tkey->tx_tfm_michael = tfm; + tkey->tx_tfm_arc4 = tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_tfm_arc4 = tfm4; + if (len == TKIP_KEY_LEN) { + memcpy(tkey->key, key, TKIP_KEY_LEN); + tkey->key_set = 1; + tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ + if (seq) { + tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | + (seq[3] << 8) | seq[2]; + tkey->rx_iv16 = (seq[1] << 8) | seq[0]; + } + } else if (len == 0) + tkey->key_set = 0; + else + return -1; + + return 0; +} + +static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct lib80211_tkip_data *tkey = priv; + + if (len < TKIP_KEY_LEN) + return -1; + + if (!tkey->key_set) + return 0; + memcpy(key, tkey->key, TKIP_KEY_LEN); + + if (seq) { + /* Return the sequence number of the last transmitted frame. */ + u16 iv16 = tkey->tx_iv16; + u32 iv32 = tkey->tx_iv32; + if (iv16 == 0) + iv32--; + iv16--; + seq[0] = tkey->tx_iv16; + seq[1] = tkey->tx_iv16 >> 8; + seq[2] = tkey->tx_iv32; + seq[3] = tkey->tx_iv32 >> 8; + seq[4] = tkey->tx_iv32 >> 16; + seq[5] = tkey->tx_iv32 >> 24; + } + + return TKIP_KEY_LEN; +} + +static char *lib80211_tkip_print_stats(char *p, void *priv) +{ + struct lib80211_tkip_data *tkip = priv; + p += sprintf(p, "key[%d] alg=TKIP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "replays=%d icv_errors=%d local_mic_failures=%d\n", + tkip->key_idx, tkip->key_set, + (tkip->tx_iv32 >> 24) & 0xff, + (tkip->tx_iv32 >> 16) & 0xff, + (tkip->tx_iv32 >> 8) & 0xff, + tkip->tx_iv32 & 0xff, + (tkip->tx_iv16 >> 8) & 0xff, + tkip->tx_iv16 & 0xff, + (tkip->rx_iv32 >> 24) & 0xff, + (tkip->rx_iv32 >> 16) & 0xff, + (tkip->rx_iv32 >> 8) & 0xff, + tkip->rx_iv32 & 0xff, + (tkip->rx_iv16 >> 8) & 0xff, + tkip->rx_iv16 & 0xff, + tkip->dot11RSNAStatsTKIPReplays, + tkip->dot11RSNAStatsTKIPICVErrors, + tkip->dot11RSNAStatsTKIPLocalMICFailures); + return p; +} + +static struct lib80211_crypto_ops lib80211_crypt_tkip = { + .name = "TKIP", + .init = lib80211_tkip_init, + .deinit = lib80211_tkip_deinit, + .encrypt_mpdu = lib80211_tkip_encrypt, + .decrypt_mpdu = lib80211_tkip_decrypt, + .encrypt_msdu = lib80211_michael_mic_add, + .decrypt_msdu = lib80211_michael_mic_verify, + .set_key = lib80211_tkip_set_key, + .get_key = lib80211_tkip_get_key, + .print_stats = lib80211_tkip_print_stats, + .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .extra_msdu_postfix_len = 8, /* MIC */ + .get_flags = lib80211_tkip_get_flags, + .set_flags = lib80211_tkip_set_flags, + .owner = THIS_MODULE, +}; + +static int __init lib80211_crypto_tkip_init(void) +{ + return lib80211_register_crypto_ops(&lib80211_crypt_tkip); +} + +static void __exit lib80211_crypto_tkip_exit(void) +{ + lib80211_unregister_crypto_ops(&lib80211_crypt_tkip); +} + +module_init(lib80211_crypto_tkip_init); +module_exit(lib80211_crypto_tkip_exit); diff --git a/net/wireless_ath/lib80211_crypt_wep.c b/net/wireless_ath/lib80211_crypt_wep.c new file mode 100644 index 00000000..c1304018 --- /dev/null +++ b/net/wireless_ath/lib80211_crypt_wep.c @@ -0,0 +1,290 @@ +/* + * lib80211 crypt: host-based WEP encryption implementation for lib80211 + * + * Copyright (c) 2002-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville + * + * 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. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("lib80211 crypt: WEP"); +MODULE_LICENSE("GPL"); + +struct lib80211_wep_data { + u32 iv; +#define WEP_KEY_LEN 13 + u8 key[WEP_KEY_LEN + 1]; + u8 key_len; + u8 key_idx; + struct crypto_blkcipher *tx_tfm; + struct crypto_blkcipher *rx_tfm; +}; + +static void *lib80211_wep_init(int keyidx) +{ + struct lib80211_wep_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + priv->key_idx = keyidx; + + priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm)) { + priv->tx_tfm = NULL; + goto fail; + } + + priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm)) { + priv->rx_tfm = NULL; + goto fail; + } + /* start WEP IV from a random value */ + get_random_bytes(&priv->iv, 4); + + return priv; + + fail: + if (priv) { + if (priv->tx_tfm) + crypto_free_blkcipher(priv->tx_tfm); + if (priv->rx_tfm) + crypto_free_blkcipher(priv->rx_tfm); + kfree(priv); + } + return NULL; +} + +static void lib80211_wep_deinit(void *priv) +{ + struct lib80211_wep_data *_priv = priv; + if (_priv) { + if (_priv->tx_tfm) + crypto_free_blkcipher(_priv->tx_tfm); + if (_priv->rx_tfm) + crypto_free_blkcipher(_priv->rx_tfm); + } + kfree(priv); +} + +/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ +static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len, + u8 *key, int keylen, void *priv) +{ + struct lib80211_wep_data *wep = priv; + u32 klen; + u8 *pos; + + if (skb_headroom(skb) < 4 || skb->len < hdr_len) + return -1; + + pos = skb_push(skb, 4); + memmove(pos, pos + 4, hdr_len); + pos += hdr_len; + + klen = 3 + wep->key_len; + + wep->iv++; + + /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key + * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) + * can be used to speedup attacks, so avoid using them. */ + if ((wep->iv & 0xff00) == 0xff00) { + u8 B = (wep->iv >> 16) & 0xff; + if (B >= 3 && B < klen) + wep->iv += 0x0100; + } + + /* Prepend 24-bit IV to RC4 key and TX frame */ + *pos++ = (wep->iv >> 16) & 0xff; + *pos++ = (wep->iv >> 8) & 0xff; + *pos++ = wep->iv & 0xff; + *pos++ = wep->key_idx << 6; + + return 0; +} + +/* Perform WEP encryption on given skb that has at least 4 bytes of headroom + * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, + * so the payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct lib80211_wep_data *wep = priv; + struct blkcipher_desc desc = { .tfm = wep->tx_tfm }; + u32 crc, klen, len; + u8 *pos, *icv; + struct scatterlist sg; + u8 key[WEP_KEY_LEN + 3]; + + /* other checks are in lib80211_wep_build_iv */ + if (skb_tailroom(skb) < 4) + return -1; + + /* add the IV to the frame */ + if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv)) + return -1; + + /* Copy the IV into the first 3 bytes of the key */ + skb_copy_from_linear_data_offset(skb, hdr_len, key, 3); + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + len = skb->len - hdr_len - 4; + pos = skb->data + hdr_len + 4; + klen = 3 + wep->key_len; + + /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */ + crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + crypto_blkcipher_setkey(wep->tx_tfm, key, klen); + sg_init_one(&sg, pos, len + 4); + return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); +} + +/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of + * the frame: IV (4 bytes), encrypted payload (including SNAP header), + * ICV (4 bytes). len includes both IV and ICV. + * + * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on + * failure. If frame is OK, IV and ICV will be removed. + */ +static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct lib80211_wep_data *wep = priv; + struct blkcipher_desc desc = { .tfm = wep->rx_tfm }; + u32 crc, klen, plen; + u8 key[WEP_KEY_LEN + 3]; + u8 keyidx, *pos, icv[4]; + struct scatterlist sg; + + if (skb->len < hdr_len + 8) + return -1; + + pos = skb->data + hdr_len; + key[0] = *pos++; + key[1] = *pos++; + key[2] = *pos++; + keyidx = *pos++ >> 6; + if (keyidx != wep->key_idx) + return -1; + + klen = 3 + wep->key_len; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + /* Apply RC4 to data and compute CRC32 over decrypted data */ + plen = skb->len - hdr_len - 8; + + crypto_blkcipher_setkey(wep->rx_tfm, key, klen); + sg_init_one(&sg, pos, plen + 4); + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) + return -7; + + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + /* ICV mismatch - drop frame */ + return -2; + } + + /* Remove IV and ICV */ + memmove(skb->data + 4, skb->data, hdr_len); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + + return 0; +} + +static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct lib80211_wep_data *wep = priv; + + if (len < 0 || len > WEP_KEY_LEN) + return -1; + + memcpy(wep->key, key, len); + wep->key_len = len; + + return 0; +} + +static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct lib80211_wep_data *wep = priv; + + if (len < wep->key_len) + return -1; + + memcpy(key, wep->key, wep->key_len); + + return wep->key_len; +} + +static char *lib80211_wep_print_stats(char *p, void *priv) +{ + struct lib80211_wep_data *wep = priv; + p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); + return p; +} + +static struct lib80211_crypto_ops lib80211_crypt_wep = { + .name = "WEP", + .init = lib80211_wep_init, + .deinit = lib80211_wep_deinit, + .encrypt_mpdu = lib80211_wep_encrypt, + .decrypt_mpdu = lib80211_wep_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = lib80211_wep_set_key, + .get_key = lib80211_wep_get_key, + .print_stats = lib80211_wep_print_stats, + .extra_mpdu_prefix_len = 4, /* IV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .owner = THIS_MODULE, +}; + +static int __init lib80211_crypto_wep_init(void) +{ + return lib80211_register_crypto_ops(&lib80211_crypt_wep); +} + +static void __exit lib80211_crypto_wep_exit(void) +{ + lib80211_unregister_crypto_ops(&lib80211_crypt_wep); +} + +module_init(lib80211_crypto_wep_init); +module_exit(lib80211_crypto_wep_exit); diff --git a/net/wireless_ath/mesh.c b/net/wireless_ath/mesh.c new file mode 100644 index 00000000..b7b7868f --- /dev/null +++ b/net/wireless_ath/mesh.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include "nl80211.h" +#include "core.h" + +/* Default values, timeouts in ms */ +#define MESH_TTL 31 +#define MESH_DEFAULT_ELEMENT_TTL 31 +#define MESH_MAX_RETR 3 +#define MESH_RET_T 100 +#define MESH_CONF_T 100 +#define MESH_HOLD_T 100 + +#define MESH_PATH_TIMEOUT 5000 +#define MESH_RANN_INTERVAL 5000 + +/* + * Minimum interval between two consecutive PREQs originated by the same + * interface + */ +#define MESH_PREQ_MIN_INT 10 +#define MESH_DIAM_TRAVERSAL_TIME 50 + +/* + * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds + * before timing out. This way it will remain ACTIVE and no data frames + * will be unnecessarily held in the pending queue. + */ +#define MESH_PATH_REFRESH_TIME 1000 +#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) + +/* Default maximum number of established plinks per interface */ +#define MESH_MAX_ESTAB_PLINKS 32 + +#define MESH_MAX_PREQ_RETRIES 4 + + +const struct mesh_config default_mesh_config = { + .dot11MeshRetryTimeout = MESH_RET_T, + .dot11MeshConfirmTimeout = MESH_CONF_T, + .dot11MeshHoldingTimeout = MESH_HOLD_T, + .dot11MeshMaxRetries = MESH_MAX_RETR, + .dot11MeshTTL = MESH_TTL, + .element_ttl = MESH_DEFAULT_ELEMENT_TTL, + .auto_open_plinks = true, + .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS, + .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT, + .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT, + .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME, + .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES, + .path_refresh_time = MESH_PATH_REFRESH_TIME, + .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, + .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL, + .dot11MeshGateAnnouncementProtocol = false, +}; + +const struct mesh_setup default_mesh_setup = { + .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, + .path_metric = IEEE80211_PATH_METRIC_AIRTIME, + .ie = NULL, + .ie_len = 0, + .is_secure = false, +}; + +int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev, + const struct mesh_setup *setup, + const struct mesh_config *conf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); + + ASSERT_WDEV_LOCK(wdev); + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && + setup->is_secure) + return -EOPNOTSUPP; + + if (wdev->mesh_id_len) + return -EALREADY; + + if (!setup->mesh_id_len) + return -EINVAL; + + if (!rdev->ops->join_mesh) + return -EOPNOTSUPP; + + err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); + if (!err) { + memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); + wdev->mesh_id_len = setup->mesh_id_len; + } + + return err; +} + +int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev, + const struct mesh_setup *setup, + const struct mesh_config *conf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_join_mesh(rdev, dev, setup, conf); + wdev_unlock(wdev); + + return err; +} + +void cfg80211_notify_new_peer_candidate(struct net_device *dev, + const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) + return; + + nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev, + macaddr, ie, ie_len, gfp); +} +EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); + +static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + ASSERT_WDEV_LOCK(wdev); + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + if (!rdev->ops->leave_mesh) + return -EOPNOTSUPP; + + if (!wdev->mesh_id_len) + return -ENOTCONN; + + err = rdev->ops->leave_mesh(&rdev->wiphy, dev); + if (!err) + wdev->mesh_id_len = 0; + return err; +} + +int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_leave_mesh(rdev, dev); + wdev_unlock(wdev); + + return err; +} diff --git a/net/wireless_ath/mlme.c b/net/wireless_ath/mlme.c new file mode 100644 index 00000000..4d74154d --- /dev/null +++ b/net/wireless_ath/mlme.c @@ -0,0 +1,1191 @@ +/* + * cfg80211 MLME SAP interface + * + * Copyright (c) 2009, Jouni Malinen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "nl80211.h" + +void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + u8 *bssid = mgmt->bssid; + int i; + u16 status = le16_to_cpu(mgmt->u.auth.status_code); + bool done = false; + + wdev_lock(wdev); + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] && + memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, + ETH_ALEN) == 0) { + if (status == WLAN_STATUS_SUCCESS) { + wdev->auth_bsses[i] = wdev->authtry_bsses[i]; + } else { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + } + wdev->authtry_bsses[i] = NULL; + done = true; + break; + } + } + + if (done) { + nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); + cfg80211_sme_rx_auth(dev, buf, len); + } + + wdev_unlock(wdev); +} +EXPORT_SYMBOL(cfg80211_send_rx_auth); + +void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) +{ + u16 status_code; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + u8 *ie = mgmt->u.assoc_resp.variable; + int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); + struct cfg80211_internal_bss *bss = NULL; + + wdev_lock(wdev); + + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + + /* + * This is a bit of a hack, we don't notify userspace of + * a (re-)association reply if we tried to send a reassoc + * and got a reject -- we only try again with an assoc + * frame instead of reassoc. + */ + if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && + cfg80211_sme_failed_reassoc(wdev)) + goto out; + + nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); + + if (status_code == WLAN_STATUS_SUCCESS) { + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (!wdev->auth_bsses[i]) + continue; + if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid, + ETH_ALEN) == 0) { + bss = wdev->auth_bsses[i]; + wdev->auth_bsses[i] = NULL; + /* additional reference to drop hold */ + cfg80211_ref_bss(bss); + break; + } + } + + /* + * We might be coming here because the driver reported + * a successful association at the same time as the + * user requested a deauth. In that case, we will have + * removed the BSS from the auth_bsses list due to the + * deauth request when the assoc response makes it. If + * the two code paths acquire the lock the other way + * around, that's just the standard situation of a + * deauth being requested while connected. + */ + if (!bss) + goto out; + } else if (wdev->conn) { + cfg80211_sme_failed_assoc(wdev); + /* + * do not call connect_result() now because the + * sme will schedule work that does it later. + */ + goto out; + } + + if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { + /* + * This is for the userspace SME, the CONNECTING + * state will be changed to CONNECTED by + * __cfg80211_connect_result() below. + */ + wdev->sme_state = CFG80211_SME_CONNECTING; + } + + /* this consumes one bss reference (unless bss is NULL) */ + __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, + status_code, + status_code == WLAN_STATUS_SUCCESS, + bss ? &bss->pub : NULL); + /* drop hold now, and also reference acquired above */ + if (bss) { + cfg80211_unhold_bss(bss); + cfg80211_put_bss(&bss->pub); + } + + out: + wdev_unlock(wdev); +} +EXPORT_SYMBOL(cfg80211_send_rx_assoc); + +void __cfg80211_send_deauth(struct net_device *dev, + const u8 *buf, size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + const u8 *bssid = mgmt->bssid; + int i; + bool found = false, was_current = false; + + ASSERT_WDEV_LOCK(wdev); + + if (wdev->current_bss && + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; + found = true; + was_current = true; + } else for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i] && + memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->auth_bsses[i]); + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + wdev->auth_bsses[i] = NULL; + found = true; + break; + } + if (wdev->authtry_bsses[i] && + memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, + ETH_ALEN) == 0 && + memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + wdev->authtry_bsses[i] = NULL; + found = true; + break; + } + } + + if (!found) + return; + + nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); + + if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { + u16 reason_code; + bool from_ap; + + reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); + + from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; + __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); + } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { + __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false, NULL); + } +} +EXPORT_SYMBOL(__cfg80211_send_deauth); + +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wdev_lock(wdev); + __cfg80211_send_deauth(dev, buf, len); + wdev_unlock(wdev); +} +EXPORT_SYMBOL(cfg80211_send_deauth); + +void __cfg80211_send_disassoc(struct net_device *dev, + const u8 *buf, size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + const u8 *bssid = mgmt->bssid; + int i; + u16 reason_code; + bool from_ap; + bool done = false; + + ASSERT_WDEV_LOCK(wdev); + + nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); + + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return; + + if (wdev->current_bss && + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) + continue; + wdev->auth_bsses[i] = wdev->current_bss; + wdev->current_bss = NULL; + done = true; + cfg80211_sme_disassoc(dev, i); + break; + } + WARN_ON(!done); + } else + WARN_ON(1); + + + reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); + + from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; + __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); +} +EXPORT_SYMBOL(__cfg80211_send_disassoc); + +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wdev_lock(wdev); + __cfg80211_send_disassoc(dev, buf, len); + wdev_unlock(wdev); +} +EXPORT_SYMBOL(cfg80211_send_disassoc); + +void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, + size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC); +} +EXPORT_SYMBOL(cfg80211_send_unprot_deauth); + +void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, + size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC); +} +EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); + +static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr) +{ + int i; + bool done = false; + + ASSERT_WDEV_LOCK(wdev); + + for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] && + memcmp(wdev->authtry_bsses[i]->pub.bssid, + addr, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + wdev->authtry_bsses[i] = NULL; + done = true; + break; + } + } + + WARN_ON(!done); +} + +void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr) +{ + __cfg80211_auth_remove(dev->ieee80211_ptr, addr); +} +EXPORT_SYMBOL(__cfg80211_auth_canceled); + +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + wdev_lock(wdev); + + nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); + if (wdev->sme_state == CFG80211_SME_CONNECTING) + __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false, NULL); + + __cfg80211_auth_remove(wdev, addr); + + wdev_unlock(wdev); +} +EXPORT_SYMBOL(cfg80211_send_auth_timeout); + +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + int i; + bool done = false; + + wdev_lock(wdev); + + nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); + if (wdev->sme_state == CFG80211_SME_CONNECTING) + __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false, NULL); + + for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i] && + memcmp(wdev->auth_bsses[i]->pub.bssid, + addr, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->auth_bsses[i]); + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + wdev->auth_bsses[i] = NULL; + done = true; + break; + } + } + + WARN_ON(!done); + + wdev_unlock(wdev); +} +EXPORT_SYMBOL(cfg80211_send_assoc_timeout); + +void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); +#ifdef CONFIG_CFG80211_WEXT + union iwreq_data wrqu; + char *buf = kmalloc(128, gfp); + + if (buf) { + sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" + "keyid=%d %scast addr=%pM)", key_id, + key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni", + addr); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); + kfree(buf); + } +#endif + + nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); +} +EXPORT_SYMBOL(cfg80211_michael_mic_failure); + +/* some MLME handling for userspace SME */ +int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, + const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx, + bool local_state_change) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_auth_request req; + struct cfg80211_internal_bss *bss; + int i, err, slot = -1, nfree = 0; + + ASSERT_WDEV_LOCK(wdev); + + if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) + if (!key || !key_len || key_idx < 0 || key_idx > 4) + return -EINVAL; + + if (wdev->current_bss && + memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) + return -EALREADY; + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] && + memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, + ETH_ALEN) == 0) + return -EALREADY; + if (wdev->auth_bsses[i] && + memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, + ETH_ALEN) == 0) + return -EALREADY; + } + + memset(&req, 0, sizeof(req)); + + req.local_state_change = local_state_change; + req.ie = ie; + req.ie_len = ie_len; + req.auth_type = auth_type; + req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + req.key = key; + req.key_len = key_len; + req.key_idx = key_idx; + if (!req.bss) + return -ENOENT; + + bss = bss_from_pub(req.bss); + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) { + slot = i; + nfree++; + } + } + + /* we need one free slot for disassoc and one for this auth */ + if (nfree < 2) { + err = -ENOSPC; + goto out; + } + + if (local_state_change) + wdev->auth_bsses[slot] = bss; + else + wdev->authtry_bsses[slot] = bss; + cfg80211_hold_bss(bss); + + err = rdev->ops->auth(&rdev->wiphy, dev, &req); + if (err) { + if (local_state_change) + wdev->auth_bsses[slot] = NULL; + else + wdev->authtry_bsses[slot] = NULL; + cfg80211_unhold_bss(bss); + } + + out: + if (err) + cfg80211_put_bss(req.bss); + return err; +} + +int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx, + bool local_state_change) +{ + int err; + + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, + ssid, ssid_len, ie, ie_len, + key, key_len, key_idx, local_state_change); + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + +int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_assoc_request req; + struct cfg80211_internal_bss *bss; + int i, err, slot = -1; + bool was_connected = false; + + ASSERT_WDEV_LOCK(wdev); + + memset(&req, 0, sizeof(req)); + + if (wdev->current_bss && prev_bssid && + memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) { + /* + * Trying to reassociate: Allow this to proceed and let the old + * association to be dropped when the new one is completed. + */ + if (wdev->sme_state == CFG80211_SME_CONNECTED) { + was_connected = true; + wdev->sme_state = CFG80211_SME_CONNECTING; + } + } else if (wdev->current_bss) + return -EALREADY; + + req.ie = ie; + req.ie_len = ie_len; + memcpy(&req.crypto, crypt, sizeof(req.crypto)); + req.use_mfp = use_mfp; + req.prev_bssid = prev_bssid; + req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (!req.bss) { + if (was_connected) + wdev->sme_state = CFG80211_SME_CONNECTED; + return -ENOENT; + } + + bss = bss_from_pub(req.bss); + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (bss == wdev->auth_bsses[i]) { + slot = i; + break; + } + } + + if (slot < 0) { + err = -ENOTCONN; + goto out; + } + + err = rdev->ops->assoc(&rdev->wiphy, dev, &req); + out: + if (err && was_connected) + wdev->sme_state = CFG80211_SME_CONNECTED; + /* still a reference in wdev->auth_bsses[slot] */ + cfg80211_put_bss(req.bss); + return err; +} + +int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, + ssid, ssid_len, ie, ie_len, use_mfp, crypt); + wdev_unlock(wdev); + + return err; +} + +int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_deauth_request req; + int i; + + ASSERT_WDEV_LOCK(wdev); + + memset(&req, 0, sizeof(req)); + req.reason_code = reason; + req.local_state_change = local_state_change; + req.ie = ie; + req.ie_len = ie_len; + if (wdev->current_bss && + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { + req.bss = &wdev->current_bss->pub; + } else for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i] && + memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) { + req.bss = &wdev->auth_bsses[i]->pub; + break; + } + if (wdev->authtry_bsses[i] && + memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) { + req.bss = &wdev->authtry_bsses[i]->pub; + break; + } + } + + if (!req.bss) + return -ENOTCONN; + + return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); +} + +int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason, + local_state_change); + wdev_unlock(wdev); + + return err; +} + +static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_disassoc_request req; + + ASSERT_WDEV_LOCK(wdev); + + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return -ENOTCONN; + + if (WARN_ON(!wdev->current_bss)) + return -ENOTCONN; + + memset(&req, 0, sizeof(req)); + req.reason_code = reason; + req.local_state_change = local_state_change; + req.ie = ie; + req.ie_len = ie_len; + if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) + req.bss = &wdev->current_bss->pub; + else + return -ENOTCONN; + + return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev); +} + +int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason, + local_state_change); + wdev_unlock(wdev); + + return err; +} + +void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_deauth_request req; + int i; + + ASSERT_WDEV_LOCK(wdev); + + if (!rdev->ops->deauth) + return; + + memset(&req, 0, sizeof(req)); + req.reason_code = WLAN_REASON_DEAUTH_LEAVING; + req.ie = NULL; + req.ie_len = 0; + + if (wdev->current_bss) { + req.bss = &wdev->current_bss->pub; + rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; + } + } + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i]) { + req.bss = &wdev->auth_bsses[i]->pub; + rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); + if (wdev->auth_bsses[i]) { + cfg80211_unhold_bss(wdev->auth_bsses[i]); + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + wdev->auth_bsses[i] = NULL; + } + } + if (wdev->authtry_bsses[i]) { + req.bss = &wdev->authtry_bsses[i]->pub; + rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); + if (wdev->authtry_bsses[i]) { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + wdev->authtry_bsses[i] = NULL; + } + } + } +} + +void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, + duration, gfp); +} +EXPORT_SYMBOL(cfg80211_ready_on_channel); + +void cfg80211_remain_on_channel_expired(struct net_device *dev, + u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, + channel_type, gfp); +} +EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); + +void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); +} +EXPORT_SYMBOL(cfg80211_new_sta); + +void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp); +} +EXPORT_SYMBOL(cfg80211_del_sta); + +void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, + enum nl80211_connect_failed_reason reason, + gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp); +} +EXPORT_SYMBOL(cfg80211_conn_failed); + +struct cfg80211_mgmt_registration { + struct list_head list; + + u32 nlpid; + + int match_len; + + __le16 frame_type; + + u8 match[]; +}; + +int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, + u16 frame_type, const u8 *match_data, + int match_len) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_mgmt_registration *reg, *nreg; + int err = 0; + u16 mgmt_type; + + if (!wdev->wiphy->mgmt_stypes) + return -EOPNOTSUPP; + + if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) + return -EINVAL; + + if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) + return -EINVAL; + + mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; + if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) + return -EINVAL; + + nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); + if (!nreg) + return -ENOMEM; + + spin_lock_bh(&wdev->mgmt_registrations_lock); + + list_for_each_entry(reg, &wdev->mgmt_registrations, list) { + int mlen = min(match_len, reg->match_len); + + if (frame_type != le16_to_cpu(reg->frame_type)) + continue; + + if (memcmp(reg->match, match_data, mlen) == 0) { + err = -EALREADY; + break; + } + } + + if (err) { + kfree(nreg); + goto out; + } + + memcpy(nreg->match, match_data, match_len); + nreg->match_len = match_len; + nreg->nlpid = snd_pid; + nreg->frame_type = cpu_to_le16(frame_type); + list_add(&nreg->list, &wdev->mgmt_registrations); + + if (rdev->ops->mgmt_frame_register) + rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + frame_type, true); + + out: + spin_unlock_bh(&wdev->mgmt_registrations_lock); + + return err; +} + +void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_mgmt_registration *reg, *tmp; + + spin_lock_bh(&wdev->mgmt_registrations_lock); + + list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { + if (reg->nlpid != nlpid) + continue; + + if (rdev->ops->mgmt_frame_register) { + u16 frame_type = le16_to_cpu(reg->frame_type); + + rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + frame_type, false); + } + + list_del(®->list); + kfree(reg); + } + + spin_unlock_bh(&wdev->mgmt_registrations_lock); + + if (nlpid == wdev->ap_unexpected_nlpid) + wdev->ap_unexpected_nlpid = 0; +} + +void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) +{ + struct cfg80211_mgmt_registration *reg, *tmp; + + spin_lock_bh(&wdev->mgmt_registrations_lock); + + list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { + list_del(®->list); + kfree(reg); + } + + spin_unlock_bh(&wdev->mgmt_registrations_lock); +} + +int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + const struct ieee80211_mgmt *mgmt; + u16 stype; + + if (!wdev->wiphy->mgmt_stypes) + return -EOPNOTSUPP; + + if (!rdev->ops->mgmt_tx) + return -EOPNOTSUPP; + + if (len < 24 + 1) + return -EINVAL; + + mgmt = (const struct ieee80211_mgmt *) buf; + + if (!ieee80211_is_mgmt(mgmt->frame_control)) + return -EINVAL; + + stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; + if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4))) + return -EINVAL; + + if (ieee80211_is_action(mgmt->frame_control) && + mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { + int err = 0; + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (!wdev->current_bss) { + err = -ENOTCONN; + break; + } + + if (memcmp(wdev->current_bss->pub.bssid, + mgmt->bssid, ETH_ALEN)) { + err = -ENOTCONN; + break; + } + + /* + * check for IBSS DA must be done by driver as + * cfg80211 doesn't track the stations + */ + if (wdev->iftype == NL80211_IFTYPE_ADHOC) + break; + + /* for station, check that DA is the AP */ + if (memcmp(wdev->current_bss->pub.bssid, + mgmt->da, ETH_ALEN)) { + err = -ENOTCONN; + break; + } + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP_VLAN: + if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) + err = -EINVAL; + break; + case NL80211_IFTYPE_MESH_POINT: + if (memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN)) { + err = -EINVAL; + break; + } + /* + * check for mesh DA must be done by driver as + * cfg80211 doesn't track the stations + */ + break; + default: + err = -EOPNOTSUPP; + break; + } + wdev_unlock(wdev); + + if (err) + return err; + } + + if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) + return -EINVAL; + + /* Transmit the Action frame as requested by user space */ + return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan, + channel_type, channel_type_valid, + wait, buf, len, no_cck, dont_wait_for_ack, + cookie); +} + +bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, + size_t len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct cfg80211_mgmt_registration *reg; + const struct ieee80211_txrx_stypes *stypes = + &wiphy->mgmt_stypes[wdev->iftype]; + struct ieee80211_mgmt *mgmt = (void *)buf; + const u8 *data; + int data_len; + bool result = false; + __le16 ftype = mgmt->frame_control & + cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); + u16 stype; + + stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; + + if (!(stypes->rx & BIT(stype))) + return false; + + data = buf + ieee80211_hdrlen(mgmt->frame_control); + data_len = len - ieee80211_hdrlen(mgmt->frame_control); + + spin_lock_bh(&wdev->mgmt_registrations_lock); + + list_for_each_entry(reg, &wdev->mgmt_registrations, list) { + if (reg->frame_type != ftype) + continue; + + if (reg->match_len > data_len) + continue; + + if (memcmp(reg->match, data, reg->match_len)) + continue; + + /* found match! */ + + /* Indicate the received Action frame to user space */ + if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, + buf, len, gfp)) + continue; + + result = true; + break; + } + + spin_unlock_bh(&wdev->mgmt_registrations_lock); + + return result; +} +EXPORT_SYMBOL(cfg80211_rx_mgmt); + +void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, + const u8 *buf, size_t len, bool ack, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + /* Indicate TX status of the Action frame to user space */ + nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); +} +EXPORT_SYMBOL(cfg80211_mgmt_tx_status); + +void cfg80211_cqm_rssi_notify(struct net_device *dev, + enum nl80211_cqm_rssi_threshold_event rssi_event, + gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + /* Indicate roaming trigger event to user space */ + nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp); +} +EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); + +void cfg80211_cqm_pktloss_notify(struct net_device *dev, + const u8 *peer, u32 num_packets, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + /* Indicate roaming trigger event to user space */ + nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); +} +EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); + +void cfg80211_cqm_txe_notify(struct net_device *dev, + const u8 *peer, u32 num_packets, + u32 rate, u32 intvl, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets, + rate, intvl, gfp); +} +EXPORT_SYMBOL(cfg80211_cqm_txe_notify); + +void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); +} +EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); + +void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, + const u8 *bssid, bool preauth, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); +} +EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); + +void cfg80211_ch_switch_notify(struct net_device *dev, int freq, + enum nl80211_channel_type type) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_channel *chan; + + wdev_lock(wdev); + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO)) + goto out; + + chan = rdev_freq_to_chan(rdev, freq, type); + if (WARN_ON(!chan)) + goto out; + + wdev->channel = chan; + + nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); +out: + wdev_unlock(wdev); + return; +} +EXPORT_SYMBOL(cfg80211_ch_switch_notify); + +bool cfg80211_rx_spurious_frame(struct net_device *dev, + const u8 *addr, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO)) + return false; + + return nl80211_unexpected_frame(dev, addr, gfp); +} +EXPORT_SYMBOL(cfg80211_rx_spurious_frame); + +bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, + const u8 *addr, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO && + wdev->iftype != NL80211_IFTYPE_AP_VLAN)) + return false; + + return nl80211_unexpected_4addr_frame(dev, addr, gfp); +} +EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); diff --git a/net/wireless_ath/nl80211.c b/net/wireless_ath/nl80211.c new file mode 100644 index 00000000..5d93939d --- /dev/null +++ b/net/wireless_ath/nl80211.c @@ -0,0 +1,8154 @@ +/* + * This is the new netlink-based wireless configuration interface. + * + * Copyright 2006-2010 Johannes Berg + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "nl80211.h" +#include "reg.h" + +static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type); +static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, + struct genl_info *info, + struct cfg80211_crypto_settings *settings, + int cipher_limit); + +static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); +static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); + +/* the netlink family */ +static struct genl_family nl80211_fam = { + .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ + .name = "nl80211", /* have users key off the name instead */ + .hdrsize = 0, /* no private header */ + .version = 1, /* no particular meaning now */ + .maxattr = NL80211_ATTR_MAX, + .netnsok = true, + .pre_doit = nl80211_pre_doit, + .post_doit = nl80211_post_doit, +}; + +/* internal helper: get rdev and dev */ +static int get_rdev_dev_by_info_ifindex(struct genl_info *info, + struct cfg80211_registered_device **rdev, + struct net_device **dev) +{ + struct nlattr **attrs = info->attrs; + int ifindex; + + if (!attrs[NL80211_ATTR_IFINDEX]) + return -EINVAL; + + ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); + *dev = dev_get_by_index(genl_info_net(info), ifindex); + if (!*dev) + return -ENODEV; + + *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex); + if (IS_ERR(*rdev)) { + dev_put(*dev); + return PTR_ERR(*rdev); + } + + return 0; +} + +/* policy for the attributes */ +static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { + [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, + .len = 20-1 }, + [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, + [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, + + [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, + [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, + + [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, + + [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, + [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, + .len = WLAN_MAX_KEY_LEN }, + [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, + [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, + [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, + [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, + [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, + + [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, + [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, + [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, + [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, + [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, + [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, + [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, + [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_MESH_ID_LEN }, + [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, + + [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, + [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, + + [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, + [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, + [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, + [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, + [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, + + [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, + [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, + + [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN }, + + [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, + [NL80211_ATTR_IE] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, + [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, + + [NL80211_ATTR_SSID] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN }, + [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, + [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, + [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, + [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, + [NL80211_ATTR_STA_FLAGS2] = { + .len = sizeof(struct nl80211_sta_flag_update), + }, + [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 }, + [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG }, + [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, + [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, + [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, + [NL80211_ATTR_PID] = { .type = NLA_U32 }, + [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, + [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, + .len = WLAN_PMKID_LEN }, + [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, + [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, + [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, + [NL80211_ATTR_FRAME] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, + [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, + [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, + [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, + [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, + [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 }, + [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, + [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, + [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, + [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, + [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, + [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, + [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, + [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED }, + [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 }, + [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED }, + [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG }, + [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 }, + [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 }, + [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, + [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, + [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, + [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 }, + [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG }, + [NL80211_ATTR_HT_CAPABILITY_MASK] = { + .len = NL80211_HT_CAPABILITY_LEN + }, + [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, + [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, + [NL80211_ATTR_BTCOEX_DATA] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_STA_CAP_REQ] = { .type = NLA_U8 }, + [NL80211_ATTR_ACS] = { .type = NLA_U8 }, + [NL80211_ATTR_MAC_ACL] = { .type = NLA_U8 }, + [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, + [NL80211_ATTR_ACL_POLICY] = { .type = NLA_U8 }, +}; + +/* policy for the key attributes */ +static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { + [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, + [NL80211_KEY_IDX] = { .type = NLA_U8 }, + [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, + [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, + [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, + [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, + [NL80211_KEY_TYPE] = { .type = NLA_U32 }, + [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, +}; + +/* policy for the key default flags */ +static const struct nla_policy +nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = { + [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG }, + [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, +}; + +/* policy for WoWLAN attributes */ +static const struct nla_policy +nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { + [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, + [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, +}; + +/* policy for GTK rekey offload attributes */ +static const struct nla_policy +nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { + [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN }, + [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN }, + [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN }, +}; + +static const struct nla_policy +nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { + [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN }, + [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, +}; + +/* ifidx get helper */ +static int nl80211_get_ifidx(struct netlink_callback *cb) +{ + int res; + + res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, + nl80211_fam.attrbuf, nl80211_fam.maxattr, + nl80211_policy); + if (res) + return res; + + if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) + return -EINVAL; + + res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); + if (!res) + return -EINVAL; + return res; +} + +static int nl80211_prepare_netdev_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct cfg80211_registered_device **rdev, + struct net_device **dev) +{ + int ifidx = cb->args[0]; + int err; + + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; + + cb->args[0] = ifidx; + + rtnl_lock(); + + *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); + if (!*dev) { + err = -ENODEV; + goto out_rtnl; + } + + *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); + if (IS_ERR(*rdev)) { + err = PTR_ERR(*rdev); + goto out_rtnl; + } + + return 0; + out_rtnl: + rtnl_unlock(); + return err; +} + +static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) +{ + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); +} + +/* IE validation */ +static bool is_valid_ie_attr(const struct nlattr *attr) +{ + const u8 *pos; + int len; + + if (!attr) + return true; + + pos = nla_data(attr); + len = nla_len(attr); + + while (len) { + u8 elemlen; + + if (len < 2) + return false; + len -= 2; + + elemlen = pos[1]; + if (elemlen > len) + return false; + + len -= elemlen; + pos += 2 + elemlen; + } + + return true; +} + +/* message building helper */ +static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, + int flags, u8 cmd) +{ + /* since there is no private header just add the generic one */ + return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); +} + +static int nl80211_msg_put_channel(struct sk_buff *msg, + struct ieee80211_channel *chan) +{ + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, + chan->center_freq); + + if (chan->flags & IEEE80211_CHAN_DISABLED) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); + if (chan->flags & IEEE80211_CHAN_RADAR) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, + DBM_TO_MBM(chan->max_power)); + + return 0; + + nla_put_failure: + return -ENOBUFS; +} + +/* netlink command implementations */ + +struct key_parse { + struct key_params p; + int idx; + int type; + bool def, defmgmt; + bool def_uni, def_multi; +}; + +static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) +{ + struct nlattr *tb[NL80211_KEY_MAX + 1]; + int err = nla_parse_nested(tb, NL80211_KEY_MAX, key, + nl80211_key_policy); + if (err) + return err; + + k->def = !!tb[NL80211_KEY_DEFAULT]; + k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; + + if (k->def) { + k->def_uni = true; + k->def_multi = true; + } + if (k->defmgmt) + k->def_multi = true; + + if (tb[NL80211_KEY_IDX]) + k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); + + if (tb[NL80211_KEY_DATA]) { + k->p.key = nla_data(tb[NL80211_KEY_DATA]); + k->p.key_len = nla_len(tb[NL80211_KEY_DATA]); + } + + if (tb[NL80211_KEY_SEQ]) { + k->p.seq = nla_data(tb[NL80211_KEY_SEQ]); + k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]); + } + + if (tb[NL80211_KEY_CIPHER]) + k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); + + if (tb[NL80211_KEY_TYPE]) { + k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); + if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) + return -EINVAL; + } + + if (tb[NL80211_KEY_DEFAULT_TYPES]) { + struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; + int err = nla_parse_nested(kdt, + NUM_NL80211_KEY_DEFAULT_TYPES - 1, + tb[NL80211_KEY_DEFAULT_TYPES], + nl80211_key_default_policy); + if (err) + return err; + + k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST]; + k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; + } + + return 0; +} + +static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) +{ + if (info->attrs[NL80211_ATTR_KEY_DATA]) { + k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); + k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); + } + + if (info->attrs[NL80211_ATTR_KEY_SEQ]) { + k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); + k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); + } + + if (info->attrs[NL80211_ATTR_KEY_IDX]) + k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); + + if (info->attrs[NL80211_ATTR_KEY_CIPHER]) + k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); + + k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; + k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; + + if (k->def) { + k->def_uni = true; + k->def_multi = true; + } + if (k->defmgmt) + k->def_multi = true; + + if (info->attrs[NL80211_ATTR_KEY_TYPE]) { + k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); + if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) { + struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; + int err = nla_parse_nested( + kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1, + info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES], + nl80211_key_default_policy); + if (err) + return err; + + k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST]; + k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; + } + + return 0; +} + +static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) +{ + int err; + + memset(k, 0, sizeof(*k)); + k->idx = -1; + k->type = -1; + + if (info->attrs[NL80211_ATTR_KEY]) + err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); + else + err = nl80211_parse_key_old(info, k); + + if (err) + return err; + + if (k->def && k->defmgmt) + return -EINVAL; + + if (k->defmgmt) { + if (k->def_uni || !k->def_multi) + return -EINVAL; + } + + if (k->idx != -1) { + if (k->defmgmt) { + if (k->idx < 4 || k->idx > 5) + return -EINVAL; + } else if (k->def) { + if (k->idx < 0 || k->idx > 3) + return -EINVAL; + } else { + if (k->idx < 0 || k->idx > 5) + return -EINVAL; + } + } + + return 0; +} + +static struct cfg80211_cached_keys * +nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, + struct nlattr *keys) +{ + struct key_parse parse; + struct nlattr *key; + struct cfg80211_cached_keys *result; + int rem, err, def = 0; + + result = kzalloc(sizeof(*result), GFP_KERNEL); + if (!result) + return ERR_PTR(-ENOMEM); + + result->def = -1; + result->defmgmt = -1; + + nla_for_each_nested(key, keys, rem) { + memset(&parse, 0, sizeof(parse)); + parse.idx = -1; + + err = nl80211_parse_key_new(key, &parse); + if (err) + goto error; + err = -EINVAL; + if (!parse.p.key) + goto error; + if (parse.idx < 0 || parse.idx > 4) + goto error; + if (parse.def) { + if (def) + goto error; + def = 1; + result->def = parse.idx; + if (!parse.def_uni || !parse.def_multi) + goto error; + } else if (parse.defmgmt) + goto error; + err = cfg80211_validate_key_settings(rdev, &parse.p, + parse.idx, false, NULL); + if (err) + goto error; + result->params[parse.idx].cipher = parse.p.cipher; + result->params[parse.idx].key_len = parse.p.key_len; + result->params[parse.idx].key = result->data[parse.idx]; + memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len); + } + + return result; + error: + kfree(result); + return ERR_PTR(err); +} + +static int nl80211_key_allowed(struct wireless_dev *wdev) +{ + ASSERT_WDEV_LOCK(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + break; + case NL80211_IFTYPE_ADHOC: + if (!wdev->current_bss) + return -ENOLINK; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return -ENOLINK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) +{ + struct nlattr *nl_modes = nla_nest_start(msg, attr); + int i; + + if (!nl_modes) + goto nla_put_failure; + + i = 0; + while (ifmodes) { + if (ifmodes & 1) + NLA_PUT_FLAG(msg, i); + ifmodes >>= 1; + i++; + } + + nla_nest_end(msg, nl_modes); + return 0; + +nla_put_failure: + return -ENOBUFS; +} + +static int nl80211_put_iface_combinations(struct wiphy *wiphy, + struct sk_buff *msg) +{ + struct nlattr *nl_combis; + int i, j; + + nl_combis = nla_nest_start(msg, + NL80211_ATTR_INTERFACE_COMBINATIONS); + if (!nl_combis) + goto nla_put_failure; + + for (i = 0; i < wiphy->n_iface_combinations; i++) { + const struct ieee80211_iface_combination *c; + struct nlattr *nl_combi, *nl_limits; + + c = &wiphy->iface_combinations[i]; + + nl_combi = nla_nest_start(msg, i + 1); + if (!nl_combi) + goto nla_put_failure; + + nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS); + if (!nl_limits) + goto nla_put_failure; + + for (j = 0; j < c->n_limits; j++) { + struct nlattr *nl_limit; + + nl_limit = nla_nest_start(msg, j + 1); + if (!nl_limit) + goto nla_put_failure; + NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX, + c->limits[j].max); + if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, + c->limits[j].types)) + goto nla_put_failure; + nla_nest_end(msg, nl_limit); + } + + nla_nest_end(msg, nl_limits); + + if (c->beacon_int_infra_match) + NLA_PUT_FLAG(msg, + NL80211_IFACE_COMB_STA_AP_BI_MATCH); + NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, + c->num_different_channels); + NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM, + c->max_interfaces); + + nla_nest_end(msg, nl_combi); + } + + nla_nest_end(msg, nl_combis); + + return 0; +nla_put_failure: + return -ENOBUFS; +} + +static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, + struct cfg80211_registered_device *dev) +{ + void *hdr; + struct nlattr *nl_bands, *nl_band; + struct nlattr *nl_freqs, *nl_freq; + struct nlattr *nl_rates, *nl_rate; + struct nlattr *nl_cmds; + enum ieee80211_band band; + struct ieee80211_channel *chan; + struct ieee80211_rate *rate; + int i; + const struct ieee80211_txrx_stypes *mgmt_stypes = + dev->wiphy.mgmt_stypes; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); + NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, + cfg80211_rdev_list_generation); + + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, + dev->wiphy.retry_short); + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, + dev->wiphy.retry_long); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + dev->wiphy.frag_threshold); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, + dev->wiphy.rts_threshold); + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, + dev->wiphy.coverage_class); + NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, + dev->wiphy.max_scan_ssids); + NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, + dev->wiphy.max_sched_scan_ssids); + NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, + dev->wiphy.max_scan_ie_len); + NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, + dev->wiphy.max_sched_scan_ie_len); + NLA_PUT_U8(msg, NL80211_ATTR_MAX_MATCH_SETS, + dev->wiphy.max_match_sets); + + if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) + NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); + if (dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) + NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); + if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) + NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD); + if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) + NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT); + if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) + NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_SUPPORT); + if (dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) + NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP); + + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, + sizeof(u32) * dev->wiphy.n_cipher_suites, + dev->wiphy.cipher_suites); + + NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, + dev->wiphy.max_num_pmkids); + + if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, + dev->wiphy.available_antennas_tx); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, + dev->wiphy.available_antennas_rx); + + if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) + NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, + dev->wiphy.probe_resp_offload); + + if ((dev->wiphy.available_antennas_tx || + dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { + u32 tx_ant = 0, rx_ant = 0; + int res; + res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant); + if (!res) { + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant); + } + } + + if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, + dev->wiphy.interface_modes)) + goto nla_put_failure; + + nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); + if (!nl_bands) + goto nla_put_failure; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!dev->wiphy.bands[band]) + continue; + + nl_band = nla_nest_start(msg, band); + if (!nl_band) + goto nla_put_failure; + + /* add HT info */ + if (dev->wiphy.bands[band]->ht_cap.ht_supported) { + NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET, + sizeof(dev->wiphy.bands[band]->ht_cap.mcs), + &dev->wiphy.bands[band]->ht_cap.mcs); + NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA, + dev->wiphy.bands[band]->ht_cap.cap); + NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, + dev->wiphy.bands[band]->ht_cap.ampdu_factor); + NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, + dev->wiphy.bands[band]->ht_cap.ampdu_density); + } + + /* add frequencies */ + nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); + if (!nl_freqs) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { + nl_freq = nla_nest_start(msg, i); + if (!nl_freq) + goto nla_put_failure; + + chan = &dev->wiphy.bands[band]->channels[i]; + + if (nl80211_msg_put_channel(msg, chan)) + goto nla_put_failure; + + nla_nest_end(msg, nl_freq); + } + + nla_nest_end(msg, nl_freqs); + + /* add bitrates */ + nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); + if (!nl_rates) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { + nl_rate = nla_nest_start(msg, i); + if (!nl_rate) + goto nla_put_failure; + + rate = &dev->wiphy.bands[band]->bitrates[i]; + NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, + rate->bitrate); + if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); + + nla_nest_end(msg, nl_rate); + } + + nla_nest_end(msg, nl_rates); + + nla_nest_end(msg, nl_band); + } + nla_nest_end(msg, nl_bands); + + nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); + if (!nl_cmds) + goto nla_put_failure; + + i = 0; +#define CMD(op, n) \ + do { \ + if (dev->ops->op) { \ + i++; \ + NLA_PUT_U32(msg, i, NL80211_CMD_ ## n); \ + } \ + } while (0) + + CMD(add_virtual_intf, NEW_INTERFACE); + CMD(change_virtual_intf, SET_INTERFACE); + CMD(add_key, NEW_KEY); + CMD(add_beacon, NEW_BEACON); + CMD(add_station, NEW_STATION); + CMD(add_mpath, NEW_MPATH); + CMD(update_mesh_config, SET_MESH_CONFIG); + CMD(change_bss, SET_BSS); + CMD(auth, AUTHENTICATE); + CMD(assoc, ASSOCIATE); + CMD(deauth, DEAUTHENTICATE); + CMD(disassoc, DISASSOCIATE); + CMD(join_ibss, JOIN_IBSS); + CMD(join_mesh, JOIN_MESH); + CMD(set_pmksa, SET_PMKSA); + CMD(del_pmksa, DEL_PMKSA); + CMD(flush_pmksa, FLUSH_PMKSA); + CMD(remain_on_channel, REMAIN_ON_CHANNEL); + CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); + CMD(mgmt_tx, FRAME); + CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); + if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); + } + CMD(set_channel, SET_CHANNEL); + CMD(set_wds_peer, SET_WDS_PEER); + if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { + CMD(tdls_mgmt, TDLS_MGMT); + CMD(tdls_oper, TDLS_OPER); + } + if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) + CMD(sched_scan_start, START_SCHED_SCAN); + CMD(probe_client, PROBE_CLIENT); + if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS); + } + +#undef CMD + + if (dev->ops->connect || dev->ops->auth) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT); + } + + if (dev->ops->disconnect || dev->ops->deauth) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT); + } + + nla_nest_end(msg, nl_cmds); + + if (dev->ops->remain_on_channel) + NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, + dev->wiphy.max_remain_on_channel_duration); + + if (dev->ops->mgmt_tx_cancel_wait) + NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + + if (mgmt_stypes) { + u16 stypes; + struct nlattr *nl_ftypes, *nl_ifs; + enum nl80211_iftype ift; + + nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); + if (!nl_ifs) + goto nla_put_failure; + + for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { + nl_ftypes = nla_nest_start(msg, ift); + if (!nl_ftypes) + goto nla_put_failure; + i = 0; + stypes = mgmt_stypes[ift].tx; + while (stypes) { + if (stypes & 1) + NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, + (i << 4) | IEEE80211_FTYPE_MGMT); + stypes >>= 1; + i++; + } + nla_nest_end(msg, nl_ftypes); + } + + nla_nest_end(msg, nl_ifs); + + nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); + if (!nl_ifs) + goto nla_put_failure; + + for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { + nl_ftypes = nla_nest_start(msg, ift); + if (!nl_ftypes) + goto nla_put_failure; + i = 0; + stypes = mgmt_stypes[ift].rx; + while (stypes) { + if (stypes & 1) + NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, + (i << 4) | IEEE80211_FTYPE_MGMT); + stypes >>= 1; + i++; + } + nla_nest_end(msg, nl_ftypes); + } + nla_nest_end(msg, nl_ifs); + } + + if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { + struct nlattr *nl_wowlan; + + nl_wowlan = nla_nest_start(msg, + NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); + if (!nl_wowlan) + goto nla_put_failure; + + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); + if (dev->wiphy.wowlan.n_patterns) { + struct nl80211_wowlan_pattern_support pat = { + .max_patterns = dev->wiphy.wowlan.n_patterns, + .min_pattern_len = + dev->wiphy.wowlan.pattern_min_len, + .max_pattern_len = + dev->wiphy.wowlan.pattern_max_len, + }; + NLA_PUT(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, + sizeof(pat), &pat); + } + + nla_nest_end(msg, nl_wowlan); + } + + if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, + dev->wiphy.software_iftypes)) + goto nla_put_failure; + + if (nl80211_put_iface_combinations(&dev->wiphy, msg)) + goto nla_put_failure; + + if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) + NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME, + dev->wiphy.ap_sme_capa); + + NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) +{ + int idx = 0; + int start = cb->args[0]; + struct cfg80211_registered_device *dev; + + mutex_lock(&cfg80211_mutex); + list_for_each_entry(dev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + continue; + if (++idx <= start) + continue; + if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + dev) < 0) { + idx--; + break; + } + } + mutex_unlock(&cfg80211_mutex); + + cb->args[0] = idx; + + return skb->len; +} + +static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct cfg80211_registered_device *dev = info->user_ptr[0]; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); +} + +static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { + [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, + [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, +}; + +static int parse_txq_params(struct nlattr *tb[], + struct ieee80211_txq_params *txq_params) +{ + if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || + !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || + !tb[NL80211_TXQ_ATTR_AIFS]) + return -EINVAL; + + txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); + txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); + txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); + txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); + txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); + + return 0; +} + +static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) +{ + /* + * You can only set the channel explicitly for AP, mesh + * and WDS type interfaces; all others have their channel + * managed via their respective "establish a connection" + * command (connect, join, ...) + * + * Monitors are special as they are normally slaved to + * whatever else is going on, so they behave as though + * you tried setting the wiphy channel itself. + */ + return !wdev || + wdev->iftype == NL80211_IFTYPE_AP || + wdev->iftype == NL80211_IFTYPE_WDS || + wdev->iftype == NL80211_IFTYPE_MESH_POINT || + wdev->iftype == NL80211_IFTYPE_MONITOR || + wdev->iftype == NL80211_IFTYPE_P2P_GO; +} + +static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct genl_info *info) +{ + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + u32 freq; + int result; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; + + if (!nl80211_can_set_dev_channel(wdev)) + return -EOPNOTSUPP; + + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + channel_type = nla_get_u32(info->attrs[ + NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (channel_type != NL80211_CHAN_NO_HT && + channel_type != NL80211_CHAN_HT20 && + channel_type != NL80211_CHAN_HT40PLUS && + channel_type != NL80211_CHAN_HT40MINUS) + return -EINVAL; + } + + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + + mutex_lock(&rdev->devlist_mtx); + if (wdev) { + wdev_lock(wdev); + result = cfg80211_set_freq(rdev, wdev, freq, channel_type); + wdev_unlock(wdev); + } else { + result = cfg80211_set_freq(rdev, NULL, freq, channel_type); + } + mutex_unlock(&rdev->devlist_mtx); + + return result; +} + +static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *netdev = info->user_ptr[1]; + + return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); +} + +static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + const u8 *bssid; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (netif_running(dev)) + return -EBUSY; + + if (!rdev->ops->set_wds_peer) + return -EOPNOTSUPP; + + if (wdev->iftype != NL80211_IFTYPE_WDS) + return -EOPNOTSUPP; + + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); +} + + +static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *netdev = NULL; + struct wireless_dev *wdev; + int result = 0, rem_txq_params = 0; + struct nlattr *nl_txq_params; + u32 changed; + u8 retry_short = 0, retry_long = 0; + u32 frag_threshold = 0, rts_threshold = 0; + u8 coverage_class = 0; + + /* + * Try to find the wiphy and netdev. Normally this + * function shouldn't need the netdev, but this is + * done for backward compatibility -- previously + * setting the channel was done per wiphy, but now + * it is per netdev. Previous userland like hostapd + * also passed a netdev to set_wiphy, so that it is + * possible to let that go to the right netdev! + */ + mutex_lock(&cfg80211_mutex); + + if (info->attrs[NL80211_ATTR_IFINDEX]) { + int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); + + netdev = dev_get_by_index(genl_info_net(info), ifindex); + if (netdev && netdev->ieee80211_ptr) { + rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); + mutex_lock(&rdev->mtx); + } else + netdev = NULL; + } + + if (!netdev) { + rdev = __cfg80211_rdev_from_info(info); + if (IS_ERR(rdev)) { + mutex_unlock(&cfg80211_mutex); + return PTR_ERR(rdev); + } + wdev = NULL; + netdev = NULL; + result = 0; + + mutex_lock(&rdev->mtx); + } else if (netif_running(netdev) && + nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) + wdev = netdev->ieee80211_ptr; + else + wdev = NULL; + + /* + * end workaround code, by now the rdev is available + * and locked, and wdev may or may not be NULL. + */ + + if (info->attrs[NL80211_ATTR_WIPHY_NAME]) + result = cfg80211_dev_rename( + rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); + + mutex_unlock(&cfg80211_mutex); + + if (result) + goto bad_res; + + if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { + struct ieee80211_txq_params txq_params; + struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; + + if (!rdev->ops->set_txq_params) { + result = -EOPNOTSUPP; + goto bad_res; + } + + if (!netdev) { + result = -EINVAL; + goto bad_res; + } + + if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { + result = -EINVAL; + goto bad_res; + } + + nla_for_each_nested(nl_txq_params, + info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], + rem_txq_params) { + nla_parse(tb, NL80211_TXQ_ATTR_MAX, + nla_data(nl_txq_params), + nla_len(nl_txq_params), + txq_params_policy); + result = parse_txq_params(tb, &txq_params); + if (result) + goto bad_res; + + result = rdev->ops->set_txq_params(&rdev->wiphy, + netdev, + &txq_params); + if (result) + goto bad_res; + } + } + + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { + result = __nl80211_set_channel(rdev, wdev, info); + if (result) + goto bad_res; + } + + if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { + enum nl80211_tx_power_setting type; + int idx, mbm = 0; + + if (!rdev->ops->set_tx_power) { + result = -EOPNOTSUPP; + goto bad_res; + } + + idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING; + type = nla_get_u32(info->attrs[idx]); + + if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] && + (type != NL80211_TX_POWER_AUTOMATIC)) { + result = -EINVAL; + goto bad_res; + } + + if (type != NL80211_TX_POWER_AUTOMATIC) { + idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL; + mbm = nla_get_u32(info->attrs[idx]); + } + + result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); + if (result) + goto bad_res; + } + + if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && + info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { + u32 tx_ant, rx_ant; + if ((!rdev->wiphy.available_antennas_tx && + !rdev->wiphy.available_antennas_rx) || + !rdev->ops->set_antenna) { + result = -EOPNOTSUPP; + goto bad_res; + } + + tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]); + rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]); + + /* reject antenna configurations which don't match the + * available antenna masks, except for the "all" mask */ + if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) || + (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) { + result = -EINVAL; + goto bad_res; + } + + tx_ant = tx_ant & rdev->wiphy.available_antennas_tx; + rx_ant = rx_ant & rdev->wiphy.available_antennas_rx; + + result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); + if (result) + goto bad_res; + } + + changed = 0; + + if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { + retry_short = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); + if (retry_short == 0) { + result = -EINVAL; + goto bad_res; + } + changed |= WIPHY_PARAM_RETRY_SHORT; + } + + if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { + retry_long = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); + if (retry_long == 0) { + result = -EINVAL; + goto bad_res; + } + changed |= WIPHY_PARAM_RETRY_LONG; + } + + if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { + frag_threshold = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); + if (frag_threshold < 256) { + result = -EINVAL; + goto bad_res; + } + if (frag_threshold != (u32) -1) { + /* + * Fragments (apart from the last one) are required to + * have even length. Make the fragmentation code + * simpler by stripping LSB should someone try to use + * odd threshold value. + */ + frag_threshold &= ~0x1; + } + changed |= WIPHY_PARAM_FRAG_THRESHOLD; + } + + if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { + rts_threshold = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); + changed |= WIPHY_PARAM_RTS_THRESHOLD; + } + + if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { + coverage_class = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); + changed |= WIPHY_PARAM_COVERAGE_CLASS; + } + + if (changed) { + u8 old_retry_short, old_retry_long; + u32 old_frag_threshold, old_rts_threshold; + u8 old_coverage_class; + + if (!rdev->ops->set_wiphy_params) { + result = -EOPNOTSUPP; + goto bad_res; + } + + old_retry_short = rdev->wiphy.retry_short; + old_retry_long = rdev->wiphy.retry_long; + old_frag_threshold = rdev->wiphy.frag_threshold; + old_rts_threshold = rdev->wiphy.rts_threshold; + old_coverage_class = rdev->wiphy.coverage_class; + + if (changed & WIPHY_PARAM_RETRY_SHORT) + rdev->wiphy.retry_short = retry_short; + if (changed & WIPHY_PARAM_RETRY_LONG) + rdev->wiphy.retry_long = retry_long; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + rdev->wiphy.frag_threshold = frag_threshold; + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + rdev->wiphy.rts_threshold = rts_threshold; + if (changed & WIPHY_PARAM_COVERAGE_CLASS) + rdev->wiphy.coverage_class = coverage_class; + + result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); + if (result) { + rdev->wiphy.retry_short = old_retry_short; + rdev->wiphy.retry_long = old_retry_long; + rdev->wiphy.frag_threshold = old_frag_threshold; + rdev->wiphy.rts_threshold = old_rts_threshold; + rdev->wiphy.coverage_class = old_coverage_class; + } + } + + bad_res: + mutex_unlock(&rdev->mtx); + if (netdev) + dev_put(netdev); + return result; +} + + +static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, + struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + void *hdr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); + + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, + rdev->devlist_generation ^ + (cfg80211_rdev_list_generation << 2)); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) +{ + int wp_idx = 0; + int if_idx = 0; + int wp_start = cb->args[0]; + int if_start = cb->args[1]; + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + + mutex_lock(&cfg80211_mutex); + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) + continue; + if (wp_idx < wp_start) { + wp_idx++; + continue; + } + if_idx = 0; + + mutex_lock(&rdev->devlist_mtx); + list_for_each_entry(wdev, &rdev->netdev_list, list) { + if (if_idx < if_start) { + if_idx++; + continue; + } + if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + rdev, wdev->netdev) < 0) { + mutex_unlock(&rdev->devlist_mtx); + goto out; + } + if_idx++; + } + mutex_unlock(&rdev->devlist_mtx); + + wp_idx++; + } + out: + mutex_unlock(&cfg80211_mutex); + + cb->args[0] = wp_idx; + cb->args[1] = if_idx; + + return skb->len; +} + +static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct cfg80211_registered_device *dev = info->user_ptr[0]; + struct net_device *netdev = info->user_ptr[1]; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, + dev, netdev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); +} + +static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { + [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, +}; + +static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) +{ + struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; + int flag; + + *mntrflags = 0; + + if (!nla) + return -EINVAL; + + if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, + nla, mntr_flags_policy)) + return -EINVAL; + + for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) + if (flags[flag]) + *mntrflags |= (1<wiphy.flags & WIPHY_FLAG_4ADDR_AP) + return 0; + break; + case NL80211_IFTYPE_STATION: + if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION) + return 0; + break; + default: + break; + } + + return -EOPNOTSUPP; +} + +static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct vif_params params; + int err; + enum nl80211_iftype otype, ntype; + struct net_device *dev = info->user_ptr[1]; + u32 _flags, *flags = NULL; + bool change = false; + + memset(¶ms, 0, sizeof(params)); + + otype = ntype = dev->ieee80211_ptr->iftype; + + if (info->attrs[NL80211_ATTR_IFTYPE]) { + ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); + if (otype != ntype) + change = true; + if (ntype > NL80211_IFTYPE_MAX) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_MESH_ID]) { + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (ntype != NL80211_IFTYPE_MESH_POINT) + return -EINVAL; + if (netif_running(dev)) + return -EBUSY; + + wdev_lock(wdev); + BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != + IEEE80211_MAX_MESH_ID_LEN); + wdev->mesh_id_up_len = + nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), + wdev->mesh_id_up_len); + wdev_unlock(wdev); + } + + if (info->attrs[NL80211_ATTR_4ADDR]) { + params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); + change = true; + err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); + if (err) + return err; + } else { + params.use_4addr = -1; + } + + if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { + if (ntype != NL80211_IFTYPE_MONITOR) + return -EINVAL; + err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], + &_flags); + if (err) + return err; + + flags = &_flags; + change = true; + } + + if (change) + err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); + else + err = 0; + + if (!err && params.use_4addr != -1) + dev->ieee80211_ptr->use_4addr = params.use_4addr; + + return err; +} + +static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct vif_params params; + struct net_device *dev; + int err; + enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; + u32 flags; + + memset(¶ms, 0, sizeof(params)); + + if (!info->attrs[NL80211_ATTR_IFNAME]) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_IFTYPE]) { + type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); + if (type > NL80211_IFTYPE_MAX) + return -EINVAL; + } + + if (!rdev->ops->add_virtual_intf || + !(rdev->wiphy.interface_modes & (1 << type))) + return -EOPNOTSUPP; + + if (info->attrs[NL80211_ATTR_4ADDR]) { + params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); + err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); + if (err) + return err; + } + + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); + dev = rdev->ops->add_virtual_intf(&rdev->wiphy, + nla_data(info->attrs[NL80211_ATTR_IFNAME]), + type, err ? NULL : &flags, ¶ms); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + if (type == NL80211_IFTYPE_MESH_POINT && + info->attrs[NL80211_ATTR_MESH_ID]) { + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wdev_lock(wdev); + BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != + IEEE80211_MAX_MESH_ID_LEN); + wdev->mesh_id_up_len = + nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), + wdev->mesh_id_up_len); + wdev_unlock(wdev); + } + + return 0; +} + +static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + + if (!rdev->ops->del_virtual_intf) + return -EOPNOTSUPP; + + return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); +} + +struct get_key_cookie { + struct sk_buff *msg; + int error; + int idx; +}; + +static void get_key_callback(void *c, struct key_params *params) +{ + struct nlattr *key; + struct get_key_cookie *cookie = c; + + if (params->key) + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA, + params->key_len, params->key); + + if (params->seq) + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ, + params->seq_len, params->seq); + + if (params->cipher) + NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, + params->cipher); + + key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY); + if (!key) + goto nla_put_failure; + + if (params->key) + NLA_PUT(cookie->msg, NL80211_KEY_DATA, + params->key_len, params->key); + + if (params->seq) + NLA_PUT(cookie->msg, NL80211_KEY_SEQ, + params->seq_len, params->seq); + + if (params->cipher) + NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER, + params->cipher); + + NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx); + + nla_nest_end(cookie->msg, key); + + return; + nla_put_failure: + cookie->error = 1; +} + +static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + struct net_device *dev = info->user_ptr[1]; + u8 key_idx = 0; + const u8 *mac_addr = NULL; + bool pairwise; + struct get_key_cookie cookie = { + .error = 0, + }; + void *hdr; + struct sk_buff *msg; + + if (info->attrs[NL80211_ATTR_KEY_IDX]) + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); + + if (key_idx > 5) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_MAC]) + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + pairwise = !!mac_addr; + if (info->attrs[NL80211_ATTR_KEY_TYPE]) { + u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); + if (kt >= NUM_NL80211_KEYTYPES) + return -EINVAL; + if (kt != NL80211_KEYTYPE_GROUP && + kt != NL80211_KEYTYPE_PAIRWISE) + return -EINVAL; + pairwise = kt == NL80211_KEYTYPE_PAIRWISE; + } + + if (!rdev->ops->get_key) + return -EOPNOTSUPP; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_NEW_KEY); + if (IS_ERR(hdr)) + return PTR_ERR(hdr); + + cookie.msg = msg; + cookie.idx = key_idx; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); + if (mac_addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + + if (pairwise && mac_addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + return -ENOENT; + + err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, + mac_addr, &cookie, get_key_callback); + + if (err) + goto free_msg; + + if (cookie.error) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + + nla_put_failure: + err = -ENOBUFS; + free_msg: + nlmsg_free(msg); + return err; +} + +static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct key_parse key; + int err; + struct net_device *dev = info->user_ptr[1]; + + err = nl80211_parse_key(info, &key); + if (err) + return err; + + if (key.idx < 0) + return -EINVAL; + + /* only support setting default key */ + if (!key.def && !key.defmgmt) + return -EINVAL; + + wdev_lock(dev->ieee80211_ptr); + + if (key.def) { + if (!rdev->ops->set_default_key) { + err = -EOPNOTSUPP; + goto out; + } + + err = nl80211_key_allowed(dev->ieee80211_ptr); + if (err) + goto out; + + err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, + key.def_uni, key.def_multi); + + if (err) + goto out; + +#ifdef CONFIG_CFG80211_WEXT + dev->ieee80211_ptr->wext.default_key = key.idx; +#endif + } else { + if (key.def_uni || !key.def_multi) { + err = -EINVAL; + goto out; + } + + if (!rdev->ops->set_default_mgmt_key) { + err = -EOPNOTSUPP; + goto out; + } + + err = nl80211_key_allowed(dev->ieee80211_ptr); + if (err) + goto out; + + err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, + dev, key.idx); + if (err) + goto out; + +#ifdef CONFIG_CFG80211_WEXT + dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; +#endif + } + + out: + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + +static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + struct net_device *dev = info->user_ptr[1]; + struct key_parse key; + const u8 *mac_addr = NULL; + + err = nl80211_parse_key(info, &key); + if (err) + return err; + + if (!key.p.key) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_MAC]) + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (key.type == -1) { + if (mac_addr) + key.type = NL80211_KEYTYPE_PAIRWISE; + else + key.type = NL80211_KEYTYPE_GROUP; + } + + /* for now */ + if (key.type != NL80211_KEYTYPE_PAIRWISE && + key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; + + if (!rdev->ops->add_key) + return -EOPNOTSUPP; + + if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr)) + return -EINVAL; + + wdev_lock(dev->ieee80211_ptr); + err = nl80211_key_allowed(dev->ieee80211_ptr); + if (!err) + err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr, &key.p); + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + +static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + struct net_device *dev = info->user_ptr[1]; + u8 *mac_addr = NULL; + struct key_parse key; + + err = nl80211_parse_key(info, &key); + if (err) + return err; + + if (info->attrs[NL80211_ATTR_MAC]) + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (key.type == -1) { + if (mac_addr) + key.type = NL80211_KEYTYPE_PAIRWISE; + else + key.type = NL80211_KEYTYPE_GROUP; + } + + /* for now */ + if (key.type != NL80211_KEYTYPE_PAIRWISE && + key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; + + if (!rdev->ops->del_key) + return -EOPNOTSUPP; + + wdev_lock(dev->ieee80211_ptr); + err = nl80211_key_allowed(dev->ieee80211_ptr); + + if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + err = -ENOENT; + + if (!err) + err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr); + +#ifdef CONFIG_CFG80211_WEXT + if (!err) { + if (key.idx == dev->ieee80211_ptr->wext.default_key) + dev->ieee80211_ptr->wext.default_key = -1; + else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key) + dev->ieee80211_ptr->wext.default_mgmt_key = -1; + } +#endif + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + +static int validate_acl_mac_addrs(struct nlattr *nl_attr) +{ + struct nlattr *attr; + int n_entries = 0, tmp; + u8 mac_addr[ETH_ALEN]; + + nla_for_each_nested(attr, nl_attr, tmp) { + if (nla_len(attr) != ETH_ALEN) + return -1; + + memcpy(mac_addr, nla_data(attr), ETH_ALEN); + if (is_multicast_ether_addr(mac_addr)) + return -1; + + n_entries++; + } + + return n_entries; +} + +static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_acl_params *params; + struct nlattr *attr; + int n_mac_addrs = 0, i = 0, tmp, err; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (!(rdev->wiphy.features & NL80211_FEATURE_MAC_ACL)) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_ACL_POLICY] || + !info->attrs[NL80211_ATTR_MAC_ADDRS]) + return -EINVAL; + + n_mac_addrs = validate_acl_mac_addrs( + info->attrs[NL80211_ATTR_MAC_ADDRS]); + if (n_mac_addrs < 0) + return -EINVAL; + + if (n_mac_addrs > rdev->wiphy.max_acl_mac_addrs) + return -EOPNOTSUPP; + + params = kzalloc(sizeof(*params) + + (sizeof(*params->mac_addrs) * n_mac_addrs), + GFP_KERNEL); + + if (!params) + return -ENOMEM; + + params->acl_policy = nla_get_u8(info->attrs[NL80211_ATTR_ACL_POLICY]); + if (params->acl_policy != NL80211_ACL_POLICY_ACCEPT && + params->acl_policy != NL80211_ACL_POLICY_DENY) { + err = -EINVAL; + goto out_free; + } + + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) { + memcpy(¶ms->mac_addrs[i].addr, nla_data(attr), ETH_ALEN); + i++; + } + + params->n_acl_entries = n_mac_addrs; + + if (!rdev->ops->set_mac_acl) { + err = -EOPNOTSUPP; + goto out_free; + } + + err = rdev->ops->set_mac_acl(&rdev->wiphy, dev, params); + +out_free: + kfree(params); + + return err; +} + +static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) +{ + int (*call)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct beacon_parameters params; + int haveinfo = 0, err; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) || + !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) || + !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) || + !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP])) + return -EINVAL; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + memset(¶ms, 0, sizeof(params)); + + switch (info->genlhdr->cmd) { + case NL80211_CMD_NEW_BEACON: + /* these are required for NEW_BEACON */ + if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || + !info->attrs[NL80211_ATTR_DTIM_PERIOD] || + !info->attrs[NL80211_ATTR_BEACON_HEAD]) + return -EINVAL; + + params.interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + params.dtim_period = + nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); + + err = cfg80211_validate_beacon_int(rdev, params.interval); + if (err) + return err; + + /* + * In theory, some of these attributes could be required for + * NEW_BEACON, but since they were not used when the command was + * originally added, keep them optional for old user space + * programs to work with drivers that do not need the additional + * information. + */ + if (info->attrs[NL80211_ATTR_SSID]) { + params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + params.ssid_len = + nla_len(info->attrs[NL80211_ATTR_SSID]); + if (params.ssid_len == 0 || + params.ssid_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) { + params.hidden_ssid = nla_get_u32( + info->attrs[NL80211_ATTR_HIDDEN_SSID]); + if (params.hidden_ssid != + NL80211_HIDDEN_SSID_NOT_IN_USE && + params.hidden_ssid != + NL80211_HIDDEN_SSID_ZERO_LEN && + params.hidden_ssid != + NL80211_HIDDEN_SSID_ZERO_CONTENTS) + return -EINVAL; + } + + params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; + + if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { + params.auth_type = nla_get_u32( + info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(params.auth_type)) + return -EINVAL; + } else + params.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + + err = nl80211_crypto_settings(rdev, info, ¶ms.crypto, + NL80211_MAX_NR_CIPHER_SUITES); + if (err) + return err; + + if (info->attrs[NL80211_ATTR_STA_CAP_REQ]) { + params.sta_cap_req = nla_get_u8( + info->attrs[NL80211_ATTR_STA_CAP_REQ]); + if (params.sta_cap_req != NL80211_STA_CAP_REQ_11BONLY && + params.sta_cap_req != NL80211_STA_CAP_REQ_11GONLY) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_ACS]) { + if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_ACS) + params.auto_channel_select = nla_get_u8( + info->attrs[NL80211_ATTR_ACS]); + else + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_MAC_ACL]) { + if (!(rdev->wiphy.features & NL80211_FEATURE_MAC_ACL)) + return -EOPNOTSUPP; + params.acl_mac = + !!nla_get_u8(info->attrs[NL80211_ATTR_MAC_ACL]); + } + + call = rdev->ops->add_beacon; + break; + case NL80211_CMD_SET_BEACON: + call = rdev->ops->set_beacon; + break; + default: + WARN_ON(1); + return -EOPNOTSUPP; + } + + if (!call) + return -EOPNOTSUPP; + + if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { + params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); + params.head_len = + nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); + haveinfo = 1; + } + + if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { + params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); + params.tail_len = + nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); + haveinfo = 1; + } + + if (!haveinfo) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_IE]) { + params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); + params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) { + params.proberesp_ies = + nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); + params.proberesp_ies_len = + nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); + } + + if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) { + params.assocresp_ies = + nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); + params.assocresp_ies_len = + nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); + } + + if (info->attrs[NL80211_ATTR_PROBE_RESP]) { + params.probe_resp = + nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); + params.probe_resp_len = + nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); + } + + err = call(&rdev->wiphy, dev, ¶ms); + if (!err && params.interval) + wdev->beacon_interval = params.interval; + return err; +} + +static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + if (!rdev->ops->del_beacon) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + err = rdev->ops->del_beacon(&rdev->wiphy, dev); + if (!err) + wdev->beacon_interval = 0; + return err; +} + +static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { + [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG }, +}; + +static int parse_station_flags(struct genl_info *info, + struct station_parameters *params) +{ + struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; + struct nlattr *nla; + int flag; + + /* + * Try parsing the new attribute first so userspace + * can specify both for older kernels. + */ + nla = info->attrs[NL80211_ATTR_STA_FLAGS2]; + if (nla) { + struct nl80211_sta_flag_update *sta_flags; + + sta_flags = nla_data(nla); + params->sta_flags_mask = sta_flags->mask; + params->sta_flags_set = sta_flags->set; + if ((params->sta_flags_mask | + params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) + return -EINVAL; + return 0; + } + + /* if present, parse the old attribute */ + + nla = info->attrs[NL80211_ATTR_STA_FLAGS]; + if (!nla) + return 0; + + if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, + nla, sta_flags_policy)) + return -EINVAL; + + params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1; + params->sta_flags_mask &= ~1; + + for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) + if (flags[flag]) + params->sta_flags_set |= (1<= 32 */ + bitrate = cfg80211_calculate_bitrate(info); + if (bitrate > 0) + NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); + + if (info->flags & RATE_INFO_FLAGS_MCS) + NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs); + if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); + if (info->flags & RATE_INFO_FLAGS_SHORT_GI) + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); + + nla_nest_end(msg, rate); + return true; + +nla_put_failure: + return false; +} + +static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, + int flags, struct net_device *dev, + const u8 *mac_addr, struct station_info *sinfo) +{ + void *hdr; + struct nlattr *sinfoattr, *bss_param; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); + + sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); + if (!sinfoattr) + goto nla_put_failure; + if (sinfo->filled & STATION_INFO_CONNECTED_TIME) + NLA_PUT_U32(msg, NL80211_STA_INFO_CONNECTED_TIME, + sinfo->connected_time); + if (sinfo->filled & STATION_INFO_INACTIVE_TIME) + NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, + sinfo->inactive_time); + if (sinfo->filled & STATION_INFO_RX_BYTES) + NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, + sinfo->rx_bytes); + if (sinfo->filled & STATION_INFO_TX_BYTES) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, + sinfo->tx_bytes); + if (sinfo->filled & STATION_INFO_LLID) + NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, + sinfo->llid); + if (sinfo->filled & STATION_INFO_PLID) + NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, + sinfo->plid); + if (sinfo->filled & STATION_INFO_PLINK_STATE) + NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, + sinfo->plink_state); + if (sinfo->filled & STATION_INFO_SIGNAL) + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, + sinfo->signal); + if (sinfo->filled & STATION_INFO_SIGNAL_AVG) + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG, + sinfo->signal_avg); + if (sinfo->filled & STATION_INFO_TX_BITRATE) { + if (!nl80211_put_sta_rate(msg, &sinfo->txrate, + NL80211_STA_INFO_TX_BITRATE)) + goto nla_put_failure; + } + if (sinfo->filled & STATION_INFO_RX_BITRATE) { + if (!nl80211_put_sta_rate(msg, &sinfo->rxrate, + NL80211_STA_INFO_RX_BITRATE)) + goto nla_put_failure; + } + if (sinfo->filled & STATION_INFO_RX_PACKETS) + NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS, + sinfo->rx_packets); + if (sinfo->filled & STATION_INFO_TX_PACKETS) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, + sinfo->tx_packets); + if (sinfo->filled & STATION_INFO_TX_RETRIES) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES, + sinfo->tx_retries); + if (sinfo->filled & STATION_INFO_TX_FAILED) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, + sinfo->tx_failed); + if (sinfo->filled & STATION_INFO_BSS_PARAM) { + bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); + if (!bss_param) + goto nla_put_failure; + + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) + NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_CTS_PROT); + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE); + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) + NLA_PUT_FLAG(msg, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME); + NLA_PUT_U8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD, + sinfo->bss_param.dtim_period); + NLA_PUT_U16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + sinfo->bss_param.beacon_interval); + + nla_nest_end(msg, bss_param); + } + if (sinfo->filled & STATION_INFO_STA_FLAGS) + NLA_PUT(msg, NL80211_STA_INFO_STA_FLAGS, + sizeof(struct nl80211_sta_flag_update), + &sinfo->sta_flags); + nla_nest_end(msg, sinfoattr); + + if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES) + NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, + sinfo->assoc_req_ies); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl80211_dump_station(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct station_info sinfo; + struct cfg80211_registered_device *dev; + struct net_device *netdev; + u8 mac_addr[ETH_ALEN]; + int sta_idx = cb->args[1]; + int err; + + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; + + if (!dev->ops->dump_station) { + err = -EOPNOTSUPP; + goto out_err; + } + + while (1) { + memset(&sinfo, 0, sizeof(sinfo)); + err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, + mac_addr, &sinfo); + if (err == -ENOENT) + break; + if (err) + goto out_err; + + if (nl80211_send_station(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + netdev, mac_addr, + &sinfo) < 0) + goto out; + + sta_idx++; + } + + + out: + cb->args[1] = sta_idx; + err = skb->len; + out_err: + nl80211_finish_netdev_dump(dev); + + return err; +} + +static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct station_info sinfo; + struct sk_buff *msg; + u8 *mac_addr = NULL; + int err; + + memset(&sinfo, 0, sizeof(sinfo)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (!rdev->ops->get_station) + return -EOPNOTSUPP; + + err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); + if (err) + return err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, + dev, mac_addr, &sinfo) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); +} + +/* + * Get vlan interface making sure it is running and on the right wiphy. + */ +static int get_vlan(struct genl_info *info, + struct cfg80211_registered_device *rdev, + struct net_device **vlan) +{ + struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; + *vlan = NULL; + + if (vlanattr) { + *vlan = dev_get_by_index(genl_info_net(info), + nla_get_u32(vlanattr)); + if (!*vlan) + return -ENODEV; + if (!(*vlan)->ieee80211_ptr) + return -EINVAL; + if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) + return -EINVAL; + if (!netif_running(*vlan)) + return -ENETDOWN; + } + return 0; +} + +static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + struct net_device *dev = info->user_ptr[1]; + struct station_parameters params; + u8 *mac_addr = NULL; + + memset(¶ms, 0, sizeof(params)); + + params.listen_interval = -1; + params.plink_state = -1; + + if (info->attrs[NL80211_ATTR_STA_AID]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { + params.supported_rates = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + params.supported_rates_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + } + + if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) + params.listen_interval = + nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); + + if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) + params.ht_capa = + nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); + + if (parse_station_flags(info, ¶ms)) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) + params.plink_action = + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); + + if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) + params.plink_state = + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); + + err = get_vlan(info, rdev, ¶ms.vlan); + if (err) + goto out; + + /* validate settings */ + err = 0; + + switch (dev->ieee80211_ptr->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + /* disallow mesh-specific things */ + if (params.plink_action) + err = -EINVAL; + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + /* disallow things sta doesn't support */ + if (params.plink_action) + err = -EINVAL; + if (params.vlan) + err = -EINVAL; + if (params.supported_rates && + !(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) + err = -EINVAL; + if (params.ht_capa) + err = -EINVAL; + if (params.listen_interval >= 0) + err = -EINVAL; + if (params.sta_flags_mask & + ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | + BIT(NL80211_STA_FLAG_TDLS_PEER))) + err = -EINVAL; + /* can't change the TDLS bit */ + if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && + (params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER))) + err = -EINVAL; + break; + case NL80211_IFTYPE_MESH_POINT: + /* disallow things mesh doesn't support */ + if (params.vlan) + err = -EINVAL; + if (params.ht_capa) + err = -EINVAL; + if (params.listen_interval >= 0) + err = -EINVAL; + if (params.sta_flags_mask & + ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | + BIT(NL80211_STA_FLAG_MFP) | + BIT(NL80211_STA_FLAG_AUTHORIZED))) + err = -EINVAL; + break; + default: + err = -EINVAL; + } + + if (err) + goto out; + + if (!rdev->ops->change_station) { + err = -EOPNOTSUPP; + goto out; + } + + err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, ¶ms); + + out: + if (params.vlan) + dev_put(params.vlan); + + return err; +} + +static struct nla_policy +nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { + [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, + [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, +}; + +static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + struct net_device *dev = info->user_ptr[1]; + struct station_parameters params; + u8 *mac_addr = NULL; + + memset(¶ms, 0, sizeof(params)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_STA_AID]) + return -EINVAL; + + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + params.supported_rates = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + params.supported_rates_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + params.listen_interval = + nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); + + params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + if (!params.aid || params.aid > IEEE80211_MAX_AID) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) + params.ht_capa = + nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); + + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) + params.plink_action = + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); + + if (parse_station_flags(info, ¶ms)) + return -EINVAL; + + /* parse WME attributes if sta is WME capable */ + if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && + (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) && + info->attrs[NL80211_ATTR_STA_WME]) { + struct nlattr *tb[NL80211_STA_WME_MAX + 1]; + struct nlattr *nla; + + nla = info->attrs[NL80211_ATTR_STA_WME]; + err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, + nl80211_sta_wme_policy); + if (err) + return err; + + if (tb[NL80211_STA_WME_UAPSD_QUEUES]) + params.uapsd_queues = + nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]); + if (params.uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) + return -EINVAL; + + if (tb[NL80211_STA_WME_MAX_SP]) + params.max_sp = + nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); + + if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) + return -EINVAL; + + params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; + } + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + /* + * Only managed stations can add TDLS peers, and only when the + * wiphy supports external TDLS setup. + */ + if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION && + !((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && + (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && + (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) + return -EINVAL; + + err = get_vlan(info, rdev, ¶ms.vlan); + if (err) + goto out; + + /* validate settings */ + err = 0; + + if (!rdev->ops->add_station) { + err = -EOPNOTSUPP; + goto out; + } + + err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); + + out: + if (params.vlan) + dev_put(params.vlan); + return err; +} + +static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u8 *mac_addr = NULL; + + if (info->attrs[NL80211_ATTR_MAC]) + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + + if (!rdev->ops->del_station) + return -EOPNOTSUPP; + + return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); +} + +static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, + int flags, struct net_device *dev, + u8 *dst, u8 *next_hop, + struct mpath_info *pinfo) +{ + void *hdr; + struct nlattr *pinfoattr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); + NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); + + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); + if (!pinfoattr) + goto nla_put_failure; + if (pinfo->filled & MPATH_INFO_FRAME_QLEN) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, + pinfo->frame_qlen); + if (pinfo->filled & MPATH_INFO_SN) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN, + pinfo->sn); + if (pinfo->filled & MPATH_INFO_METRIC) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, + pinfo->metric); + if (pinfo->filled & MPATH_INFO_EXPTIME) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, + pinfo->exptime); + if (pinfo->filled & MPATH_INFO_FLAGS) + NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, + pinfo->flags); + if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, + pinfo->discovery_timeout); + if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) + NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, + pinfo->discovery_retries); + + nla_nest_end(msg, pinfoattr); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl80211_dump_mpath(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct mpath_info pinfo; + struct cfg80211_registered_device *dev; + struct net_device *netdev; + u8 dst[ETH_ALEN]; + u8 next_hop[ETH_ALEN]; + int path_idx = cb->args[1]; + int err; + + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; + + if (!dev->ops->dump_mpath) { + err = -EOPNOTSUPP; + goto out_err; + } + + if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { + err = -EOPNOTSUPP; + goto out_err; + } + + while (1) { + err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, + dst, next_hop, &pinfo); + if (err == -ENOENT) + break; + if (err) + goto out_err; + + if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + netdev, dst, next_hop, + &pinfo) < 0) + goto out; + + path_idx++; + } + + + out: + cb->args[1] = path_idx; + err = skb->len; + out_err: + nl80211_finish_netdev_dump(dev); + return err; +} + +static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + struct net_device *dev = info->user_ptr[1]; + struct mpath_info pinfo; + struct sk_buff *msg; + u8 *dst = NULL; + u8 next_hop[ETH_ALEN]; + + memset(&pinfo, 0, sizeof(pinfo)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (!rdev->ops->get_mpath) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); + if (err) + return err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, + dev, dst, next_hop, &pinfo) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); +} + +static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u8 *dst = NULL; + u8 *next_hop = NULL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); + + if (!rdev->ops->change_mpath) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); +} + +static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u8 *dst = NULL; + u8 *next_hop = NULL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); + + if (!rdev->ops->add_mpath) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); +} + +static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u8 *dst = NULL; + + if (info->attrs[NL80211_ATTR_MAC]) + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (!rdev->ops->del_mpath) + return -EOPNOTSUPP; + + return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); +} + +static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct bss_parameters params; + + memset(¶ms, 0, sizeof(params)); + /* default to not changing parameters */ + params.use_cts_prot = -1; + params.use_short_preamble = -1; + params.use_short_slot_time = -1; + params.ap_isolate = -1; + params.ht_opmode = -1; + + if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) + params.use_cts_prot = + nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]); + if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]) + params.use_short_preamble = + nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]); + if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) + params.use_short_slot_time = + nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); + if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { + params.basic_rates = + nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + params.basic_rates_len = + nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + } + if (info->attrs[NL80211_ATTR_AP_ISOLATE]) + params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); + if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE]) + params.ht_opmode = + nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]); + + if (!rdev->ops->change_bss) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); +} + +static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { + [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, + [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, + [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, + [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, + [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, + [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, +}; + +static int parse_reg_rule(struct nlattr *tb[], + struct ieee80211_reg_rule *reg_rule) +{ + struct ieee80211_freq_range *freq_range = ®_rule->freq_range; + struct ieee80211_power_rule *power_rule = ®_rule->power_rule; + + if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) + return -EINVAL; + if (!tb[NL80211_ATTR_FREQ_RANGE_START]) + return -EINVAL; + if (!tb[NL80211_ATTR_FREQ_RANGE_END]) + return -EINVAL; + if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) + return -EINVAL; + if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) + return -EINVAL; + + reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); + + freq_range->start_freq_khz = + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); + freq_range->end_freq_khz = + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); + freq_range->max_bandwidth_khz = + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); + + power_rule->max_eirp = + nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); + + if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) + power_rule->max_antenna_gain = + nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); + + return 0; +} + +static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) +{ + int r; + char *data = NULL; + + /* + * You should only get this when cfg80211 hasn't yet initialized + * completely when built-in to the kernel right between the time + * window between nl80211_init() and regulatory_init(), if that is + * even possible. + */ + mutex_lock(&cfg80211_mutex); + if (unlikely(!cfg80211_regdomain)) { + mutex_unlock(&cfg80211_mutex); + return -EINPROGRESS; + } + mutex_unlock(&cfg80211_mutex); + + if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) + return -EINVAL; + + data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); + + r = regulatory_hint_user(data); + + return r; +} + +static int nl80211_get_mesh_config(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct mesh_config cur_params; + int err = 0; + void *hdr; + struct nlattr *pinfoattr; + struct sk_buff *msg; + + if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + if (!rdev->ops->get_mesh_config) + return -EOPNOTSUPP; + + wdev_lock(wdev); + /* If not connected, get default parameters */ + if (!wdev->mesh_id_len) + memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); + else + err = rdev->ops->get_mesh_config(&rdev->wiphy, dev, + &cur_params); + wdev_unlock(wdev); + + if (err) + return err; + + /* Draw up a netlink message to send back */ + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_GET_MESH_CONFIG); + if (!hdr) + goto out; + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG); + if (!pinfoattr) + goto nla_put_failure; + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT, + cur_params.dot11MeshRetryTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT, + cur_params.dot11MeshConfirmTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT, + cur_params.dot11MeshHoldingTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, + cur_params.dot11MeshMaxPeerLinks); + NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES, + cur_params.dot11MeshMaxRetries); + NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, + cur_params.dot11MeshTTL); + NLA_PUT_U8(msg, NL80211_MESHCONF_ELEMENT_TTL, + cur_params.element_ttl); + NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, + cur_params.auto_open_plinks); + NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + cur_params.dot11MeshHWMPmaxPREQretries); + NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME, + cur_params.path_refresh_time); + NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + cur_params.min_discovery_timeout); + NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + cur_params.dot11MeshHWMPactivePathTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + cur_params.dot11MeshHWMPpreqMinInterval); + NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + cur_params.dot11MeshHWMPnetDiameterTraversalTime); + NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, + cur_params.dot11MeshHWMPRootMode); + NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL, + cur_params.dot11MeshHWMPRannInterval); + NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, + cur_params.dot11MeshGateAnnouncementProtocol); + nla_nest_end(msg, pinfoattr); + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + out: + nlmsg_free(msg); + return -ENOBUFS; +} + +static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { + [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, + [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, + [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, + [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, + [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, + + [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, + [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, + [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 }, + [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 }, + [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, + [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, +}; + +static const struct nla_policy + nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { + [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, + [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, + [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, + [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, +}; + +static int nl80211_parse_mesh_config(struct genl_info *info, + struct mesh_config *cfg, + u32 *mask_out) +{ + struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; + u32 mask = 0; + +#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ +do {\ + if (table[attr_num]) {\ + cfg->param = nla_fn(table[attr_num]); \ + mask |= (1 << (attr_num - 1)); \ + } \ +} while (0);\ + + + if (!info->attrs[NL80211_ATTR_MESH_CONFIG]) + return -EINVAL; + if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, + info->attrs[NL80211_ATTR_MESH_CONFIG], + nl80211_meshconf_params_policy)) + return -EINVAL; + + /* This makes sure that there aren't more than 32 mesh config + * parameters (otherwise our bitfield scheme would not work.) */ + BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); + + /* Fill in the params struct */ + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, + mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, + mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, + mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, + mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, + mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, + mask, NL80211_MESHCONF_TTL, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, + mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, + mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, + mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, + mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, + mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, + mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, + mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, + dot11MeshHWMPnetDiameterTraversalTime, + mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, + dot11MeshHWMPRootMode, mask, + NL80211_MESHCONF_HWMP_ROOTMODE, + nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, + dot11MeshHWMPRannInterval, mask, + NL80211_MESHCONF_HWMP_RANN_INTERVAL, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, + dot11MeshGateAnnouncementProtocol, mask, + NL80211_MESHCONF_GATE_ANNOUNCEMENTS, + nla_get_u8); + if (mask_out) + *mask_out = mask; + + return 0; + +#undef FILL_IN_MESH_PARAM_IF_SET +} + +static int nl80211_parse_mesh_setup(struct genl_info *info, + struct mesh_setup *setup) +{ + struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; + + if (!info->attrs[NL80211_ATTR_MESH_SETUP]) + return -EINVAL; + if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX, + info->attrs[NL80211_ATTR_MESH_SETUP], + nl80211_mesh_setup_params_policy)) + return -EINVAL; + + if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL]) + setup->path_sel_proto = + (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ? + IEEE80211_PATH_PROTOCOL_VENDOR : + IEEE80211_PATH_PROTOCOL_HWMP; + + if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC]) + setup->path_metric = + (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ? + IEEE80211_PATH_METRIC_VENDOR : + IEEE80211_PATH_METRIC_AIRTIME; + + + if (tb[NL80211_MESH_SETUP_IE]) { + struct nlattr *ieattr = + tb[NL80211_MESH_SETUP_IE]; + if (!is_valid_ie_attr(ieattr)) + return -EINVAL; + setup->ie = nla_data(ieattr); + setup->ie_len = nla_len(ieattr); + } + setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); + setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); + + return 0; +} + +static int nl80211_update_mesh_config(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct mesh_config cfg; + u32 mask; + int err; + + if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + + if (!rdev->ops->update_mesh_config) + return -EOPNOTSUPP; + + err = nl80211_parse_mesh_config(info, &cfg, &mask); + if (err) + return err; + + wdev_lock(wdev); + if (!wdev->mesh_id_len) + err = -ENOLINK; + + if (!err) + err = rdev->ops->update_mesh_config(&rdev->wiphy, dev, + mask, &cfg); + + wdev_unlock(wdev); + + return err; +} + +static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *hdr = NULL; + struct nlattr *nl_reg_rules; + unsigned int i; + int err = -EINVAL; + + mutex_lock(&cfg80211_mutex); + + if (!cfg80211_regdomain) + goto out; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + err = -ENOBUFS; + goto out; + } + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_GET_REG); + if (!hdr) + goto put_failure; + + NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, + cfg80211_regdomain->alpha2); + + nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); + if (!nl_reg_rules) + goto nla_put_failure; + + for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { + struct nlattr *nl_reg_rule; + const struct ieee80211_reg_rule *reg_rule; + const struct ieee80211_freq_range *freq_range; + const struct ieee80211_power_rule *power_rule; + + reg_rule = &cfg80211_regdomain->reg_rules[i]; + freq_range = ®_rule->freq_range; + power_rule = ®_rule->power_rule; + + nl_reg_rule = nla_nest_start(msg, i); + if (!nl_reg_rule) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_ATTR_REG_RULE_FLAGS, + reg_rule->flags); + NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_START, + freq_range->start_freq_khz); + NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_END, + freq_range->end_freq_khz); + NLA_PUT_U32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, + freq_range->max_bandwidth_khz); + NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, + power_rule->max_antenna_gain); + NLA_PUT_U32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, + power_rule->max_eirp); + + nla_nest_end(msg, nl_reg_rule); + } + + nla_nest_end(msg, nl_reg_rules); + + genlmsg_end(msg, hdr); + err = genlmsg_reply(msg, info); + goto out; + +nla_put_failure: + genlmsg_cancel(msg, hdr); +put_failure: + nlmsg_free(msg); + err = -EMSGSIZE; +out: + mutex_unlock(&cfg80211_mutex); + return err; +} + +static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; + struct nlattr *nl_reg_rule; + char *alpha2 = NULL; + int rem_reg_rules = 0, r = 0; + u32 num_rules = 0, rule_idx = 0, size_of_regd; + struct ieee80211_regdomain *rd = NULL; + + if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_REG_RULES]) + return -EINVAL; + + alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); + + nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], + rem_reg_rules) { + num_rules++; + if (num_rules > NL80211_MAX_SUPP_REG_RULES) + return -EINVAL; + } + + mutex_lock(&cfg80211_mutex); + + if (!reg_is_valid_request(alpha2)) { + r = -EINVAL; + goto bad_reg; + } + + size_of_regd = sizeof(struct ieee80211_regdomain) + + (num_rules * sizeof(struct ieee80211_reg_rule)); + + rd = kzalloc(size_of_regd, GFP_KERNEL); + if (!rd) { + r = -ENOMEM; + goto bad_reg; + } + + rd->n_reg_rules = num_rules; + rd->alpha2[0] = alpha2[0]; + rd->alpha2[1] = alpha2[1]; + + nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], + rem_reg_rules) { + nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, + nla_data(nl_reg_rule), nla_len(nl_reg_rule), + reg_rule_policy); + r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); + if (r) + goto bad_reg; + + rule_idx++; + + if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { + r = -EINVAL; + goto bad_reg; + } + } + + BUG_ON(rule_idx != num_rules); + + r = set_regdom(rd); + + mutex_unlock(&cfg80211_mutex); + + return r; + + bad_reg: + mutex_unlock(&cfg80211_mutex); + kfree(rd); + return r; +} + +static int validate_scan_freqs(struct nlattr *freqs) +{ + struct nlattr *attr1, *attr2; + int n_channels = 0, tmp1, tmp2; + + nla_for_each_nested(attr1, freqs, tmp1) { + n_channels++; + /* + * Some hardware has a limited channel list for + * scanning, and it is pretty much nonsensical + * to scan for a channel twice, so disallow that + * and don't require drivers to check that the + * channel list they get isn't longer than what + * they can scan, as long as they can scan all + * the channels they registered at once. + */ + nla_for_each_nested(attr2, freqs, tmp2) + if (attr1 != attr2 && + nla_get_u32(attr1) == nla_get_u32(attr2)) + return 0; + } + + return n_channels; +} + +static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_scan_request *request; + struct nlattr *attr; + struct wiphy *wiphy; + int err, tmp, n_ssids = 0, n_channels, i; + size_t ie_len; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + wiphy = &rdev->wiphy; + + if (!rdev->ops->scan) + return -EOPNOTSUPP; + + if (rdev->scan_req) + return -EBUSY; + + if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { + n_channels = validate_scan_freqs( + info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); + if (!n_channels) + return -EINVAL; + } else { + enum ieee80211_band band; + n_channels = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } + + if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) + n_ssids++; + + if (n_ssids > wiphy->max_scan_ssids) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_IE]) + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + else + ie_len = 0; + + if (ie_len > wiphy->max_scan_ie_len) + return -EINVAL; + + request = kzalloc(sizeof(*request) + + sizeof(*request->ssids) * n_ssids + + sizeof(*request->channels) * n_channels + + ie_len, GFP_KERNEL); + if (!request) + return -ENOMEM; + + if (n_ssids) + request->ssids = (void *)&request->channels[n_channels]; + request->n_ssids = n_ssids; + if (ie_len) { + if (request->ssids) + request->ie = (void *)(request->ssids + n_ssids); + else + request->ie = (void *)(request->channels + n_channels); + } + + i = 0; + if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { + /* user specified, bail out if channel not found */ + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) { + struct ieee80211_channel *chan; + + chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); + + if (!chan) { + err = -EINVAL; + goto out_free; + } + + /* ignore disabled channels */ + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; + i++; + } + } else { + enum ieee80211_band band; + + /* all channels */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + int j; + if (!wiphy->bands[band]) + continue; + for (j = 0; j < wiphy->bands[band]->n_channels; j++) { + struct ieee80211_channel *chan; + + chan = &wiphy->bands[band]->channels[j]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; + i++; + } + } + } + + if (!i) { + err = -EINVAL; + goto out_free; + } + + request->n_channels = i; + + i = 0; + if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { + if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { + err = -EINVAL; + goto out_free; + } + request->ssids[i].ssid_len = nla_len(attr); + memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr)); + i++; + } + } + + if (info->attrs[NL80211_ATTR_IE]) { + request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + memcpy((void *)request->ie, + nla_data(info->attrs[NL80211_ATTR_IE]), + request->ie_len); + } + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + if (wiphy->bands[i]) + request->rates[i] = + (1 << wiphy->bands[i]->n_bitrates) - 1; + + if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) { + nla_for_each_nested(attr, + info->attrs[NL80211_ATTR_SCAN_SUPP_RATES], + tmp) { + enum ieee80211_band band = nla_type(attr); + + if (band < 0 || band >= IEEE80211_NUM_BANDS) { + err = -EINVAL; + goto out_free; + } + err = ieee80211_get_ratemask(wiphy->bands[band], + nla_data(attr), + nla_len(attr), + &request->rates[band]); + if (err) + goto out_free; + } + } + + request->no_cck = + nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); + + request->dev = dev; + request->wiphy = &rdev->wiphy; + + rdev->scan_req = request; + err = rdev->ops->scan(&rdev->wiphy, dev, request); + + if (!err) { + nl80211_send_scan_start(rdev, dev); + dev_hold(dev); + } else { + out_free: + rdev->scan_req = NULL; + kfree(request); + } + + return err; +} + +static int nl80211_start_sched_scan(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_sched_scan_request *request; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct nlattr *attr; + struct wiphy *wiphy; + int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i; + u32 interval; + enum ieee80211_band band; + size_t ie_len; + struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || + !rdev->ops->sched_scan_start) + return -EOPNOTSUPP; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) + return -EINVAL; + + interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); + if (interval == 0) + return -EINVAL; + + wiphy = &rdev->wiphy; + + if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { + n_channels = validate_scan_freqs( + info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); + if (!n_channels) + return -EINVAL; + } else { + n_channels = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } + + if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], + tmp) + n_ssids++; + + if (n_ssids > wiphy->max_sched_scan_ssids) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) + nla_for_each_nested(attr, + info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], + tmp) + n_match_sets++; + + if (n_match_sets > wiphy->max_match_sets) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_IE]) + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + else + ie_len = 0; + + if (ie_len > wiphy->max_sched_scan_ie_len) + return -EINVAL; + + mutex_lock(&rdev->sched_scan_mtx); + + if (rdev->sched_scan_req) { + err = -EINPROGRESS; + goto out; + } + + request = kzalloc(sizeof(*request) + + sizeof(*request->ssids) * n_ssids + + sizeof(*request->match_sets) * n_match_sets + + sizeof(*request->channels) * n_channels + + ie_len, GFP_KERNEL); + if (!request) { + err = -ENOMEM; + goto out; + } + + if (n_ssids) + request->ssids = (void *)&request->channels[n_channels]; + request->n_ssids = n_ssids; + if (ie_len) { + if (request->ssids) + request->ie = (void *)(request->ssids + n_ssids); + else + request->ie = (void *)(request->channels + n_channels); + } + + if (n_match_sets) { + if (request->ie) + request->match_sets = (void *)(request->ie + ie_len); + else if (request->ssids) + request->match_sets = + (void *)(request->ssids + n_ssids); + else + request->match_sets = + (void *)(request->channels + n_channels); + } + request->n_match_sets = n_match_sets; + + i = 0; + if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { + /* user specified, bail out if channel not found */ + nla_for_each_nested(attr, + info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], + tmp) { + struct ieee80211_channel *chan; + + chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); + + if (!chan) { + err = -EINVAL; + goto out_free; + } + + /* ignore disabled channels */ + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; + i++; + } + } else { + /* all channels */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + int j; + if (!wiphy->bands[band]) + continue; + for (j = 0; j < wiphy->bands[band]->n_channels; j++) { + struct ieee80211_channel *chan; + + chan = &wiphy->bands[band]->channels[j]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; + i++; + } + } + } + + if (!i) { + err = -EINVAL; + goto out_free; + } + + request->n_channels = i; + + i = 0; + if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], + tmp) { + if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) { + err = -EINVAL; + goto out_free; + } + request->ssids[i].ssid_len = nla_len(attr); + memcpy(request->ssids[i].ssid, nla_data(attr), + nla_len(attr)); + i++; + } + } + + i = 0; + if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { + nla_for_each_nested(attr, + info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], + tmp) { + struct nlattr *ssid, *rssi; + + nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, + nla_data(attr), nla_len(attr), + nl80211_match_policy); + ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; + if (ssid) { + if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { + err = -EINVAL; + goto out_free; + } + memcpy(request->match_sets[i].ssid.ssid, + nla_data(ssid), nla_len(ssid)); + request->match_sets[i].ssid.ssid_len = + nla_len(ssid); + } + rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; + if (rssi) + request->rssi_thold = nla_get_u32(rssi); + else + request->rssi_thold = + NL80211_SCAN_RSSI_THOLD_OFF; + i++; + } + } + + if (info->attrs[NL80211_ATTR_IE]) { + request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + memcpy((void *)request->ie, + nla_data(info->attrs[NL80211_ATTR_IE]), + request->ie_len); + } + + request->dev = dev; + request->wiphy = &rdev->wiphy; + request->interval = interval; + + err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); + if (!err) { + rdev->sched_scan_req = request; + nl80211_send_sched_scan(rdev, dev, + NL80211_CMD_START_SCHED_SCAN); + goto out; + } + +out_free: + kfree(request); +out: + mutex_unlock(&rdev->sched_scan_mtx); + return err; +} + +static int nl80211_stop_sched_scan(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || + !rdev->ops->sched_scan_stop) + return -EOPNOTSUPP; + + mutex_lock(&rdev->sched_scan_mtx); + err = __cfg80211_stop_sched_scan(rdev, false); + mutex_unlock(&rdev->sched_scan_mtx); + + return err; +} + +static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, + u32 seq, int flags, + struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_internal_bss *intbss) +{ + struct cfg80211_bss *res = &intbss->pub; + void *hdr; + struct nlattr *bss; + int i; + + ASSERT_WDEV_LOCK(wdev); + + hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).pid, seq, flags, + NL80211_CMD_NEW_SCAN_RESULTS); + if (!hdr) + return -1; + + genl_dump_check_consistent(cb, hdr, &nl80211_fam); + + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); + + bss = nla_nest_start(msg, NL80211_ATTR_BSS); + if (!bss) + goto nla_put_failure; + if (!is_zero_ether_addr(res->bssid)) + NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid); + if (res->information_elements && res->len_information_elements) + NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, + res->len_information_elements, + res->information_elements); + if (res->beacon_ies && res->len_beacon_ies && + res->beacon_ies != res->information_elements) + NLA_PUT(msg, NL80211_BSS_BEACON_IES, + res->len_beacon_ies, res->beacon_ies); + if (res->tsf) + NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); + if (res->beacon_interval) + NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval); + NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); + NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); + NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO, + jiffies_to_msecs(jiffies - intbss->ts)); + + switch (rdev->wiphy.signal_type) { + case CFG80211_SIGNAL_TYPE_MBM: + NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); + break; + case CFG80211_SIGNAL_TYPE_UNSPEC: + NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal); + break; + default: + break; + } + + switch (wdev->iftype) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + if (intbss == wdev->current_bss) + NLA_PUT_U32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_ASSOCIATED); + else for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (intbss != wdev->auth_bsses[i]) + continue; + NLA_PUT_U32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_AUTHENTICATED); + break; + } + break; + case NL80211_IFTYPE_ADHOC: + if (intbss == wdev->current_bss) + NLA_PUT_U32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_IBSS_JOINED); + break; + default: + break; + } + + nla_nest_end(msg, bss); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl80211_dump_scan(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + struct cfg80211_internal_bss *scan; + struct wireless_dev *wdev; + int start = cb->args[1], idx = 0; + int err; + + err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); + if (err) + return err; + + wdev = dev->ieee80211_ptr; + + wdev_lock(wdev); + spin_lock_bh(&rdev->bss_lock); + cfg80211_bss_expire(rdev); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) + cb->seq = rdev->bss_generation; +#endif + + list_for_each_entry(scan, &rdev->bss_list, list) { + if (++idx <= start) + continue; + if (nl80211_send_bss(skb, cb, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + rdev, wdev, scan) < 0) { + idx--; + break; + } + } + + spin_unlock_bh(&rdev->bss_lock); + wdev_unlock(wdev); + + cb->args[1] = idx; + nl80211_finish_netdev_dump(rdev); + + return skb->len; +} + +static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, + int flags, struct net_device *dev, + struct survey_info *survey) +{ + void *hdr; + struct nlattr *infoattr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, + NL80211_CMD_NEW_SURVEY_RESULTS); + if (!hdr) + return -ENOMEM; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + + infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); + if (!infoattr) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY, + survey->channel->center_freq); + if (survey->filled & SURVEY_INFO_NOISE_DBM) + NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, + survey->noise); + if (survey->filled & SURVEY_INFO_IN_USE) + NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME, + survey->channel_time); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + survey->channel_time_busy); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, + survey->channel_time_ext_busy); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX, + survey->channel_time_rx); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX, + survey->channel_time_tx); + + nla_nest_end(msg, infoattr); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl80211_dump_survey(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct survey_info survey; + struct cfg80211_registered_device *dev; + struct net_device *netdev; + int survey_idx = cb->args[1]; + int res; + + res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (res) + return res; + + if (!dev->ops->dump_survey) { + res = -EOPNOTSUPP; + goto out_err; + } + + while (1) { + struct ieee80211_channel *chan; + + res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, + &survey); + if (res == -ENOENT) + break; + if (res) + goto out_err; + + /* Survey without a channel doesn't make sense */ + if (!survey.channel) { + res = -EINVAL; + goto out; + } + + chan = ieee80211_get_channel(&dev->wiphy, + survey.channel->center_freq); + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { + survey_idx++; + continue; + } + + if (nl80211_send_survey(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + netdev, + &survey) < 0) + goto out; + survey_idx++; + } + + out: + cb->args[1] = survey_idx; + res = skb->len; + out_err: + nl80211_finish_netdev_dump(dev); + return res; +} + +static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) +{ + return auth_type <= NL80211_AUTHTYPE_MAX; +} + +static bool nl80211_valid_wpa_versions(u32 wpa_versions) +{ + return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | + NL80211_WPA_VERSION_2)); +} + +static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct ieee80211_channel *chan; + const u8 *bssid, *ssid, *ie = NULL; + int err, ssid_len, ie_len = 0; + enum nl80211_auth_type auth_type; + struct key_parse key; + bool local_state_change; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_SSID]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; + + err = nl80211_parse_key(info, &key); + if (err) + return err; + + if (key.idx >= 0) { + if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; + if (!key.p.key || !key.p.key_len) + return -EINVAL; + if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || + key.p.key_len != WLAN_KEY_LEN_WEP40) && + (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 || + key.p.key_len != WLAN_KEY_LEN_WEP104)) + return -EINVAL; + if (key.idx > 4) + return -EINVAL; + } else { + key.p.key_len = 0; + key.p.key = NULL; + } + + if (key.idx >= 0) { + int i; + bool ok = false; + for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) { + if (key.p.cipher == rdev->wiphy.cipher_suites[i]) { + ok = true; + break; + } + } + if (!ok) + return -EINVAL; + } + + if (!rdev->ops->auth) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + chan = ieee80211_get_channel(&rdev->wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; + + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + + if (info->attrs[NL80211_ATTR_IE]) { + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(auth_type)) + return -EINVAL; + + local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; + + return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, + ssid, ssid_len, ie, ie_len, + key.p.key, key.p.key_len, key.idx, + local_state_change); +} + +static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, + struct genl_info *info, + struct cfg80211_crypto_settings *settings, + int cipher_limit) +{ + memset(settings, 0, sizeof(*settings)); + + settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; + + if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) { + u16 proto; + proto = nla_get_u16( + info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + settings->control_port_ethertype = cpu_to_be16(proto); + if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && + proto != ETH_P_PAE) + return -EINVAL; + if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) + settings->control_port_no_encrypt = true; + } else + settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE); + + if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { + void *data; + int len, i; + + data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); + len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); + settings->n_ciphers_pairwise = len / sizeof(u32); + + if (len % sizeof(u32)) + return -EINVAL; + + if (settings->n_ciphers_pairwise > cipher_limit) + return -EINVAL; + + memcpy(settings->ciphers_pairwise, data, len); + + for (i = 0; i < settings->n_ciphers_pairwise; i++) + if (!cfg80211_supported_cipher_suite( + &rdev->wiphy, + settings->ciphers_pairwise[i])) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) { + settings->cipher_group = + nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]); + if (!cfg80211_supported_cipher_suite(&rdev->wiphy, + settings->cipher_group)) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) { + settings->wpa_versions = + nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]); + if (!nl80211_valid_wpa_versions(settings->wpa_versions)) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_AKM_SUITES]) { + void *data; + int len; + + data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]); + len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]); + settings->n_akm_suites = len / sizeof(u32); + + if (len % sizeof(u32)) + return -EINVAL; + + if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES) + return -EINVAL; + + memcpy(settings->akm_suites, data, len); + } + + return 0; +} + +static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_crypto_settings crypto; + struct ieee80211_channel *chan; + const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; + int err, ssid_len, ie_len = 0; + bool use_mfp = false; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_SSID] || + !info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; + + if (!rdev->ops->assoc) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + + chan = ieee80211_get_channel(&rdev->wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; + + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + + if (info->attrs[NL80211_ATTR_IE]) { + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + if (info->attrs[NL80211_ATTR_USE_MFP]) { + enum nl80211_mfp mfp = + nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); + if (mfp == NL80211_MFP_REQUIRED) + use_mfp = true; + else if (mfp != NL80211_MFP_NO) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_PREV_BSSID]) + prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); + + err = nl80211_crypto_settings(rdev, info, &crypto, 1); + if (!err) + err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, + ssid, ssid_len, ie, ie_len, use_mfp, + &crypto); + + return err; +} + +static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + const u8 *ie = NULL, *bssid; + int ie_len = 0; + u16 reason_code; + bool local_state_change; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + return -EINVAL; + + if (!rdev->ops->deauth) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + + reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (reason_code == 0) { + /* Reason Code 0 is reserved */ + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_IE]) { + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; + + return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); +} + +static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + const u8 *ie = NULL, *bssid; + int ie_len = 0; + u16 reason_code; + bool local_state_change; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + return -EINVAL; + + if (!rdev->ops->disassoc) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + + reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (reason_code == 0) { + /* Reason Code 0 is reserved */ + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_IE]) { + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; + + return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); +} + +static bool +nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev, + int mcast_rate[IEEE80211_NUM_BANDS], + int rateval) +{ + struct wiphy *wiphy = &rdev->wiphy; + bool found = false; + int band, i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + + sband = wiphy->bands[band]; + if (!sband) + continue; + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == rateval) { + mcast_rate[band] = i + 1; + found = true; + break; + } + } + } + + return found; +} + +static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_ibss_params ibss; + struct wiphy *wiphy; + struct cfg80211_cached_keys *connkeys = NULL; + int err; + + memset(&ibss, 0, sizeof(ibss)); + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || + !info->attrs[NL80211_ATTR_SSID] || + !nla_len(info->attrs[NL80211_ATTR_SSID])) + return -EINVAL; + + ibss.beacon_interval = 100; + + if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { + ibss.beacon_interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) + return -EINVAL; + } + + if (!rdev->ops->join_ibss) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; + + wiphy = &rdev->wiphy; + + if (info->attrs[NL80211_ATTR_MAC]) { + ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (!is_valid_ether_addr(ibss.bssid)) + return -EINVAL; + } + ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + + if (info->attrs[NL80211_ATTR_IE]) { + ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + ibss.channel = ieee80211_get_channel(wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!ibss.channel || + ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || + ibss.channel->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + + ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; + ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; + + if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { + u8 *rates = + nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + int n_rates = + nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + struct ieee80211_supported_band *sband = + wiphy->bands[ibss.channel->band]; + int err; + + err = ieee80211_get_ratemask(sband, rates, n_rates, + &ibss.basic_rates); + if (err) + return err; + } + + if (info->attrs[NL80211_ATTR_MCAST_RATE] && + !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate, + nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]))) + return -EINVAL; + + if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { + connkeys = nl80211_parse_connkeys(rdev, + info->attrs[NL80211_ATTR_KEYS]); + if (IS_ERR(connkeys)) + return PTR_ERR(connkeys); + } + + err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); + if (err) + kfree(connkeys); + return err; +} + +static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + + if (!rdev->ops->leave_ibss) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; + + return cfg80211_leave_ibss(rdev, dev, false); +} + +#ifdef CONFIG_NL80211_TESTMODE +static struct genl_multicast_group nl80211_testmode_mcgrp = { + .name = "testmode", +}; + +static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; + + if (!info->attrs[NL80211_ATTR_TESTDATA]) + return -EINVAL; + + err = -EOPNOTSUPP; + if (rdev->ops->testmode_cmd) { + rdev->testmode_info = info; + err = rdev->ops->testmode_cmd(&rdev->wiphy, + nla_data(info->attrs[NL80211_ATTR_TESTDATA]), + nla_len(info->attrs[NL80211_ATTR_TESTDATA])); + rdev->testmode_info = NULL; + } + + return err; +} + +static int nl80211_testmode_dump(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct cfg80211_registered_device *dev; + int err; + long phy_idx; + void *data = NULL; + int data_len = 0; + + if (cb->args[0]) { + /* + * 0 is a valid index, but not valid for args[0], + * so we need to offset by 1. + */ + phy_idx = cb->args[0] - 1; + } else { + err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, + nl80211_fam.attrbuf, nl80211_fam.maxattr, + nl80211_policy); + if (err) + return err; + if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) + return -EINVAL; + phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); + if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) + cb->args[1] = + (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; + } + + if (cb->args[1]) { + data = nla_data((void *)cb->args[1]); + data_len = nla_len((void *)cb->args[1]); + } + + mutex_lock(&cfg80211_mutex); + dev = cfg80211_rdev_by_wiphy_idx(phy_idx); + if (!dev) { + mutex_unlock(&cfg80211_mutex); + return -ENOENT; + } + cfg80211_lock_rdev(dev); + mutex_unlock(&cfg80211_mutex); + + if (!dev->ops->testmode_dump) { + err = -EOPNOTSUPP; + goto out_err; + } + + while (1) { + void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + NL80211_CMD_TESTMODE); + struct nlattr *tmdata; + + if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) { + genlmsg_cancel(skb, hdr); + break; + } + + tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA); + if (!tmdata) { + genlmsg_cancel(skb, hdr); + break; + } + err = dev->ops->testmode_dump(&dev->wiphy, skb, cb, + data, data_len); + nla_nest_end(skb, tmdata); + + if (err == -ENOBUFS || err == -ENOENT) { + genlmsg_cancel(skb, hdr); + break; + } else if (err) { + genlmsg_cancel(skb, hdr); + goto out_err; + } + + genlmsg_end(skb, hdr); + } + + err = skb->len; + /* see above */ + cb->args[0] = phy_idx + 1; + out_err: + cfg80211_unlock_rdev(dev); + return err; +} + +static struct sk_buff * +__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, + int approxlen, u32 pid, u32 seq, gfp_t gfp) +{ + struct sk_buff *skb; + void *hdr; + struct nlattr *data; + + skb = nlmsg_new(approxlen + 100, gfp); + if (!skb) + return NULL; + + hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE); + if (!hdr) { + kfree_skb(skb); + return NULL; + } + + NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + data = nla_nest_start(skb, NL80211_ATTR_TESTDATA); + + ((void **)skb->cb)[0] = rdev; + ((void **)skb->cb)[1] = hdr; + ((void **)skb->cb)[2] = data; + + return skb; + + nla_put_failure: + kfree_skb(skb); + return NULL; +} + +struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, + int approxlen) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + if (WARN_ON(!rdev->testmode_info)) + return NULL; + + return __cfg80211_testmode_alloc_skb(rdev, approxlen, + rdev->testmode_info->snd_pid, + rdev->testmode_info->snd_seq, + GFP_KERNEL); +} +EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb); + +int cfg80211_testmode_reply(struct sk_buff *skb) +{ + struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; + void *hdr = ((void **)skb->cb)[1]; + struct nlattr *data = ((void **)skb->cb)[2]; + + if (WARN_ON(!rdev->testmode_info)) { + kfree_skb(skb); + return -EINVAL; + } + + nla_nest_end(skb, data); + genlmsg_end(skb, hdr); + return genlmsg_reply(skb, rdev->testmode_info); +} +EXPORT_SYMBOL(cfg80211_testmode_reply); + +struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, + int approxlen, gfp_t gfp) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp); +} +EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); + +void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) +{ + void *hdr = ((void **)skb->cb)[1]; + struct nlattr *data = ((void **)skb->cb)[2]; + + nla_nest_end(skb, data); + genlmsg_end(skb, hdr); + genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp); +} +EXPORT_SYMBOL(cfg80211_testmode_event); +#endif + +static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_connect_params connect; + struct wiphy *wiphy; + struct cfg80211_cached_keys *connkeys = NULL; + int err; + + memset(&connect, 0, sizeof(connect)); + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_SSID] || + !nla_len(info->attrs[NL80211_ATTR_SSID])) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { + connect.auth_type = + nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(connect.auth_type)) + return -EINVAL; + } else + connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + + connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; + + err = nl80211_crypto_settings(rdev, info, &connect.crypto, + NL80211_MAX_NR_CIPHER_SUITES); + if (err) + return err; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + wiphy = &rdev->wiphy; + + connect.bg_scan_period = -1; + if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] && + (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) { + connect.bg_scan_period = + nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]); + } + + if (info->attrs[NL80211_ATTR_MAC]) + connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + + if (info->attrs[NL80211_ATTR_IE]) { + connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]); + connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { + connect.channel = + ieee80211_get_channel(wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!connect.channel || + connect.channel->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + } + + if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { + connkeys = nl80211_parse_connkeys(rdev, + info->attrs[NL80211_ATTR_KEYS]); + if (IS_ERR(connkeys)) + return PTR_ERR(connkeys); + } + + err = cfg80211_connect(rdev, dev, &connect, connkeys); + if (err) + kfree(connkeys); + return err; +} + +static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u16 reason; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + reason = WLAN_REASON_DEAUTH_LEAVING; + else + reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + + if (reason == 0) + return -EINVAL; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + return cfg80211_disconnect(rdev, dev, reason, true); +} + +static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net *net; + int err; + u32 pid; + + if (!info->attrs[NL80211_ATTR_PID]) + return -EINVAL; + + pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); + + net = get_net_ns_by_pid(pid); + if (IS_ERR(net)) + return PTR_ERR(net); + + err = 0; + + /* check if anything to do */ + if (!net_eq(wiphy_net(&rdev->wiphy), net)) + err = cfg80211_switch_netns(rdev, net); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + put_net(net); +#endif + return err; +} + +static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) = NULL; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_pmksa pmksa; + + memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_PMKID]) + return -EINVAL; + + pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); + pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + switch (info->genlhdr->cmd) { + case NL80211_CMD_SET_PMKSA: + rdev_ops = rdev->ops->set_pmksa; + break; + case NL80211_CMD_DEL_PMKSA: + rdev_ops = rdev->ops->del_pmksa; + break; + default: + WARN_ON(1); + break; + } + + if (!rdev_ops) + return -EOPNOTSUPP; + + return rdev_ops(&rdev->wiphy, dev, &pmksa); +} + +static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + if (!rdev->ops->flush_pmksa) + return -EOPNOTSUPP; + + return rdev->ops->flush_pmksa(&rdev->wiphy, dev); +} + +static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u8 action_code, dialog_token; + u16 status_code; + u8 *peer; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || + !rdev->ops->tdls_mgmt) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_TDLS_ACTION] || + !info->attrs[NL80211_ATTR_STATUS_CODE] || + !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] || + !info->attrs[NL80211_ATTR_IE] || + !info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + peer = nla_data(info->attrs[NL80211_ATTR_MAC]); + action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); + status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); + dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); + + return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, + dialog_token, status_code, + nla_data(info->attrs[NL80211_ATTR_IE]), + nla_len(info->attrs[NL80211_ATTR_IE])); +} + +static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + enum nl80211_tdls_operation operation; + u8 *peer; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || + !rdev->ops->tdls_oper) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] || + !info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]); + peer = nla_data(info->attrs[NL80211_ATTR_MAC]); + + return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation); +} + +static int nl80211_remain_on_channel(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct ieee80211_channel *chan; + struct sk_buff *msg; + void *hdr; + u64 cookie; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + u32 freq, duration; + int err; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || + !info->attrs[NL80211_ATTR_DURATION]) + return -EINVAL; + + duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); + + /* + * We should be on that channel for at least one jiffie, + * and more than 5 seconds seems excessive. + */ + if (!duration || !msecs_to_jiffies(duration) || + duration > rdev->wiphy.max_remain_on_channel_duration) + return -EINVAL; + + if (!rdev->ops->remain_on_channel) + return -EOPNOTSUPP; + + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + channel_type = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (channel_type != NL80211_CHAN_NO_HT && + channel_type != NL80211_CHAN_HT20 && + channel_type != NL80211_CHAN_HT40PLUS && + channel_type != NL80211_CHAN_HT40MINUS) + return -EINVAL; + } + + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + chan = rdev_freq_to_chan(rdev, freq, channel_type); + if (chan == NULL) + return -EINVAL; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_REMAIN_ON_CHANNEL); + + if (IS_ERR(hdr)) { + err = PTR_ERR(hdr); + goto free_msg; + } + + err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, + channel_type, duration, &cookie); + + if (err) + goto free_msg; + + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); + + nla_put_failure: + err = -ENOBUFS; + free_msg: + nlmsg_free(msg); + return err; +} + +static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u64 cookie; + + if (!info->attrs[NL80211_ATTR_COOKIE]) + return -EINVAL; + + if (!rdev->ops->cancel_remain_on_channel) + return -EOPNOTSUPP; + + cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); + + return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); +} + +static u32 rateset_to_mask(struct ieee80211_supported_band *sband, + u8 *rates, u8 rates_len) +{ + u8 i; + u32 mask = 0; + + for (i = 0; i < rates_len; i++) { + int rate = (rates[i] & 0x7f) * 5; + int ridx; + for (ridx = 0; ridx < sband->n_bitrates; ridx++) { + struct ieee80211_rate *srate = + &sband->bitrates[ridx]; + if (rate == srate->bitrate) { + mask |= 1 << ridx; + break; + } + } + if (ridx == sband->n_bitrates) + return 0; /* rate not found */ + } + + return mask; +} + +static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, + u8 *rates, u8 rates_len, + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]) +{ + u8 i; + + memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN); + + for (i = 0; i < rates_len; i++) { + int ridx, rbit; + + ridx = rates[i] / 8; + rbit = BIT(rates[i] % 8); + + /* check validity */ + if ((ridx < 0) || (ridx > IEEE80211_HT_MCS_MASK_LEN)) + return false; + + /* check availability */ + if (sband->ht_cap.mcs.rx_mask[ridx] & rbit) + mcs[ridx] |= rbit; + else + return false; + } + + return true; +} + +static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { + [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, + [NL80211_TXRATE_MCS] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_HT_RATES }, +}; + +static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, + struct genl_info *info) +{ + struct nlattr *tb[NL80211_TXRATE_MAX + 1]; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct cfg80211_bitrate_mask mask; + int rem, i; + struct net_device *dev = info->user_ptr[1]; + struct nlattr *tx_rates; + struct ieee80211_supported_band *sband; + + if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) + return -EINVAL; + + if (!rdev->ops->set_bitrate_mask) + return -EOPNOTSUPP; + + memset(&mask, 0, sizeof(mask)); + /* Default to all rates enabled */ + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + sband = rdev->wiphy.bands[i]; + mask.control[i].legacy = + sband ? (1 << sband->n_bitrates) - 1 : 0; + if (sband) + memcpy(mask.control[i].mcs, + sband->ht_cap.mcs.rx_mask, + sizeof(mask.control[i].mcs)); + else + memset(mask.control[i].mcs, 0, + sizeof(mask.control[i].mcs)); + } + + /* + * The nested attribute uses enum nl80211_band as the index. This maps + * directly to the enum ieee80211_band values used in cfg80211. + */ + BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); + nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) + { + enum ieee80211_band band = nla_type(tx_rates); + if (band < 0 || band >= IEEE80211_NUM_BANDS) + return -EINVAL; + sband = rdev->wiphy.bands[band]; + if (sband == NULL) + return -EINVAL; + nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), + nla_len(tx_rates), nl80211_txattr_policy); + if (tb[NL80211_TXRATE_LEGACY]) { + mask.control[band].legacy = rateset_to_mask( + sband, + nla_data(tb[NL80211_TXRATE_LEGACY]), + nla_len(tb[NL80211_TXRATE_LEGACY])); + } + if (tb[NL80211_TXRATE_MCS]) { + if (!ht_rateset_to_mask( + sband, + nla_data(tb[NL80211_TXRATE_MCS]), + nla_len(tb[NL80211_TXRATE_MCS]), + mask.control[band].mcs)) + return -EINVAL; + } + + if (mask.control[band].legacy == 0) { + /* don't allow empty legacy rates if HT + * is not even supported. */ + if (!rdev->wiphy.bands[band]->ht_cap.ht_supported) + return -EINVAL; + + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) + if (mask.control[band].mcs[i]) + break; + + /* legacy and mcs rates may not be both empty */ + if (i == IEEE80211_HT_MCS_MASK_LEN) + return -EINVAL; + } + } + + return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); +} + +static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; + + if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_FRAME_TYPE]) + frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + /* not much point in registering if we can't reply */ + if (!rdev->ops->mgmt_tx) + return -EOPNOTSUPP; + + return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, + frame_type, + nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), + nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); +} + +static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct ieee80211_channel *chan; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + bool channel_type_valid = false; + u32 freq; + int err; + void *hdr = NULL; + u64 cookie; + struct sk_buff *msg = NULL; + unsigned int wait = 0; + bool offchan, no_cck, dont_wait_for_ack; + + dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; + + if (!rdev->ops->mgmt_tx) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (info->attrs[NL80211_ATTR_DURATION]) { + if (!rdev->ops->mgmt_tx_cancel_wait) + return -EINVAL; + wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); + } + + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + channel_type = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (channel_type != NL80211_CHAN_NO_HT && + channel_type != NL80211_CHAN_HT20 && + channel_type != NL80211_CHAN_HT40PLUS && + channel_type != NL80211_CHAN_HT40MINUS) + return -EINVAL; + channel_type_valid = true; + } + + offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; + + no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); + + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + chan = rdev_freq_to_chan(rdev, freq, channel_type); + if (chan == NULL) + return -EINVAL; + + if (!dont_wait_for_ack) { + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_FRAME); + + if (IS_ERR(hdr)) { + err = PTR_ERR(hdr); + goto free_msg; + } + } + + err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, + channel_type_valid, wait, + nla_data(info->attrs[NL80211_ATTR_FRAME]), + nla_len(info->attrs[NL80211_ATTR_FRAME]), + no_cck, dont_wait_for_ack, &cookie); + if (err) + goto free_msg; + + if (msg) { + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + } + + return 0; + + nla_put_failure: + err = -ENOBUFS; + free_msg: + nlmsg_free(msg); + return err; +} + +static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + u64 cookie; + + if (!info->attrs[NL80211_ATTR_COOKIE]) + return -EINVAL; + + if (!rdev->ops->mgmt_tx_cancel_wait) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); + + return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); +} + +static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev; + struct net_device *dev = info->user_ptr[1]; + u8 ps_state; + bool state; + int err; + + if (!info->attrs[NL80211_ATTR_PS_STATE]) + return -EINVAL; + + ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); + + if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) + return -EINVAL; + + wdev = dev->ieee80211_ptr; + + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; + + state = (ps_state == NL80211_PS_ENABLED) ? true : false; + + if (state == wdev->ps) + return 0; + + err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, + wdev->ps_timeout); + if (!err) + wdev->ps = state; + return err; +} + +static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + enum nl80211_ps_state ps_state; + struct wireless_dev *wdev; + struct net_device *dev = info->user_ptr[1]; + struct sk_buff *msg; + void *hdr; + int err; + + wdev = dev->ieee80211_ptr; + + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_GET_POWER_SAVE); + if (!hdr) { + err = -ENOBUFS; + goto free_msg; + } + + if (wdev->ps) + ps_state = NL80211_PS_ENABLED; + else + ps_state = NL80211_PS_DISABLED; + + NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); + + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + + nla_put_failure: + err = -ENOBUFS; + free_msg: + nlmsg_free(msg); + return err; +} + +static struct nla_policy +nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { + [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 }, +}; + +static int nl80211_set_cqm_txe(struct genl_info *info, + u32 rate, u32 pkts, u32 intvl) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev; + struct net_device *dev = info->user_ptr[1]; + + if ((rate < 0 || rate > 100) || + (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) + return -EINVAL; + + wdev = dev->ieee80211_ptr; + + if (!rdev->ops->set_cqm_txe_config) + return -EOPNOTSUPP; + + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev, + rate, pkts, intvl); +} + +static int nl80211_set_cqm_rssi(struct genl_info *info, + s32 threshold, u32 hysteresis) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev; + struct net_device *dev = info->user_ptr[1]; + + if (threshold > 0) + return -EINVAL; + + wdev = dev->ieee80211_ptr; + + if (!rdev->ops->set_cqm_rssi_config) + return -EOPNOTSUPP; + + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, + threshold, hysteresis); +} + +static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1]; + struct nlattr *cqm; + int err; + + cqm = info->attrs[NL80211_ATTR_CQM]; + if (!cqm) { + err = -EINVAL; + goto out; + } + + err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm, + nl80211_attr_cqm_policy); + if (err) + goto out; + + if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] && + attrs[NL80211_ATTR_CQM_RSSI_HYST]) { + s32 threshold; + u32 hysteresis; + threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); + hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); + err = nl80211_set_cqm_rssi(info, threshold, hysteresis); + } else if (attrs[NL80211_ATTR_CQM_TXE_RATE] && + attrs[NL80211_ATTR_CQM_TXE_PKTS] && + attrs[NL80211_ATTR_CQM_TXE_INTVL]) { + u32 rate, pkts, intvl; + rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]); + pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]); + intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]); + err = nl80211_set_cqm_txe(info, rate, pkts, intvl); + } else + err = -EINVAL; + +out: + return err; +} + +static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct mesh_config cfg; + struct mesh_setup setup; + int err; + + /* start with default */ + memcpy(&cfg, &default_mesh_config, sizeof(cfg)); + memcpy(&setup, &default_mesh_setup, sizeof(setup)); + + if (info->attrs[NL80211_ATTR_MESH_CONFIG]) { + /* and parse parameters if given */ + err = nl80211_parse_mesh_config(info, &cfg, NULL); + if (err) + return err; + } + + if (!info->attrs[NL80211_ATTR_MESH_ID] || + !nla_len(info->attrs[NL80211_ATTR_MESH_ID])) + return -EINVAL; + + setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); + setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + + if (info->attrs[NL80211_ATTR_MESH_SETUP]) { + /* parse additional setup parameters if given */ + err = nl80211_parse_mesh_setup(info, &setup); + if (err) + return err; + } + + return cfg80211_join_mesh(rdev, dev, &setup, &cfg); +} + +static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + + return cfg80211_leave_mesh(rdev, dev); +} + +static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct sk_buff *msg; + void *hdr; + + if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) + return -EOPNOTSUPP; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_GET_WOWLAN); + if (!hdr) + goto nla_put_failure; + + if (rdev->wowlan) { + struct nlattr *nl_wowlan; + + nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); + if (!nl_wowlan) + goto nla_put_failure; + + if (rdev->wowlan->any) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); + if (rdev->wowlan->disconnect) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); + if (rdev->wowlan->magic_pkt) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); + if (rdev->wowlan->gtk_rekey_failure) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); + if (rdev->wowlan->eap_identity_req) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); + if (rdev->wowlan->four_way_handshake) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); + if (rdev->wowlan->rfkill_release) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); + if (rdev->wowlan->n_patterns) { + struct nlattr *nl_pats, *nl_pat; + int i, pat_len; + + nl_pats = nla_nest_start(msg, + NL80211_WOWLAN_TRIG_PKT_PATTERN); + if (!nl_pats) + goto nla_put_failure; + + for (i = 0; i < rdev->wowlan->n_patterns; i++) { + nl_pat = nla_nest_start(msg, i + 1); + if (!nl_pat) + goto nla_put_failure; + pat_len = rdev->wowlan->patterns[i].pattern_len; + NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_MASK, + DIV_ROUND_UP(pat_len, 8), + rdev->wowlan->patterns[i].mask); + NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_PATTERN, + pat_len, + rdev->wowlan->patterns[i].pattern); + nla_nest_end(msg, nl_pat); + } + nla_nest_end(msg, nl_pats); + } + + nla_nest_end(msg, nl_wowlan); + } + + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + +static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; + struct cfg80211_wowlan no_triggers = {}; + struct cfg80211_wowlan new_triggers = {}; + struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; + int err, i; + + if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) + goto no_triggers; + + err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, + nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + nl80211_wowlan_policy); + if (err) + return err; + + if (tb[NL80211_WOWLAN_TRIG_ANY]) { + if (!(wowlan->flags & WIPHY_WOWLAN_ANY)) + return -EINVAL; + new_triggers.any = true; + } + + if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) { + if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) + return -EINVAL; + new_triggers.disconnect = true; + } + + if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { + if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) + return -EINVAL; + new_triggers.magic_pkt = true; + } + + if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) + return -EINVAL; + + if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) { + if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) + return -EINVAL; + new_triggers.gtk_rekey_failure = true; + } + + if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { + if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) + return -EINVAL; + new_triggers.eap_identity_req = true; + } + + if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { + if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) + return -EINVAL; + new_triggers.four_way_handshake = true; + } + + if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { + if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) + return -EINVAL; + new_triggers.rfkill_release = true; + } + + if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { + struct nlattr *pat; + int n_patterns = 0; + int rem, pat_len, mask_len; + struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; + + nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], + rem) + n_patterns++; + if (n_patterns > wowlan->n_patterns) + return -EINVAL; + + new_triggers.patterns = kcalloc(n_patterns, + sizeof(new_triggers.patterns[0]), + GFP_KERNEL); + if (!new_triggers.patterns) + return -ENOMEM; + + new_triggers.n_patterns = n_patterns; + i = 0; + + nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], + rem) { + nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT, + nla_data(pat), nla_len(pat), NULL); + err = -EINVAL; + if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] || + !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]) + goto error; + pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]); + mask_len = DIV_ROUND_UP(pat_len, 8); + if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) != + mask_len) + goto error; + if (pat_len > wowlan->pattern_max_len || + pat_len < wowlan->pattern_min_len) + goto error; + + new_triggers.patterns[i].mask = + kmalloc(mask_len + pat_len, GFP_KERNEL); + if (!new_triggers.patterns[i].mask) { + err = -ENOMEM; + goto error; + } + new_triggers.patterns[i].pattern = + new_triggers.patterns[i].mask + mask_len; + memcpy(new_triggers.patterns[i].mask, + nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]), + mask_len); + new_triggers.patterns[i].pattern_len = pat_len; + memcpy(new_triggers.patterns[i].pattern, + nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]), + pat_len); + i++; + } + } + + if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { + struct cfg80211_wowlan *ntrig; + ntrig = kmemdup(&new_triggers, sizeof(new_triggers), + GFP_KERNEL); + if (!ntrig) { + err = -ENOMEM; + goto error; + } + cfg80211_rdev_free_wowlan(rdev); + rdev->wowlan = ntrig; + if (rdev->ops->set_wow_mode) + rdev->ops->set_wow_mode(&rdev->wiphy, ntrig); + } else { + no_triggers: + cfg80211_rdev_free_wowlan(rdev); + rdev->wowlan = NULL; + if (rdev->ops->clr_wow_mode) + rdev->ops->clr_wow_mode(&rdev->wiphy); + } + + return 0; + error: + for (i = 0; i < new_triggers.n_patterns; i++) + kfree(new_triggers.patterns[i].mask); + kfree(new_triggers.patterns); + return err; +} + +static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct nlattr *tb[NUM_NL80211_REKEY_DATA]; + struct cfg80211_gtk_rekey_data rekey_data; + int err; + + if (!info->attrs[NL80211_ATTR_REKEY_DATA]) + return -EINVAL; + + err = nla_parse(tb, MAX_NL80211_REKEY_DATA, + nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]), + nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]), + nl80211_rekey_policy); + if (err) + return err; + + if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN) + return -ERANGE; + if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN) + return -ERANGE; + if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN) + return -ERANGE; + + memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]), + NL80211_KEK_LEN); + memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]), + NL80211_KCK_LEN); + memcpy(rekey_data.replay_ctr, + nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]), + NL80211_REPLAY_CTR_LEN); + + wdev_lock(wdev); + if (!wdev->current_bss) { + err = -ENOTCONN; + goto out; + } + + if (!rdev->ops->set_rekey_data) { + err = -EOPNOTSUPP; + goto out; + } + + err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data); + out: + wdev_unlock(wdev); + return err; +} + +static int nl80211_register_unexpected_frame(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + + if (wdev->ap_unexpected_nlpid) + return -EBUSY; + + wdev->ap_unexpected_nlpid = info->snd_pid; + return 0; +} + +static int nl80211_probe_client(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct sk_buff *msg; + void *hdr; + const u8 *addr; + u64 cookie; + int err; + + if (wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!rdev->ops->probe_client) + return -EOPNOTSUPP; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_PROBE_CLIENT); + + if (IS_ERR(hdr)) { + err = PTR_ERR(hdr); + goto free_msg; + } + + addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie); + if (err) + goto free_msg; + + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); + + nla_put_failure: + err = -ENOBUFS; + free_msg: + nlmsg_free(msg); + return err; +} + +static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) + return -EOPNOTSUPP; + + if (rdev->ap_beacons_nlpid) + return -EBUSY; + + rdev->ap_beacons_nlpid = info->snd_pid; + + return 0; +} + +static int nl80211_btcoex_notify(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *dev = info->user_ptr[0]; + u8 *buf; + int len; + + if (!dev) + return -ENODEV; + + if (!info->attrs[NL80211_ATTR_BTCOEX_DATA]) + return -EINVAL; + + if (!dev->ops->notify_btcoex) + return -EOPNOTSUPP; + + buf = (char *)nla_data(info->attrs[NL80211_ATTR_BTCOEX_DATA]); + len = nla_len(info->attrs[NL80211_ATTR_BTCOEX_DATA]); + + return dev->ops->notify_btcoex(&dev->wiphy, buf, len); +} + +#define NL80211_FLAG_NEED_WIPHY 0x01 +#define NL80211_FLAG_NEED_NETDEV 0x02 +#define NL80211_FLAG_NEED_RTNL 0x04 +#define NL80211_FLAG_CHECK_NETDEV_UP 0x08 +#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ + NL80211_FLAG_CHECK_NETDEV_UP) + +static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + int err; + bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; + + if (rtnl) + rtnl_lock(); + + if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) { + if (rtnl) + rtnl_unlock(); + return PTR_ERR(rdev); + } + info->user_ptr[0] = rdev; + } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) { + if (rtnl) + rtnl_unlock(); + return err; + } + if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && + !netif_running(dev)) { + cfg80211_unlock_rdev(rdev); + dev_put(dev); + if (rtnl) + rtnl_unlock(); + return -ENETDOWN; + } + info->user_ptr[0] = rdev; + info->user_ptr[1] = dev; + } + + return 0; +} + +static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + if (info->user_ptr[0]) + cfg80211_unlock_rdev(info->user_ptr[0]); + if (info->user_ptr[1]) + dev_put(info->user_ptr[1]); + if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) + rtnl_unlock(); +} + +static struct genl_ops nl80211_ops[] = { + { + .cmd = NL80211_CMD_GET_WIPHY, + .doit = nl80211_get_wiphy, + .dumpit = nl80211_dump_wiphy, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_WIPHY, + }, + { + .cmd = NL80211_CMD_SET_WIPHY, + .doit = nl80211_set_wiphy, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_INTERFACE, + .doit = nl80211_get_interface, + .dumpit = nl80211_dump_interface, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV, + }, + { + .cmd = NL80211_CMD_SET_INTERFACE, + .doit = nl80211_set_interface, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_NEW_INTERFACE, + .doit = nl80211_new_interface, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEL_INTERFACE, + .doit = nl80211_del_interface, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_KEY, + .doit = nl80211_get_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_KEY, + .doit = nl80211_set_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_NEW_KEY, + .doit = nl80211_new_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEL_KEY, + .doit = nl80211_del_key, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_BEACON, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .doit = nl80211_addset_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_NEW_BEACON, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .doit = nl80211_addset_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEL_BEACON, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .doit = nl80211_del_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_STATION, + .doit = nl80211_get_station, + .dumpit = nl80211_dump_station, + .policy = nl80211_policy, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_STATION, + .doit = nl80211_set_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_NEW_STATION, + .doit = nl80211_new_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEL_STATION, + .doit = nl80211_del_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_MPATH, + .doit = nl80211_get_mpath, + .dumpit = nl80211_dump_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_MPATH, + .doit = nl80211_set_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_NEW_MPATH, + .doit = nl80211_new_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEL_MPATH, + .doit = nl80211_del_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_BSS, + .doit = nl80211_set_bss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_REG, + .doit = nl80211_get_reg, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + }, + { + .cmd = NL80211_CMD_SET_REG, + .doit = nl80211_set_reg, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_REQ_SET_REG, + .doit = nl80211_req_set_reg, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_GET_MESH_CONFIG, + .doit = nl80211_get_mesh_config, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_MESH_CONFIG, + .doit = nl80211_update_mesh_config, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_TRIGGER_SCAN, + .doit = nl80211_trigger_scan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_SCAN, + .policy = nl80211_policy, + .dumpit = nl80211_dump_scan, + }, + { + .cmd = NL80211_CMD_START_SCHED_SCAN, + .doit = nl80211_start_sched_scan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_STOP_SCHED_SCAN, + .doit = nl80211_stop_sched_scan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_AUTHENTICATE, + .doit = nl80211_authenticate, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_ASSOCIATE, + .doit = nl80211_associate, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEAUTHENTICATE, + .doit = nl80211_deauthenticate, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DISASSOCIATE, + .doit = nl80211_disassociate, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_JOIN_IBSS, + .doit = nl80211_join_ibss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_LEAVE_IBSS, + .doit = nl80211_leave_ibss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, +#ifdef CONFIG_NL80211_TESTMODE + { + .cmd = NL80211_CMD_TESTMODE, + .doit = nl80211_testmode_do, + .dumpit = nl80211_testmode_dump, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, +#endif + { + .cmd = NL80211_CMD_CONNECT, + .doit = nl80211_connect, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DISCONNECT, + .doit = nl80211_disconnect, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_WIPHY_NETNS, + .doit = nl80211_wiphy_netns, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_SURVEY, + .policy = nl80211_policy, + .dumpit = nl80211_dump_survey, + }, + { + .cmd = NL80211_CMD_SET_PMKSA, + .doit = nl80211_setdel_pmksa, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEL_PMKSA, + .doit = nl80211_setdel_pmksa, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_FLUSH_PMKSA, + .doit = nl80211_flush_pmksa, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, + .doit = nl80211_remain_on_channel, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + .doit = nl80211_cancel_remain_on_channel, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, + .doit = nl80211_set_tx_bitrate_mask, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_REGISTER_FRAME, + .doit = nl80211_register_mgmt, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_FRAME, + .doit = nl80211_tx_mgmt, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_FRAME_WAIT_CANCEL, + .doit = nl80211_tx_mgmt_cancel_wait, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_POWER_SAVE, + .doit = nl80211_set_power_save, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_POWER_SAVE, + .doit = nl80211_get_power_save, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_CQM, + .doit = nl80211_set_cqm, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_CHANNEL, + .doit = nl80211_set_channel, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_WDS_PEER, + .doit = nl80211_set_wds_peer, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_JOIN_MESH, + .doit = nl80211_join_mesh, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_LEAVE_MESH, + .doit = nl80211_leave_mesh, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_GET_WOWLAN, + .doit = nl80211_get_wowlan, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_WOWLAN, + .doit = nl80211_set_wowlan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, + .doit = nl80211_set_rekey_data, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_TDLS_MGMT, + .doit = nl80211_tdls_mgmt, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_TDLS_OPER, + .doit = nl80211_tdls_oper, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_UNEXPECTED_FRAME, + .doit = nl80211_register_unexpected_frame, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_PROBE_CLIENT, + .doit = nl80211_probe_client, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_REGISTER_BEACONS, + .doit = nl80211_register_beacons, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_BTCOEX, + .doit = nl80211_btcoex_notify, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_MAC_ACL, + .doit = nl80211_set_mac_acl, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, +}; + +static struct genl_multicast_group nl80211_mlme_mcgrp = { + .name = "mlme", +}; + +/* multicast groups */ +static struct genl_multicast_group nl80211_config_mcgrp = { + .name = "config", +}; +static struct genl_multicast_group nl80211_scan_mcgrp = { + .name = "scan", +}; +static struct genl_multicast_group nl80211_regulatory_mcgrp = { + .name = "regulatory", +}; + +/* notification functions */ + +void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_config_mcgrp.id, GFP_KERNEL); +} + +static int nl80211_add_scan_req(struct sk_buff *msg, + struct cfg80211_registered_device *rdev) +{ + struct cfg80211_scan_request *req = rdev->scan_req; + struct nlattr *nest; + int i; + + ASSERT_RDEV_LOCK(rdev); + + if (WARN_ON(!req)) + return 0; + + nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); + if (!nest) + goto nla_put_failure; + for (i = 0; i < req->n_ssids; i++) + NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); + nla_nest_end(msg, nest); + + nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); + if (!nest) + goto nla_put_failure; + for (i = 0; i < req->n_channels; i++) + NLA_PUT_U32(msg, i, req->channels[i]->center_freq); + nla_nest_end(msg, nest); + + if (req->ie) + NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); + + return 0; + nla_put_failure: + return -ENOBUFS; +} + +static int nl80211_send_scan_msg(struct sk_buff *msg, + struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u32 pid, u32 seq, int flags, + u32 cmd) +{ + void *hdr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + + /* ignore errors and send incomplete event anyway */ + nl80211_add_scan_req(msg, rdev); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int +nl80211_send_sched_scan_msg(struct sk_buff *msg, + struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u32 pid, u32 seq, int flags, u32 cmd) +{ + void *hdr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, + struct net_device *netdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_TRIGGER_SCAN) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); +} + +void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, + struct net_device *netdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_NEW_SCAN_RESULTS) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); +} + +void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, + struct net_device *netdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_SCAN_ABORTED) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); +} + +void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, + struct net_device *netdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_SCHED_SCAN_RESULTS) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); +} + +void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 cmd) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); +} + +/* + * This can happen on global regulatory changes or device specific settings + * based on custom world regulatory domains. + */ +void nl80211_send_reg_change_event(struct regulatory_request *request) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE); + if (!hdr) { + nlmsg_free(msg); + return; + } + + /* Userspace can always count this one always being set */ + NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator); + + if (request->alpha2[0] == '0' && request->alpha2[1] == '0') + NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, + NL80211_REGDOM_TYPE_WORLD); + else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') + NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, + NL80211_REGDOM_TYPE_CUSTOM_WORLD); + else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') || + request->intersect) + NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, + NL80211_REGDOM_TYPE_INTERSECTION); + else { + NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, + NL80211_REGDOM_TYPE_COUNTRY); + NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2); + } + + if (wiphy_idx_valid(request->wiphy_idx)) + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx); + + genlmsg_end(msg, hdr); + + rcu_read_lock(); + genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, + GFP_ATOMIC); + rcu_read_unlock(); + + return; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len, + enum nl80211_commands cmd, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) +{ + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_AUTHENTICATE, gfp); +} + +void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) +{ + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_ASSOCIATE, gfp); +} + +void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) +{ + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_DEAUTHENTICATE, gfp); +} + +void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) +{ + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_DISASSOCIATE, gfp); +} + +void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) +{ + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp); +} + +void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) +{ + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_UNPROT_DISASSOCIATE, gfp); +} + +static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int cmd, + const u8 *addr, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + gfp_t gfp) +{ + nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, + addr, gfp); +} + +void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + gfp_t gfp) +{ + nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, + addr, gfp); +} + +void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + if (bssid) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status); + if (req_ie) + NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); + if (resp_ie) + NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + +} + +void nl80211_send_roamed(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + if (req_ie) + NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); + if (resp_ie) + NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + +} + +void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u16 reason, + const u8 *ie, size_t ie_len, bool from_ap) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + if (from_ap && reason) + NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason); + if (from_ap) + NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP); + if (ie) + NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, GFP_KERNEL); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + +} + +void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *macaddr, const u8* ie, u8 ie_len, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr); + if (ie_len && ie) + NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + if (addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); + if (key_id != -1) + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); + if (tsc) + NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_beacon_hint_event(struct wiphy *wiphy, + struct ieee80211_channel *channel_before, + struct ieee80211_channel *channel_after) +{ + struct sk_buff *msg; + void *hdr; + struct nlattr *nl_freq; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + /* + * Since we are applying the beacon hint to a wiphy we know its + * wiphy_idx is valid + */ + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); + + /* Before */ + nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); + if (!nl_freq) + goto nla_put_failure; + if (nl80211_msg_put_channel(msg, channel_before)) + goto nla_put_failure; + nla_nest_end(msg, nl_freq); + + /* After */ + nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); + if (!nl_freq) + goto nla_put_failure; + if (nl80211_msg_put_channel(msg, channel_after)) + goto nla_put_failure; + nla_nest_end(msg, nl_freq); + + genlmsg_end(msg, hdr); + + rcu_read_lock(); + genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, + GFP_ATOMIC); + rcu_read_unlock(); + + return; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +static void nl80211_send_remain_on_chan_event( + int cmd, struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + + if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL) + NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp) +{ + nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, + rdev, netdev, cookie, chan, + channel_type, duration, gfp); +} + +void nl80211_send_remain_on_channel_cancel( + struct cfg80211_registered_device *rdev, struct net_device *netdev, + u64 cookie, struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, gfp_t gfp) +{ + nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + rdev, netdev, cookie, chan, + channel_type, 0, gfp); +} + +void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); +} + +void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + enum nl80211_connect_failed_reason reason, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) || + nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, + const u8 *addr, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + int err; + u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid); + + if (!nlpid) + return false; + + msg = nlmsg_new(100, gfp); + if (!msg) + return true; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return true; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + err = genlmsg_end(msg, hdr); + if (err < 0) { + nlmsg_free(msg); + return true; + } + + genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); + return true; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + return true; +} + +bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) +{ + return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, + addr, gfp); +} + +bool nl80211_unexpected_4addr_frame(struct net_device *dev, + const u8 *addr, gfp_t gfp) +{ + return __nl80211_unexpected_frame(dev, + NL80211_CMD_UNEXPECTED_4ADDR_FRAME, + addr, gfp); +} + +int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 nlpid, + int freq, const u8 *buf, size_t len, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); + + genlmsg_end(msg, hdr); + + return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + return -ENOBUFS; +} + +void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + const u8 *buf, size_t len, bool ack, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + if (ack) + NLA_PUT_FLAG(msg, NL80211_ATTR_ACK); + + genlmsg_end(msg, hdr); + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void +nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + enum nl80211_cqm_rssi_threshold_event rssi_event, + gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *pinfoattr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); + if (!pinfoattr) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, + rssi_event); + + nla_nest_end(msg, pinfoattr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *rekey_attr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + + rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); + if (!rekey_attr) + goto nla_put_failure; + + NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, + NL80211_REPLAY_CTR_LEN, replay_ctr); + + nla_nest_end(msg, rekey_attr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int index, + const u8 *bssid, bool preauth, gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *attr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + + attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE); + if (!attr) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index); + NLA_PUT(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid); + if (preauth) + NLA_PUT_FLAG(msg, NL80211_PMKSA_CANDIDATE_PREAUTH); + + nla_nest_end(msg, attr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int freq, + enum nl80211_channel_type type, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CH_SWITCH_NOTIFY); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void +nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *pinfoattr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) + goto nla_put_failure; + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); + if (!pinfoattr) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) + goto nla_put_failure; + + nla_nest_end(msg, pinfoattr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void +nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *pinfoattr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); + if (!pinfoattr) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets); + + nla_nest_end(msg, pinfoattr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void cfg80211_probe_status(struct net_device *dev, const u8 *addr, + u64 cookie, bool acked, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + int err; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); + if (acked) + NLA_PUT_FLAG(msg, NL80211_ATTR_ACK); + + err = genlmsg_end(msg, hdr); + if (err < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_probe_status); + +void cfg80211_report_obss_beacon(struct wiphy *wiphy, + const u8 *frame, size_t len, + int freq, gfp_t gfp) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct sk_buff *msg; + void *hdr; + u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid); + + if (!nlpid) + return; + + msg = nlmsg_new(len + 100, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + if (freq) + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame); + + genlmsg_end(msg, hdr); + + genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_report_obss_beacon); + +static int nl80211_netlink_notify(struct notifier_block * nb, + unsigned long state, + void *_notify) +{ + struct netlink_notify *notify = _notify; + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + + if (state != NETLINK_URELEASE) + return NOTIFY_DONE; + + rcu_read_lock(); + + list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { + list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) + cfg80211_mlme_unregister_socket(wdev, notify->pid); + if (rdev->ap_beacons_nlpid == notify->pid) + rdev->ap_beacons_nlpid = 0; + } + + rcu_read_unlock(); + + return NOTIFY_DONE; +} + +static struct notifier_block nl80211_netlink_notifier = { + .notifier_call = nl80211_netlink_notify, +}; + +/* initialisation/exit functions */ + +int nl80211_init(void) +{ + int err; + + err = genl_register_family_with_ops(&nl80211_fam, + nl80211_ops, ARRAY_SIZE(nl80211_ops)); + if (err) + return err; + + err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); + if (err) + goto err_out; + + err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp); + if (err) + goto err_out; + + err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp); + if (err) + goto err_out; + + err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); + if (err) + goto err_out; + +#ifdef CONFIG_NL80211_TESTMODE + err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp); + if (err) + goto err_out; +#endif + + err = netlink_register_notifier(&nl80211_netlink_notifier); + if (err) + goto err_out; + + return 0; + err_out: + genl_unregister_family(&nl80211_fam); + return err; +} + +void nl80211_exit(void) +{ + netlink_unregister_notifier(&nl80211_netlink_notifier); + genl_unregister_family(&nl80211_fam); +} diff --git a/net/wireless_ath/nl80211.h b/net/wireless_ath/nl80211.h new file mode 100644 index 00000000..4928ef8c --- /dev/null +++ b/net/wireless_ath/nl80211.h @@ -0,0 +1,139 @@ +#ifndef __NET_WIRELESS_NL80211_H +#define __NET_WIRELESS_NL80211_H + +#include "core.h" + +int nl80211_init(void); +void nl80211_exit(void); +void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); +void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, + struct net_device *netdev); +void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, + struct net_device *netdev); +void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, + struct net_device *netdev); +void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 cmd); +void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, + struct net_device *netdev); +void nl80211_send_reg_change_event(struct regulatory_request *request); +void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr, gfp_t gfp); +void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr, gfp_t gfp); +void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp); +void nl80211_send_roamed(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); +void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u16 reason, + const u8 *ie, size_t ie_len, bool from_ap); + +void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *macaddr, const u8* ie, u8 ie_len, + gfp_t gfp); +void +nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, + int key_id, const u8 *tsc, gfp_t gfp); + +void +nl80211_send_beacon_hint_event(struct wiphy *wiphy, + struct ieee80211_channel *channel_before, + struct ieee80211_channel *channel_after); + +void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + gfp_t gfp); + +void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp); +void nl80211_send_remain_on_channel_cancel( + struct cfg80211_registered_device *rdev, struct net_device *netdev, + u64 cookie, struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, gfp_t gfp); + +void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp); +void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + gfp_t gfp); + +void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + enum nl80211_connect_failed_reason reason, + gfp_t gfp); + +int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 nlpid, int freq, + const u8 *buf, size_t len, gfp_t gfp); +void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + const u8 *buf, size_t len, bool ack, + gfp_t gfp); + +void +nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + enum nl80211_cqm_rssi_threshold_event rssi_event, + gfp_t gfp); +void +nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, gfp_t gfp); + +void +nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); + +void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp); + +void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int index, + const u8 *bssid, bool preauth, gfp_t gfp); + +void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, + struct net_device *dev, int freq, + enum nl80211_channel_type type, gfp_t gfp); + +bool nl80211_unexpected_frame(struct net_device *dev, + const u8 *addr, gfp_t gfp); +bool nl80211_unexpected_4addr_frame(struct net_device *dev, + const u8 *addr, gfp_t gfp); + +#endif /* __NET_WIRELESS_NL80211_H */ diff --git a/net/wireless_ath/radiotap.c b/net/wireless_ath/radiotap.c new file mode 100644 index 00000000..c4ad7958 --- /dev/null +++ b/net/wireless_ath/radiotap.c @@ -0,0 +1,358 @@ +/* + * Radiotap parser + * + * Copyright 2007 Andy Green + * Copyright 2009 Johannes Berg + * + * 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. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See COPYING for more details. + */ + +#include +#include +#include +#include +#include + +/* function prototypes and related defs are in include/net/cfg80211.h */ + +static const struct radiotap_align_size rtap_namespace_sizes[] = { + [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, + [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, + [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, + [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, + [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, + /* + * add more here as they are defined in radiotap.h + */ +}; + +static const struct ieee80211_radiotap_namespace radiotap_ns = { + .n_bits = ARRAY_SIZE(rtap_namespace_sizes), + .align_size = rtap_namespace_sizes, +}; + +/** + * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization + * @iterator: radiotap_iterator to initialize + * @radiotap_header: radiotap header to parse + * @max_length: total length we can parse into (eg, whole packet length) + * + * Returns: 0 or a negative error code if there is a problem. + * + * This function initializes an opaque iterator struct which can then + * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap + * argument which is present in the header. It knows about extended + * present headers and handles them. + * + * How to use: + * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator + * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) + * checking for a good 0 return code. Then loop calling + * __ieee80211_radiotap_iterator_next()... it returns either 0, + * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. + * The iterator's @this_arg member points to the start of the argument + * associated with the current argument index that is present, which can be + * found in the iterator's @this_arg_index member. This arg index corresponds + * to the IEEE80211_RADIOTAP_... defines. + * + * Radiotap header length: + * You can find the CPU-endian total radiotap header length in + * iterator->max_length after executing ieee80211_radiotap_iterator_init() + * successfully. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + * + * Example code: + * See Documentation/networking/radiotap-headers.txt + */ + +int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) +{ + /* Linux only supports version 0 radiotap format */ + if (radiotap_header->it_version) + return -EINVAL; + + /* sanity check for allowed length and radiotap length field */ + if (max_length < get_unaligned_le16(&radiotap_header->it_len)) + return -EINVAL; + + iterator->_rtheader = radiotap_header; + iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); + iterator->_arg_index = 0; + iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); + iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); + iterator->_reset_on_ext = 0; + iterator->_next_bitmap = &radiotap_header->it_present; + iterator->_next_bitmap++; + iterator->_vns = vns; + iterator->current_namespace = &radiotap_ns; + iterator->is_radiotap_ns = 1; + + /* find payload start allowing for extended bitmap(s) */ + + if (iterator->_bitmap_shifter & (1<_arg) & + (1 << IEEE80211_RADIOTAP_EXT)) { + iterator->_arg += sizeof(uint32_t); + + /* + * check for insanity where the present bitmaps + * keep claiming to extend up to or even beyond the + * stated radiotap header length + */ + + if ((unsigned long)iterator->_arg - + (unsigned long)iterator->_rtheader > + (unsigned long)iterator->_max_length) + return -EINVAL; + } + + iterator->_arg += sizeof(uint32_t); + + /* + * no need to check again for blowing past stated radiotap + * header length, because ieee80211_radiotap_iterator_next + * checks it before it is dereferenced + */ + } + + iterator->this_arg = iterator->_arg; + + /* we are all initialized happily */ + + return 0; +} +EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); + +static void find_ns(struct ieee80211_radiotap_iterator *iterator, + uint32_t oui, uint8_t subns) +{ + int i; + + iterator->current_namespace = NULL; + + if (!iterator->_vns) + return; + + for (i = 0; i < iterator->_vns->n_ns; i++) { + if (iterator->_vns->ns[i].oui != oui) + continue; + if (iterator->_vns->ns[i].subns != subns) + continue; + + iterator->current_namespace = &iterator->_vns->ns[i]; + break; + } +} + + + +/** + * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg + * @iterator: radiotap_iterator to move to next arg (if any) + * + * Returns: 0 if there is an argument to handle, + * -ENOENT if there are no more args or -EINVAL + * if there is something else wrong. + * + * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) + * in @this_arg_index and sets @this_arg to point to the + * payload for the field. It takes care of alignment handling and extended + * present fields. @this_arg can be changed by the caller (eg, + * incremented to move inside a compound argument like + * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in + * little-endian format whatever the endianess of your CPU. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + */ + +int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator) +{ + while (1) { + int hit = 0; + int pad, align, size, subns; + uint32_t oui; + + /* if no more EXT bits, that's it */ + if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && + !(iterator->_bitmap_shifter & 1)) + return -ENOENT; + + if (!(iterator->_bitmap_shifter & 1)) + goto next_entry; /* arg not present */ + + /* get alignment/size of data */ + switch (iterator->_arg_index % 32) { + case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: + case IEEE80211_RADIOTAP_EXT: + align = 1; + size = 0; + break; + case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: + align = 2; + size = 6; + break; + default: + if (!iterator->current_namespace || + iterator->_arg_index >= iterator->current_namespace->n_bits) { + if (iterator->current_namespace == &radiotap_ns) + return -ENOENT; + align = 0; + } else { + align = iterator->current_namespace->align_size[iterator->_arg_index].align; + size = iterator->current_namespace->align_size[iterator->_arg_index].size; + } + if (!align) { + /* skip all subsequent data */ + iterator->_arg = iterator->_next_ns_data; + /* give up on this namespace */ + iterator->current_namespace = NULL; + goto next_entry; + } + break; + } + + /* + * arg is present, account for alignment padding + * + * Note that these alignments are relative to the start + * of the radiotap header. There is no guarantee + * that the radiotap header itself is aligned on any + * kind of boundary. + * + * The above is why get_unaligned() is used to dereference + * multibyte elements from the radiotap area. + */ + + pad = ((unsigned long)iterator->_arg - + (unsigned long)iterator->_rtheader) & (align - 1); + + if (pad) + iterator->_arg += align - pad; + + if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { + int vnslen; + + if ((unsigned long)iterator->_arg + size - + (unsigned long)iterator->_rtheader > + (unsigned long)iterator->_max_length) + return -EINVAL; + + oui = (*iterator->_arg << 16) | + (*(iterator->_arg + 1) << 8) | + *(iterator->_arg + 2); + subns = *(iterator->_arg + 3); + + find_ns(iterator, oui, subns); + + vnslen = get_unaligned_le16(iterator->_arg + 4); + iterator->_next_ns_data = iterator->_arg + size + vnslen; + if (!iterator->current_namespace) + size += vnslen; + } + + /* + * this is what we will return to user, but we need to + * move on first so next call has something fresh to test + */ + iterator->this_arg_index = iterator->_arg_index; + iterator->this_arg = iterator->_arg; + iterator->this_arg_size = size; + + /* internally move on the size of this arg */ + iterator->_arg += size; + + /* + * check for insanity where we are given a bitmap that + * claims to have more arg content than the length of the + * radiotap section. We will normally end up equalling this + * max_length on the last arg, never exceeding it. + */ + + if ((unsigned long)iterator->_arg - + (unsigned long)iterator->_rtheader > + (unsigned long)iterator->_max_length) + return -EINVAL; + + /* these special ones are valid in each bitmap word */ + switch (iterator->_arg_index % 32) { + case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: + iterator->_reset_on_ext = 1; + + iterator->is_radiotap_ns = 0; + /* + * If parser didn't register this vendor + * namespace with us, allow it to show it + * as 'raw. Do do that, set argument index + * to vendor namespace. + */ + iterator->this_arg_index = + IEEE80211_RADIOTAP_VENDOR_NAMESPACE; + if (!iterator->current_namespace) + hit = 1; + goto next_entry; + case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: + iterator->_reset_on_ext = 1; + iterator->current_namespace = &radiotap_ns; + iterator->is_radiotap_ns = 1; + goto next_entry; + case IEEE80211_RADIOTAP_EXT: + /* + * bit 31 was set, there is more + * -- move to next u32 bitmap + */ + iterator->_bitmap_shifter = + get_unaligned_le32(iterator->_next_bitmap); + iterator->_next_bitmap++; + if (iterator->_reset_on_ext) + iterator->_arg_index = 0; + else + iterator->_arg_index++; + iterator->_reset_on_ext = 0; + break; + default: + /* we've got a hit! */ + hit = 1; + next_entry: + iterator->_bitmap_shifter >>= 1; + iterator->_arg_index++; + } + + /* if we found a valid arg earlier, return it now */ + if (hit) + return 0; + } +} +EXPORT_SYMBOL(ieee80211_radiotap_iterator_next); diff --git a/net/wireless_ath/reg.c b/net/wireless_ath/reg.c new file mode 100644 index 00000000..f232d9e3 --- /dev/null +++ b/net/wireless_ath/reg.c @@ -0,0 +1,2299 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2007 Johannes Berg + * Copyright 2008 Luis R. Rodriguez + * + * 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. + */ + +/** + * DOC: Wireless regulatory infrastructure + * + * The usual implementation is for a driver to read a device EEPROM to + * determine which regulatory domain it should be operating under, then + * looking up the allowable channels in a driver-local table and finally + * registering those channels in the wiphy structure. + * + * Another set of compliance enforcement is for drivers to use their + * own compliance limits which can be stored on the EEPROM. The host + * driver or firmware may ensure these are used. + * + * In addition to all this we provide an extra layer of regulatory + * conformance. For drivers which do not have any regulatory + * information CRDA provides the complete regulatory solution. + * For others it provides a community effort on further restrictions + * to enhance compliance. + * + * Note: When number of rules --> infinity we will not be able to + * index on alpha2 any more, instead we'll probably have to + * rely on some SHA1 checksum of the regdomain for example. + * + */ + +//#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "reg.h" +#include "regdb.h" +#include "nl80211.h" + +#ifdef CONFIG_CFG80211_REG_DEBUG +#define REG_DBG_PRINT(format, args...) \ + printk(KERN_DEBUG pr_fmt(format), ##args) +#else +#define REG_DBG_PRINT(args...) +#endif + +/* Receipt of information from last regulatory request */ +static struct regulatory_request *last_request; + +/* To trigger userspace events */ +static struct platform_device *reg_pdev; + +static struct device_type reg_device_type = { + .uevent = reg_device_uevent, +}; + +/* + * Central wireless core regulatory domains, we only need two, + * the current one and a world regulatory domain in case we have no + * information to give us an alpha2 + */ +const struct ieee80211_regdomain *cfg80211_regdomain; + +/* + * Protects static reg.c components: + * - cfg80211_world_regdom + * - cfg80211_regdom + * - last_request + */ +static DEFINE_MUTEX(reg_mutex); + +static inline void assert_reg_lock(void) +{ + lockdep_assert_held(®_mutex); +} + +/* Used to queue up regulatory hints */ +static LIST_HEAD(reg_requests_list); +static spinlock_t reg_requests_lock; + +/* Used to queue up beacon hints for review */ +static LIST_HEAD(reg_pending_beacons); +static spinlock_t reg_pending_beacons_lock; + +/* Used to keep track of processed beacon hints */ +static LIST_HEAD(reg_beacon_list); + +struct reg_beacon { + struct list_head list; + struct ieee80211_channel chan; +}; + +static void reg_todo(struct work_struct *work); +static DECLARE_WORK(reg_work, reg_todo); + +static void reg_timeout_work(struct work_struct *work); +static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); + +/* We keep a static world regulatory domain in case of the absence of CRDA */ +static const struct ieee80211_regdomain world_regdom = { + .n_reg_rules = 5, + .alpha2 = "00", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), + /* IEEE 802.11b/g, channels 12..13. No HT40 + * channel fits here. */ + REG_RULE(2467-10, 2472+10, 20, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS), + /* IEEE 802.11 channel 14 - Only JP enables + * this and for 802.11b only */ + REG_RULE(2484-10, 2484+10, 20, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_OFDM), + /* IEEE 802.11a, channel 36..48 */ + REG_RULE(5180-10, 5240+10, 40, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS), + + /* NB: 5260 MHz - 5700 MHz requies DFS */ + + /* IEEE 802.11a, channel 149..165 */ + REG_RULE(5745-10, 5825+10, 40, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS), + } +}; + +static const struct ieee80211_regdomain *cfg80211_world_regdom = + &world_regdom; + +static char *ieee80211_regdom = "00"; +static char user_alpha2[2]; + +module_param(ieee80211_regdom, charp, 0444); +MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); + +static void reset_regdomains(void) +{ + /* avoid freeing static information or freeing something twice */ + if (cfg80211_regdomain == cfg80211_world_regdom) + cfg80211_regdomain = NULL; + if (cfg80211_world_regdom == &world_regdom) + cfg80211_world_regdom = NULL; + if (cfg80211_regdomain == &world_regdom) + cfg80211_regdomain = NULL; + + kfree(cfg80211_regdomain); + kfree(cfg80211_world_regdom); + + cfg80211_world_regdom = &world_regdom; + cfg80211_regdomain = NULL; +} + +/* + * Dynamic world regulatory domain requested by the wireless + * core upon initialization + */ +static void update_world_regdomain(const struct ieee80211_regdomain *rd) +{ + BUG_ON(!last_request); + + reset_regdomains(); + + cfg80211_world_regdom = rd; + cfg80211_regdomain = rd; +} + +bool is_world_regdom(const char *alpha2) +{ + if (!alpha2) + return false; + if (alpha2[0] == '0' && alpha2[1] == '0') + return true; + return false; +} + +static bool is_alpha2_set(const char *alpha2) +{ + if (!alpha2) + return false; + if (alpha2[0] != 0 && alpha2[1] != 0) + return true; + return false; +} + +static bool is_unknown_alpha2(const char *alpha2) +{ + if (!alpha2) + return false; + /* + * Special case where regulatory domain was built by driver + * but a specific alpha2 cannot be determined + */ + if (alpha2[0] == '9' && alpha2[1] == '9') + return true; + return false; +} + +static bool is_intersected_alpha2(const char *alpha2) +{ + if (!alpha2) + return false; + /* + * Special case where regulatory domain is the + * result of an intersection between two regulatory domain + * structures + */ + if (alpha2[0] == '9' && alpha2[1] == '8') + return true; + return false; +} + +static bool is_an_alpha2(const char *alpha2) +{ + if (!alpha2) + return false; + if (isalpha(alpha2[0]) && isalpha(alpha2[1])) + return true; + return false; +} + +static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y) +{ + if (!alpha2_x || !alpha2_y) + return false; + if (alpha2_x[0] == alpha2_y[0] && + alpha2_x[1] == alpha2_y[1]) + return true; + return false; +} + +static bool regdom_changes(const char *alpha2) +{ + assert_cfg80211_lock(); + + if (!cfg80211_regdomain) + return true; + if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) + return false; + return true; +} + +/* + * The NL80211_REGDOM_SET_BY_USER regdom alpha2 is cached, this lets + * you know if a valid regulatory hint with NL80211_REGDOM_SET_BY_USER + * has ever been issued. + */ +static bool is_user_regdom_saved(void) +{ + if (user_alpha2[0] == '9' && user_alpha2[1] == '7') + return false; + + /* This would indicate a mistake on the design */ + if (WARN((!is_world_regdom(user_alpha2) && + !is_an_alpha2(user_alpha2)), + "Unexpected user alpha2: %c%c\n", + user_alpha2[0], + user_alpha2[1])) + return false; + + return true; +} + +static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, + const struct ieee80211_regdomain *src_regd) +{ + struct ieee80211_regdomain *regd; + int size_of_regd = 0; + unsigned int i; + + size_of_regd = sizeof(struct ieee80211_regdomain) + + ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); + + regd = kzalloc(size_of_regd, GFP_KERNEL); + if (!regd) + return -ENOMEM; + + memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); + + for (i = 0; i < src_regd->n_reg_rules; i++) + memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], + sizeof(struct ieee80211_reg_rule)); + + *dst_regd = regd; + return 0; +} + +#ifdef CONFIG_CFG80211_INTERNAL_REGDB +struct reg_regdb_search_request { + char alpha2[2]; + struct list_head list; +}; + +static LIST_HEAD(reg_regdb_search_list); +static DEFINE_MUTEX(reg_regdb_search_mutex); + +static void reg_regdb_search(struct work_struct *work) +{ + struct reg_regdb_search_request *request; + const struct ieee80211_regdomain *curdom, *regdom; + int i, r; + + mutex_lock(®_regdb_search_mutex); + while (!list_empty(®_regdb_search_list)) { + request = list_first_entry(®_regdb_search_list, + struct reg_regdb_search_request, + list); + list_del(&request->list); + + for (i=0; ialpha2, curdom->alpha2, 2)) { + r = reg_copy_regd(®dom, curdom); + if (r) + break; + mutex_lock(&cfg80211_mutex); + set_regdom(regdom); + mutex_unlock(&cfg80211_mutex); + break; + } + } + + kfree(request); + } + mutex_unlock(®_regdb_search_mutex); +} + +static DECLARE_WORK(reg_regdb_work, reg_regdb_search); + +static void reg_regdb_query(const char *alpha2) +{ + struct reg_regdb_search_request *request; + + if (!alpha2) + return; + + request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); + if (!request) + return; + + memcpy(request->alpha2, alpha2, 2); + + mutex_lock(®_regdb_search_mutex); + list_add_tail(&request->list, ®_regdb_search_list); + mutex_unlock(®_regdb_search_mutex); + + schedule_work(®_regdb_work); +} +#else +static inline void reg_regdb_query(const char *alpha2) {} +#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ + +/* + * This lets us keep regulatory code which is updated on a regulatory + * basis in userspace. Country information is filled in by + * reg_device_uevent + */ +static int call_crda(const char *alpha2) +{ + if (!is_world_regdom((char *) alpha2)) + pr_info("Calling CRDA for country: %c%c\n", + alpha2[0], alpha2[1]); + else + pr_info("Calling CRDA to update world regulatory domain\n"); + + /* query internal regulatory database (if it exists) */ + reg_regdb_query(alpha2); + + return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); +} + +/* Used by nl80211 before kmalloc'ing our regulatory domain */ +bool reg_is_valid_request(const char *alpha2) +{ + assert_cfg80211_lock(); + + if (!last_request) + return false; + + return alpha2_equal(last_request->alpha2, alpha2); +} + +/* Sanity check on a regulatory rule */ +static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) +{ + const struct ieee80211_freq_range *freq_range = &rule->freq_range; + u32 freq_diff; + + if (freq_range->start_freq_khz <= 0 || freq_range->end_freq_khz <= 0) + return false; + + if (freq_range->start_freq_khz > freq_range->end_freq_khz) + return false; + + freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; + + if (freq_range->end_freq_khz <= freq_range->start_freq_khz || + freq_range->max_bandwidth_khz > freq_diff) + return false; + + return true; +} + +static bool is_valid_rd(const struct ieee80211_regdomain *rd) +{ + const struct ieee80211_reg_rule *reg_rule = NULL; + unsigned int i; + + if (!rd->n_reg_rules) + return false; + + if (WARN_ON(rd->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) + return false; + + for (i = 0; i < rd->n_reg_rules; i++) { + reg_rule = &rd->reg_rules[i]; + if (!is_valid_reg_rule(reg_rule)) + return false; + } + + return true; +} + +static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, + u32 center_freq_khz, + u32 bw_khz) +{ + u32 start_freq_khz, end_freq_khz; + + start_freq_khz = center_freq_khz - (bw_khz/2); + end_freq_khz = center_freq_khz + (bw_khz/2); + + if (start_freq_khz >= freq_range->start_freq_khz && + end_freq_khz <= freq_range->end_freq_khz) + return true; + + return false; +} + +/** + * freq_in_rule_band - tells us if a frequency is in a frequency band + * @freq_range: frequency rule we want to query + * @freq_khz: frequency we are inquiring about + * + * This lets us know if a specific frequency rule is or is not relevant to + * a specific frequency's band. Bands are device specific and artificial + * definitions (the "2.4 GHz band" and the "5 GHz band"), however it is + * safe for now to assume that a frequency rule should not be part of a + * frequency's band if the start freq or end freq are off by more than 2 GHz. + * This resolution can be lowered and should be considered as we add + * regulatory rule support for other "bands". + **/ +static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, + u32 freq_khz) +{ +#define ONE_GHZ_IN_KHZ 1000000 + if (abs(freq_khz - freq_range->start_freq_khz) <= (2 * ONE_GHZ_IN_KHZ)) + return true; + if (abs(freq_khz - freq_range->end_freq_khz) <= (2 * ONE_GHZ_IN_KHZ)) + return true; + return false; +#undef ONE_GHZ_IN_KHZ +} + +/* + * Helper for regdom_intersect(), this does the real + * mathematical intersection fun + */ +static int reg_rules_intersect( + const struct ieee80211_reg_rule *rule1, + const struct ieee80211_reg_rule *rule2, + struct ieee80211_reg_rule *intersected_rule) +{ + const struct ieee80211_freq_range *freq_range1, *freq_range2; + struct ieee80211_freq_range *freq_range; + const struct ieee80211_power_rule *power_rule1, *power_rule2; + struct ieee80211_power_rule *power_rule; + u32 freq_diff; + + freq_range1 = &rule1->freq_range; + freq_range2 = &rule2->freq_range; + freq_range = &intersected_rule->freq_range; + + power_rule1 = &rule1->power_rule; + power_rule2 = &rule2->power_rule; + power_rule = &intersected_rule->power_rule; + + freq_range->start_freq_khz = max(freq_range1->start_freq_khz, + freq_range2->start_freq_khz); + freq_range->end_freq_khz = min(freq_range1->end_freq_khz, + freq_range2->end_freq_khz); + freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, + freq_range2->max_bandwidth_khz); + + freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; + if (freq_range->max_bandwidth_khz > freq_diff) + freq_range->max_bandwidth_khz = freq_diff; + + power_rule->max_eirp = min(power_rule1->max_eirp, + power_rule2->max_eirp); + power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, + power_rule2->max_antenna_gain); + + intersected_rule->flags = (rule1->flags | rule2->flags); + + if (!is_valid_reg_rule(intersected_rule)) + return -EINVAL; + + return 0; +} + +/** + * regdom_intersect - do the intersection between two regulatory domains + * @rd1: first regulatory domain + * @rd2: second regulatory domain + * + * Use this function to get the intersection between two regulatory domains. + * Once completed we will mark the alpha2 for the rd as intersected, "98", + * as no one single alpha2 can represent this regulatory domain. + * + * Returns a pointer to the regulatory domain structure which will hold the + * resulting intersection of rules between rd1 and rd2. We will + * kzalloc() this structure for you. + */ +static struct ieee80211_regdomain *regdom_intersect( + const struct ieee80211_regdomain *rd1, + const struct ieee80211_regdomain *rd2) +{ + int r, size_of_regd; + unsigned int x, y; + unsigned int num_rules = 0, rule_idx = 0; + const struct ieee80211_reg_rule *rule1, *rule2; + struct ieee80211_reg_rule *intersected_rule; + struct ieee80211_regdomain *rd; + /* This is just a dummy holder to help us count */ + struct ieee80211_reg_rule irule; + + /* Uses the stack temporarily for counter arithmetic */ + intersected_rule = &irule; + + memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule)); + + if (!rd1 || !rd2) + return NULL; + + /* + * First we get a count of the rules we'll need, then we actually + * build them. This is to so we can malloc() and free() a + * regdomain once. The reason we use reg_rules_intersect() here + * is it will return -EINVAL if the rule computed makes no sense. + * All rules that do check out OK are valid. + */ + + for (x = 0; x < rd1->n_reg_rules; x++) { + rule1 = &rd1->reg_rules[x]; + for (y = 0; y < rd2->n_reg_rules; y++) { + rule2 = &rd2->reg_rules[y]; + if (!reg_rules_intersect(rule1, rule2, + intersected_rule)) + num_rules++; + memset(intersected_rule, 0, + sizeof(struct ieee80211_reg_rule)); + } + } + + if (!num_rules) + return NULL; + + size_of_regd = sizeof(struct ieee80211_regdomain) + + ((num_rules + 1) * sizeof(struct ieee80211_reg_rule)); + + rd = kzalloc(size_of_regd, GFP_KERNEL); + if (!rd) + return NULL; + + for (x = 0; x < rd1->n_reg_rules; x++) { + rule1 = &rd1->reg_rules[x]; + for (y = 0; y < rd2->n_reg_rules; y++) { + rule2 = &rd2->reg_rules[y]; + /* + * This time around instead of using the stack lets + * write to the target rule directly saving ourselves + * a memcpy() + */ + intersected_rule = &rd->reg_rules[rule_idx]; + r = reg_rules_intersect(rule1, rule2, + intersected_rule); + /* + * No need to memset here the intersected rule here as + * we're not using the stack anymore + */ + if (r) + continue; + rule_idx++; + } + } + + if (rule_idx != num_rules) { + kfree(rd); + return NULL; + } + + rd->n_reg_rules = num_rules; + rd->alpha2[0] = '9'; + rd->alpha2[1] = '8'; + + return rd; +} + +/* + * XXX: add support for the rest of enum nl80211_reg_rule_flags, we may + * want to just have the channel structure use these + */ +static u32 map_regdom_flags(u32 rd_flags) +{ + u32 channel_flags = 0; + if (rd_flags & NL80211_RRF_PASSIVE_SCAN) + channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN; + if (rd_flags & NL80211_RRF_NO_IBSS) + channel_flags |= IEEE80211_CHAN_NO_IBSS; + if (rd_flags & NL80211_RRF_DFS) + channel_flags |= IEEE80211_CHAN_RADAR; + return channel_flags; +} + +static int freq_reg_info_regd(struct wiphy *wiphy, + u32 center_freq, + u32 desired_bw_khz, + const struct ieee80211_reg_rule **reg_rule, + const struct ieee80211_regdomain *custom_regd) +{ + int i; + bool band_rule_found = false; + const struct ieee80211_regdomain *regd; + bool bw_fits = false; + + if (!desired_bw_khz) + desired_bw_khz = MHZ_TO_KHZ(20); + + regd = custom_regd ? custom_regd : cfg80211_regdomain; + + /* + * Follow the driver's regulatory domain, if present, unless a country + * IE has been processed or a user wants to help complaince further + */ + if (!custom_regd && + last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && + last_request->initiator != NL80211_REGDOM_SET_BY_USER && + wiphy->regd) + regd = wiphy->regd; + + if (!regd) + return -EINVAL; + + for (i = 0; i < regd->n_reg_rules; i++) { + const struct ieee80211_reg_rule *rr; + const struct ieee80211_freq_range *fr = NULL; + + rr = ®d->reg_rules[i]; + fr = &rr->freq_range; + + /* + * We only need to know if one frequency rule was + * was in center_freq's band, that's enough, so lets + * not overwrite it once found + */ + if (!band_rule_found) + band_rule_found = freq_in_rule_band(fr, center_freq); + + bw_fits = reg_does_bw_fit(fr, + center_freq, + desired_bw_khz); + + if (band_rule_found && bw_fits) { + *reg_rule = rr; + return 0; + } + } + + if (!band_rule_found) + return -ERANGE; + + return -EINVAL; +} + +int freq_reg_info(struct wiphy *wiphy, + u32 center_freq, + u32 desired_bw_khz, + const struct ieee80211_reg_rule **reg_rule) +{ + assert_cfg80211_lock(); + return freq_reg_info_regd(wiphy, + center_freq, + desired_bw_khz, + reg_rule, + NULL); +} +EXPORT_SYMBOL(freq_reg_info); + +#ifdef CONFIG_CFG80211_REG_DEBUG +static const char *reg_initiator_name(enum nl80211_reg_initiator initiator) +{ + switch (initiator) { + case NL80211_REGDOM_SET_BY_CORE: + return "Set by core"; + case NL80211_REGDOM_SET_BY_USER: + return "Set by user"; + case NL80211_REGDOM_SET_BY_DRIVER: + return "Set by driver"; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + return "Set by country IE"; + default: + WARN_ON(1); + return "Set by bug"; + } +} + +static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, + u32 desired_bw_khz, + const struct ieee80211_reg_rule *reg_rule) +{ + const struct ieee80211_power_rule *power_rule; + const struct ieee80211_freq_range *freq_range; + char max_antenna_gain[32]; + + power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; + + if (!power_rule->max_antenna_gain) + snprintf(max_antenna_gain, 32, "N/A"); + else + snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); + + REG_DBG_PRINT("Updating information on frequency %d MHz " + "for a %d MHz width channel with regulatory rule:\n", + chan->center_freq, + KHZ_TO_MHZ(desired_bw_khz)); + + REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n", + freq_range->start_freq_khz, + freq_range->end_freq_khz, + freq_range->max_bandwidth_khz, + max_antenna_gain, + power_rule->max_eirp); +} +#else +static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, + u32 desired_bw_khz, + const struct ieee80211_reg_rule *reg_rule) +{ + return; +} +#endif + +/* + * Note that right now we assume the desired channel bandwidth + * is always 20 MHz for each individual channel (HT40 uses 20 MHz + * per channel, the primary and the extension channel). To support + * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a + * new ieee80211_channel.target_bw and re run the regulatory check + * on the wiphy with the target_bw specified. Then we can simply use + * that below for the desired_bw_khz below. + */ +static void handle_channel(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + enum ieee80211_band band, + unsigned int chan_idx) +{ + int r; + u32 flags, bw_flags = 0; + u32 desired_bw_khz = MHZ_TO_KHZ(20); + const struct ieee80211_reg_rule *reg_rule = NULL; + const struct ieee80211_power_rule *power_rule = NULL; + const struct ieee80211_freq_range *freq_range = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + struct wiphy *request_wiphy = NULL; + + assert_cfg80211_lock(); + + request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + + sband = wiphy->bands[band]; + BUG_ON(chan_idx >= sband->n_channels); + chan = &sband->channels[chan_idx]; + + flags = chan->orig_flags; + + r = freq_reg_info(wiphy, + MHZ_TO_KHZ(chan->center_freq), + desired_bw_khz, + ®_rule); + + if (r) { + /* + * We will disable all channels that do not match our + * received regulatory rule unless the hint is coming + * from a Country IE and the Country IE had no information + * about a band. The IEEE 802.11 spec allows for an AP + * to send only a subset of the regulatory rules allowed, + * so an AP in the US that only supports 2.4 GHz may only send + * a country IE with information for the 2.4 GHz band + * while 5 GHz is still supported. + */ + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && + r == -ERANGE) + return; + + REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); + chan->flags = IEEE80211_CHAN_DISABLED; + return; + } + + chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule); + + power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; + + if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + bw_flags = IEEE80211_CHAN_NO_HT40; + + if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && + request_wiphy && request_wiphy == wiphy && + request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + /* + * This guarantees the driver's requested regulatory domain + * will always be used as a base for further regulatory + * settings + */ + chan->flags = chan->orig_flags = + map_regdom_flags(reg_rule->flags) | bw_flags; + chan->max_antenna_gain = chan->orig_mag = + (int) MBI_TO_DBI(power_rule->max_antenna_gain); + chan->max_power = chan->orig_mpwr = + (int) MBM_TO_DBM(power_rule->max_eirp); + return; + } + + chan->beacon_found = false; + chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); + chan->max_antenna_gain = min(chan->orig_mag, + (int) MBI_TO_DBI(power_rule->max_antenna_gain)); + if (chan->orig_mpwr) + chan->max_power = min(chan->orig_mpwr, + (int) MBM_TO_DBM(power_rule->max_eirp)); + else + chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); +} + +static void handle_band(struct wiphy *wiphy, + enum ieee80211_band band, + enum nl80211_reg_initiator initiator) +{ + unsigned int i; + struct ieee80211_supported_band *sband; + + BUG_ON(!wiphy->bands[band]); + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) + handle_channel(wiphy, initiator, band, i); +} + +static bool ignore_reg_update(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) +{ + if (!last_request) { + REG_DBG_PRINT("Ignoring regulatory request %s since " + "last_request is not set\n", + reg_initiator_name(initiator)); + return true; + } + + if (initiator == NL80211_REGDOM_SET_BY_CORE && + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { + REG_DBG_PRINT("Ignoring regulatory request %s " + "since the driver uses its own custom " + "regulatory domain\n", + reg_initiator_name(initiator)); + return true; + } + + /* + * wiphy->regd will be set once the device has its own + * desired regulatory domain set + */ + if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && + initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && + !is_world_regdom(last_request->alpha2)) { + REG_DBG_PRINT("Ignoring regulatory request %s " + "since the driver requires its own regulatory " + "domain to be set first\n", + reg_initiator_name(initiator)); + return true; + } + + return false; +} + +static void handle_reg_beacon(struct wiphy *wiphy, + unsigned int chan_idx, + struct reg_beacon *reg_beacon) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + bool channel_changed = false; + struct ieee80211_channel chan_before; + + assert_cfg80211_lock(); + + sband = wiphy->bands[reg_beacon->chan.band]; + chan = &sband->channels[chan_idx]; + + if (likely(chan->center_freq != reg_beacon->chan.center_freq)) + return; + + if (chan->beacon_found) + return; + + chan->beacon_found = true; + + if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) + return; + + chan_before.center_freq = chan->center_freq; + chan_before.flags = chan->flags; + + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { + chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + channel_changed = true; + } + + if (chan->flags & IEEE80211_CHAN_NO_IBSS) { + chan->flags &= ~IEEE80211_CHAN_NO_IBSS; + channel_changed = true; + } + + if (channel_changed) + nl80211_send_beacon_hint_event(wiphy, &chan_before, chan); +} + +/* + * Called when a scan on a wiphy finds a beacon on + * new channel + */ +static void wiphy_update_new_beacon(struct wiphy *wiphy, + struct reg_beacon *reg_beacon) +{ + unsigned int i; + struct ieee80211_supported_band *sband; + + assert_cfg80211_lock(); + + if (!wiphy->bands[reg_beacon->chan.band]) + return; + + sband = wiphy->bands[reg_beacon->chan.band]; + + for (i = 0; i < sband->n_channels; i++) + handle_reg_beacon(wiphy, i, reg_beacon); +} + +/* + * Called upon reg changes or a new wiphy is added + */ +static void wiphy_update_beacon_reg(struct wiphy *wiphy) +{ + unsigned int i; + struct ieee80211_supported_band *sband; + struct reg_beacon *reg_beacon; + + assert_cfg80211_lock(); + + if (list_empty(®_beacon_list)) + return; + + list_for_each_entry(reg_beacon, ®_beacon_list, list) { + if (!wiphy->bands[reg_beacon->chan.band]) + continue; + sband = wiphy->bands[reg_beacon->chan.band]; + for (i = 0; i < sband->n_channels; i++) + handle_reg_beacon(wiphy, i, reg_beacon); + } +} + +static bool reg_is_world_roaming(struct wiphy *wiphy) +{ + if (is_world_regdom(cfg80211_regdomain->alpha2) || + (wiphy->regd && is_world_regdom(wiphy->regd->alpha2))) + return true; + if (last_request && + last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) + return true; + return false; +} + +/* Reap the advantages of previously found beacons */ +static void reg_process_beacons(struct wiphy *wiphy) +{ + /* + * Means we are just firing up cfg80211, so no beacons would + * have been processed yet. + */ + if (!last_request) + return; + if (!reg_is_world_roaming(wiphy)) + return; + wiphy_update_beacon_reg(wiphy); +} + +static bool is_ht40_not_allowed(struct ieee80211_channel *chan) +{ + if (!chan) + return true; + if (chan->flags & IEEE80211_CHAN_DISABLED) + return true; + /* This would happen when regulatory rules disallow HT40 completely */ + if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40))) + return true; + return false; +} + +static void reg_process_ht_flags_channel(struct wiphy *wiphy, + enum ieee80211_band band, + unsigned int chan_idx) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *channel; + struct ieee80211_channel *channel_before = NULL, *channel_after = NULL; + unsigned int i; + + assert_cfg80211_lock(); + + sband = wiphy->bands[band]; + BUG_ON(chan_idx >= sband->n_channels); + channel = &sband->channels[chan_idx]; + + if (is_ht40_not_allowed(channel)) { + channel->flags |= IEEE80211_CHAN_NO_HT40; + return; + } + + /* + * We need to ensure the extension channels exist to + * be able to use HT40- or HT40+, this finds them (or not) + */ + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *c = &sband->channels[i]; + if (c->center_freq == (channel->center_freq - 20)) + channel_before = c; + if (c->center_freq == (channel->center_freq + 20)) + channel_after = c; + } + + /* + * Please note that this assumes target bandwidth is 20 MHz, + * if that ever changes we also need to change the below logic + * to include that as well. + */ + if (is_ht40_not_allowed(channel_before)) + channel->flags |= IEEE80211_CHAN_NO_HT40MINUS; + else + channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; + + if (is_ht40_not_allowed(channel_after)) + channel->flags |= IEEE80211_CHAN_NO_HT40PLUS; + else + channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; +} + +static void reg_process_ht_flags_band(struct wiphy *wiphy, + enum ieee80211_band band) +{ + unsigned int i; + struct ieee80211_supported_band *sband; + + BUG_ON(!wiphy->bands[band]); + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) + reg_process_ht_flags_channel(wiphy, band, i); +} + +static void reg_process_ht_flags(struct wiphy *wiphy) +{ + enum ieee80211_band band; + + if (!wiphy) + return; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (wiphy->bands[band]) + reg_process_ht_flags_band(wiphy, band); + } + +} + +static void wiphy_update_regulatory(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) +{ + enum ieee80211_band band; + + assert_reg_lock(); + + if (ignore_reg_update(wiphy, initiator)) + return; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (wiphy->bands[band]) + handle_band(wiphy, band, initiator); + } + + reg_process_beacons(wiphy); + reg_process_ht_flags(wiphy); + if (wiphy->reg_notifier) + wiphy->reg_notifier(wiphy, last_request); +} + +void regulatory_update(struct wiphy *wiphy, + enum nl80211_reg_initiator setby) +{ + mutex_lock(®_mutex); + wiphy_update_regulatory(wiphy, setby); + mutex_unlock(®_mutex); +} + +static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) +{ + struct cfg80211_registered_device *rdev; + + list_for_each_entry(rdev, &cfg80211_rdev_list, list) + wiphy_update_regulatory(&rdev->wiphy, initiator); +} + +static void handle_channel_custom(struct wiphy *wiphy, + enum ieee80211_band band, + unsigned int chan_idx, + const struct ieee80211_regdomain *regd) +{ + int r; + u32 desired_bw_khz = MHZ_TO_KHZ(20); + u32 bw_flags = 0; + const struct ieee80211_reg_rule *reg_rule = NULL; + const struct ieee80211_power_rule *power_rule = NULL; + const struct ieee80211_freq_range *freq_range = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + + assert_reg_lock(); + + sband = wiphy->bands[band]; + BUG_ON(chan_idx >= sband->n_channels); + chan = &sband->channels[chan_idx]; + + r = freq_reg_info_regd(wiphy, + MHZ_TO_KHZ(chan->center_freq), + desired_bw_khz, + ®_rule, + regd); + + if (r) { + REG_DBG_PRINT("Disabling freq %d MHz as custom " + "regd has no rule that fits a %d MHz " + "wide channel\n", + chan->center_freq, + KHZ_TO_MHZ(desired_bw_khz)); + chan->flags = IEEE80211_CHAN_DISABLED; + return; + } + + chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule); + + power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; + + if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + bw_flags = IEEE80211_CHAN_NO_HT40; + + chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; + chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); + chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); +} + +static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band, + const struct ieee80211_regdomain *regd) +{ + unsigned int i; + struct ieee80211_supported_band *sband; + + BUG_ON(!wiphy->bands[band]); + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) + handle_channel_custom(wiphy, band, i, regd); +} + +/* Used by drivers prior to wiphy registration */ +void wiphy_apply_custom_regulatory(struct wiphy *wiphy, + const struct ieee80211_regdomain *regd) +{ + enum ieee80211_band band; + unsigned int bands_set = 0; + + mutex_lock(®_mutex); + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + handle_band_custom(wiphy, band, regd); + bands_set++; + } + mutex_unlock(®_mutex); + + /* + * no point in calling this if it won't have any effect + * on your device's supportd bands. + */ + WARN_ON(!bands_set); +} +EXPORT_SYMBOL(wiphy_apply_custom_regulatory); + +/* + * Return value which can be used by ignore_request() to indicate + * it has been determined we should intersect two regulatory domains + */ +#define REG_INTERSECT 1 + +/* This has the logic which determines when a new request + * should be ignored. */ +static int ignore_request(struct wiphy *wiphy, + struct regulatory_request *pending_request) +{ + struct wiphy *last_wiphy = NULL; + + assert_cfg80211_lock(); + + /* All initial requests are respected */ + if (!last_request) + return 0; + + switch (pending_request->initiator) { + case NL80211_REGDOM_SET_BY_CORE: + return 0; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + + last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + + if (unlikely(!is_an_alpha2(pending_request->alpha2))) + return -EINVAL; + if (last_request->initiator == + NL80211_REGDOM_SET_BY_COUNTRY_IE) { + if (last_wiphy != wiphy) { + /* + * Two cards with two APs claiming different + * Country IE alpha2s. We could + * intersect them, but that seems unlikely + * to be correct. Reject second one for now. + */ + if (regdom_changes(pending_request->alpha2)) + return -EOPNOTSUPP; + return -EALREADY; + } + /* + * Two consecutive Country IE hints on the same wiphy. + * This should be picked up early by the driver/stack + */ + if (WARN_ON(regdom_changes(pending_request->alpha2))) + return 0; + return -EALREADY; + } + return 0; + case NL80211_REGDOM_SET_BY_DRIVER: + if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { + if (regdom_changes(pending_request->alpha2)) + return 0; + return -EALREADY; + } + + /* + * This would happen if you unplug and plug your card + * back in or if you add a new device for which the previously + * loaded card also agrees on the regulatory domain. + */ + if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && + !regdom_changes(pending_request->alpha2)) + return -EALREADY; + + return 0; + case NL80211_REGDOM_SET_BY_USER: + if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) + return REG_INTERSECT; + /* + * If the user knows better the user should set the regdom + * to their country before the IE is picked up + */ + if (last_request->initiator == NL80211_REGDOM_SET_BY_USER && + last_request->intersect) + return -EOPNOTSUPP; + /* + * Process user requests only after previous user/driver/core + * requests have been processed + */ + if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE || + last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || + last_request->initiator == NL80211_REGDOM_SET_BY_USER) { + if (regdom_changes(last_request->alpha2)) + return -EAGAIN; + } + + if (!regdom_changes(pending_request->alpha2)) + return -EALREADY; + + return 0; + } + + return -EINVAL; +} + +static void reg_set_request_processed(void) +{ + bool need_more_processing = false; + + last_request->processed = true; + + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list)) + need_more_processing = true; + spin_unlock(®_requests_lock); + + if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) + cancel_delayed_work_sync(®_timeout); + + if (need_more_processing) + schedule_work(®_work); +} + +/** + * __regulatory_hint - hint to the wireless core a regulatory domain + * @wiphy: if the hint comes from country information from an AP, this + * is required to be set to the wiphy that received the information + * @pending_request: the regulatory request currently being processed + * + * The Wireless subsystem can use this function to hint to the wireless core + * what it believes should be the current regulatory domain. + * + * Returns zero if all went fine, %-EALREADY if a regulatory domain had + * already been set or other standard error codes. + * + * Caller must hold &cfg80211_mutex and ®_mutex + */ +static int __regulatory_hint(struct wiphy *wiphy, + struct regulatory_request *pending_request) +{ + bool intersect = false; + int r = 0; + + assert_cfg80211_lock(); + + r = ignore_request(wiphy, pending_request); + + if (r == REG_INTERSECT) { + if (pending_request->initiator == + NL80211_REGDOM_SET_BY_DRIVER) { + r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); + if (r) { + kfree(pending_request); + return r; + } + } + intersect = true; + } else if (r) { + /* + * If the regulatory domain being requested by the + * driver has already been set just copy it to the + * wiphy + */ + if (r == -EALREADY && + pending_request->initiator == + NL80211_REGDOM_SET_BY_DRIVER) { + r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); + if (r) { + kfree(pending_request); + return r; + } + r = -EALREADY; + goto new_request; + } + kfree(pending_request); + return r; + } + +new_request: + kfree(last_request); + + last_request = pending_request; + last_request->intersect = intersect; + + pending_request = NULL; + + if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) { + user_alpha2[0] = last_request->alpha2[0]; + user_alpha2[1] = last_request->alpha2[1]; + } + + /* When r == REG_INTERSECT we do need to call CRDA */ + if (r < 0) { + /* + * Since CRDA will not be called in this case as we already + * have applied the requested regulatory domain before we just + * inform userspace we have processed the request + */ + if (r == -EALREADY) { + nl80211_send_reg_change_event(last_request); + reg_set_request_processed(); + } + return r; + } + + return call_crda(last_request->alpha2); +} + +/* This processes *all* regulatory hints */ +static void reg_process_hint(struct regulatory_request *reg_request) +{ + int r = 0; + struct wiphy *wiphy = NULL; + enum nl80211_reg_initiator initiator = reg_request->initiator; + + BUG_ON(!reg_request->alpha2); + + if (wiphy_idx_valid(reg_request->wiphy_idx)) + wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); + + if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && + !wiphy) { + kfree(reg_request); + return; + } + + r = __regulatory_hint(wiphy, reg_request); + /* This is required so that the orig_* parameters are saved */ + if (r == -EALREADY && wiphy && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + wiphy_update_regulatory(wiphy, initiator); + return; + } + + /* + * We only time out user hints, given that they should be the only + * source of bogus requests. + */ + if (r != -EALREADY && + reg_request->initiator == NL80211_REGDOM_SET_BY_USER) + schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); +} + +/* + * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* + * Regulatory hints come on a first come first serve basis and we + * must process each one atomically. + */ +static void reg_process_pending_hints(void) +{ + struct regulatory_request *reg_request; + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + /* When last_request->processed becomes true this will be rescheduled */ + if (last_request && !last_request->processed) { + REG_DBG_PRINT("Pending regulatory request, waiting " + "for it to be processed...\n"); + goto out; + } + + spin_lock(®_requests_lock); + + if (list_empty(®_requests_list)) { + spin_unlock(®_requests_lock); + goto out; + } + + reg_request = list_first_entry(®_requests_list, + struct regulatory_request, + list); + list_del_init(®_request->list); + + spin_unlock(®_requests_lock); + + reg_process_hint(reg_request); + +out: + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); +} + +/* Processes beacon hints -- this has nothing to do with country IEs */ +static void reg_process_pending_beacon_hints(void) +{ + struct cfg80211_registered_device *rdev; + struct reg_beacon *pending_beacon, *tmp; + + /* + * No need to hold the reg_mutex here as we just touch wiphys + * and do not read or access regulatory variables. + */ + mutex_lock(&cfg80211_mutex); + + /* This goes through the _pending_ beacon list */ + spin_lock_bh(®_pending_beacons_lock); + + if (list_empty(®_pending_beacons)) { + spin_unlock_bh(®_pending_beacons_lock); + goto out; + } + + list_for_each_entry_safe(pending_beacon, tmp, + ®_pending_beacons, list) { + + list_del_init(&pending_beacon->list); + + /* Applies the beacon hint to current wiphys */ + list_for_each_entry(rdev, &cfg80211_rdev_list, list) + wiphy_update_new_beacon(&rdev->wiphy, pending_beacon); + + /* Remembers the beacon hint for new wiphys or reg changes */ + list_add_tail(&pending_beacon->list, ®_beacon_list); + } + + spin_unlock_bh(®_pending_beacons_lock); +out: + mutex_unlock(&cfg80211_mutex); +} + +static void reg_todo(struct work_struct *work) +{ + reg_process_pending_hints(); + reg_process_pending_beacon_hints(); +} + +static void queue_regulatory_request(struct regulatory_request *request) +{ + if (isalpha(request->alpha2[0])) + request->alpha2[0] = toupper(request->alpha2[0]); + if (isalpha(request->alpha2[1])) + request->alpha2[1] = toupper(request->alpha2[1]); + + spin_lock(®_requests_lock); + list_add_tail(&request->list, ®_requests_list); + spin_unlock(®_requests_lock); + + schedule_work(®_work); +} + +/* + * Core regulatory hint -- happens during cfg80211_init() + * and when we restore regulatory settings. + */ +static int regulatory_hint_core(const char *alpha2) +{ + struct regulatory_request *request; + + kfree(last_request); + last_request = NULL; + + request = kzalloc(sizeof(struct regulatory_request), + GFP_KERNEL); + if (!request) + return -ENOMEM; + + request->alpha2[0] = alpha2[0]; + request->alpha2[1] = alpha2[1]; + request->initiator = NL80211_REGDOM_SET_BY_CORE; + + queue_regulatory_request(request); + + return 0; +} + +/* User hints */ +int regulatory_hint_user(const char *alpha2) +{ + struct regulatory_request *request; + + BUG_ON(!alpha2); + + request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); + if (!request) + return -ENOMEM; + + request->wiphy_idx = WIPHY_IDX_STALE; + request->alpha2[0] = alpha2[0]; + request->alpha2[1] = alpha2[1]; + request->initiator = NL80211_REGDOM_SET_BY_USER; + + queue_regulatory_request(request); + + return 0; +} + +/* Driver hints */ +int regulatory_hint(struct wiphy *wiphy, const char *alpha2) +{ + struct regulatory_request *request; + + BUG_ON(!alpha2); + BUG_ON(!wiphy); + + request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); + if (!request) + return -ENOMEM; + + request->wiphy_idx = get_wiphy_idx(wiphy); + + /* Must have registered wiphy first */ + BUG_ON(!wiphy_idx_valid(request->wiphy_idx)); + + request->alpha2[0] = alpha2[0]; + request->alpha2[1] = alpha2[1]; + request->initiator = NL80211_REGDOM_SET_BY_DRIVER; + + queue_regulatory_request(request); + + return 0; +} +EXPORT_SYMBOL(regulatory_hint); + +/* + * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and + * therefore cannot iterate over the rdev list here. + */ +void regulatory_hint_11d(struct wiphy *wiphy, + enum ieee80211_band band, + u8 *country_ie, + u8 country_ie_len) +{ + char alpha2[2]; + enum environment_cap env = ENVIRON_ANY; + struct regulatory_request *request; + + mutex_lock(®_mutex); + + if (unlikely(!last_request)) + goto out; + + /* IE len must be evenly divisible by 2 */ + if (country_ie_len & 0x01) + goto out; + + if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) + goto out; + + alpha2[0] = country_ie[0]; + alpha2[1] = country_ie[1]; + + if (country_ie[2] == 'I') + env = ENVIRON_INDOOR; + else if (country_ie[2] == 'O') + env = ENVIRON_OUTDOOR; + + /* + * We will run this only upon a successful connection on cfg80211. + * We leave conflict resolution to the workqueue, where can hold + * cfg80211_mutex. + */ + if (likely(last_request->initiator == + NL80211_REGDOM_SET_BY_COUNTRY_IE && + wiphy_idx_valid(last_request->wiphy_idx))) + goto out; + + request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); + if (!request) + goto out; + + request->wiphy_idx = get_wiphy_idx(wiphy); + request->alpha2[0] = alpha2[0]; + request->alpha2[1] = alpha2[1]; + request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; + request->country_ie_env = env; + + mutex_unlock(®_mutex); + + queue_regulatory_request(request); + + return; + +out: + mutex_unlock(®_mutex); +} + +static void restore_alpha2(char *alpha2, bool reset_user) +{ + /* indicates there is no alpha2 to consider for restoration */ + alpha2[0] = '9'; + alpha2[1] = '7'; + + /* The user setting has precedence over the module parameter */ + if (is_user_regdom_saved()) { + /* Unless we're asked to ignore it and reset it */ + if (reset_user) { + REG_DBG_PRINT("Restoring regulatory settings " + "including user preference\n"); + user_alpha2[0] = '9'; + user_alpha2[1] = '7'; + + /* + * If we're ignoring user settings, we still need to + * check the module parameter to ensure we put things + * back as they were for a full restore. + */ + if (!is_world_regdom(ieee80211_regdom)) { + REG_DBG_PRINT("Keeping preference on " + "module parameter ieee80211_regdom: %c%c\n", + ieee80211_regdom[0], + ieee80211_regdom[1]); + alpha2[0] = ieee80211_regdom[0]; + alpha2[1] = ieee80211_regdom[1]; + } + } else { + REG_DBG_PRINT("Restoring regulatory settings " + "while preserving user preference for: %c%c\n", + user_alpha2[0], + user_alpha2[1]); + alpha2[0] = user_alpha2[0]; + alpha2[1] = user_alpha2[1]; + } + } else if (!is_world_regdom(ieee80211_regdom)) { + REG_DBG_PRINT("Keeping preference on " + "module parameter ieee80211_regdom: %c%c\n", + ieee80211_regdom[0], + ieee80211_regdom[1]); + alpha2[0] = ieee80211_regdom[0]; + alpha2[1] = ieee80211_regdom[1]; + } else + REG_DBG_PRINT("Restoring regulatory settings\n"); +} + +/* + * Restoring regulatory settings involves ingoring any + * possibly stale country IE information and user regulatory + * settings if so desired, this includes any beacon hints + * learned as we could have traveled outside to another country + * after disconnection. To restore regulatory settings we do + * exactly what we did at bootup: + * + * - send a core regulatory hint + * - send a user regulatory hint if applicable + * + * Device drivers that send a regulatory hint for a specific country + * keep their own regulatory domain on wiphy->regd so that does does + * not need to be remembered. + */ +static void restore_regulatory_settings(bool reset_user) +{ + char alpha2[2]; + struct reg_beacon *reg_beacon, *btmp; + struct regulatory_request *reg_request, *tmp; + LIST_HEAD(tmp_reg_req_list); + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + reset_regdomains(); + restore_alpha2(alpha2, reset_user); + + /* + * If there's any pending requests we simply + * stash them to a temporary pending queue and + * add then after we've restored regulatory + * settings. + */ + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list)) { + list_for_each_entry_safe(reg_request, tmp, + ®_requests_list, list) { + if (reg_request->initiator != + NL80211_REGDOM_SET_BY_USER) + continue; + list_del(®_request->list); + list_add_tail(®_request->list, &tmp_reg_req_list); + } + } + spin_unlock(®_requests_lock); + + /* Clear beacon hints */ + spin_lock_bh(®_pending_beacons_lock); + if (!list_empty(®_pending_beacons)) { + list_for_each_entry_safe(reg_beacon, btmp, + ®_pending_beacons, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + } + spin_unlock_bh(®_pending_beacons_lock); + + if (!list_empty(®_beacon_list)) { + list_for_each_entry_safe(reg_beacon, btmp, + ®_beacon_list, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + } + + /* First restore to the basic regulatory settings */ + cfg80211_regdomain = cfg80211_world_regdom; + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); + + regulatory_hint_core(cfg80211_regdomain->alpha2); + + /* + * This restores the ieee80211_regdom module parameter + * preference or the last user requested regulatory + * settings, user regulatory settings takes precedence. + */ + if (is_an_alpha2(alpha2)) + regulatory_hint_user(user_alpha2); + + if (list_empty(&tmp_reg_req_list)) + return; + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + spin_lock(®_requests_lock); + list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) { + REG_DBG_PRINT("Adding request for country %c%c back " + "into the queue\n", + reg_request->alpha2[0], + reg_request->alpha2[1]); + list_del(®_request->list); + list_add_tail(®_request->list, ®_requests_list); + } + spin_unlock(®_requests_lock); + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); + + REG_DBG_PRINT("Kicking the queue\n"); + + schedule_work(®_work); +} + +void regulatory_hint_disconnect(void) +{ + REG_DBG_PRINT("All devices are disconnected, going to " + "restore regulatory settings\n"); + restore_regulatory_settings(false); +} + +static bool freq_is_chan_12_13_14(u16 freq) +{ + if (freq == ieee80211_channel_to_frequency(12, IEEE80211_BAND_2GHZ) || + freq == ieee80211_channel_to_frequency(13, IEEE80211_BAND_2GHZ) || + freq == ieee80211_channel_to_frequency(14, IEEE80211_BAND_2GHZ)) + return true; + return false; +} + +int regulatory_hint_found_beacon(struct wiphy *wiphy, + struct ieee80211_channel *beacon_chan, + gfp_t gfp) +{ + struct reg_beacon *reg_beacon; + + if (likely((beacon_chan->beacon_found || + (beacon_chan->flags & IEEE80211_CHAN_RADAR) || + (beacon_chan->band == IEEE80211_BAND_2GHZ && + !freq_is_chan_12_13_14(beacon_chan->center_freq))))) + return 0; + + reg_beacon = kzalloc(sizeof(struct reg_beacon), gfp); + if (!reg_beacon) + return -ENOMEM; + + REG_DBG_PRINT("Found new beacon on " + "frequency: %d MHz (Ch %d) on %s\n", + beacon_chan->center_freq, + ieee80211_frequency_to_channel(beacon_chan->center_freq), + wiphy_name(wiphy)); + + memcpy(®_beacon->chan, beacon_chan, + sizeof(struct ieee80211_channel)); + + + /* + * Since we can be called from BH or and non-BH context + * we must use spin_lock_bh() + */ + spin_lock_bh(®_pending_beacons_lock); + list_add_tail(®_beacon->list, ®_pending_beacons); + spin_unlock_bh(®_pending_beacons_lock); + + schedule_work(®_work); + + return 0; +} + +static void print_rd_rules(const struct ieee80211_regdomain *rd) +{ + unsigned int i; + const struct ieee80211_reg_rule *reg_rule = NULL; + const struct ieee80211_freq_range *freq_range = NULL; + const struct ieee80211_power_rule *power_rule = NULL; + + pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); + + for (i = 0; i < rd->n_reg_rules; i++) { + reg_rule = &rd->reg_rules[i]; + freq_range = ®_rule->freq_range; + power_rule = ®_rule->power_rule; + + /* + * There may not be documentation for max antenna gain + * in certain regions + */ + if (power_rule->max_antenna_gain) + pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", + freq_range->start_freq_khz, + freq_range->end_freq_khz, + freq_range->max_bandwidth_khz, + power_rule->max_antenna_gain, + power_rule->max_eirp); + else + pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", + freq_range->start_freq_khz, + freq_range->end_freq_khz, + freq_range->max_bandwidth_khz, + power_rule->max_eirp); + } +} + +static void print_regdomain(const struct ieee80211_regdomain *rd) +{ + + if (is_intersected_alpha2(rd->alpha2)) { + + if (last_request->initiator == + NL80211_REGDOM_SET_BY_COUNTRY_IE) { + struct cfg80211_registered_device *rdev; + rdev = cfg80211_rdev_by_wiphy_idx( + last_request->wiphy_idx); + if (rdev) { + pr_info("Current regulatory domain updated by AP to: %c%c\n", + rdev->country_ie_alpha2[0], + rdev->country_ie_alpha2[1]); + } else + pr_info("Current regulatory domain intersected:\n"); + } else + pr_info("Current regulatory domain intersected:\n"); + } else if (is_world_regdom(rd->alpha2)) + pr_info("World regulatory domain updated:\n"); + else { + if (is_unknown_alpha2(rd->alpha2)) + pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); + else + pr_info("Regulatory domain changed to country: %c%c\n", + rd->alpha2[0], rd->alpha2[1]); + } + print_rd_rules(rd); +} + +static void print_regdomain_info(const struct ieee80211_regdomain *rd) +{ + pr_info("Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]); + print_rd_rules(rd); +} + +/* Takes ownership of rd only if it doesn't fail */ +static int __set_regdom(const struct ieee80211_regdomain *rd) +{ + const struct ieee80211_regdomain *intersected_rd = NULL; + struct cfg80211_registered_device *rdev = NULL; + struct wiphy *request_wiphy; + /* Some basic sanity checks first */ + + if (is_world_regdom(rd->alpha2)) { + if (WARN_ON(!reg_is_valid_request(rd->alpha2))) + return -EINVAL; + update_world_regdomain(rd); + return 0; + } + + if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && + !is_unknown_alpha2(rd->alpha2)) + return -EINVAL; + + if (!last_request) + return -EINVAL; + + /* + * Lets only bother proceeding on the same alpha2 if the current + * rd is non static (it means CRDA was present and was used last) + * and the pending request came in from a country IE + */ + if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + /* + * If someone else asked us to change the rd lets only bother + * checking if the alpha2 changes if CRDA was already called + */ + if (!regdom_changes(rd->alpha2)) + return -EALREADY; + } + + /* + * Now lets set the regulatory domain, update all driver channels + * and finally inform them of what we have done, in case they want + * to review or adjust their own settings based on their own + * internal EEPROM data + */ + + if (WARN_ON(!reg_is_valid_request(rd->alpha2))) + return -EINVAL; + + if (!is_valid_rd(rd)) { + pr_err("Invalid regulatory domain detected:\n"); + print_regdomain_info(rd); + return -EINVAL; + } + + request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + + if (!last_request->intersect) { + int r; + + if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { + reset_regdomains(); + cfg80211_regdomain = rd; + return 0; + } + + /* + * For a driver hint, lets copy the regulatory domain the + * driver wanted to the wiphy to deal with conflicts + */ + + r = reg_copy_regd(&request_wiphy->regd, rd); + if (r) + return r; + + reset_regdomains(); + cfg80211_regdomain = rd; + return 0; + } + + /* Intersection requires a bit more work */ + + if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + + intersected_rd = regdom_intersect(rd, cfg80211_regdomain); + if (!intersected_rd) + return -EINVAL; + + /* + * We can trash what CRDA provided now. + * However if a driver requested this specific regulatory + * domain we keep it for its private use + */ + if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) + request_wiphy->regd = rd; + else + kfree(rd); + + rd = NULL; + + reset_regdomains(); + cfg80211_regdomain = intersected_rd; + + return 0; + } + + if (!intersected_rd) + return -EINVAL; + + rdev = wiphy_to_dev(request_wiphy); + + rdev->country_ie_alpha2[0] = rd->alpha2[0]; + rdev->country_ie_alpha2[1] = rd->alpha2[1]; + rdev->env = last_request->country_ie_env; + + BUG_ON(intersected_rd == rd); + + kfree(rd); + rd = NULL; + + reset_regdomains(); + cfg80211_regdomain = intersected_rd; + + return 0; +} + + +/* + * Use this call to set the current regulatory domain. Conflicts with + * multiple drivers can be ironed out later. Caller must've already + * kmalloc'd the rd structure. Caller must hold cfg80211_mutex + */ +int set_regdom(const struct ieee80211_regdomain *rd) +{ + int r; + + assert_cfg80211_lock(); + + mutex_lock(®_mutex); + + /* Note that this doesn't update the wiphys, this is done below */ + r = __set_regdom(rd); + if (r) { + if (r == -EALREADY) + reg_set_request_processed(); + + kfree(rd); + mutex_unlock(®_mutex); + return r; + } + + /* This would make this whole thing pointless */ + if (!last_request->intersect) + BUG_ON(rd != cfg80211_regdomain); + + /* update all wiphys now with the new established regulatory domain */ + update_all_wiphy_regulatory(last_request->initiator); + + print_regdomain(cfg80211_regdomain); + + nl80211_send_reg_change_event(last_request); + + reg_set_request_processed(); + + mutex_unlock(®_mutex); + + return r; +} + +#ifdef CONFIG_HOTPLUG +int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + if (last_request && !last_request->processed) { + if (add_uevent_var(env, "COUNTRY=%c%c", + last_request->alpha2[0], + last_request->alpha2[1])) + return -ENOMEM; + } + + return 0; +} +#else +int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + return -ENODEV; +} +#endif /* CONFIG_HOTPLUG */ + +/* Caller must hold cfg80211_mutex */ +void reg_device_remove(struct wiphy *wiphy) +{ + struct wiphy *request_wiphy = NULL; + + assert_cfg80211_lock(); + + mutex_lock(®_mutex); + + kfree(wiphy->regd); + + if (last_request) + request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + + if (!request_wiphy || request_wiphy != wiphy) + goto out; + + last_request->wiphy_idx = WIPHY_IDX_STALE; + last_request->country_ie_env = ENVIRON_ANY; +out: + mutex_unlock(®_mutex); +} + +static void reg_timeout_work(struct work_struct *work) +{ + REG_DBG_PRINT("Timeout while waiting for CRDA to reply, " + "restoring regulatory settings\n"); + restore_regulatory_settings(true); +} + +int __init regulatory_init(void) +{ + int err = 0; + + reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); + if (IS_ERR(reg_pdev)) + return PTR_ERR(reg_pdev); + + reg_pdev->dev.type = ®_device_type; + + spin_lock_init(®_requests_lock); + spin_lock_init(®_pending_beacons_lock); + + cfg80211_regdomain = cfg80211_world_regdom; + + user_alpha2[0] = '9'; + user_alpha2[1] = '7'; + + /* We always try to get an update for the static regdomain */ + err = regulatory_hint_core(cfg80211_regdomain->alpha2); + if (err) { + if (err == -ENOMEM) + return err; + /* + * N.B. kobject_uevent_env() can fail mainly for when we're out + * memory which is handled and propagated appropriately above + * but it can also fail during a netlink_broadcast() or during + * early boot for call_usermodehelper(). For now treat these + * errors as non-fatal. + */ + pr_err("kobject_uevent_env() was unable to call CRDA during init\n"); +#ifdef CONFIG_CFG80211_REG_DEBUG + /* We want to find out exactly why when debugging */ + WARN_ON(err); +#endif + } + + /* + * Finally, if the user set the module parameter treat it + * as a user hint. + */ + if (!is_world_regdom(ieee80211_regdom)) + regulatory_hint_user(ieee80211_regdom); + + return 0; +} + +void /* __init_or_exit */ regulatory_exit(void) +{ + struct regulatory_request *reg_request, *tmp; + struct reg_beacon *reg_beacon, *btmp; + + cancel_work_sync(®_work); + cancel_delayed_work_sync(®_timeout); + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + reset_regdomains(); + + kfree(last_request); + + last_request = NULL; + dev_set_uevent_suppress(®_pdev->dev, true); + + platform_device_unregister(reg_pdev); + + spin_lock_bh(®_pending_beacons_lock); + if (!list_empty(®_pending_beacons)) { + list_for_each_entry_safe(reg_beacon, btmp, + ®_pending_beacons, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + } + spin_unlock_bh(®_pending_beacons_lock); + + if (!list_empty(®_beacon_list)) { + list_for_each_entry_safe(reg_beacon, btmp, + ®_beacon_list, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + } + + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list)) { + list_for_each_entry_safe(reg_request, tmp, + ®_requests_list, list) { + list_del(®_request->list); + kfree(reg_request); + } + } + spin_unlock(®_requests_lock); + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); +} diff --git a/net/wireless_ath/reg.h b/net/wireless_ath/reg.h new file mode 100644 index 00000000..4a56799d --- /dev/null +++ b/net/wireless_ath/reg.h @@ -0,0 +1,87 @@ +#ifndef __NET_WIRELESS_REG_H +#define __NET_WIRELESS_REG_H + +extern const struct ieee80211_regdomain *cfg80211_regdomain; + +bool is_world_regdom(const char *alpha2); +bool reg_is_valid_request(const char *alpha2); + +int regulatory_hint_user(const char *alpha2); + +int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env); +void reg_device_remove(struct wiphy *wiphy); + +int __init regulatory_init(void); +void regulatory_exit(void); + +int set_regdom(const struct ieee80211_regdomain *rd); + +void regulatory_update(struct wiphy *wiphy, enum nl80211_reg_initiator setby); + +/** + * regulatory_hint_found_beacon - hints a beacon was found on a channel + * @wiphy: the wireless device where the beacon was found on + * @beacon_chan: the channel on which the beacon was found on + * @gfp: context flags + * + * This informs the wireless core that a beacon from an AP was found on + * the channel provided. This allows the wireless core to make educated + * guesses on regulatory to help with world roaming. This is only used for + * world roaming -- when we do not know our current location. This is + * only useful on channels 12, 13 and 14 on the 2 GHz band as channels + * 1-11 are already enabled by the world regulatory domain; and on + * non-radar 5 GHz channels. + * + * Drivers do not need to call this, cfg80211 will do it for after a scan + * on a newly found BSS. If you cannot make use of this feature you can + * set the wiphy->disable_beacon_hints to true. + */ +int regulatory_hint_found_beacon(struct wiphy *wiphy, + struct ieee80211_channel *beacon_chan, + gfp_t gfp); + +/** + * regulatory_hint_11d - hints a country IE as a regulatory domain + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) + * @band: the band on which the country IE was received on. This determines + * the band we'll process the country IE channel triplets for. + * @country_ie: pointer to the country IE + * @country_ie_len: length of the country IE + * + * We will intersect the rd with the what CRDA tells us should apply + * for the alpha2 this country IE belongs to, this prevents APs from + * sending us incorrect or outdated information against a country. + * + * The AP is expected to provide Country IE channel triplets for the + * band it is on. It is technically possible for APs to send channel + * country IE triplets even for channels outside of the band they are + * in but for that they would have to use the regulatory extension + * in combination with a triplet but this behaviour is currently + * not observed. For this reason if a triplet is seen with channel + * information for a band the BSS is not present in it will be ignored. + */ +void regulatory_hint_11d(struct wiphy *wiphy, + enum ieee80211_band band, + u8 *country_ie, + u8 country_ie_len); + +/** + * regulatory_hint_disconnect - informs all devices have been disconneted + * + * Regulotory rules can be enhanced further upon scanning and upon + * connection to an AP. These rules become stale if we disconnect + * and go to another country, whether or not we suspend and resume. + * If we suspend, go to another country and resume we'll automatically + * get disconnected shortly after resuming and things will be reset as well. + * This routine is a helper to restore regulatory settings to how they were + * prior to our first connect attempt. This includes ignoring country IE and + * beacon regulatory hints. The ieee80211_regdom module parameter will always + * be respected but if a user had set the regulatory domain that will take + * precedence. + * + * Must be called from process context. + */ +void regulatory_hint_disconnect(void); + +#endif /* __NET_WIRELESS_REG_H */ diff --git a/net/wireless_ath/regdb.h b/net/wireless_ath/regdb.h new file mode 100644 index 00000000..818222c9 --- /dev/null +++ b/net/wireless_ath/regdb.h @@ -0,0 +1,7 @@ +#ifndef __REGDB_H__ +#define __REGDB_H__ + +extern const struct ieee80211_regdomain *reg_regdb[]; +extern int reg_regdb_size; + +#endif /* __REGDB_H__ */ diff --git a/net/wireless_ath/scan.c b/net/wireless_ath/scan.c new file mode 100644 index 00000000..c0beb650 --- /dev/null +++ b/net/wireless_ath/scan.c @@ -0,0 +1,1352 @@ +/* + * cfg80211 scan result handling + * + * Copyright 2008 Johannes Berg + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "nl80211.h" +#include "wext-compat.h" + +#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) + +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) +{ + struct cfg80211_scan_request *request; + struct net_device *dev; +#ifdef CONFIG_CFG80211_WEXT + union iwreq_data wrqu; +#endif + + ASSERT_RDEV_LOCK(rdev); + + request = rdev->scan_req; + + if (!request) + return; + + dev = request->dev; + + /* + * This must be before sending the other events! + * Otherwise, wpa_supplicant gets completely confused with + * wext events. + */ + cfg80211_sme_scan_done(dev); + + if (request->aborted) + nl80211_send_scan_aborted(rdev, dev); + else + nl80211_send_scan_done(rdev, dev); + +#ifdef CONFIG_CFG80211_WEXT + if (!request->aborted) { + memset(&wrqu, 0, sizeof(wrqu)); + + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + } +#endif + + dev_put(dev); + + rdev->scan_req = NULL; + + /* + * OK. If this is invoked with "leak" then we can't + * free this ... but we've cleaned it up anyway. The + * driver failed to call the scan_done callback, so + * all bets are off, it might still be trying to use + * the scan request or not ... if it accesses the dev + * in there (it shouldn't anyway) then it may crash. + */ + if (!leak) + kfree(request); +} + +void __cfg80211_scan_done(struct work_struct *wk) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(wk, struct cfg80211_registered_device, + scan_done_wk); + + cfg80211_lock_rdev(rdev); + ___cfg80211_scan_done(rdev, false); + cfg80211_unlock_rdev(rdev); +} + +void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) +{ + WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); + + request->aborted = aborted; + queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); +} +EXPORT_SYMBOL(cfg80211_scan_done); + +void __cfg80211_sched_scan_results(struct work_struct *wk) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(wk, struct cfg80211_registered_device, + sched_scan_results_wk); + + mutex_lock(&rdev->sched_scan_mtx); + + /* we don't have sched_scan_req anymore if the scan is stopping */ + if (rdev->sched_scan_req) + nl80211_send_sched_scan_results(rdev, + rdev->sched_scan_req->dev); + + mutex_unlock(&rdev->sched_scan_mtx); +} + +void cfg80211_sched_scan_results(struct wiphy *wiphy) +{ + /* ignore if we're not scanning */ + if (wiphy_to_dev(wiphy)->sched_scan_req) + queue_work(cfg80211_wq, + &wiphy_to_dev(wiphy)->sched_scan_results_wk); +} +EXPORT_SYMBOL(cfg80211_sched_scan_results); + +void cfg80211_sched_scan_stopped(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + mutex_lock(&rdev->sched_scan_mtx); + __cfg80211_stop_sched_scan(rdev, true); + mutex_unlock(&rdev->sched_scan_mtx); +} +EXPORT_SYMBOL(cfg80211_sched_scan_stopped); + +int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, + bool driver_initiated) +{ + struct net_device *dev; + + lockdep_assert_held(&rdev->sched_scan_mtx); + + if (!rdev->sched_scan_req) + return -ENOENT; + + dev = rdev->sched_scan_req->dev; + + if (!driver_initiated) { + int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); + if (err) + return err; + } + + nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); + + kfree(rdev->sched_scan_req); + rdev->sched_scan_req = NULL; + + return 0; +} + +static void bss_release(struct kref *ref) +{ + struct cfg80211_internal_bss *bss; + + bss = container_of(ref, struct cfg80211_internal_bss, ref); + if (bss->pub.free_priv) + bss->pub.free_priv(&bss->pub); + + if (bss->beacon_ies_allocated) + kfree(bss->pub.beacon_ies); + if (bss->proberesp_ies_allocated) + kfree(bss->pub.proberesp_ies); + + BUG_ON(atomic_read(&bss->hold)); + + kfree(bss); +} + +/* must hold dev->bss_lock! */ +void cfg80211_bss_age(struct cfg80211_registered_device *dev, + unsigned long age_secs) +{ + struct cfg80211_internal_bss *bss; + unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); + + list_for_each_entry(bss, &dev->bss_list, list) { + bss->ts -= age_jiffies; + } +} + +/* must hold dev->bss_lock! */ +static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, + struct cfg80211_internal_bss *bss) +{ + list_del_init(&bss->list); + rb_erase(&bss->rbn, &dev->bss_tree); + kref_put(&bss->ref, bss_release); +} + +/* must hold dev->bss_lock! */ +void cfg80211_bss_expire(struct cfg80211_registered_device *dev) +{ + struct cfg80211_internal_bss *bss, *tmp; + bool expired = false; + + list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { + if (atomic_read(&bss->hold)) + continue; + if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) + continue; + __cfg80211_unlink_bss(dev, bss); + expired = true; + } + + if (expired) + dev->bss_generation++; +} + +const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) +{ + while (len > 2 && ies[0] != eid) { + len -= ies[1] + 2; + ies += ies[1] + 2; + } + if (len < 2) + return NULL; + if (len < 2 + ies[1]) + return NULL; + return ies; +} +EXPORT_SYMBOL(cfg80211_find_ie); + +const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, + const u8 *ies, int len) +{ + struct ieee80211_vendor_ie *ie; + const u8 *pos = ies, *end = ies + len; + int ie_oui; + + while (pos < end) { + pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos, + end - pos); + if (!pos) + return NULL; + + if (end - pos < sizeof(*ie)) + return NULL; + + ie = (struct ieee80211_vendor_ie *)pos; + ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; + if (ie_oui == oui && ie->oui_type == oui_type) + return pos; + + pos += 2 + ie->len; + } + return NULL; +} +EXPORT_SYMBOL(cfg80211_find_vendor_ie); + +static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) +{ + const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); + const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); + + /* equal if both missing */ + if (!ie1 && !ie2) + return 0; + /* sort missing IE before (left of) present IE */ + if (!ie1) + return -1; + if (!ie2) + return 1; + + /* sort by length first, then by contents */ + if (ie1[1] != ie2[1]) + return ie2[1] - ie1[1]; + return memcmp(ie1 + 2, ie2 + 2, ie1[1]); +} + +static bool is_bss(struct cfg80211_bss *a, + const u8 *bssid, + const u8 *ssid, size_t ssid_len) +{ + const u8 *ssidie; + + if (bssid && compare_ether_addr(a->bssid, bssid)) + return false; + + if (!ssid) + return true; + + ssidie = cfg80211_find_ie(WLAN_EID_SSID, + a->information_elements, + a->len_information_elements); + if (!ssidie) + return false; + if (ssidie[1] != ssid_len) + return false; + return memcmp(ssidie + 2, ssid, ssid_len) == 0; +} + +static bool is_mesh_bss(struct cfg80211_bss *a) +{ + const u8 *ie; + + if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_ID, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + + return true; +} + +static bool is_mesh(struct cfg80211_bss *a, + const u8 *meshid, size_t meshidlen, + const u8 *meshcfg) +{ + const u8 *ie; + + if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_ID, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + if (ie[1] != meshidlen) + return false; + if (memcmp(ie + 2, meshid, meshidlen)) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) + return false; + + /* + * Ignore mesh capability (last two bytes of the IE) when + * comparing since that may differ between stations taking + * part in the same mesh. + */ + return memcmp(ie + 2, meshcfg, + sizeof(struct ieee80211_meshconf_ie) - 2) == 0; +} + +static int cmp_bss_core(struct cfg80211_bss *a, + struct cfg80211_bss *b) +{ + int r; + + if (a->channel != b->channel) + return b->channel->center_freq - a->channel->center_freq; + + if (is_mesh_bss(a) && is_mesh_bss(b)) { + r = cmp_ies(WLAN_EID_MESH_ID, + a->information_elements, + a->len_information_elements, + b->information_elements, + b->len_information_elements); + if (r) + return r; + return cmp_ies(WLAN_EID_MESH_CONFIG, + a->information_elements, + a->len_information_elements, + b->information_elements, + b->len_information_elements); + } + + return memcmp(a->bssid, b->bssid, ETH_ALEN); +} + +static int cmp_bss(struct cfg80211_bss *a, + struct cfg80211_bss *b) +{ + int r; + + r = cmp_bss_core(a, b); + if (r) + return r; + + return cmp_ies(WLAN_EID_SSID, + a->information_elements, + a->len_information_elements, + b->information_elements, + b->len_information_elements); +} + +static int cmp_hidden_bss(struct cfg80211_bss *a, + struct cfg80211_bss *b) +{ + const u8 *ie1; + const u8 *ie2; + int i; + int r; + + r = cmp_bss_core(a, b); + if (r) + return r; + + ie1 = cfg80211_find_ie(WLAN_EID_SSID, + a->information_elements, + a->len_information_elements); + ie2 = cfg80211_find_ie(WLAN_EID_SSID, + b->information_elements, + b->len_information_elements); + + /* Key comparator must use same algorithm in any rb-tree + * search function (order is important), otherwise ordering + * of items in the tree is broken and search gives incorrect + * results. This code uses same order as cmp_ies() does. */ + + /* sort missing IE before (left of) present IE */ + if (!ie1) + return -1; + if (!ie2) + return 1; + + /* zero-size SSID is used as an indication of the hidden bss */ + if (!ie2[1]) + return 0; + + /* sort by length first, then by contents */ + if (ie1[1] != ie2[1]) + return ie2[1] - ie1[1]; + + /* zeroed SSID ie is another indication of a hidden bss */ + for (i = 0; i < ie2[1]; i++) + if (ie2[i + 2]) + return -1; + + return 0; +} + +struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len, + u16 capa_mask, u16 capa_val) +{ + struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_internal_bss *bss, *res = NULL; + unsigned long now = jiffies; + + spin_lock_bh(&dev->bss_lock); + + list_for_each_entry(bss, &dev->bss_list, list) { + if ((bss->pub.capability & capa_mask) != capa_val) + continue; + if (channel && bss->pub.channel != channel) + continue; + /* Don't get expired BSS structs */ + if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) && + !atomic_read(&bss->hold)) + continue; + if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { + res = bss; + kref_get(&res->ref); + break; + } + } + + spin_unlock_bh(&dev->bss_lock); + if (!res) + return NULL; + return &res->pub; +} +EXPORT_SYMBOL(cfg80211_get_bss); + +struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *meshid, size_t meshidlen, + const u8 *meshcfg) +{ + struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_internal_bss *bss, *res = NULL; + + spin_lock_bh(&dev->bss_lock); + + list_for_each_entry(bss, &dev->bss_list, list) { + if (channel && bss->pub.channel != channel) + continue; + if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) { + res = bss; + kref_get(&res->ref); + break; + } + } + + spin_unlock_bh(&dev->bss_lock); + if (!res) + return NULL; + return &res->pub; +} +EXPORT_SYMBOL(cfg80211_get_mesh); + + +static void rb_insert_bss(struct cfg80211_registered_device *dev, + struct cfg80211_internal_bss *bss) +{ + struct rb_node **p = &dev->bss_tree.rb_node; + struct rb_node *parent = NULL; + struct cfg80211_internal_bss *tbss; + int cmp; + + while (*p) { + parent = *p; + tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn); + + cmp = cmp_bss(&bss->pub, &tbss->pub); + + if (WARN_ON(!cmp)) { + /* will sort of leak this BSS */ + return; + } + + if (cmp < 0) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&bss->rbn, parent, p); + rb_insert_color(&bss->rbn, &dev->bss_tree); +} + +static struct cfg80211_internal_bss * +rb_find_bss(struct cfg80211_registered_device *dev, + struct cfg80211_internal_bss *res) +{ + struct rb_node *n = dev->bss_tree.rb_node; + struct cfg80211_internal_bss *bss; + int r; + + while (n) { + bss = rb_entry(n, struct cfg80211_internal_bss, rbn); + r = cmp_bss(&res->pub, &bss->pub); + + if (r == 0) + return bss; + else if (r < 0) + n = n->rb_left; + else + n = n->rb_right; + } + + return NULL; +} + +static struct cfg80211_internal_bss * +rb_find_hidden_bss(struct cfg80211_registered_device *dev, + struct cfg80211_internal_bss *res) +{ + struct rb_node *n = dev->bss_tree.rb_node; + struct cfg80211_internal_bss *bss; + int r; + + while (n) { + bss = rb_entry(n, struct cfg80211_internal_bss, rbn); + r = cmp_hidden_bss(&res->pub, &bss->pub); + + if (r == 0) + return bss; + else if (r < 0) + n = n->rb_left; + else + n = n->rb_right; + } + + return NULL; +} + +static void +copy_hidden_ies(struct cfg80211_internal_bss *res, + struct cfg80211_internal_bss *hidden) +{ + if (unlikely(res->pub.beacon_ies)) + return; + if (WARN_ON(!hidden->pub.beacon_ies)) + return; + + res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC); + if (unlikely(!res->pub.beacon_ies)) + return; + + res->beacon_ies_allocated = true; + res->pub.len_beacon_ies = hidden->pub.len_beacon_ies; + memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies, + res->pub.len_beacon_ies); +} + +static struct cfg80211_internal_bss * +cfg80211_bss_update(struct cfg80211_registered_device *dev, + struct cfg80211_internal_bss *res) +{ + struct cfg80211_internal_bss *found = NULL; + + /* + * The reference to "res" is donated to this function. + */ + + if (WARN_ON(!res->pub.channel)) { + kref_put(&res->ref, bss_release); + return NULL; + } + + res->ts = jiffies; + + spin_lock_bh(&dev->bss_lock); + + found = rb_find_bss(dev, res); + + if (found) { + found->pub.beacon_interval = res->pub.beacon_interval; + found->pub.tsf = res->pub.tsf; + found->pub.signal = res->pub.signal; + found->pub.capability = res->pub.capability; + found->ts = res->ts; + + /* Update IEs */ + if (res->pub.proberesp_ies) { + size_t used = dev->wiphy.bss_priv_size + sizeof(*res); + size_t ielen = res->pub.len_proberesp_ies; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28) + if (0) { + used = 0; /* just to shut up the compiler */ +#else + if (found->pub.proberesp_ies && + !found->proberesp_ies_allocated && + ksize(found) >= used + ielen) { +#endif + memcpy(found->pub.proberesp_ies, + res->pub.proberesp_ies, ielen); + found->pub.len_proberesp_ies = ielen; + } else { + u8 *ies = found->pub.proberesp_ies; + + if (found->proberesp_ies_allocated) + ies = krealloc(ies, ielen, GFP_ATOMIC); + else + ies = kmalloc(ielen, GFP_ATOMIC); + + if (ies) { + memcpy(ies, res->pub.proberesp_ies, + ielen); + found->proberesp_ies_allocated = true; + found->pub.proberesp_ies = ies; + found->pub.len_proberesp_ies = ielen; + } + } + + /* Override possible earlier Beacon frame IEs */ + found->pub.information_elements = + found->pub.proberesp_ies; + found->pub.len_information_elements = + found->pub.len_proberesp_ies; + } + if (res->pub.beacon_ies) { + size_t used = dev->wiphy.bss_priv_size + sizeof(*res); + size_t ielen = res->pub.len_beacon_ies; + bool information_elements_is_beacon_ies = + (found->pub.information_elements == + found->pub.beacon_ies); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28) + if (0) { + used = 0; /* just to shut up the compiler */ +#else + if (found->pub.beacon_ies && + !found->beacon_ies_allocated && + ksize(found) >= used + ielen) { +#endif + memcpy(found->pub.beacon_ies, + res->pub.beacon_ies, ielen); + found->pub.len_beacon_ies = ielen; + } else { + u8 *ies = found->pub.beacon_ies; + + if (found->beacon_ies_allocated) + ies = krealloc(ies, ielen, GFP_ATOMIC); + else + ies = kmalloc(ielen, GFP_ATOMIC); + + if (ies) { + memcpy(ies, res->pub.beacon_ies, + ielen); + found->beacon_ies_allocated = true; + found->pub.beacon_ies = ies; + found->pub.len_beacon_ies = ielen; + } + } + + /* Override IEs if they were from a beacon before */ + if (information_elements_is_beacon_ies) { + found->pub.information_elements = + found->pub.beacon_ies; + found->pub.len_information_elements = + found->pub.len_beacon_ies; + } + } + + kref_put(&res->ref, bss_release); + } else { + struct cfg80211_internal_bss *hidden; + + /* First check if the beacon is a probe response from + * a hidden bss. If so, copy beacon ies (with nullified + * ssid) into the probe response bss entry (with real ssid). + * It is required basically for PSM implementation + * (probe responses do not contain tim ie) */ + + /* TODO: The code is not trying to update existing probe + * response bss entries when beacon ies are + * getting changed. */ + hidden = rb_find_hidden_bss(dev, res); + if (hidden) + copy_hidden_ies(res, hidden); + + /* this "consumes" the reference */ + list_add_tail(&res->list, &dev->bss_list); + rb_insert_bss(dev, res); + found = res; + } + + dev->bss_generation++; + spin_unlock_bh(&dev->bss_lock); + + kref_get(&found->ref); + return found; +} + +struct cfg80211_bss* +cfg80211_inform_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + u64 timestamp, u16 capability, u16 beacon_interval, + const u8 *ie, size_t ielen, + s32 signal, gfp_t gfp) +{ + struct cfg80211_internal_bss *res; + size_t privsz; + + if (WARN_ON(!wiphy)) + return NULL; + + privsz = wiphy->bss_priv_size; + + if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && + (signal < 0 || signal > 100))) + return NULL; + + res = kzalloc(sizeof(*res) + privsz + ielen, gfp); + if (!res) + return NULL; + + memcpy(res->pub.bssid, bssid, ETH_ALEN); + res->pub.channel = channel; + res->pub.signal = signal; + res->pub.tsf = timestamp; + res->pub.beacon_interval = beacon_interval; + res->pub.capability = capability; + /* + * Since we do not know here whether the IEs are from a Beacon or Probe + * Response frame, we need to pick one of the options and only use it + * with the driver that does not provide the full Beacon/Probe Response + * frame. Use Beacon frame pointer to avoid indicating that this should + * override the information_elements pointer should we have received an + * earlier indication of Probe Response data. + * + * The initial buffer for the IEs is allocated with the BSS entry and + * is located after the private area. + */ + res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; + memcpy(res->pub.beacon_ies, ie, ielen); + res->pub.len_beacon_ies = ielen; + res->pub.information_elements = res->pub.beacon_ies; + res->pub.len_information_elements = res->pub.len_beacon_ies; + + kref_init(&res->ref); + + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); + if (!res) + return NULL; + + if (res->pub.capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + + /* cfg80211_bss_update gives us a referenced result */ + return &res->pub; +} +EXPORT_SYMBOL(cfg80211_inform_bss); + +struct cfg80211_bss * +cfg80211_inform_bss_frame(struct wiphy *wiphy, + struct ieee80211_channel *channel, + struct ieee80211_mgmt *mgmt, size_t len, + s32 signal, gfp_t gfp) +{ + struct cfg80211_internal_bss *res; + size_t ielen = len - offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); + size_t privsz; + + if (WARN_ON(!mgmt)) + return NULL; + + if (WARN_ON(!wiphy)) + return NULL; + + if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && + (signal < 0 || signal > 100))) + return NULL; + + if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) + return NULL; + + privsz = wiphy->bss_priv_size; + + res = kzalloc(sizeof(*res) + privsz + ielen, gfp); + if (!res) + return NULL; + + memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); + res->pub.channel = channel; + res->pub.signal = signal; + res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); + res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); + res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); + /* + * The initial buffer for the IEs is allocated with the BSS entry and + * is located after the private area. + */ + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; + memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, + ielen); + res->pub.len_proberesp_ies = ielen; + res->pub.information_elements = res->pub.proberesp_ies; + res->pub.len_information_elements = res->pub.len_proberesp_ies; + } else { + res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; + memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); + res->pub.len_beacon_ies = ielen; + res->pub.information_elements = res->pub.beacon_ies; + res->pub.len_information_elements = res->pub.len_beacon_ies; + } + + kref_init(&res->ref); + + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); + if (!res) + return NULL; + + if (res->pub.capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + + /* cfg80211_bss_update gives us a referenced result */ + return &res->pub; +} +EXPORT_SYMBOL(cfg80211_inform_bss_frame); + +void cfg80211_put_bss(struct cfg80211_bss *pub) +{ + struct cfg80211_internal_bss *bss; + + if (!pub) + return; + + bss = container_of(pub, struct cfg80211_internal_bss, pub); + kref_put(&bss->ref, bss_release); +} +EXPORT_SYMBOL(cfg80211_put_bss); + +void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) +{ + struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_internal_bss *bss; + + if (WARN_ON(!pub)) + return; + + bss = container_of(pub, struct cfg80211_internal_bss, pub); + + spin_lock_bh(&dev->bss_lock); + if (!list_empty(&bss->list)) { + __cfg80211_unlink_bss(dev, bss); + dev->bss_generation++; + } + spin_unlock_bh(&dev->bss_lock); +} +EXPORT_SYMBOL(cfg80211_unlink_bss); + +#ifdef CONFIG_CFG80211_WEXT +int cfg80211_wext_siwscan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct cfg80211_registered_device *rdev; + struct wiphy *wiphy; + struct iw_scan_req *wreq = NULL; + struct cfg80211_scan_request *creq = NULL; + int i, err, n_channels = 0; + enum ieee80211_band band; + + if (!netif_running(dev)) + return -ENETDOWN; + + if (wrqu->data.length == sizeof(struct iw_scan_req)) + wreq = (struct iw_scan_req *)extra; + + rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); + + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + if (rdev->scan_req) { + err = -EBUSY; + goto out; + } + + wiphy = &rdev->wiphy; + + /* Determine number of channels, needed to allocate creq */ + if (wreq && wreq->num_channels) + n_channels = wreq->num_channels; + else { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } + + creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + + n_channels * sizeof(void *), + GFP_ATOMIC); + if (!creq) { + err = -ENOMEM; + goto out; + } + + creq->wiphy = wiphy; + creq->dev = dev; + /* SSIDs come after channels */ + creq->ssids = (void *)&creq->channels[n_channels]; + creq->n_channels = n_channels; + creq->n_ssids = 1; + + /* translate "Scan on frequencies" request */ + i = 0; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + int j; + + if (!wiphy->bands[band]) + continue; + + for (j = 0; j < wiphy->bands[band]->n_channels; j++) { + /* ignore disabled channels */ + if (wiphy->bands[band]->channels[j].flags & + IEEE80211_CHAN_DISABLED) + continue; + + /* If we have a wireless request structure and the + * wireless request specifies frequencies, then search + * for the matching hardware channel. + */ + if (wreq && wreq->num_channels) { + int k; + int wiphy_freq = wiphy->bands[band]->channels[j].center_freq; + for (k = 0; k < wreq->num_channels; k++) { + int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]); + if (wext_freq == wiphy_freq) + goto wext_freq_found; + } + goto wext_freq_not_found; + } + + wext_freq_found: + creq->channels[i] = &wiphy->bands[band]->channels[j]; + i++; + wext_freq_not_found: ; + } + } + /* No channels found? */ + if (!i) { + err = -EINVAL; + goto out; + } + + /* Set real number of channels specified in creq->channels[] */ + creq->n_channels = i; + + /* translate "Scan for SSID" request */ + if (wreq) { + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) { + err = -EINVAL; + goto out; + } + memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len); + creq->ssids[0].ssid_len = wreq->essid_len; + } + if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE) + creq->n_ssids = 0; + } + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + if (wiphy->bands[i]) + creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; + + rdev->scan_req = creq; + err = rdev->ops->scan(wiphy, dev, creq); + if (err) { + rdev->scan_req = NULL; + /* creq will be freed below */ + } else { + nl80211_send_scan_start(rdev, dev); + /* creq now owned by driver */ + creq = NULL; + dev_hold(dev); + } + out: + kfree(creq); + cfg80211_unlock_rdev(rdev); + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); + +static void ieee80211_scan_add_ies(struct iw_request_info *info, + struct cfg80211_bss *bss, + char **current_ev, char *end_buf) +{ + u8 *pos, *end, *next; + struct iw_event iwe; + + if (!bss->information_elements || + !bss->len_information_elements) + return; + + /* + * If needed, fragment the IEs buffer (at IE boundaries) into short + * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. + */ + pos = bss->information_elements; + end = pos + bss->len_information_elements; + + while (end - pos > IW_GENERIC_IE_MAX) { + next = pos + 2 + pos[1]; + while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) + next = next + 2 + next[1]; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = next - pos; + *current_ev = iwe_stream_add_point(info, *current_ev, + end_buf, &iwe, pos); + + pos = next; + } + + if (end > pos) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = end - pos; + *current_ev = iwe_stream_add_point(info, *current_ev, + end_buf, &iwe, pos); + } +} + +static inline unsigned int elapsed_jiffies_msecs(unsigned long start) +{ + unsigned long end = jiffies; + + if (end >= start) + return jiffies_to_msecs(end - start); + + return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); +} + +static char * +ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, + struct cfg80211_internal_bss *bss, char *current_ev, + char *end_buf) +{ + struct iw_event iwe; + u8 *buf, *cfg, *p; + u8 *ie = bss->pub.information_elements; + int rem = bss->pub.len_information_elements, i, sig; + bool ismesh = false; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, + IW_EV_ADDR_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = bss->pub.channel->center_freq; + iwe.u.freq.e = 6; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + + if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_UPDATED; + switch (wiphy->signal_type) { + case CFG80211_SIGNAL_TYPE_MBM: + sig = bss->pub.signal / 100; + iwe.u.qual.level = sig; + iwe.u.qual.updated |= IW_QUAL_DBM; + if (sig < -110) /* rather bad */ + sig = -110; + else if (sig > -40) /* perfect */ + sig = -40; + /* will give a range of 0 .. 70 */ + iwe.u.qual.qual = sig + 110; + break; + case CFG80211_SIGNAL_TYPE_UNSPEC: + iwe.u.qual.level = bss->pub.signal; + /* will give range 0 .. 100 */ + iwe.u.qual.qual = bss->pub.signal; + break; + default: + /* not reached */ + break; + } + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); + } + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ""); + + while (rem >= 2) { + /* invalid data */ + if (ie[1] > rem - 2) + break; + + switch (ie[0]) { + case WLAN_EID_SSID: + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = ie[1]; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie + 2); + break; + case WLAN_EID_MESH_ID: + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = ie[1]; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie + 2); + break; + case WLAN_EID_MESH_CONFIG: + ismesh = true; + if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) + break; + buf = kmalloc(50, GFP_ATOMIC); + if (!buf) + break; + cfg = ie + 2; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "Mesh Network Path Selection Protocol ID: " + "0x%02X", cfg[0]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Path Selection Metric ID: 0x%02X", + cfg[1]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Congestion Control Mode ID: 0x%02X", + cfg[2]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Formation Info: 0x%02X", cfg[5]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Capabilities: 0x%02X", cfg[6]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + kfree(buf); + break; + case WLAN_EID_SUPP_RATES: + case WLAN_EID_EXT_SUPP_RATES: + /* display all supported rates in readable format */ + p = current_ev + iwe_stream_lcp_len(info); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + + for (i = 0; i < ie[1]; i++) { + iwe.u.bitrate.value = + ((ie[i + 2] & 0x7f) * 500000); + p = iwe_stream_add_value(info, current_ev, p, + end_buf, &iwe, IW_EV_PARAM_LEN); + } + current_ev = p; + break; + } + rem -= ie[1] + 2; + ie += ie[1] + 2; + } + + if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) || + ismesh) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + if (ismesh) + iwe.u.mode = IW_MODE_MESH; + else if (bss->pub.capability & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); + } + + buf = kmalloc(30, GFP_ATOMIC); + if (buf) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, buf); + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, " Last beacon: %ums ago", + elapsed_jiffies_msecs(bss->ts)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, &iwe, buf); + kfree(buf); + } + + ieee80211_scan_add_ies(info, &bss->pub, ¤t_ev, end_buf); + + return current_ev; +} + + +static int ieee80211_scan_results(struct cfg80211_registered_device *dev, + struct iw_request_info *info, + char *buf, size_t len) +{ + char *current_ev = buf; + char *end_buf = buf + len; + struct cfg80211_internal_bss *bss; + + spin_lock_bh(&dev->bss_lock); + cfg80211_bss_expire(dev); + + list_for_each_entry(bss, &dev->bss_list, list) { + if (buf + len - current_ev <= IW_EV_ADDR_LEN) { + spin_unlock_bh(&dev->bss_lock); + return -E2BIG; + } + current_ev = ieee80211_bss(&dev->wiphy, info, bss, + current_ev, end_buf); + } + spin_unlock_bh(&dev->bss_lock); + return current_ev - buf; +} + + +int cfg80211_wext_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct cfg80211_registered_device *rdev; + int res; + + if (!netif_running(dev)) + return -ENETDOWN; + + rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); + + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + if (rdev->scan_req) { + res = -EAGAIN; + goto out; + } + + res = ieee80211_scan_results(rdev, info, extra, data->length); + data->length = 0; + if (res >= 0) { + data->length = res; + res = 0; + } + + out: + cfg80211_unlock_rdev(rdev); + return res; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); +#endif diff --git a/net/wireless_ath/sme.c b/net/wireless_ath/sme.c new file mode 100644 index 00000000..38d32487 --- /dev/null +++ b/net/wireless_ath/sme.c @@ -0,0 +1,1041 @@ +/* + * SME code for cfg80211's connect emulation. + * + * Copyright 2009 Johannes Berg + * Copyright (C) 2009 Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nl80211.h" +#include "reg.h" + +struct cfg80211_conn { + struct cfg80211_connect_params params; + /* these are sub-states of the _CONNECTING sme_state */ + enum { + CFG80211_CONN_IDLE, + CFG80211_CONN_SCANNING, + CFG80211_CONN_SCAN_AGAIN, + CFG80211_CONN_AUTHENTICATE_NEXT, + CFG80211_CONN_AUTHENTICATING, + CFG80211_CONN_ASSOCIATE_NEXT, + CFG80211_CONN_ASSOCIATING, + CFG80211_CONN_DEAUTH_ASSOC_FAIL, + } state; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + u8 *ie; + size_t ie_len; + bool auto_auth, prev_bssid_valid; +}; + +static bool cfg80211_is_all_idle(void) +{ + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + bool is_all_idle = true; + + mutex_lock(&cfg80211_mutex); + + /* + * All devices must be idle as otherwise if you are actively + * scanning some new beacon hints could be learned and would + * count as new regulatory hints. + */ + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + cfg80211_lock_rdev(rdev); + list_for_each_entry(wdev, &rdev->netdev_list, list) { + wdev_lock(wdev); + if (wdev->sme_state != CFG80211_SME_IDLE) + is_all_idle = false; + wdev_unlock(wdev); + } + cfg80211_unlock_rdev(rdev); + } + + mutex_unlock(&cfg80211_mutex); + + return is_all_idle; +} + +static void disconnect_work(struct work_struct *work) +{ + if (!cfg80211_is_all_idle()) + return; + + regulatory_hint_disconnect(); +} + +static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); + +static int cfg80211_conn_scan(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_scan_request *request; + int n_channels, err; + + ASSERT_RTNL(); + ASSERT_RDEV_LOCK(rdev); + ASSERT_WDEV_LOCK(wdev); + + if (rdev->scan_req) + return -EBUSY; + + if (wdev->conn->params.channel) { + n_channels = 1; + } else { + enum ieee80211_band band; + n_channels = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wdev->wiphy->bands[band]) + continue; + n_channels += wdev->wiphy->bands[band]->n_channels; + } + } + request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) + + sizeof(request->channels[0]) * n_channels, + GFP_KERNEL); + if (!request) + return -ENOMEM; + + if (wdev->conn->params.channel) + request->channels[0] = wdev->conn->params.channel; + else { + int i = 0, j; + enum ieee80211_band band; + struct ieee80211_supported_band *bands; + struct ieee80211_channel *channel; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + bands = wdev->wiphy->bands[band]; + if (!bands) + continue; + for (j = 0; j < bands->n_channels; j++) { + channel = &bands->channels[j]; + if (channel->flags & IEEE80211_CHAN_DISABLED) + continue; + request->channels[i++] = channel; + } + request->rates[band] = (1 << bands->n_bitrates) - 1; + } + n_channels = i; + } + request->n_channels = n_channels; + request->ssids = (void *)&request->channels[n_channels]; + request->n_ssids = 1; + + memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, + wdev->conn->params.ssid_len); + request->ssids[0].ssid_len = wdev->conn->params.ssid_len; + + request->dev = wdev->netdev; + request->wiphy = &rdev->wiphy; + + rdev->scan_req = request; + + err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request); + if (!err) { + wdev->conn->state = CFG80211_CONN_SCANNING; + nl80211_send_scan_start(rdev, wdev->netdev); + dev_hold(wdev->netdev); + } else { + rdev->scan_req = NULL; + kfree(request); + } + return err; +} + +static int cfg80211_conn_do_work(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_connect_params *params; + const u8 *prev_bssid = NULL; + int err; + + ASSERT_WDEV_LOCK(wdev); + + if (!wdev->conn) + return 0; + + params = &wdev->conn->params; + + switch (wdev->conn->state) { + case CFG80211_CONN_SCAN_AGAIN: + return cfg80211_conn_scan(wdev); + case CFG80211_CONN_AUTHENTICATE_NEXT: + BUG_ON(!rdev->ops->auth); + wdev->conn->state = CFG80211_CONN_AUTHENTICATING; + return __cfg80211_mlme_auth(rdev, wdev->netdev, + params->channel, params->auth_type, + params->bssid, + params->ssid, params->ssid_len, + NULL, 0, + params->key, params->key_len, + params->key_idx, false); + case CFG80211_CONN_ASSOCIATE_NEXT: + BUG_ON(!rdev->ops->assoc); + wdev->conn->state = CFG80211_CONN_ASSOCIATING; + if (wdev->conn->prev_bssid_valid) + prev_bssid = wdev->conn->prev_bssid; + err = __cfg80211_mlme_assoc(rdev, wdev->netdev, + params->channel, params->bssid, + prev_bssid, + params->ssid, params->ssid_len, + params->ie, params->ie_len, + false, ¶ms->crypto); + if (err) + __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, + NULL, 0, + WLAN_REASON_DEAUTH_LEAVING, + false); + return err; + case CFG80211_CONN_DEAUTH_ASSOC_FAIL: + __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, + NULL, 0, + WLAN_REASON_DEAUTH_LEAVING, false); + /* return an error so that we call __cfg80211_connect_result() */ + return -EINVAL; + default: + return 0; + } +} + +void cfg80211_conn_work(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev = + container_of(work, struct cfg80211_registered_device, conn_work); + struct wireless_dev *wdev; + u8 bssid_buf[ETH_ALEN], *bssid = NULL; + + rtnl_lock(); + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->netdev_list, list) { + wdev_lock(wdev); + if (!netif_running(wdev->netdev)) { + wdev_unlock(wdev); + continue; + } + if (wdev->sme_state != CFG80211_SME_CONNECTING) { + wdev_unlock(wdev); + continue; + } + if (wdev->conn->params.bssid) { + memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); + bssid = bssid_buf; + } + if (cfg80211_conn_do_work(wdev)) + __cfg80211_connect_result( + wdev->netdev, bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false, NULL); + wdev_unlock(wdev); + } + + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); +} + +static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_bss *bss; + u16 capa = WLAN_CAPABILITY_ESS; + + ASSERT_WDEV_LOCK(wdev); + + if (wdev->conn->params.privacy) + capa |= WLAN_CAPABILITY_PRIVACY; + + bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel, + wdev->conn->params.bssid, + wdev->conn->params.ssid, + wdev->conn->params.ssid_len, + WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, + capa); + if (!bss) + return NULL; + + memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN); + wdev->conn->params.bssid = wdev->conn->bssid; + wdev->conn->params.channel = bss->channel; + wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; + schedule_work(&rdev->conn_work); + + return bss; +} + +static void __cfg80211_sme_scan_done(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_bss *bss; + + ASSERT_WDEV_LOCK(wdev); + + if (wdev->sme_state != CFG80211_SME_CONNECTING) + return; + + if (!wdev->conn) + return; + + if (wdev->conn->state != CFG80211_CONN_SCANNING && + wdev->conn->state != CFG80211_CONN_SCAN_AGAIN) + return; + + bss = cfg80211_get_conn_bss(wdev); + if (bss) { + cfg80211_put_bss(bss); + } else { + /* not found */ + if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) + schedule_work(&rdev->conn_work); + else + __cfg80211_connect_result( + wdev->netdev, + wdev->conn->params.bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false, NULL); + } +} + +void cfg80211_sme_scan_done(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); + wdev_lock(wdev); + __cfg80211_sme_scan_done(dev); + wdev_unlock(wdev); + mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); +} + +void cfg80211_sme_rx_auth(struct net_device *dev, + const u8 *buf, size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); + + ASSERT_WDEV_LOCK(wdev); + + /* should only RX auth frames when connecting */ + if (wdev->sme_state != CFG80211_SME_CONNECTING) + return; + + if (WARN_ON(!wdev->conn)) + return; + + if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && + wdev->conn->auto_auth && + wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) { + /* select automatically between only open, shared, leap */ + switch (wdev->conn->params.auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + if (wdev->connect_keys) + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_SHARED_KEY; + else + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_NETWORK_EAP; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_NETWORK_EAP; + break; + default: + /* huh? */ + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_OPEN_SYSTEM; + break; + } + wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; + schedule_work(&rdev->conn_work); + } else if (status_code != WLAN_STATUS_SUCCESS) { + __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, + status_code, false, NULL); + } else if (wdev->sme_state == CFG80211_SME_CONNECTING && + wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { + wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; + schedule_work(&rdev->conn_work); + } +} + +bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + if (WARN_ON(!wdev->conn)) + return false; + + if (!wdev->conn->prev_bssid_valid) + return false; + + /* + * Some stupid APs don't accept reassoc, so we + * need to fall back to trying regular assoc. + */ + wdev->conn->prev_bssid_valid = false; + wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; + schedule_work(&rdev->conn_work); + + return true; +} + +void cfg80211_sme_failed_assoc(struct wireless_dev *wdev) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL; + schedule_work(&rdev->conn_work); +} + +void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, bool wextev, + struct cfg80211_bss *bss) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + u8 *country_ie; +#ifdef CONFIG_CFG80211_WEXT + union iwreq_data wrqu; +#endif + + ASSERT_WDEV_LOCK(wdev); + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) + return; + + if (wdev->sme_state != CFG80211_SME_CONNECTING) + return; + + nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, + bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, + status, GFP_KERNEL); + +#ifdef CONFIG_CFG80211_WEXT + if (wextev) { + if (req_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = req_ie_len; + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie); + } + + if (resp_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = resp_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); + } + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (bssid && status == WLAN_STATUS_SUCCESS) { + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); + wdev->wext.prev_bssid_valid = true; + } + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + } +#endif + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; + } + + if (wdev->conn) + wdev->conn->state = CFG80211_CONN_IDLE; + + if (status != WLAN_STATUS_SUCCESS) { + wdev->sme_state = CFG80211_SME_IDLE; + if (wdev->conn) + kfree(wdev->conn->ie); + kfree(wdev->conn); + wdev->conn = NULL; + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + wdev->ssid_len = 0; + return; + } + + if (!bss) + bss = cfg80211_get_bss(wdev->wiphy, + wdev->conn ? wdev->conn->params.channel : + NULL, + bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + if (WARN_ON(!bss)) + return; + + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); + + wdev->sme_state = CFG80211_SME_CONNECTED; + cfg80211_upload_connect_keys(wdev); + + country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + + if (!country_ie) + return; + + /* + * ieee80211_bss_get_ie() ensures we can access: + * - country_ie + 2, the start of the country ie data, and + * - and country_ie[1] which is the IE length + */ + regulatory_hint_11d(wdev->wiphy, + bss->channel->band, + country_ie + 2, + country_ie[1]); +} + +void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING); + + ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); + if (!ev) + return; + + ev->type = EVENT_CONNECT_RESULT; + if (bssid) + memcpy(ev->cr.bssid, bssid, ETH_ALEN); + if (req_ie_len) { + ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); + ev->cr.req_ie_len = req_ie_len; + memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); + } + if (resp_ie_len) { + ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; + ev->cr.resp_ie_len = resp_ie_len; + memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); + } + ev->cr.status = status; + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + queue_work(cfg80211_wq, &rdev->event_work); +} +EXPORT_SYMBOL(cfg80211_connect_result); + +void __cfg80211_roamed(struct wireless_dev *wdev, + struct cfg80211_bss *bss, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len) +{ +#ifdef CONFIG_CFG80211_WEXT + union iwreq_data wrqu; +#endif + ASSERT_WDEV_LOCK(wdev); + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) + goto out; + + if (wdev->sme_state != CFG80211_SME_CONNECTED) + goto out; + + /* internal error -- how did we get to CONNECTED w/o BSS? */ + if (WARN_ON(!wdev->current_bss)) { + goto out; + } + + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; + + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); + + nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bss->bssid, + req_ie, req_ie_len, resp_ie, resp_ie_len, + GFP_KERNEL); + +#ifdef CONFIG_CFG80211_WEXT + if (req_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = req_ie_len; + wireless_send_event(wdev->netdev, IWEVASSOCREQIE, + &wrqu, req_ie); + } + + if (resp_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = resp_ie_len; + wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, + &wrqu, resp_ie); + } + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, bss->bssid, ETH_ALEN); + wdev->wext.prev_bssid_valid = true; + wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); +#endif + + return; +out: + cfg80211_put_bss(bss); +} + +void cfg80211_roamed(struct net_device *dev, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_bss *bss; + + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); + + bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, + wdev->ssid_len, WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + if (WARN_ON(!bss)) + return; + + cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie, + resp_ie_len, gfp); +} +EXPORT_SYMBOL(cfg80211_roamed); + +void cfg80211_roamed_bss(struct net_device *dev, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); + + if (WARN_ON(!bss)) + return; + + ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); + if (!ev) { + cfg80211_put_bss(bss); + return; + } + + ev->type = EVENT_ROAMED; + ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev); + ev->rm.req_ie_len = req_ie_len; + memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len); + ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; + ev->rm.resp_ie_len = resp_ie_len; + memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len); + ev->rm.bss = bss; + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + queue_work(cfg80211_wq, &rdev->event_work); +} +EXPORT_SYMBOL(cfg80211_roamed_bss); + +void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, + size_t ie_len, u16 reason, bool from_ap) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int i; +#ifdef CONFIG_CFG80211_WEXT + union iwreq_data wrqu; +#endif + + ASSERT_WDEV_LOCK(wdev); + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) + return; + + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + } + + wdev->current_bss = NULL; + wdev->sme_state = CFG80211_SME_IDLE; + wdev->ssid_len = 0; + + if (wdev->conn) { + const u8 *bssid; + int ret; + + kfree(wdev->conn->ie); + wdev->conn->ie = NULL; + kfree(wdev->conn); + wdev->conn = NULL; + + /* + * If this disconnect was due to a disassoc, we + * we might still have an auth BSS around. For + * the userspace SME that's currently expected, + * but for the kernel SME (nl80211 CONNECT or + * wireless extensions) we want to clear up all + * state. + */ + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (!wdev->auth_bsses[i]) + continue; + bssid = wdev->auth_bsses[i]->pub.bssid; + ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, + WLAN_REASON_DEAUTH_LEAVING, + false); + WARN(ret, "deauth failed: %d\n", ret); + } + } + + nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); + + /* + * Delete all the keys ... pairwise keys can't really + * exist any more anyway, but default keys might. + */ + if (rdev->ops->del_key) + for (i = 0; i < 6; i++) + rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); + +#ifdef CONFIG_CFG80211_WEXT + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + wdev->wext.connect.ssid_len = 0; +#endif + + schedule_work(&cfg80211_disconnect_work); +} + +void cfg80211_disconnected(struct net_device *dev, u16 reason, + u8 *ie, size_t ie_len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); + + ev = kzalloc(sizeof(*ev) + ie_len, gfp); + if (!ev) + return; + + ev->type = EVENT_DISCONNECTED; + ev->dc.ie = ((u8 *)ev) + sizeof(*ev); + ev->dc.ie_len = ie_len; + memcpy((void *)ev->dc.ie, ie, ie_len); + ev->dc.reason = reason; + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + queue_work(cfg80211_wq, &rdev->event_work); +} +EXPORT_SYMBOL(cfg80211_disconnected); + +int __cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys, + const u8 *prev_bssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_bss *bss = NULL; + int err; + + ASSERT_WDEV_LOCK(wdev); + + if (wdev->sme_state != CFG80211_SME_IDLE) + return -EALREADY; + + if (WARN_ON(wdev->connect_keys)) { + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + } + + if (connkeys && connkeys->def >= 0) { + int idx; + u32 cipher; + + idx = connkeys->def; + cipher = connkeys->params[idx].cipher; + /* If given a WEP key we may need it for shared key auth */ + if (cipher == WLAN_CIPHER_SUITE_WEP40 || + cipher == WLAN_CIPHER_SUITE_WEP104) { + connect->key_idx = idx; + connect->key = connkeys->params[idx].key; + connect->key_len = connkeys->params[idx].key_len; + + /* + * If ciphers are not set (e.g. when going through + * iwconfig), we have to set them appropriately here. + */ + if (connect->crypto.cipher_group == 0) + connect->crypto.cipher_group = cipher; + + if (connect->crypto.n_ciphers_pairwise == 0) { + connect->crypto.n_ciphers_pairwise = 1; + connect->crypto.ciphers_pairwise[0] = cipher; + } + } + } + + if (!rdev->ops->connect) { + if (!rdev->ops->auth || !rdev->ops->assoc) + return -EOPNOTSUPP; + + if (WARN_ON(wdev->conn)) + return -EINPROGRESS; + + wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); + if (!wdev->conn) + return -ENOMEM; + + /* + * Copy all parameters, and treat explicitly IEs, BSSID, SSID. + */ + memcpy(&wdev->conn->params, connect, sizeof(*connect)); + if (connect->bssid) { + wdev->conn->params.bssid = wdev->conn->bssid; + memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); + } + + if (connect->ie) { + wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, + GFP_KERNEL); + wdev->conn->params.ie = wdev->conn->ie; + if (!wdev->conn->ie) { + kfree(wdev->conn); + wdev->conn = NULL; + return -ENOMEM; + } + } + + if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { + wdev->conn->auto_auth = true; + /* start with open system ... should mostly work */ + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_OPEN_SYSTEM; + } else { + wdev->conn->auto_auth = false; + } + + memcpy(wdev->ssid, connect->ssid, connect->ssid_len); + wdev->ssid_len = connect->ssid_len; + wdev->conn->params.ssid = wdev->ssid; + wdev->conn->params.ssid_len = connect->ssid_len; + + /* see if we have the bss already */ + bss = cfg80211_get_conn_bss(wdev); + + wdev->sme_state = CFG80211_SME_CONNECTING; + wdev->connect_keys = connkeys; + + if (prev_bssid) { + memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); + wdev->conn->prev_bssid_valid = true; + } + + /* we're good if we have a matching bss struct */ + if (bss) { + wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; + err = cfg80211_conn_do_work(wdev); + cfg80211_put_bss(bss); + } else { + /* otherwise we'll need to scan for the AP first */ + err = cfg80211_conn_scan(wdev); + /* + * If we can't scan right now, then we need to scan again + * after the current scan finished, since the parameters + * changed (unless we find a good AP anyway). + */ + if (err == -EBUSY) { + err = 0; + wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; + } + } + if (err) { + kfree(wdev->conn->ie); + kfree(wdev->conn); + wdev->conn = NULL; + wdev->sme_state = CFG80211_SME_IDLE; + wdev->connect_keys = NULL; + wdev->ssid_len = 0; + } + + return err; + } else { + wdev->sme_state = CFG80211_SME_CONNECTING; + wdev->connect_keys = connkeys; + err = rdev->ops->connect(&rdev->wiphy, dev, connect); + if (err) { + wdev->connect_keys = NULL; + wdev->sme_state = CFG80211_SME_IDLE; + return err; + } + + memcpy(wdev->ssid, connect->ssid, connect->ssid_len); + wdev->ssid_len = connect->ssid_len; + + return 0; + } +} + +int cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys) +{ + int err; + + mutex_lock(&rdev->devlist_mtx); + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); + wdev_unlock(dev->ieee80211_ptr); + mutex_unlock(&rdev->devlist_mtx); + + return err; +} + +int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason, bool wextev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + ASSERT_WDEV_LOCK(wdev); + + if (wdev->sme_state == CFG80211_SME_IDLE) + return -EINVAL; + + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + + if (!rdev->ops->disconnect) { + if (!rdev->ops->deauth) + return -EOPNOTSUPP; + + /* was it connected by userspace SME? */ + if (!wdev->conn) { + cfg80211_mlme_down(rdev, dev); + return 0; + } + + if (wdev->sme_state == CFG80211_SME_CONNECTING && + (wdev->conn->state == CFG80211_CONN_SCANNING || + wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { + wdev->sme_state = CFG80211_SME_IDLE; + kfree(wdev->conn->ie); + kfree(wdev->conn); + wdev->conn = NULL; + wdev->ssid_len = 0; + return 0; + } + + /* wdev->conn->params.bssid must be set if > SCANNING */ + err = __cfg80211_mlme_deauth(rdev, dev, + wdev->conn->params.bssid, + NULL, 0, reason, false); + if (err) + return err; + } else { + err = rdev->ops->disconnect(&rdev->wiphy, dev, reason); + if (err) + return err; + } + + if (wdev->sme_state == CFG80211_SME_CONNECTED) + __cfg80211_disconnected(dev, NULL, 0, 0, false); + else if (wdev->sme_state == CFG80211_SME_CONNECTING) + __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + wextev, NULL); + + return 0; +} + +int cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + u16 reason, bool wextev) +{ + int err; + + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_disconnect(rdev, dev, reason, wextev); + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + +void cfg80211_sme_disassoc(struct net_device *dev, int idx) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u8 bssid[ETH_ALEN]; + + ASSERT_WDEV_LOCK(wdev); + + if (!wdev->conn) + return; + + if (wdev->conn->state == CFG80211_CONN_IDLE) + return; + + /* + * Ok, so the association was made by this SME -- we don't + * want it any more so deauthenticate too. + */ + + if (!wdev->auth_bsses[idx]) + return; + + memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); + if (__cfg80211_mlme_deauth(rdev, dev, bssid, + NULL, 0, WLAN_REASON_DEAUTH_LEAVING, + false)) { + /* whatever -- assume gone anyway */ + cfg80211_unhold_bss(wdev->auth_bsses[idx]); + cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); + wdev->auth_bsses[idx] = NULL; + } +} diff --git a/net/wireless_ath/sysfs.c b/net/wireless_ath/sysfs.c new file mode 100644 index 00000000..2f8af6e2 --- /dev/null +++ b/net/wireless_ath/sysfs.c @@ -0,0 +1,157 @@ +/* + * This file provides /sys/class/ieee80211// + * and some default attributes. + * + * Copyright 2005-2006 Jiri Benc + * Copyright 2006 Johannes Berg + * + * This file is GPLv2 as found in COPYING. + */ + +#include +#include +#include +#include +#include +#include +#include "sysfs.h" +#include "core.h" + +static inline struct cfg80211_registered_device *dev_to_rdev( + struct device *dev) +{ + return container_of(dev, struct cfg80211_registered_device, wiphy.dev); +} + +#define SHOW_FMT(name, fmt, member) \ +static ssize_t name ## _show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ +} + +SHOW_FMT(index, "%d", wiphy_idx); +SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); +SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); + +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, + char *buf) { + struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; + return sprintf(buf, "%s\n", dev_name(&wiphy->dev)); +} + + +static ssize_t addresses_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; + char *start = buf; + int i; + + if (!wiphy->addresses) + return sprintf(buf, "%pM\n", wiphy->perm_addr); + + for (i = 0; i < wiphy->n_addresses; i++) + buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr); + + return buf - start; +} + +static struct device_attribute ieee80211_dev_attrs[] = { + __ATTR_RO(index), + __ATTR_RO(macaddress), + __ATTR_RO(address_mask), + __ATTR_RO(addresses), + __ATTR_RO(name), + {} +}; + +static void wiphy_dev_release(struct device *dev) +{ + struct cfg80211_registered_device *rdev = dev_to_rdev(dev); + + cfg80211_dev_free(rdev); +} + +#ifdef CONFIG_HOTPLUG +static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + /* TODO, we probably need stuff here */ + return 0; +} +#endif + +static int wiphy_suspend(struct device *dev, pm_message_t state) +{ + struct cfg80211_registered_device *rdev = dev_to_rdev(dev); + int ret = 0; + + rdev->suspend_at = get_seconds(); + + if (rdev->ops->suspend) { + rtnl_lock(); + if (rdev->wiphy.registered) + ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); + rtnl_unlock(); + } + + return ret; +} + +static int wiphy_resume(struct device *dev) +{ + struct cfg80211_registered_device *rdev = dev_to_rdev(dev); + int ret = 0; + + /* Age scan results with time spent in suspend */ + spin_lock_bh(&rdev->bss_lock); + cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); + spin_unlock_bh(&rdev->bss_lock); + + if (rdev->ops->resume) { + rtnl_lock(); + if (rdev->wiphy.registered) + ret = rdev->ops->resume(&rdev->wiphy); + rtnl_unlock(); + } + + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) +static const void *wiphy_namespace(struct device *d) +{ + struct wiphy *wiphy = container_of(d, struct wiphy, dev); + + return wiphy_net(wiphy); +} +#endif + +struct class ieee80211_class = { + .name = "ieee80211", + .owner = THIS_MODULE, + .dev_release = wiphy_dev_release, + .dev_attrs = ieee80211_dev_attrs, +#ifdef CONFIG_HOTPLUG + .dev_uevent = wiphy_uevent, +#endif + .suspend = wiphy_suspend, + .resume = wiphy_resume, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) + .ns_type = &net_ns_type_operations, + .namespace = wiphy_namespace, +#endif +}; + +int wiphy_sysfs_init(void) +{ + return class_register(&ieee80211_class); +} + +void wiphy_sysfs_exit(void) +{ + class_unregister(&ieee80211_class); +} diff --git a/net/wireless_ath/sysfs.h b/net/wireless_ath/sysfs.h new file mode 100644 index 00000000..65acbebd --- /dev/null +++ b/net/wireless_ath/sysfs.h @@ -0,0 +1,9 @@ +#ifndef __WIRELESS_SYSFS_H +#define __WIRELESS_SYSFS_H + +extern int wiphy_sysfs_init(void); +extern void wiphy_sysfs_exit(void); + +extern struct class ieee80211_class; + +#endif /* __WIRELESS_SYSFS_H */ diff --git a/net/wireless_ath/util.c b/net/wireless_ath/util.c new file mode 100644 index 00000000..b4195101 --- /dev/null +++ b/net/wireless_ath/util.c @@ -0,0 +1,1219 @@ +/* + * Wireless utility functions + * + * Copyright 2007-2009 Johannes Berg + */ +#include +#include +#include +#include +#include +#include +#include +#include "core.h" + +struct ieee80211_rate * +ieee80211_get_response_rate(struct ieee80211_supported_band *sband, + u32 basic_rates, int bitrate) +{ + struct ieee80211_rate *result = &sband->bitrates[0]; + int i; + + for (i = 0; i < sband->n_bitrates; i++) { + if (!(basic_rates & BIT(i))) + continue; + if (sband->bitrates[i].bitrate > bitrate) + continue; + result = &sband->bitrates[i]; + } + + return result; +} +EXPORT_SYMBOL(ieee80211_get_response_rate); + +int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) +{ + /* see 802.11 17.3.8.3.2 and Annex J + * there are overlapping channel numbers in 5GHz and 2GHz bands */ + if (band == IEEE80211_BAND_5GHZ) { + if (chan >= 182 && chan <= 196) + return 4000 + chan * 5; + else + return 5000 + chan * 5; + } else { /* IEEE80211_BAND_2GHZ */ + if (chan == 14) + return 2484; + else if (chan < 14) + return 2407 + chan * 5; + else + return 0; /* not supported */ + } +} +EXPORT_SYMBOL(ieee80211_channel_to_frequency); + +int ieee80211_frequency_to_channel(int freq) +{ + /* see 802.11 17.3.8.3.2 and Annex J */ + if (freq == 2484) + return 14; + else if (freq < 2484) + return (freq - 2407) / 5; + else if (freq >= 4910 && freq <= 4980) + return (freq - 4000) / 5; + else + return (freq - 5000) / 5; +} +EXPORT_SYMBOL(ieee80211_frequency_to_channel); + +struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, + int freq) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + int i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].center_freq == freq) + return &sband->channels[i]; + } + } + + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_channel); + +static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, + enum ieee80211_band band) +{ + int i, want; + + switch (band) { + case IEEE80211_BAND_5GHZ: + want = 3; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_A; + want--; + } + } + WARN_ON(want); + break; + case IEEE80211_BAND_2GHZ: + want = 7; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 10) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_B | + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate == 20 || + sband->bitrates[i].bitrate == 55 || + sband->bitrates[i].bitrate == 110 || + sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate != 10 && + sband->bitrates[i].bitrate != 20 && + sband->bitrates[i].bitrate != 55 && + sband->bitrates[i].bitrate != 110) + sband->bitrates[i].flags |= + IEEE80211_RATE_ERP_G; + } + WARN_ON(want != 0 && want != 3 && want != 6); + break; + case IEEE80211_NUM_BANDS: + WARN_ON(1); + break; + } +} + +void ieee80211_set_bitrate_flags(struct wiphy *wiphy) +{ + enum ieee80211_band band; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + set_mandatory_flags_band(wiphy->bands[band], band); +} + +bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher) +{ + int i; + for (i = 0; i < wiphy->n_cipher_suites; i++) + if (cipher == wiphy->cipher_suites[i]) + return true; + return false; +} + +int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, + struct key_params *params, int key_idx, + bool pairwise, const u8 *mac_addr) +{ + if (key_idx > 5) + return -EINVAL; + + if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + return -EINVAL; + + if (pairwise && !mac_addr) + return -EINVAL; + + /* + * Disallow pairwise keys with non-zero index unless it's WEP + * or a vendor specific cipher (because current deployments use + * pairwise WEP keys with non-zero indices and for vendor specific + * ciphers this should be validated in the driver or hardware level + * - but 802.11i clearly specifies to use zero) + */ + if (pairwise && key_idx && + ((params->cipher == WLAN_CIPHER_SUITE_TKIP) || + (params->cipher == WLAN_CIPHER_SUITE_CCMP) || + (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC))) + return -EINVAL; + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + if (params->key_len != WLAN_KEY_LEN_WEP40) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_TKIP: + if (params->key_len != WLAN_KEY_LEN_TKIP) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_CCMP: + if (params->key_len != WLAN_KEY_LEN_CCMP) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_WEP104: + if (params->key_len != WLAN_KEY_LEN_WEP104) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + if (params->key_len != WLAN_KEY_LEN_AES_CMAC) + return -EINVAL; + break; + default: + /* + * We don't know anything about this algorithm, + * allow using it -- but the driver must check + * all parameters! We still check below whether + * or not the driver supports this algorithm, + * of course. + */ + break; + } + + if (params->seq) { + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + /* These ciphers do not use key sequence */ + return -EINVAL; + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + if (params->seq_len != 6) + return -EINVAL; + break; + } + } + + if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher)) + return -EINVAL; + + return 0; +} + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +const unsigned char rfc1042_header[] __aligned(2) = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +EXPORT_SYMBOL(rfc1042_header); + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +const unsigned char bridge_tunnel_header[] __aligned(2) = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +EXPORT_SYMBOL(bridge_tunnel_header); + +unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) +{ + unsigned int hdrlen = 24; + + if (ieee80211_is_data(fc)) { + if (ieee80211_has_a4(fc)) + hdrlen = 30; + if (ieee80211_is_data_qos(fc)) { + hdrlen += IEEE80211_QOS_CTL_LEN; + if (ieee80211_has_order(fc)) + hdrlen += IEEE80211_HT_CTL_LEN; + } + goto out; + } + + if (ieee80211_is_ctl(fc)) { + /* + * ACK and CTS are 10 bytes, all others 16. To see how + * to get this condition consider + * subtype mask: 0b0000000011110000 (0x00F0) + * ACK subtype: 0b0000000011010000 (0x00D0) + * CTS subtype: 0b0000000011000000 (0x00C0) + * bits that matter: ^^^ (0x00E0) + * value of those: 0b0000000011000000 (0x00C0) + */ + if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) + hdrlen = 10; + else + hdrlen = 16; + } +out: + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_hdrlen); + +unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = + (const struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (unlikely(hdrlen > skb->len)) + return 0; + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); + +static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) +{ + int ae = meshhdr->flags & MESH_FLAGS_AE; + /* 7.1.3.5a.2 */ + switch (ae) { + case 0: + return 6; + case MESH_FLAGS_AE_A4: + return 12; + case MESH_FLAGS_AE_A5_A6: + return 18; + case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): + return 24; + default: + return 6; + } +} + +int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, + enum nl80211_iftype iftype) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 hdrlen, ethertype; + u8 *payload; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN] __aligned(2); + + if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) + return -1; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + + /* convert IEEE 802.11 header + possible LLC headers into Ethernet + * header + * IEEE 802.11 address fields: + * ToDS FromDS Addr1 Addr2 Addr3 Addr4 + * 0 0 DA SA BSSID n/a + * 0 1 DA BSSID SA n/a + * 1 0 BSSID SA DA n/a + * 1 1 RA TA DA SA + */ + memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); + + switch (hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case cpu_to_le16(IEEE80211_FCTL_TODS): + if (unlikely(iftype != NL80211_IFTYPE_AP && + iftype != NL80211_IFTYPE_AP_VLAN && + iftype != NL80211_IFTYPE_P2P_GO)) + return -1; + break; + case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + if (unlikely(iftype != NL80211_IFTYPE_WDS && + iftype != NL80211_IFTYPE_MESH_POINT && + iftype != NL80211_IFTYPE_AP_VLAN && + iftype != NL80211_IFTYPE_STATION)) + return -1; + if (iftype == NL80211_IFTYPE_MESH_POINT) { + struct ieee80211s_hdr *meshdr = + (struct ieee80211s_hdr *) (skb->data + hdrlen); + /* make sure meshdr->flags is on the linear part */ + if (!pskb_may_pull(skb, hdrlen + 1)) + return -1; + if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { + skb_copy_bits(skb, hdrlen + + offsetof(struct ieee80211s_hdr, eaddr1), + dst, ETH_ALEN); + skb_copy_bits(skb, hdrlen + + offsetof(struct ieee80211s_hdr, eaddr2), + src, ETH_ALEN); + } + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); + } + break; + case cpu_to_le16(IEEE80211_FCTL_FROMDS): + if ((iftype != NL80211_IFTYPE_STATION && + iftype != NL80211_IFTYPE_P2P_CLIENT && + iftype != NL80211_IFTYPE_MESH_POINT) || + (is_multicast_ether_addr(dst) && + !compare_ether_addr(src, addr))) + return -1; + if (iftype == NL80211_IFTYPE_MESH_POINT) { + struct ieee80211s_hdr *meshdr = + (struct ieee80211s_hdr *) (skb->data + hdrlen); + /* make sure meshdr->flags is on the linear part */ + if (!pskb_may_pull(skb, hdrlen + 1)) + return -1; + if (meshdr->flags & MESH_FLAGS_AE_A4) + skb_copy_bits(skb, hdrlen + + offsetof(struct ieee80211s_hdr, eaddr1), + src, ETH_ALEN); + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); + } + break; + case cpu_to_le16(0): + if (iftype != NL80211_IFTYPE_ADHOC && + iftype != NL80211_IFTYPE_STATION) + return -1; + break; + } + + if (!pskb_may_pull(skb, hdrlen + 8)) + return -1; + + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + struct ethhdr *ehdr; + __be16 len; + + skb_pull(skb, hdrlen); + len = htons(skb->len); + ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dst, ETH_ALEN); + memcpy(ehdr->h_source, src, ETH_ALEN); + ehdr->h_proto = len; + } + return 0; +} +EXPORT_SYMBOL(ieee80211_data_to_8023); + +int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, + enum nl80211_iftype iftype, u8 *bssid, bool qos) +{ + struct ieee80211_hdr hdr; + u16 hdrlen, ethertype; + __le16 fc; + const u8 *encaps_data; + int encaps_len, skip_header_bytes; + int nh_pos, h_pos; + int head_need; + + if (unlikely(skb->len < ETH_HLEN)) + return -EINVAL; + + nh_pos = skb_network_header(skb) - skb->data; + h_pos = skb_transport_header(skb) - skb->data; + + /* convert Ethernet header to proper 802.11 header (based on + * operation mode) */ + ethertype = (skb->data[12] << 8) | skb->data[13]; + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); + + switch (iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); + /* DA BSSID SA */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 24; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + fc |= cpu_to_le16(IEEE80211_FCTL_TODS); + /* BSSID SA DA */ + memcpy(hdr.addr1, bssid, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + hdrlen = 24; + break; + case NL80211_IFTYPE_ADHOC: + /* DA SA BSSID */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, bssid, ETH_ALEN); + hdrlen = 24; + break; + default: + return -EOPNOTSUPP; + } + + if (qos) { + fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + hdrlen += 2; + } + + hdr.frame_control = fc; + hdr.duration_id = 0; + hdr.seq_ctrl = 0; + + skip_header_bytes = ETH_HLEN; + if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { + encaps_data = bridge_tunnel_header; + encaps_len = sizeof(bridge_tunnel_header); + skip_header_bytes -= 2; + } else if (ethertype > 0x600) { + encaps_data = rfc1042_header; + encaps_len = sizeof(rfc1042_header); + skip_header_bytes -= 2; + } else { + encaps_data = NULL; + encaps_len = 0; + } + + skb_pull(skb, skip_header_bytes); + nh_pos -= skip_header_bytes; + h_pos -= skip_header_bytes; + + head_need = hdrlen + encaps_len - skb_headroom(skb); + + if (head_need > 0 || skb_cloned(skb)) { + head_need = max(head_need, 0); + if (head_need) + skb_orphan(skb); + + if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) + return -ENOMEM; + + skb->truesize += head_need; + } + + if (encaps_data) { + memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); + nh_pos += encaps_len; + h_pos += encaps_len; + } + + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + + nh_pos += hdrlen; + h_pos += hdrlen; + + /* Update skb pointers to various headers since this modified frame + * is going to go through Linux networking code that may potentially + * need things like pointer to IP header. */ + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, nh_pos); + skb_set_transport_header(skb, h_pos); + + return 0; +} +EXPORT_SYMBOL(ieee80211_data_from_8023); + + +void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, + const u8 *addr, enum nl80211_iftype iftype, + const unsigned int extra_headroom, + bool has_80211_header) +{ + struct sk_buff *frame = NULL; + u16 ethertype; + u8 *payload; + const struct ethhdr *eth; + int remaining, err; + u8 dst[ETH_ALEN], src[ETH_ALEN]; + + if (has_80211_header) { + err = ieee80211_data_to_8023(skb, addr, iftype); + if (err) + goto out; + + /* skip the wrapping header */ + eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); + if (!eth) + goto out; + } else { + eth = (struct ethhdr *) skb->data; + } + + while (skb != frame) { + u8 padding; + __be16 len = eth->h_proto; + unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); + + remaining = skb->len; + memcpy(dst, eth->h_dest, ETH_ALEN); + memcpy(src, eth->h_source, ETH_ALEN); + + padding = (4 - subframe_len) & 0x3; + /* the last MSDU has no padding */ + if (subframe_len > remaining) + goto purge; + + skb_pull(skb, sizeof(struct ethhdr)); + /* reuse skb for the last subframe */ + if (remaining <= subframe_len + padding) + frame = skb; + else { + unsigned int hlen = ALIGN(extra_headroom, 4); + /* + * Allocate and reserve two bytes more for payload + * alignment since sizeof(struct ethhdr) is 14. + */ + frame = dev_alloc_skb(hlen + subframe_len + 2); + if (!frame) + goto purge; + + skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); + memcpy(skb_put(frame, ntohs(len)), skb->data, + ntohs(len)); + + eth = (struct ethhdr *)skb_pull(skb, ntohs(len) + + padding); + if (!eth) { + dev_kfree_skb(frame); + goto purge; + } + } + + skb_reset_network_header(frame); + frame->dev = skb->dev; + frame->priority = skb->priority; + + payload = frame->data; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, + bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel + * encapsulation and replace EtherType */ + skb_pull(frame, 6); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } else { + memcpy(skb_push(frame, sizeof(__be16)), &len, + sizeof(__be16)); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } + __skb_queue_tail(list, frame); + } + + return; + + purge: + __skb_queue_purge(list); + out: + dev_kfree_skb(skb); +} +EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); + +/* Given a data frame determine the 802.1p/1d tag to use. */ +unsigned int cfg80211_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; +} +EXPORT_SYMBOL(cfg80211_classify8021d); + +const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) +{ + u8 *end, *pos; + + pos = bss->information_elements; + if (pos == NULL) + return NULL; + end = pos + bss->len_information_elements; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == ie) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} +EXPORT_SYMBOL(ieee80211_bss_get_ie); + +void cfg80211_upload_connect_keys(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct net_device *dev = wdev->netdev; + int i; + + if (!wdev->connect_keys) + return; + + for (i = 0; i < 6; i++) { + if (!wdev->connect_keys->params[i].cipher) + continue; + if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, + &wdev->connect_keys->params[i])) { + netdev_err(dev, "failed to set key %d\n", i); + continue; + } + if (wdev->connect_keys->def == i) + if (rdev->ops->set_default_key(wdev->wiphy, dev, + i, true, true)) { + netdev_err(dev, "failed to set defkey %d\n", i); + continue; + } + if (wdev->connect_keys->defmgmt == i) + if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) + netdev_err(dev, "failed to set mgtdef %d\n", i); + } + + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; +} + +static void cfg80211_process_wdev_events(struct wireless_dev *wdev) +{ + struct cfg80211_event *ev; + unsigned long flags; + const u8 *bssid = NULL; + + spin_lock_irqsave(&wdev->event_lock, flags); + while (!list_empty(&wdev->event_list)) { + ev = list_first_entry(&wdev->event_list, + struct cfg80211_event, list); + list_del(&ev->list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + + wdev_lock(wdev); + switch (ev->type) { + case EVENT_CONNECT_RESULT: + if (!is_zero_ether_addr(ev->cr.bssid)) + bssid = ev->cr.bssid; + __cfg80211_connect_result( + wdev->netdev, bssid, + ev->cr.req_ie, ev->cr.req_ie_len, + ev->cr.resp_ie, ev->cr.resp_ie_len, + ev->cr.status, + ev->cr.status == WLAN_STATUS_SUCCESS, + NULL); + break; + case EVENT_ROAMED: + __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie, + ev->rm.req_ie_len, ev->rm.resp_ie, + ev->rm.resp_ie_len); + break; + case EVENT_DISCONNECTED: + __cfg80211_disconnected(wdev->netdev, + ev->dc.ie, ev->dc.ie_len, + ev->dc.reason, true); + break; + case EVENT_IBSS_JOINED: + __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); + break; + } + wdev_unlock(wdev); + + kfree(ev); + + spin_lock_irqsave(&wdev->event_lock, flags); + } + spin_unlock_irqrestore(&wdev->event_lock, flags); +} + +void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) +{ + struct wireless_dev *wdev; + + ASSERT_RTNL(); + ASSERT_RDEV_LOCK(rdev); + + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->netdev_list, list) + cfg80211_process_wdev_events(wdev); + + mutex_unlock(&rdev->devlist_mtx); +} + +int cfg80211_change_iface(struct cfg80211_registered_device *rdev, + struct net_device *dev, enum nl80211_iftype ntype, + u32 *flags, struct vif_params *params) +{ + int err; + enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; + + ASSERT_RDEV_LOCK(rdev); + + /* don't support changing VLANs, you just re-create them */ + if (otype == NL80211_IFTYPE_AP_VLAN) + return -EOPNOTSUPP; + + if (!rdev->ops->change_virtual_intf || + !(rdev->wiphy.interface_modes & (1 << ntype))) + return -EOPNOTSUPP; + + /* if it's part of a bridge, reject changing type to station/ibss */ + if (br_port_exists(dev) && + (ntype == NL80211_IFTYPE_ADHOC || + ntype == NL80211_IFTYPE_STATION || + ntype == NL80211_IFTYPE_P2P_CLIENT)) + return -EBUSY; + + if (ntype != otype) { + err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, + ntype); + if (err) + return err; + + dev->ieee80211_ptr->use_4addr = false; + dev->ieee80211_ptr->mesh_id_up_len = 0; + + switch (otype) { + case NL80211_IFTYPE_ADHOC: + cfg80211_leave_ibss(rdev, dev, false); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, true); + break; + case NL80211_IFTYPE_MESH_POINT: + /* mesh should be handled? */ + break; + default: + break; + } + + cfg80211_process_rdev_events(rdev); + } + + err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, + ntype, flags, params); + + WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); + + if (!err && params && params->use_4addr != -1) + dev->ieee80211_ptr->use_4addr = params->use_4addr; + + if (!err) { + dev->priv_flags &= ~IFF_DONT_BRIDGE; + switch (ntype) { + case NL80211_IFTYPE_STATION: + if (dev->ieee80211_ptr->use_4addr) + break; + /* fall through */ + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_ADHOC: + dev->priv_flags |= IFF_DONT_BRIDGE; + break; + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + /* bridging OK */ + break; + case NL80211_IFTYPE_MONITOR: + /* monitor can't bridge anyway */ + break; + case NL80211_IFTYPE_UNSPECIFIED: + case NUM_NL80211_IFTYPES: + /* not happening */ + break; + } + } + + return err; +} + +u16 cfg80211_calculate_bitrate(struct rate_info *rate) +{ + int modulation, streams, bitrate; + + if (!(rate->flags & RATE_INFO_FLAGS_MCS)) + return rate->legacy; + + /* the formula below does only work for MCS values smaller than 32 */ + if (rate->mcs >= 32) + return 0; + + modulation = rate->mcs & 7; + streams = (rate->mcs >> 3) + 1; + + bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? + 13500000 : 6500000; + + if (modulation < 4) + bitrate *= (modulation + 1); + else if (modulation == 4) + bitrate *= (modulation + 2); + else + bitrate *= (modulation + 3); + + bitrate *= streams; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} + +int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, + u32 beacon_int) +{ + struct wireless_dev *wdev; + int res = 0; + + if (!beacon_int) + return -EINVAL; + + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->netdev_list, list) { + if (!wdev->beacon_interval) + continue; + if (wdev->beacon_interval != beacon_int) { + res = -EINVAL; + break; + } + } + + mutex_unlock(&rdev->devlist_mtx); + + return res; +} + +int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + enum nl80211_iftype iftype) +{ + struct wireless_dev *wdev_iter; + int num[NUM_NL80211_IFTYPES]; + int total = 1; + int i, j; + + ASSERT_RTNL(); + + /* Always allow software iftypes */ + if (rdev->wiphy.software_iftypes & BIT(iftype)) + return 0; + + /* + * Drivers will gradually all set this flag, until all + * have it we only enforce for those that set it. + */ + if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS)) + return 0; + + memset(num, 0, sizeof(num)); + + num[iftype] = 1; + + mutex_lock(&rdev->devlist_mtx); + list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { + if (wdev_iter == wdev) + continue; + if (!netif_running(wdev_iter->netdev)) + continue; + + if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) + continue; + + num[wdev_iter->iftype]++; + total++; + } + mutex_unlock(&rdev->devlist_mtx); + + for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { + const struct ieee80211_iface_combination *c; + struct ieee80211_iface_limit *limits; + + c = &rdev->wiphy.iface_combinations[i]; + + limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, + GFP_KERNEL); + if (!limits) + return -ENOMEM; + if (total > c->max_interfaces) + goto cont; + + for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { + if (rdev->wiphy.software_iftypes & BIT(iftype)) + continue; + for (j = 0; j < c->n_limits; j++) { + if (!(limits[j].types & iftype)) + continue; + if (limits[j].max < num[iftype]) + goto cont; + limits[j].max -= num[iftype]; + } + } + /* yay, it fits */ + kfree(limits); + return 0; + cont: + kfree(limits); + } + + return -EBUSY; +} + +int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, + const u8 *rates, unsigned int n_rates, + u32 *mask) +{ + int i, j; + + if (!sband) + return -EINVAL; + + if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES) + return -EINVAL; + + *mask = 0; + + for (i = 0; i < n_rates; i++) { + int rate = (rates[i] & 0x7f) * 5; + bool found = false; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) { + found = true; + *mask |= BIT(j); + break; + } + } + if (!found) + return -EINVAL; + } + + /* + * mask must have at least one bit set here since we + * didn't accept a 0-length rates array nor allowed + * entries in the array that didn't exist + */ + + return 0; +} + +u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, + struct ieee802_11_elems *elems, + u64 filter, u32 crc) +{ + size_t left = len; + u8 *pos = start; + bool calc_crc = filter != 0; + + memset(elems, 0, sizeof(*elems)); + elems->ie_start = start; + elems->total_len = len; + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) + break; + + if (calc_crc && id < 64 && (filter & (1ULL << id))) + crc = crc32_be(crc, pos - 2, elen + 2); + + 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: + if (elen >= sizeof(struct ieee80211_tim_ie)) { + elems->tim = (void *)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_VENDOR_SPECIFIC: + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && + pos[2] == 0xf2) { + /* Microsoft OUI (00:50:F2) */ + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + + if (pos[3] == 1) { + /* OUI Type 1 - WPA IE */ + elems->wpa = pos; + elems->wpa_len = elen; + } else if (elen >= 5 && pos[3] == 2) { + /* OUI Type 2 - WMM IE */ + if (pos[4] == 0) { + elems->wmm_info = pos; + elems->wmm_info_len = elen; + } else if (pos[4] == 1) { + elems->wmm_param = pos; + elems->wmm_param_len = elen; + } + } + } + break; + case WLAN_EID_RSN: + elems->rsn = pos; + elems->rsn_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_HT_CAPABILITY: + if (elen >= sizeof(struct ieee80211_ht_cap)) + elems->ht_cap_elem = (void *)pos; + break; + case WLAN_EID_HT_INFORMATION: + if (elen >= sizeof(struct ieee80211_ht_info)) + elems->ht_info_elem = (void *)pos; + break; + case WLAN_EID_MESH_ID: + elems->mesh_id = pos; + elems->mesh_id_len = elen; + break; + case WLAN_EID_MESH_CONFIG: + if (elen >= sizeof(struct ieee80211_meshconf_ie)) + elems->mesh_config = (void *)pos; + break; + case WLAN_EID_PEER_MGMT: + elems->peering = pos; + elems->peering_len = elen; + break; + case WLAN_EID_PREQ: + elems->preq = pos; + elems->preq_len = elen; + break; + case WLAN_EID_PREP: + elems->prep = pos; + elems->prep_len = elen; + break; + case WLAN_EID_PERR: + elems->perr = pos; + elems->perr_len = elen; + break; + case WLAN_EID_RANN: + if (elen >= sizeof(struct ieee80211_rann_ie)) + elems->rann = (void *)pos; + break; + case WLAN_EID_CHANNEL_SWITCH: + elems->ch_switch_elem = pos; + elems->ch_switch_elem_len = elen; + break; + case WLAN_EID_QUIET: + if (!elems->quiet_elem) { + elems->quiet_elem = pos; + elems->quiet_elem_len = elen; + } + elems->num_of_quiet_elem++; + break; + case WLAN_EID_COUNTRY: + elems->country_elem = pos; + elems->country_elem_len = elen; + break; + case WLAN_EID_PWR_CONSTRAINT: + elems->pwr_constr_elem = pos; + elems->pwr_constr_elem_len = elen; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + elems->timeout_int = pos; + elems->timeout_int_len = elen; + break; + default: + break; + } + + left -= elen; + pos += elen; + } + + return crc; +} +EXPORT_SYMBOL(ieee802_11_parse_elems_crc); diff --git a/net/wireless_ath/wext-compat.c b/net/wireless_ath/wext-compat.c new file mode 100644 index 00000000..3c24eb97 --- /dev/null +++ b/net/wireless_ath/wext-compat.c @@ -0,0 +1,1531 @@ +/* + * cfg80211 - wext compat code + * + * This is temporary code until all wireless functionality is migrated + * into cfg80211, when that happens all the exports here go away and + * we directly assign the wireless handlers of wireless interfaces. + * + * Copyright 2008-2009 Johannes Berg + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wext-compat.h" +#include "core.h" + +int cfg80211_wext_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_supported_band *sband; + bool is_ht = false, is_a = false, is_b = false, is_g = false; + + if (!wdev) + return -EOPNOTSUPP; + + sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + if (sband) { + is_a = true; + is_ht |= sband->ht_cap.ht_supported; + } + + sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + if (sband) { + int i; + /* Check for mandatory rates */ + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 10) + is_b = true; + if (sband->bitrates[i].bitrate == 60) + is_g = true; + } + is_ht |= sband->ht_cap.ht_supported; + } + + strcpy(name, "IEEE 802.11"); + if (is_a) + strcat(name, "a"); + if (is_b) + strcat(name, "b"); + if (is_g) + strcat(name, "g"); + if (is_ht) + strcat(name, "n"); + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); + +int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev; + struct vif_params vifparams; + enum nl80211_iftype type; + int ret; + + rdev = wiphy_to_dev(wdev->wiphy); + + switch (*mode) { + case IW_MODE_INFRA: + type = NL80211_IFTYPE_STATION; + break; + case IW_MODE_ADHOC: + type = NL80211_IFTYPE_ADHOC; + break; + case IW_MODE_REPEAT: + type = NL80211_IFTYPE_WDS; + break; + case IW_MODE_MONITOR: + type = NL80211_IFTYPE_MONITOR; + break; + default: + return -EINVAL; + } + + if (type == wdev->iftype) + return 0; + + memset(&vifparams, 0, sizeof(vifparams)); + + cfg80211_lock_rdev(rdev); + ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); + cfg80211_unlock_rdev(rdev); + + return ret; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); + +int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (!wdev) + return -EOPNOTSUPP; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + *mode = IW_MODE_MASTER; + break; + case NL80211_IFTYPE_STATION: + *mode = IW_MODE_INFRA; + break; + case NL80211_IFTYPE_ADHOC: + *mode = IW_MODE_ADHOC; + break; + case NL80211_IFTYPE_MONITOR: + *mode = IW_MODE_MONITOR; + break; + case NL80211_IFTYPE_WDS: + *mode = IW_MODE_REPEAT; + break; + case NL80211_IFTYPE_AP_VLAN: + *mode = IW_MODE_SECOND; /* FIXME */ + break; + default: + *mode = IW_MODE_AUTO; + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); + + +int cfg80211_wext_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct iw_range *range = (struct iw_range *) extra; + enum ieee80211_band band; + int i, c = 0; + + if (!wdev) + return -EOPNOTSUPP; + + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 21; + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 0; + range->max_retry = 255; + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->max_encoding_tokens = 4; + + range->max_qual.updated = IW_QUAL_NOISE_INVALID; + + switch (wdev->wiphy->signal_type) { + case CFG80211_SIGNAL_TYPE_NONE: + break; + case CFG80211_SIGNAL_TYPE_MBM: + range->max_qual.level = -110; + range->max_qual.qual = 70; + range->avg_qual.qual = 35; + range->max_qual.updated |= IW_QUAL_DBM; + range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; + range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; + break; + case CFG80211_SIGNAL_TYPE_UNSPEC: + range->max_qual.level = 100; + range->max_qual.qual = 100; + range->avg_qual.qual = 50; + range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; + range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; + break; + } + + range->avg_qual.level = range->max_qual.level / 2; + range->avg_qual.noise = range->max_qual.noise / 2; + range->avg_qual.updated = range->max_qual.updated; + + for (i = 0; i < wdev->wiphy->n_cipher_suites; i++) { + switch (wdev->wiphy->cipher_suites[i]) { + case WLAN_CIPHER_SUITE_TKIP: + range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_WPA); + break; + + case WLAN_CIPHER_SUITE_CCMP: + range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP | + IW_ENC_CAPA_WPA2); + break; + + case WLAN_CIPHER_SUITE_WEP40: + range->encoding_size[range->num_encoding_sizes++] = + WLAN_KEY_LEN_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + range->encoding_size[range->num_encoding_sizes++] = + WLAN_KEY_LEN_WEP104; + break; + } + } + + for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { + struct ieee80211_supported_band *sband; + + sband = wdev->wiphy->bands[band]; + + if (!sband) + continue; + + for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + + if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { + range->freq[c].i = + ieee80211_frequency_to_channel( + chan->center_freq); + range->freq[c].m = chan->center_freq; + range->freq[c].e = 6; + c++; + } + } + } + range->num_channels = c; + range->num_frequency = c; + + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + + if (wdev->wiphy->max_scan_ssids > 0) + range->scan_capa |= IW_SCAN_CAPA_ESSID; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); + + +/** + * cfg80211_wext_freq - get wext frequency for non-"auto" + * @wiphy: the wiphy + * @freq: the wext freq encoding + * + * Returns a frequency, or a negative error code, or 0 for auto. + */ +int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) +{ + /* + * Parse frequency - return 0 for auto and + * -EINVAL for impossible things. + */ + if (freq->e == 0) { + enum ieee80211_band band = IEEE80211_BAND_2GHZ; + if (freq->m < 0) + return 0; + if (freq->m > 14) + band = IEEE80211_BAND_5GHZ; + return ieee80211_channel_to_frequency(freq->m, band); + } else { + int i, div = 1000000; + for (i = 0; i < freq->e; i++) + div /= 10; + if (div <= 0) + return -EINVAL; + return freq->m / div; + } +} + +int cfg80211_wext_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 orts = wdev->wiphy->rts_threshold; + int err; + + if (rts->disabled || !rts->fixed) + wdev->wiphy->rts_threshold = (u32) -1; + else if (rts->value < 0) + return -EINVAL; + else + wdev->wiphy->rts_threshold = rts->value; + + err = rdev->ops->set_wiphy_params(wdev->wiphy, + WIPHY_PARAM_RTS_THRESHOLD); + if (err) + wdev->wiphy->rts_threshold = orts; + + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); + +int cfg80211_wext_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + rts->value = wdev->wiphy->rts_threshold; + rts->disabled = rts->value == (u32) -1; + rts->fixed = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); + +int cfg80211_wext_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 ofrag = wdev->wiphy->frag_threshold; + int err; + + if (frag->disabled || !frag->fixed) + wdev->wiphy->frag_threshold = (u32) -1; + else if (frag->value < 256) + return -EINVAL; + else { + /* Fragment length must be even, so strip LSB. */ + wdev->wiphy->frag_threshold = frag->value & ~0x1; + } + + err = rdev->ops->set_wiphy_params(wdev->wiphy, + WIPHY_PARAM_FRAG_THRESHOLD); + if (err) + wdev->wiphy->frag_threshold = ofrag; + + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); + +int cfg80211_wext_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + frag->value = wdev->wiphy->frag_threshold; + frag->disabled = frag->value == (u32) -1; + frag->fixed = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); + +static int cfg80211_wext_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 changed = 0; + u8 olong = wdev->wiphy->retry_long; + u8 oshort = wdev->wiphy->retry_short; + int err; + + if (retry->disabled || + (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) + return -EINVAL; + + if (retry->flags & IW_RETRY_LONG) { + wdev->wiphy->retry_long = retry->value; + changed |= WIPHY_PARAM_RETRY_LONG; + } else if (retry->flags & IW_RETRY_SHORT) { + wdev->wiphy->retry_short = retry->value; + changed |= WIPHY_PARAM_RETRY_SHORT; + } else { + wdev->wiphy->retry_short = retry->value; + wdev->wiphy->retry_long = retry->value; + changed |= WIPHY_PARAM_RETRY_LONG; + changed |= WIPHY_PARAM_RETRY_SHORT; + } + + if (!changed) + return 0; + + err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); + if (err) { + wdev->wiphy->retry_short = oshort; + wdev->wiphy->retry_long = olong; + } + + return err; +} + +int cfg80211_wext_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + retry->disabled = 0; + + if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) { + /* + * First return short value, iwconfig will ask long value + * later if needed + */ + retry->flags |= IW_RETRY_LIMIT; + retry->value = wdev->wiphy->retry_short; + if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) + retry->flags |= IW_RETRY_LONG; + + return 0; + } + + if (retry->flags & IW_RETRY_LONG) { + retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + retry->value = wdev->wiphy->retry_long; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); + +static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool pairwise, + const u8 *addr, bool remove, bool tx_key, + int idx, struct key_params *params) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err, i; + bool rejoin = false; + + if (pairwise && !addr) + return -EINVAL; + + if (!wdev->wext.keys) { + wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), + GFP_KERNEL); + if (!wdev->wext.keys) + return -ENOMEM; + for (i = 0; i < 6; i++) + wdev->wext.keys->params[i].key = + wdev->wext.keys->data[i]; + } + + if (wdev->iftype != NL80211_IFTYPE_ADHOC && + wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + if (!wdev->current_bss) + return -ENOLINK; + + if (!rdev->ops->set_default_mgmt_key) + return -EOPNOTSUPP; + + if (idx < 4 || idx > 5) + return -EINVAL; + } else if (idx < 0 || idx > 3) + return -EINVAL; + + if (remove) { + err = 0; + if (wdev->current_bss) { + /* + * If removing the current TX key, we will need to + * join a new IBSS without the privacy bit clear. + */ + if (idx == wdev->wext.default_key && + wdev->iftype == NL80211_IFTYPE_ADHOC) { + __cfg80211_leave_ibss(rdev, wdev->netdev, true); + rejoin = true; + } + + if (!pairwise && addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + err = -ENOENT; + else + err = rdev->ops->del_key(&rdev->wiphy, dev, idx, + pairwise, addr); + } + wdev->wext.connect.privacy = false; + /* + * Applications using wireless extensions expect to be + * able to delete keys that don't exist, so allow that. + */ + if (err == -ENOENT) + err = 0; + if (!err) { + if (!addr) { + wdev->wext.keys->params[idx].key_len = 0; + wdev->wext.keys->params[idx].cipher = 0; + } + if (idx == wdev->wext.default_key) + wdev->wext.default_key = -1; + else if (idx == wdev->wext.default_mgmt_key) + wdev->wext.default_mgmt_key = -1; + } + + if (!err && rejoin) + err = cfg80211_ibss_wext_join(rdev, wdev); + + return err; + } + + if (addr) + tx_key = false; + + if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) + return -EINVAL; + + err = 0; + if (wdev->current_bss) + err = rdev->ops->add_key(&rdev->wiphy, dev, idx, + pairwise, addr, params); + if (err) + return err; + + if (!addr) { + wdev->wext.keys->params[idx] = *params; + memcpy(wdev->wext.keys->data[idx], + params->key, params->key_len); + wdev->wext.keys->params[idx].key = + wdev->wext.keys->data[idx]; + } + + if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || + params->cipher == WLAN_CIPHER_SUITE_WEP104) && + (tx_key || (!addr && wdev->wext.default_key == -1))) { + if (wdev->current_bss) { + /* + * If we are getting a new TX key from not having + * had one before we need to join a new IBSS with + * the privacy bit set. + */ + if (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->wext.default_key == -1) { + __cfg80211_leave_ibss(rdev, wdev->netdev, true); + rejoin = true; + } + err = rdev->ops->set_default_key(&rdev->wiphy, dev, + idx, true, true); + } + if (!err) { + wdev->wext.default_key = idx; + if (rejoin) + err = cfg80211_ibss_wext_join(rdev, wdev); + } + return err; + } + + if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && + (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { + if (wdev->current_bss) + err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, + dev, idx); + if (!err) + wdev->wext.default_mgmt_key = idx; + return err; + } + + return 0; +} + +static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool pairwise, + const u8 *addr, bool remove, bool tx_key, + int idx, struct key_params *params) +{ + int err; + + /* devlist mutex needed for possible IBSS re-join */ + mutex_lock(&rdev->devlist_mtx); + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, + remove, tx_key, idx, params); + wdev_unlock(dev->ieee80211_ptr); + mutex_unlock(&rdev->devlist_mtx); + + return err; +} + +static int cfg80211_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int idx, err; + bool remove = false; + struct key_params params; + + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; + + /* no use -- only MFP (set_default_mgmt_key) is optional */ + if (!rdev->ops->del_key || + !rdev->ops->add_key || + !rdev->ops->set_default_key) + return -EOPNOTSUPP; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + idx = wdev->wext.default_key; + if (idx < 0) + idx = 0; + } else if (idx < 1 || idx > 4) + return -EINVAL; + else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = true; + else if (erq->length == 0) { + /* No key data - just set the default TX key index */ + err = 0; + wdev_lock(wdev); + if (wdev->current_bss) + err = rdev->ops->set_default_key(&rdev->wiphy, dev, + idx, true, true); + if (!err) + wdev->wext.default_key = idx; + wdev_unlock(wdev); + return err; + } + + memset(¶ms, 0, sizeof(params)); + params.key = keybuf; + params.key_len = erq->length; + if (erq->length == 5) + params.cipher = WLAN_CIPHER_SUITE_WEP40; + else if (erq->length == 13) + params.cipher = WLAN_CIPHER_SUITE_WEP104; + else if (!remove) + return -EINVAL; + + return cfg80211_set_encryption(rdev, dev, false, NULL, remove, + wdev->wext.default_key == -1, + idx, ¶ms); +} + +static int cfg80211_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + const u8 *addr; + int idx; + bool remove = false; + struct key_params params; + u32 cipher; + + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; + + /* no use -- only MFP (set_default_mgmt_key) is optional */ + if (!rdev->ops->del_key || + !rdev->ops->add_key || + !rdev->ops->set_default_key) + return -EOPNOTSUPP; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + remove = true; + cipher = 0; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len == 5) + cipher = WLAN_CIPHER_SUITE_WEP40; + else if (ext->key_len == 13) + cipher = WLAN_CIPHER_SUITE_WEP104; + else + return -EINVAL; + break; + case IW_ENCODE_ALG_TKIP: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case IW_ENCODE_ALG_AES_CMAC: + cipher = WLAN_CIPHER_SUITE_AES_CMAC; + break; + default: + return -EOPNOTSUPP; + } + + if (erq->flags & IW_ENCODE_DISABLED) + remove = true; + + idx = erq->flags & IW_ENCODE_INDEX; + if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + if (idx < 4 || idx > 5) { + idx = wdev->wext.default_mgmt_key; + if (idx < 0) + return -EINVAL; + } else + idx--; + } else { + if (idx < 1 || idx > 4) { + idx = wdev->wext.default_key; + if (idx < 0) + return -EINVAL; + } else + idx--; + } + + addr = ext->addr.sa_data; + if (is_broadcast_ether_addr(addr)) + addr = NULL; + + memset(¶ms, 0, sizeof(params)); + params.key = ext->key; + params.key_len = ext->key_len; + params.cipher = cipher; + + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + params.seq = ext->rx_seq; + params.seq_len = 6; + } + + return cfg80211_set_encryption( + rdev, dev, + !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), + addr, remove, + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, + idx, ¶ms); +} + +static int cfg80211_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int idx; + + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + idx = wdev->wext.default_key; + if (idx < 0) + idx = 0; + } else if (idx < 1 || idx > 4) + return -EINVAL; + else + idx--; + + erq->flags = idx + 1; + + if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) { + erq->flags |= IW_ENCODE_DISABLED; + erq->length = 0; + return 0; + } + + erq->length = min_t(size_t, erq->length, + wdev->wext.keys->params[idx].key_len); + memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length); + erq->flags |= IW_ENCODE_ENABLED; + + return 0; +} + +static int cfg80211_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wextfreq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int freq, err; + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + if (freq < 0) + return freq; + if (freq == 0) + return -EINVAL; + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + return err; + default: + return -EOPNOTSUPP; + } +} + +static int cfg80211_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan; + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + case NL80211_IFTYPE_MONITOR: + if (!rdev->ops->get_channel) + return -EINVAL; + + chan = rdev->ops->get_channel(wdev->wiphy); + if (!chan) + return -EINVAL; + freq->m = chan->center_freq; + freq->e = 6; + return 0; + default: + if (!wdev->channel) + return -EINVAL; + freq->m = wdev->channel->center_freq; + freq->e = 6; + return 0; + } +} + +static int cfg80211_wext_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + enum nl80211_tx_power_setting type; + int dbm = 0; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + + if (!rdev->ops->set_tx_power) + return -EOPNOTSUPP; + + /* only change when not disabling */ + if (!data->txpower.disabled) { + rfkill_set_sw_state(rdev->rfkill, false); + + if (data->txpower.fixed) { + /* + * wext doesn't support negative values, see + * below where it's for automatic + */ + if (data->txpower.value < 0) + return -EINVAL; + dbm = data->txpower.value; + type = NL80211_TX_POWER_FIXED; + /* TODO: do regulatory check! */ + } else { + /* + * Automatic power level setting, max being the value + * passed in from userland. + */ + if (data->txpower.value < 0) { + type = NL80211_TX_POWER_AUTOMATIC; + } else { + dbm = data->txpower.value; + type = NL80211_TX_POWER_LIMITED; + } + } + } else { + rfkill_set_sw_state(rdev->rfkill, true); + schedule_work(&rdev->rfkill_sync); + return 0; + } + + return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm)); +} + +static int cfg80211_wext_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int err, val; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + + if (!rdev->ops->get_tx_power) + return -EOPNOTSUPP; + + err = rdev->ops->get_tx_power(wdev->wiphy, &val); + if (err) + return err; + + /* well... oh well */ + data->txpower.fixed = 1; + data->txpower.disabled = rfkill_blocked(rdev->rfkill); + data->txpower.value = val; + data->txpower.flags = IW_TXPOW_DBM; + + return 0; +} + +static int cfg80211_set_auth_alg(struct wireless_dev *wdev, + s32 auth_alg) +{ + int nr_alg = 0; + + if (!auth_alg) + return -EINVAL; + + if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM | + IW_AUTH_ALG_SHARED_KEY | + IW_AUTH_ALG_LEAP)) + return -EINVAL; + + if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) { + nr_alg++; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; + } + + if (auth_alg & IW_AUTH_ALG_SHARED_KEY) { + nr_alg++; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY; + } + + if (auth_alg & IW_AUTH_ALG_LEAP) { + nr_alg++; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP; + } + + if (nr_alg > 1) + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + + return 0; +} + +static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) +{ + if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | + IW_AUTH_WPA_VERSION_WPA2| + IW_AUTH_WPA_VERSION_DISABLED)) + return -EINVAL; + + if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) && + (wpa_versions & (IW_AUTH_WPA_VERSION_WPA| + IW_AUTH_WPA_VERSION_WPA2))) + return -EINVAL; + + if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) + wdev->wext.connect.crypto.wpa_versions &= + ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2); + + if (wpa_versions & IW_AUTH_WPA_VERSION_WPA) + wdev->wext.connect.crypto.wpa_versions |= + NL80211_WPA_VERSION_1; + + if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2) + wdev->wext.connect.crypto.wpa_versions |= + NL80211_WPA_VERSION_2; + + return 0; +} + +static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) +{ + if (cipher & IW_AUTH_CIPHER_WEP40) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_WEP40; + else if (cipher & IW_AUTH_CIPHER_WEP104) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_WEP104; + else if (cipher & IW_AUTH_CIPHER_TKIP) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_TKIP; + else if (cipher & IW_AUTH_CIPHER_CCMP) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_CCMP; + else if (cipher & IW_AUTH_CIPHER_AES_CMAC) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_AES_CMAC; + else if (cipher & IW_AUTH_CIPHER_NONE) + wdev->wext.connect.crypto.cipher_group = 0; + else + return -EINVAL; + + return 0; +} + +static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) +{ + int nr_ciphers = 0; + u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise; + + if (cipher & IW_AUTH_CIPHER_WEP40) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_WEP104) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_TKIP) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_CCMP) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_AES_CMAC) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC; + nr_ciphers++; + } + + BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5); + + wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers; + + return 0; +} + + +static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) +{ + int nr_akm_suites = 0; + + if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X | + IW_AUTH_KEY_MGMT_PSK)) + return -EINVAL; + + if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) { + wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = + WLAN_AKM_SUITE_8021X; + nr_akm_suites++; + } + + if (key_mgt & IW_AUTH_KEY_MGMT_PSK) { + wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = + WLAN_AKM_SUITE_PSK; + nr_akm_suites++; + } + + wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites; + + return 0; +} + +static int cfg80211_wext_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_PRIVACY_INVOKED: + wdev->wext.connect.privacy = data->value; + return 0; + case IW_AUTH_WPA_VERSION: + return cfg80211_set_wpa_version(wdev, data->value); + case IW_AUTH_CIPHER_GROUP: + return cfg80211_set_cipher_group(wdev, data->value); + case IW_AUTH_KEY_MGMT: + return cfg80211_set_key_mgt(wdev, data->value); + case IW_AUTH_CIPHER_PAIRWISE: + return cfg80211_set_cipher_pairwise(wdev, data->value); + case IW_AUTH_80211_AUTH_ALG: + return cfg80211_set_auth_alg(wdev, data->value); + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_MFP: + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int cfg80211_wext_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + /* XXX: what do we need? */ + + return -EOPNOTSUPP; +} + +static int cfg80211_wext_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + bool ps = wdev->ps; + int timeout = wdev->ps_timeout; + int err; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; + + if (wrq->disabled) { + ps = false; + } else { + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_ON: /* If not specified */ + case IW_POWER_MODE: /* If set all mask */ + case IW_POWER_ALL_R: /* If explicitely state all */ + ps = true; + break; + default: /* Otherwise we ignore */ + return -EINVAL; + } + + if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) + return -EINVAL; + + if (wrq->flags & IW_POWER_TIMEOUT) + timeout = wrq->value / 1000; + } + + err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout); + if (err) + return err; + + wdev->ps = ps; + wdev->ps_timeout = timeout; + + return 0; + +} + +static int cfg80211_wext_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wrq->disabled = !wdev->ps; + + return 0; +} + +static int cfg80211_wds_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int err; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) + return -EINVAL; + + if (addr->sa_family != ARPHRD_ETHER) + return -EINVAL; + + if (netif_running(dev)) + return -EBUSY; + + if (!rdev->ops->set_wds_peer) + return -EOPNOTSUPP; + + err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data); + if (err) + return err; + + memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN); + + return 0; +} + +static int cfg80211_wds_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) + return -EINVAL; + + addr->sa_family = ARPHRD_ETHER; + memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN); + + return 0; +} + +static int cfg80211_wext_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_bitrate_mask mask; + u32 fixed, maxrate; + struct ieee80211_supported_band *sband; + int band, ridx; + bool match = false; + + if (!rdev->ops->set_bitrate_mask) + return -EOPNOTSUPP; + + memset(&mask, 0, sizeof(mask)); + fixed = 0; + maxrate = (u32)-1; + + if (rate->value < 0) { + /* nothing */ + } else if (rate->fixed) { + fixed = rate->value / 100000; + } else { + maxrate = rate->value / 100000; + } + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wdev->wiphy->bands[band]; + if (sband == NULL) + continue; + for (ridx = 0; ridx < sband->n_bitrates; ridx++) { + struct ieee80211_rate *srate = &sband->bitrates[ridx]; + if (fixed == srate->bitrate) { + mask.control[band].legacy = 1 << ridx; + match = true; + break; + } + if (srate->bitrate <= maxrate) { + mask.control[band].legacy |= 1 << ridx; + match = true; + } + } + } + + if (!match) + return -EINVAL; + + return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); +} + +static int cfg80211_wext_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + /* we are under RTNL - globally locked - so can use a static struct */ + static struct station_info sinfo; + u8 addr[ETH_ALEN]; + int err; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (!rdev->ops->get_station) + return -EOPNOTSUPP; + + err = 0; + wdev_lock(wdev); + if (wdev->current_bss) + memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); + else + err = -EOPNOTSUPP; + wdev_unlock(wdev); + if (err) + return err; + + err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); + if (err) + return err; + + if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) + return -EOPNOTSUPP; + + rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); + + return 0; +} + +/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ +static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + /* we are under RTNL - globally locked - so can use static structs */ + static struct iw_statistics wstats; + static struct station_info sinfo; + u8 bssid[ETH_ALEN]; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) + return NULL; + + if (!rdev->ops->get_station) + return NULL; + + /* Grab BSSID of current BSS, if any */ + wdev_lock(wdev); + if (!wdev->current_bss) { + wdev_unlock(wdev); + return NULL; + } + memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); + wdev_unlock(wdev); + + if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo)) + return NULL; + + memset(&wstats, 0, sizeof(wstats)); + + switch (rdev->wiphy.signal_type) { + case CFG80211_SIGNAL_TYPE_MBM: + if (sinfo.filled & STATION_INFO_SIGNAL) { + int sig = sinfo.signal; + wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; + wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; + wstats.qual.updated |= IW_QUAL_DBM; + wstats.qual.level = sig; + if (sig < -110) + sig = -110; + else if (sig > -40) + sig = -40; + wstats.qual.qual = sig + 110; + break; + } + case CFG80211_SIGNAL_TYPE_UNSPEC: + if (sinfo.filled & STATION_INFO_SIGNAL) { + wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; + wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; + wstats.qual.level = sinfo.signal; + wstats.qual.qual = sinfo.signal; + break; + } + default: + wstats.qual.updated |= IW_QUAL_LEVEL_INVALID; + wstats.qual.updated |= IW_QUAL_QUAL_INVALID; + } + + wstats.qual.updated |= IW_QUAL_NOISE_INVALID; + if (sinfo.filled & STATION_INFO_RX_DROP_MISC) + wstats.discard.misc = sinfo.rx_dropped_misc; + if (sinfo.filled & STATION_INFO_TX_FAILED) + wstats.discard.retries = sinfo.tx_failed; + + return &wstats; +} + +static int cfg80211_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_WDS: + return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; + } +} + +static int cfg80211_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_WDS: + return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; + } +} + +static int cfg80211_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; + } +} + +static int cfg80211_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + data->flags = 0; + data->length = 0; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; + } +} + +static int cfg80211_wext_siwpmksa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_pmksa cfg_pmksa; + struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; + + memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa)); + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + cfg_pmksa.bssid = pmksa->bssid.sa_data; + cfg_pmksa.pmkid = pmksa->pmkid; + + switch (pmksa->cmd) { + case IW_PMKSA_ADD: + if (!rdev->ops->set_pmksa) + return -EOPNOTSUPP; + + return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa); + + case IW_PMKSA_REMOVE: + if (!rdev->ops->del_pmksa) + return -EOPNOTSUPP; + + return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa); + + case IW_PMKSA_FLUSH: + if (!rdev->ops->flush_pmksa) + return -EOPNOTSUPP; + + return rdev->ops->flush_pmksa(&rdev->wiphy, dev); + + default: + return -EOPNOTSUPP; + } +} + +static const iw_handler cfg80211_handlers[] = { + [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, + [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, + [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, + [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, + [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, + [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, + [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, + [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, + [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, + [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, + [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, + [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, + [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, + [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, + [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, + [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, + [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, + [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, + [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, + [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, + [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, + [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, + [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, + [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, + [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, + [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, + [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, + [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, + [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, + [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, + [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, + [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, +}; + +const struct iw_handler_def cfg80211_wext_handler = { + .num_standard = ARRAY_SIZE(cfg80211_handlers), + .standard = cfg80211_handlers, + .get_wireless_stats = cfg80211_wireless_stats, +}; diff --git a/net/wireless_ath/wext-compat.h b/net/wireless_ath/wext-compat.h new file mode 100644 index 00000000..5d766b01 --- /dev/null +++ b/net/wireless_ath/wext-compat.h @@ -0,0 +1,57 @@ +#ifndef __WEXT_COMPAT +#define __WEXT_COMPAT + +#include +#include + +int cfg80211_ibss_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_ibss_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_ibss_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_ibss_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); + +int cfg80211_mgd_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_mgd_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); + +int cfg80211_wext_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); + + +int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); + + +extern const struct iw_handler_def cfg80211_wext_handler; +#endif /* __WEXT_COMPAT */ diff --git a/net/wireless_ath/wext-core.c b/net/wireless_ath/wext-core.c new file mode 100644 index 00000000..ae45584d --- /dev/null +++ b/net/wireless_ath/wext-core.c @@ -0,0 +1,1123 @@ +/* + * This file implement the Wireless Extensions core API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * Copyright 2009 Johannes Berg + * + * (As all part of the Linux kernel, this file is GPL) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, + unsigned int, struct iw_request_info *, + iw_handler); + + +/* + * Meta-data about all the standard Wireless Extension request we + * know about. + */ +static const struct iw_ioctl_description standard_ioctl[] = { + [IW_IOCTL_IDX(SIOCSIWCOMMIT)] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [IW_IOCTL_IDX(SIOCGIWNAME)] = { + .header_type = IW_HEADER_TYPE_CHAR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWNWID)] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_EVENT, + }, + [IW_IOCTL_IDX(SIOCGIWNWID)] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWFREQ)] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_EVENT, + }, + [IW_IOCTL_IDX(SIOCGIWFREQ)] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWMODE)] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_EVENT, + }, + [IW_IOCTL_IDX(SIOCGIWMODE)] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWSENS)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWSENS)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWRANGE)] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [IW_IOCTL_IDX(SIOCGIWRANGE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_range), + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWPRIV)] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [IW_IOCTL_IDX(SIOCGIWPRIV)] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_priv_args), + .max_tokens = 16, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [IW_IOCTL_IDX(SIOCSIWSTATS)] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [IW_IOCTL_IDX(SIOCGIWSTATS)] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_statistics), + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWSPY)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr), + .max_tokens = IW_MAX_SPY, + }, + [IW_IOCTL_IDX(SIOCGIWSPY)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_SPY, + }, + [IW_IOCTL_IDX(SIOCSIWTHRSPY)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [IW_IOCTL_IDX(SIOCGIWTHRSPY)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [IW_IOCTL_IDX(SIOCSIWAP)] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IW_IOCTL_IDX(SIOCGIWAP)] = { + .header_type = IW_HEADER_TYPE_ADDR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWMLME)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_mlme), + .max_tokens = sizeof(struct iw_mlme), + }, + [IW_IOCTL_IDX(SIOCGIWAPLIST)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_AP, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [IW_IOCTL_IDX(SIOCSIWSCAN)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = 0, + .max_tokens = sizeof(struct iw_scan_req), + }, + [IW_IOCTL_IDX(SIOCGIWSCAN)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_SCAN_MAX_DATA, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [IW_IOCTL_IDX(SIOCSIWESSID)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_EVENT, + }, + [IW_IOCTL_IDX(SIOCGIWESSID)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_DUMP, + }, + [IW_IOCTL_IDX(SIOCSIWNICKN)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [IW_IOCTL_IDX(SIOCGIWNICKN)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [IW_IOCTL_IDX(SIOCSIWRATE)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWRATE)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWRTS)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWRTS)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWFRAG)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWFRAG)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWTXPOW)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWTXPOW)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWRETRY)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWRETRY)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWENCODE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, + }, + [IW_IOCTL_IDX(SIOCGIWENCODE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, + }, + [IW_IOCTL_IDX(SIOCSIWPOWER)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWPOWER)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWGENIE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IW_IOCTL_IDX(SIOCGIWGENIE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IW_IOCTL_IDX(SIOCSIWAUTH)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCGIWAUTH)] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [IW_IOCTL_IDX(SIOCSIWENCODEEXT)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [IW_IOCTL_IDX(SIOCGIWENCODEEXT)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [IW_IOCTL_IDX(SIOCSIWPMKSA)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_pmksa), + .max_tokens = sizeof(struct iw_pmksa), + }, +}; +static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); + +/* + * Meta-data about all the additional standard Wireless Extension events + * we know about. + */ +static const struct iw_ioctl_description standard_event[] = { + [IW_EVENT_IDX(IWEVTXDROP)] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IW_EVENT_IDX(IWEVQUAL)] = { + .header_type = IW_HEADER_TYPE_QUAL, + }, + [IW_EVENT_IDX(IWEVCUSTOM)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_CUSTOM_MAX, + }, + [IW_EVENT_IDX(IWEVREGISTERED)] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IW_EVENT_IDX(IWEVEXPIRED)] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IW_EVENT_IDX(IWEVGENIE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IW_EVENT_IDX(IWEVMICHAELMICFAILURE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_michaelmicfailure), + }, + [IW_EVENT_IDX(IWEVASSOCREQIE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IW_EVENT_IDX(IWEVASSOCRESPIE)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IW_EVENT_IDX(IWEVPMKIDCAND)] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_pmkid_cand), + }, +}; +static const unsigned standard_event_num = ARRAY_SIZE(standard_event); + +/* Size (in bytes) of various events */ +static const int event_type_size[] = { + IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_POINT_LEN, /* Without variable payload */ + IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; + +#ifdef CONFIG_COMPAT +static const int compat_event_type_size[] = { + IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ + IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; +#endif + + +/* IW event code */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) +static int __net_init wext_pernet_init(struct net *net) +{ + skb_queue_head_init(&net->wext_nlevents); + return 0; +} + +static void __net_exit wext_pernet_exit(struct net *net) +{ + skb_queue_purge(&net->wext_nlevents); +} + +static struct pernet_operations wext_pernet_ops = { + .init = wext_pernet_init, + .exit = wext_pernet_exit, +}; + +static int __init wireless_nlevent_init(void) +{ + return register_pernet_subsys(&wext_pernet_ops); +} + +subsys_initcall(wireless_nlevent_init); + +/* Process events generated by the wireless layer or the driver. */ +static void wireless_nlevent_process(struct work_struct *work) +{ + struct sk_buff *skb; + struct net *net; + + rtnl_lock(); + + for_each_net(net) { + while ((skb = skb_dequeue(&net->wext_nlevents))) + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, + GFP_KERNEL); + } + + rtnl_unlock(); +} + +static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); + +#else +/* Older kernels get the old way of doing stuff*/ +static struct sk_buff_head wireless_nlevent_queue; + +static int __init wireless_nlevent_init(void) +{ + skb_queue_head_init(&wireless_nlevent_queue); + return 0; +} + +subsys_initcall(wireless_nlevent_init); + +static void wireless_nlevent_process(unsigned long data) +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(&wireless_nlevent_queue))) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); +#else + rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); +#endif +} + +static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); + +#endif + +static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev, + struct sk_buff *skb) +{ + struct ifinfomsg *r; + struct nlmsghdr *nlh; + + nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0); + if (!nlh) + return NULL; + + r = nlmsg_data(nlh); + r->ifi_family = AF_UNSPEC; + r->__ifi_pad = 0; + r->ifi_type = dev->type; + r->ifi_index = dev->ifindex; + r->ifi_flags = dev_get_flags(dev); + r->ifi_change = 0; /* Wireless changes don't affect those flags */ + + NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); + + return nlh; + nla_put_failure: + nlmsg_cancel(skb, nlh); + return NULL; +} + + +/* + * Main event dispatcher. Called from other parts and drivers. + * Send the event on the appropriate channels. + * May be called from interrupt context. + */ +void wireless_send_event(struct net_device * dev, + unsigned int cmd, + union iwreq_data * wrqu, + const char * extra) +{ + const struct iw_ioctl_description * descr = NULL; + int extra_len = 0; + struct iw_event *event; /* Mallocated whole event */ + int event_len; /* Its size */ + int hdr_len; /* Size of the event header */ + int wrqu_off = 0; /* Offset in wrqu */ + /* Don't "optimise" the following variable, it will crash */ + unsigned cmd_index; /* *MUST* be unsigned */ + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct nlattr *nla; +#ifdef CONFIG_COMPAT + struct __compat_iw_event *compat_event; + struct compat_iw_point compat_wrqu; + struct sk_buff *compskb; +#endif + + /* + * Nothing in the kernel sends scan events with data, be safe. + * This is necessary because we cannot fix up scan event data + * for compat, due to being contained in 'extra', but normally + * applications are required to retrieve the scan data anyway + * and no data is included in the event, this codifies that + * practice. + */ + if (WARN_ON(cmd == SIOCGIWSCAN && extra)) + extra = NULL; + + /* Get the description of the Event */ + if (cmd <= SIOCIWLAST) { + cmd_index = IW_IOCTL_IDX(cmd); + if (cmd_index < standard_ioctl_num) + descr = &(standard_ioctl[cmd_index]); + } else { + cmd_index = IW_EVENT_IDX(cmd); + if (cmd_index < standard_event_num) + descr = &(standard_event[cmd_index]); + } + /* Don't accept unknown events */ + if (descr == NULL) { + /* Note : we don't return an error to the driver, because + * the driver would not know what to do about it. It can't + * return an error to the user, because the event is not + * initiated by a user request. + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ + netdev_err(dev, "(WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + cmd); + return; + } + + /* Check extra parameters and set extra_len */ + if (descr->header_type == IW_HEADER_TYPE_POINT) { + /* Check if number of token fits within bounds */ + if (wrqu->data.length > descr->max_tokens) { + netdev_err(dev, "(WE) : Wireless Event too big (%d)\n", + wrqu->data.length); + return; + } + if (wrqu->data.length < descr->min_tokens) { + netdev_err(dev, "(WE) : Wireless Event too small (%d)\n", + wrqu->data.length); + return; + } + /* Calculate extra_len - extra is NULL for restricted events */ + if (extra != NULL) + extra_len = wrqu->data.length * descr->token_size; + /* Always at an offset in wrqu */ + wrqu_off = IW_EV_POINT_OFF; + } + + /* Total length of the event */ + hdr_len = event_type_size[descr->header_type]; + event_len = hdr_len + extra_len; + + /* + * The problem for 64/32 bit. + * + * On 64-bit, a regular event is laid out as follows: + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | event.len | event.cmd | p a d d i n g | + * | wrqu data ... (with the correct size) | + * + * This padding exists because we manipulate event->u, + * and 'event' is not packed. + * + * An iw_point event is laid out like this instead: + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | event.len | event.cmd | p a d d i n g | + * | iwpnt.len | iwpnt.flg | p a d d i n g | + * | extra data ... + * + * The second padding exists because struct iw_point is extended, + * but this depends on the platform... + * + * On 32-bit, all the padding shouldn't be there. + */ + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return; + + /* Send via the RtNetlink event channel */ + nlh = rtnetlink_ifinfo_prep(dev, skb); + if (WARN_ON(!nlh)) { + kfree_skb(skb); + return; + } + + /* Add the wireless events in the netlink packet */ + nla = nla_reserve(skb, IFLA_WIRELESS, event_len); + if (!nla) { + kfree_skb(skb); + return; + } + event = nla_data(nla); + + /* Fill event - first clear to avoid data leaking */ + memset(event, 0, hdr_len); + event->len = event_len; + event->cmd = cmd; + memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); + if (extra_len) + memcpy(((char *) event) + hdr_len, extra, extra_len); + + nlmsg_end(skb, nlh); +#ifdef CONFIG_COMPAT + hdr_len = compat_event_type_size[descr->header_type]; + event_len = hdr_len + extra_len; + + compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!compskb) { + kfree_skb(skb); + return; + } + + /* Send via the RtNetlink event channel */ + nlh = rtnetlink_ifinfo_prep(dev, compskb); + if (WARN_ON(!nlh)) { + kfree_skb(skb); + kfree_skb(compskb); + return; + } + + /* Add the wireless events in the netlink packet */ + nla = nla_reserve(compskb, IFLA_WIRELESS, event_len); + if (!nla) { + kfree_skb(skb); + kfree_skb(compskb); + return; + } + compat_event = nla_data(nla); + + compat_event->len = event_len; + compat_event->cmd = cmd; + if (descr->header_type == IW_HEADER_TYPE_POINT) { + compat_wrqu.length = wrqu->data.length; + compat_wrqu.flags = wrqu->data.flags; + memcpy(&compat_event->pointer, + ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF, + hdr_len - IW_EV_COMPAT_LCP_LEN); + if (extra_len) + memcpy(((char *) compat_event) + hdr_len, + extra, extra_len); + } else { + /* extra_len must be zero, so no if (extra) needed */ + memcpy(&compat_event->pointer, wrqu, + hdr_len - IW_EV_COMPAT_LCP_LEN); + } + + nlmsg_end(compskb, nlh); + + skb_shinfo(skb)->frag_list = compskb; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) + skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); + schedule_work(&wireless_nlevent_work); +#else + skb_queue_tail(&wireless_nlevent_queue, skb); + tasklet_schedule(&wireless_nlevent_tasklet); +#endif +} +EXPORT_SYMBOL(wireless_send_event); + + + +/* IW handlers */ + +struct iw_statistics *get_wireless_stats(struct net_device *dev) +{ +#ifdef CONFIG_WIRELESS_EXT + if ((dev->wireless_handlers != NULL) && + (dev->wireless_handlers->get_wireless_stats != NULL)) + return dev->wireless_handlers->get_wireless_stats(dev); +#endif + +#ifdef CONFIG_CFG80211_WEXT + if (dev->ieee80211_ptr && + dev->ieee80211_ptr->wiphy && + dev->ieee80211_ptr->wiphy->wext && + dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) + return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev); +#endif + + /* not found */ + return NULL; +} + +static int iw_handler_get_iwstats(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + /* Get stats from the driver */ + struct iw_statistics *stats; + + stats = get_wireless_stats(dev); + if (stats) { + /* Copy statistics to extra */ + memcpy(extra, stats, sizeof(struct iw_statistics)); + wrqu->data.length = sizeof(struct iw_statistics); + + /* Check if we need to clear the updated flag */ + if (wrqu->data.flags != 0) + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; + return 0; + } else + return -EOPNOTSUPP; +} + +static iw_handler get_handler(struct net_device *dev, unsigned int cmd) +{ + /* Don't "optimise" the following variable, it will crash */ + unsigned int index; /* *MUST* be unsigned */ + const struct iw_handler_def *handlers = NULL; + +#ifdef CONFIG_CFG80211_WEXT + if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy) + handlers = dev->ieee80211_ptr->wiphy->wext; +#endif +#ifdef CONFIG_WIRELESS_EXT + if (dev->wireless_handlers) + handlers = dev->wireless_handlers; +#endif + + if (!handlers) + return NULL; + + /* Try as a standard command */ + index = IW_IOCTL_IDX(cmd); + if (index < handlers->num_standard) + return handlers->standard[index]; + +#ifdef CONFIG_WEXT_PRIV + /* Try as a private command */ + index = cmd - SIOCIWFIRSTPRIV; + if (index < handlers->num_private) + return handlers->private[index]; +#endif + + /* Not found */ + return NULL; +} + +static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, + const struct iw_ioctl_description *descr, + iw_handler handler, struct net_device *dev, + struct iw_request_info *info) +{ + int err, extra_size, user_length = 0, essid_compat = 0; + char *extra; + + /* Calculate space needed by arguments. Always allocate + * for max space. + */ + extra_size = descr->max_tokens * descr->token_size; + + /* Check need for ESSID compatibility for WE < 21 */ + switch (cmd) { + case SIOCSIWESSID: + case SIOCGIWESSID: + case SIOCSIWNICKN: + case SIOCGIWNICKN: + if (iwp->length == descr->max_tokens + 1) + essid_compat = 1; + else if (IW_IS_SET(cmd) && (iwp->length != 0)) { + char essid[IW_ESSID_MAX_SIZE + 1]; + unsigned int len; + len = iwp->length * descr->token_size; + + if (len > IW_ESSID_MAX_SIZE) + return -EFAULT; + + err = copy_from_user(essid, iwp->pointer, len); + if (err) + return -EFAULT; + + if (essid[iwp->length - 1] == '\0') + essid_compat = 1; + } + break; + default: + break; + } + + iwp->length -= essid_compat; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + /* Check NULL pointer */ + if (!iwp->pointer && iwp->length != 0) + return -EFAULT; + /* Check if number of token fits within bounds */ + if (iwp->length > descr->max_tokens) + return -E2BIG; + if (iwp->length < descr->min_tokens) + return -EINVAL; + } else { + /* Check NULL pointer */ + if (!iwp->pointer) + return -EFAULT; + /* Save user space buffer size for checking */ + user_length = iwp->length; + + /* Don't check if user_length > max to allow forward + * compatibility. The test user_length < min is + * implied by the test at the end. + */ + + /* Support for very large requests */ + if ((descr->flags & IW_DESCR_FLAG_NOMAX) && + (user_length > descr->max_tokens)) { + /* Allow userspace to GET more than max so + * we can support any size GET requests. + * There is still a limit : -ENOMEM. + */ + extra_size = user_length * descr->token_size; + + /* Note : user_length is originally a __u16, + * and token_size is controlled by us, + * so extra_size won't get negative and + * won't overflow... + */ + } + } + + /* kzalloc() ensures NULL-termination for essid_compat. */ + extra = kzalloc(extra_size, GFP_KERNEL); + if (!extra) + return -ENOMEM; + + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwp->length != 0)) { + if (copy_from_user(extra, iwp->pointer, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + + if (cmd == SIOCSIWENCODEEXT) { + struct iw_encode_ext *ee = (void *) extra; + + if (iwp->length < sizeof(*ee) + ee->key_len) + return -EFAULT; + } + } + + if (IW_IS_GET(cmd) && !(descr->flags & IW_DESCR_FLAG_NOMAX)) { + /* + * If this is a GET, but not NOMAX, it means that the extra + * data is not bounded by userspace, but by max_tokens. Thus + * set the length to max_tokens. This matches the extra data + * allocation. + * The driver should fill it with the number of tokens it + * provided, and it may check iwp->length rather than having + * knowledge of max_tokens. If the driver doesn't change the + * iwp->length, this ioctl just copies back max_token tokens + * filled with zeroes. Hopefully the driver isn't claiming + * them to be valid data. + */ + iwp->length = descr->max_tokens; + } + + err = handler(dev, info, (union iwreq_data *) iwp, extra); + + iwp->length += essid_compat; + + /* If we have something to return to the user */ + if (!err && IW_IS_GET(cmd)) { + /* Check if there is enough buffer up there */ + if (user_length < iwp->length) { + err = -E2BIG; + goto out; + } + + if (copy_to_user(iwp->pointer, extra, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + } + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && + ((err == 0) || (err == -EIWCOMMIT))) { + union iwreq_data *data = (union iwreq_data *) iwp; + + if (descr->flags & IW_DESCR_FLAG_RESTRICT) + /* If the event is restricted, don't + * export the payload. + */ + wireless_send_event(dev, cmd, data, NULL); + else + wireless_send_event(dev, cmd, data, extra); + } + +out: + kfree(extra); + return err; +} + +/* + * Call the commit handler in the driver + * (if exist and if conditions are right) + * + * Note : our current commit strategy is currently pretty dumb, + * but we will be able to improve on that... + * The goal is to try to agreagate as many changes as possible + * before doing the commit. Drivers that will define a commit handler + * are usually those that need a reset after changing parameters, so + * we want to minimise the number of reset. + * A cool idea is to use a timer : at each "set" command, we re-set the + * timer, when the timer eventually fires, we call the driver. + * Hopefully, more on that later. + * + * Also, I'm waiting to see how many people will complain about the + * netif_running(dev) test. I'm open on that one... + * Hopefully, the driver will remember to do a commit in "open()" ;-) + */ +int call_commit_handler(struct net_device *dev) +{ +#ifdef CONFIG_WIRELESS_EXT + if ((netif_running(dev)) && + (dev->wireless_handlers->standard[0] != NULL)) + /* Call the commit handler on the driver */ + return dev->wireless_handlers->standard[0](dev, NULL, + NULL, NULL); + else + return 0; /* Command completed successfully */ +#else + /* cfg80211 has no commit */ + return 0; +#endif +} + +/* + * Main IOCTl dispatcher. + * Check the type of IOCTL and call the appropriate wrapper... + */ +static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, + unsigned int cmd, + struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) +{ + struct iwreq *iwr = (struct iwreq *) ifr; + struct net_device *dev; + iw_handler handler; + + /* Permissions are already checked in dev_ioctl() before calling us. + * The copy_to/from_user() of ifr is also dealt with in there */ + + /* Make sure the device exist */ + if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) + return -ENODEV; + + /* A bunch of special cases, then the generic case... + * Note that 'cmd' is already filtered in dev_ioctl() with + * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ + if (cmd == SIOCGIWSTATS) + return standard(dev, iwr, cmd, info, + &iw_handler_get_iwstats); + +#ifdef CONFIG_WEXT_PRIV + if (cmd == SIOCGIWPRIV && dev->wireless_handlers) + return standard(dev, iwr, cmd, info, + iw_handler_get_private); +#endif + + /* Basic check */ + if (!netif_device_present(dev)) + return -ENODEV; + + /* New driver API : try to find the handler */ + handler = get_handler(dev, cmd); + if (handler) { + /* Standard and private are not the same */ + if (cmd < SIOCIWFIRSTPRIV) + return standard(dev, iwr, cmd, info, handler); + else if (private) + return private(dev, iwr, cmd, info, handler); + } + /* Old driver API : call driver ioctl handler */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) + if (dev->netdev_ops->ndo_do_ioctl) + return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); +#else + if (dev->do_ioctl) + return dev->do_ioctl(dev, ifr, cmd); +#endif + return -EOPNOTSUPP; +} + +/* If command is `set a parameter', or `get the encoding parameters', + * check if the user has the right to do it. + */ +static int wext_permission_check(unsigned int cmd) +{ + if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || + cmd == SIOCGIWENCODEEXT) && + !capable(CAP_NET_ADMIN)) + return -EPERM; + + return 0; +} + +/* entry point from dev ioctl */ +static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, + unsigned int cmd, struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) +{ + int ret = wext_permission_check(cmd); + + if (ret) + return ret; + + dev_load(net, ifr->ifr_name); + rtnl_lock(); + ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); + rtnl_unlock(); + + return ret; +} + +/* + * Wrapper to call a standard Wireless Extension handler. + * We do various checks and also take care of moving data between + * user space and kernel space. + */ +static int ioctl_standard_call(struct net_device * dev, + struct iwreq *iwr, + unsigned int cmd, + struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_ioctl_description * descr; + int ret = -EINVAL; + + /* Get the description of the IOCTL */ + if (IW_IOCTL_IDX(cmd) >= standard_ioctl_num) + return -EOPNOTSUPP; + descr = &(standard_ioctl[IW_IOCTL_IDX(cmd)]); + + /* Check if we have a pointer to user space data or not */ + if (descr->header_type != IW_HEADER_TYPE_POINT) { + + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), NULL); + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && + ((ret == 0) || (ret == -EIWCOMMIT))) + wireless_send_event(dev, cmd, &(iwr->u), NULL); + } else { + ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, + handler, dev, info); + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + /* Here, we will generate the appropriate event if needed */ + + return ret; +} + + +int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, + void __user *arg) +{ + struct iw_request_info info = { .cmd = cmd, .flags = 0 }; + int ret; + + ret = wext_ioctl_dispatch(net, ifr, cmd, &info, + ioctl_standard_call, + ioctl_private_call); + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(arg, ifr, sizeof(struct iwreq))) + return -EFAULT; + + return ret; +} + +#ifdef CONFIG_COMPAT +static int compat_standard_call(struct net_device *dev, + struct iwreq *iwr, + unsigned int cmd, + struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_ioctl_description *descr; + struct compat_iw_point *iwp_compat; + struct iw_point iwp; + int err; + + descr = standard_ioctl + IW_IOCTL_IDX(cmd); + + if (descr->header_type != IW_HEADER_TYPE_POINT) + return ioctl_standard_call(dev, iwr, cmd, info, handler); + + iwp_compat = (struct compat_iw_point *) &iwr->u.data; + iwp.pointer = compat_ptr(iwp_compat->pointer); + iwp.length = iwp_compat->length; + iwp.flags = iwp_compat->flags; + + err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); + + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + + return err; +} + +int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct iw_request_info info; + struct iwreq iwr; + char *colon; + int ret; + + if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) + return -EFAULT; + + iwr.ifr_name[IFNAMSIZ-1] = 0; + colon = strchr(iwr.ifr_name, ':'); + if (colon) + *colon = 0; + + info.cmd = cmd; + info.flags = IW_REQUEST_FLAG_COMPAT; + + ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, + compat_standard_call, + compat_private_call); + + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(argp, &iwr, sizeof(struct iwreq))) + return -EFAULT; + + return ret; +} +#endif diff --git a/net/wireless_ath/wext-priv.c b/net/wireless_ath/wext-priv.c new file mode 100644 index 00000000..674d426a --- /dev/null +++ b/net/wireless_ath/wext-priv.c @@ -0,0 +1,249 @@ +/* + * This file implement the Wireless Extensions priv API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * Copyright 2009 Johannes Berg + * + * (As all part of the Linux kernel, this file is GPL) + */ +#include +#include +#include +#include +#include + +int iw_handler_get_private(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + /* Check if the driver has something to export */ + if ((dev->wireless_handlers->num_private_args == 0) || + (dev->wireless_handlers->private_args == NULL)) + return -EOPNOTSUPP; + + /* Check if there is enough buffer up there */ + if (wrqu->data.length < dev->wireless_handlers->num_private_args) { + /* User space can't know in advance how large the buffer + * needs to be. Give it a hint, so that we can support + * any size buffer we want somewhat efficiently... */ + wrqu->data.length = dev->wireless_handlers->num_private_args; + return -E2BIG; + } + + /* Set the number of available ioctls. */ + wrqu->data.length = dev->wireless_handlers->num_private_args; + + /* Copy structure to the user buffer. */ + memcpy(extra, dev->wireless_handlers->private_args, + sizeof(struct iw_priv_args) * wrqu->data.length); + + return 0; +} + +/* Size (in bytes) of the various private data types */ +static const char iw_priv_type_size[] = { + 0, /* IW_PRIV_TYPE_NONE */ + 1, /* IW_PRIV_TYPE_BYTE */ + 1, /* IW_PRIV_TYPE_CHAR */ + 0, /* Not defined */ + sizeof(__u32), /* IW_PRIV_TYPE_INT */ + sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ + sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ + 0, /* Not defined */ +}; + +static int get_priv_size(__u16 args) +{ + int num = args & IW_PRIV_SIZE_MASK; + int type = (args & IW_PRIV_TYPE_MASK) >> 12; + + return num * iw_priv_type_size[type]; +} + +static int adjust_priv_size(__u16 args, struct iw_point *iwp) +{ + int num = iwp->length; + int max = args & IW_PRIV_SIZE_MASK; + int type = (args & IW_PRIV_TYPE_MASK) >> 12; + + /* Make sure the driver doesn't goof up */ + if (max < num) + num = max; + + return num * iw_priv_type_size[type]; +} + +/* + * Wrapper to call a private Wireless Extension handler. + * We do various checks and also take care of moving data between + * user space and kernel space. + * It's not as nice and slimline as the standard wrapper. The cause + * is struct iw_priv_args, which was not really designed for the + * job we are going here. + * + * IMPORTANT : This function prevent to set and get data on the same + * IOCTL and enforce the SET/GET convention. Not doing it would be + * far too hairy... + * If you need to set and get data at the same time, please don't use + * a iw_handler but process it in your ioctl handler (i.e. use the + * old driver API). + */ +static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, + const struct iw_priv_args **descrp) +{ + const struct iw_priv_args *descr; + int i, extra_size; + + descr = NULL; + for (i = 0; i < dev->wireless_handlers->num_private_args; i++) { + if (cmd == dev->wireless_handlers->private_args[i].cmd) { + descr = &dev->wireless_handlers->private_args[i]; + break; + } + } + + extra_size = 0; + if (descr) { + if (IW_IS_SET(cmd)) { + int offset = 0; /* For sub-ioctls */ + /* Check for sub-ioctl handler */ + if (descr->name[0] == '\0') + /* Reserve one int for sub-ioctl index */ + offset = sizeof(__u32); + + /* Size of set arguments */ + extra_size = get_priv_size(descr->set_args); + + /* Does it fits in iwr ? */ + if ((descr->set_args & IW_PRIV_SIZE_FIXED) && + ((extra_size + offset) <= IFNAMSIZ)) + extra_size = 0; + } else { + /* Size of get arguments */ + extra_size = get_priv_size(descr->get_args); + + /* Does it fits in iwr ? */ + if ((descr->get_args & IW_PRIV_SIZE_FIXED) && + (extra_size <= IFNAMSIZ)) + extra_size = 0; + } + } + *descrp = descr; + return extra_size; +} + +static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, + const struct iw_priv_args *descr, + iw_handler handler, struct net_device *dev, + struct iw_request_info *info, int extra_size) +{ + char *extra; + int err; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + if (!iwp->pointer && iwp->length != 0) + return -EFAULT; + + if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK)) + return -E2BIG; + } else if (!iwp->pointer) + return -EFAULT; + + extra = kzalloc(extra_size, GFP_KERNEL); + if (!extra) + return -ENOMEM; + + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwp->length != 0)) { + if (copy_from_user(extra, iwp->pointer, extra_size)) { + err = -EFAULT; + goto out; + } + } + + /* Call the handler */ + err = handler(dev, info, (union iwreq_data *) iwp, extra); + + /* If we have something to return to the user */ + if (!err && IW_IS_GET(cmd)) { + /* Adjust for the actual length if it's variable, + * avoid leaking kernel bits outside. + */ + if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) + extra_size = adjust_priv_size(descr->get_args, iwp); + + if (copy_to_user(iwp->pointer, extra, extra_size)) + err = -EFAULT; + } + +out: + kfree(extra); + return err; +} + +int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler) +{ + int extra_size = 0, ret = -EINVAL; + const struct iw_priv_args *descr; + + extra_size = get_priv_descr_and_size(dev, cmd, &descr); + + /* Check if we have a pointer to user space data or not. */ + if (extra_size == 0) { + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); + } else { + ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, + handler, dev, info, extra_size); + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + return ret; +} + +#ifdef CONFIG_COMPAT +int compat_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_priv_args *descr; + int ret, extra_size; + + extra_size = get_priv_descr_and_size(dev, cmd, &descr); + + /* Check if we have a pointer to user space data or not. */ + if (extra_size == 0) { + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); + } else { + struct compat_iw_point *iwp_compat; + struct iw_point iwp; + + iwp_compat = (struct compat_iw_point *) &iwr->u.data; + iwp.pointer = compat_ptr(iwp_compat->pointer); + iwp.length = iwp_compat->length; + iwp.flags = iwp_compat->flags; + + ret = ioctl_private_iw_point(&iwp, cmd, descr, + handler, dev, info, extra_size); + + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + return ret; +} +#endif diff --git a/net/wireless_ath/wext-proc.c b/net/wireless_ath/wext-proc.c new file mode 100644 index 00000000..f2fbfa6f --- /dev/null +++ b/net/wireless_ath/wext-proc.c @@ -0,0 +1,159 @@ +/* + * This file implement the Wireless Extensions proc API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +/* + * The /proc/net/wireless file is a human readable user-space interface + * exporting various wireless specific statistics from the wireless devices. + * This is the most popular part of the Wireless Extensions ;-) + * + * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). + * The content of the file is basically the content of "struct iw_statistics". + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +static void wireless_seq_printf_stats(struct seq_file *seq, + struct net_device *dev) +{ + /* Get stats from the driver */ + struct iw_statistics *stats = get_wireless_stats(dev); + static struct iw_statistics nullstats = {}; + + /* show device if it's wireless regardless of current stats */ + if (!stats) { +#ifdef CONFIG_WIRELESS_EXT + if (dev->wireless_handlers) + stats = &nullstats; +#endif +#ifdef CONFIG_CFG80211 + if (dev->ieee80211_ptr) + stats = &nullstats; +#endif + } + + if (stats) { + seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " + "%6d %6d %6d\n", + dev->name, stats->status, stats->qual.qual, + stats->qual.updated & IW_QUAL_QUAL_UPDATED + ? '.' : ' ', + ((__s32) stats->qual.level) - + ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), + stats->qual.updated & IW_QUAL_LEVEL_UPDATED + ? '.' : ' ', + ((__s32) stats->qual.noise) - + ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), + stats->qual.updated & IW_QUAL_NOISE_UPDATED + ? '.' : ' ', + stats->discard.nwid, stats->discard.code, + stats->discard.fragment, stats->discard.retries, + stats->discard.misc, stats->miss.beacon); + + if (stats != &nullstats) + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; + } +} + +/* ---------------------------------------------------------------- */ +/* + * Print info for /proc/net/wireless (print all entries) + */ +static int wireless_dev_seq_show(struct seq_file *seq, void *v) +{ + might_sleep(); + + if (v == SEQ_START_TOKEN) + seq_printf(seq, "Inter-| sta-| Quality | Discarded " + "packets | Missed | WE\n" + " face | tus | link level noise | nwid " + "crypt frag retry misc | beacon | %d\n", + WIRELESS_EXT); + else + wireless_seq_printf_stats(seq, v); + return 0; +} + +static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + loff_t off; + struct net_device *dev; + + rtnl_lock(); + if (!*pos) + return SEQ_START_TOKEN; + + off = 1; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + for_each_netdev(net, dev) +#else + for_each_netdev(net) +#endif + if (off++ == *pos) + return dev; + return NULL; +} + +static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + + ++*pos; + + return v == SEQ_START_TOKEN ? + first_net_device(net) : next_net_device(v); +} + +static void wireless_dev_seq_stop(struct seq_file *seq, void *v) +{ + rtnl_unlock(); +} + +static const struct seq_operations wireless_seq_ops = { + .start = wireless_dev_seq_start, + .next = wireless_dev_seq_next, + .stop = wireless_dev_seq_stop, + .show = wireless_dev_seq_show, +}; + +static int seq_open_wireless(struct inode *inode, struct file *file) +{ + return seq_open_net(inode, file, &wireless_seq_ops, + sizeof(struct seq_net_private)); +} + +static const struct file_operations wireless_seq_fops = { + .owner = THIS_MODULE, + .open = seq_open_wireless, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net, +}; + +int __net_init wext_proc_init(struct net *net) +{ + /* Create /proc/net/wireless entry */ + if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) + return -ENOMEM; + + return 0; +} + +void __net_exit wext_proc_exit(struct net *net) +{ + proc_net_remove(net, "wireless"); +} diff --git a/net/wireless_ath/wext-sme.c b/net/wireless_ath/wext-sme.c new file mode 100644 index 00000000..7c01c2f3 --- /dev/null +++ b/net/wireless_ath/wext-sme.c @@ -0,0 +1,408 @@ +/* + * cfg80211 wext compat for managed mode. + * + * Copyright 2009 Johannes Berg + * Copyright (C) 2009 Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include "wext-compat.h" +#include "nl80211.h" + +int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + struct cfg80211_cached_keys *ck = NULL; + const u8 *prev_bssid = NULL; + int err, i; + + ASSERT_RDEV_LOCK(rdev); + ASSERT_WDEV_LOCK(wdev); + + if (!netif_running(wdev->netdev)) + return 0; + + wdev->wext.connect.ie = wdev->wext.ie; + wdev->wext.connect.ie_len = wdev->wext.ie_len; + + /* Use default background scan period */ + wdev->wext.connect.bg_scan_period = -1; + + if (wdev->wext.keys) { + wdev->wext.keys->def = wdev->wext.default_key; + wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; + if (wdev->wext.default_key != -1) + wdev->wext.connect.privacy = true; + } + + if (!wdev->wext.connect.ssid_len) + return 0; + + if (wdev->wext.keys) { + ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); + if (!ck) + return -ENOMEM; + for (i = 0; i < 6; i++) + ck->params[i].key = ck->data[i]; + } + + if (wdev->wext.prev_bssid_valid) + prev_bssid = wdev->wext.prev_bssid; + + err = __cfg80211_connect(rdev, wdev->netdev, + &wdev->wext.connect, ck, prev_bssid); + if (err) + kfree(ck); + + return err; +} + +int cfg80211_mgd_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wextfreq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan = NULL; + int err, freq; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + if (freq < 0) + return freq; + + if (freq) { + chan = ieee80211_get_channel(wdev->wiphy, freq); + if (!chan) + return -EINVAL; + if (chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + } + + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + + if (wdev->sme_state != CFG80211_SME_IDLE) { + bool event = true; + + if (wdev->wext.connect.channel == chan) { + err = 0; + goto out; + } + + /* if SSID set, we'll try right again, avoid event */ + if (wdev->wext.connect.ssid_len) + event = false; + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, event); + if (err) + goto out; + } + + + wdev->wext.connect.channel = chan; + + /* SSID is not set, we just want to switch channel */ + if (chan && !wdev->wext.connect.ssid_len) { + err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); + goto out; + } + + err = cfg80211_mgd_wext_connect(rdev, wdev); + out: + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); + return err; +} + +int cfg80211_mgd_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan = NULL; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + wdev_lock(wdev); + if (wdev->current_bss) + chan = wdev->current_bss->pub.channel; + else if (wdev->wext.connect.channel) + chan = wdev->wext.connect.channel; + wdev_unlock(wdev); + + if (chan) { + freq->m = chan->center_freq; + freq->e = 6; + return 0; + } + + /* no channel if not joining */ + return -EINVAL; +} + +int cfg80211_mgd_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + size_t len = data->length; + int err; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + if (!data->flags) + len = 0; + + /* iwconfig uses nul termination in SSID.. */ + if (len > 0 && ssid[len - 1] == '\0') + len--; + + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + + err = 0; + + if (wdev->sme_state != CFG80211_SME_IDLE) { + bool event = true; + + if (wdev->wext.connect.ssid && len && + len == wdev->wext.connect.ssid_len && + memcmp(wdev->wext.connect.ssid, ssid, len) == 0) + goto out; + + /* if SSID set now, we'll try to connect, avoid event */ + if (len) + event = false; + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, event); + if (err) + goto out; + } + + wdev->wext.prev_bssid_valid = false; + wdev->wext.connect.ssid = wdev->wext.ssid; + memcpy(wdev->wext.ssid, ssid, len); + wdev->wext.connect.ssid_len = len; + + wdev->wext.connect.crypto.control_port = false; + wdev->wext.connect.crypto.control_port_ethertype = + cpu_to_be16(ETH_P_PAE); + + err = cfg80211_mgd_wext_connect(rdev, wdev); + out: + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); + return err; +} + +int cfg80211_mgd_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + data->flags = 0; + + wdev_lock(wdev); + if (wdev->current_bss) { + const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, + WLAN_EID_SSID); + if (ie) { + data->flags = 1; + data->length = ie[1]; + memcpy(ssid, ie + 2, data->length); + } + } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { + data->flags = 1; + data->length = wdev->wext.connect.ssid_len; + memcpy(ssid, wdev->wext.connect.ssid, data->length); + } + wdev_unlock(wdev); + + return 0; +} + +int cfg80211_mgd_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u8 *bssid = ap_addr->sa_data; + int err; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + if (ap_addr->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* automatic mode */ + if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) + bssid = NULL; + + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); + wdev_lock(wdev); + + if (wdev->sme_state != CFG80211_SME_IDLE) { + err = 0; + /* both automatic */ + if (!bssid && !wdev->wext.connect.bssid) + goto out; + + /* fixed already - and no change */ + if (wdev->wext.connect.bssid && bssid && + compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) + goto out; + + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, false); + if (err) + goto out; + } + + if (bssid) { + memcpy(wdev->wext.bssid, bssid, ETH_ALEN); + wdev->wext.connect.bssid = wdev->wext.bssid; + } else + wdev->wext.connect.bssid = NULL; + + err = cfg80211_mgd_wext_connect(rdev, wdev); + out: + wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); + return err; +} + +int cfg80211_mgd_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + ap_addr->sa_family = ARPHRD_ETHER; + + wdev_lock(wdev); + if (wdev->current_bss) + memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); + else + memset(ap_addr->sa_data, 0, ETH_ALEN); + wdev_unlock(wdev); + + return 0; +} + +int cfg80211_wext_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u8 *ie = extra; + int ie_len = data->length, err; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (!ie_len) + ie = NULL; + + wdev_lock(wdev); + + /* no change */ + err = 0; + if (wdev->wext.ie_len == ie_len && + memcmp(wdev->wext.ie, ie, ie_len) == 0) + goto out; + + if (ie_len) { + ie = kmemdup(extra, ie_len, GFP_KERNEL); + if (!ie) { + err = -ENOMEM; + goto out; + } + } else + ie = NULL; + + kfree(wdev->wext.ie); + wdev->wext.ie = ie; + wdev->wext.ie_len = ie_len; + + if (wdev->sme_state != CFG80211_SME_IDLE) { + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, false); + if (err) + goto out; + } + + /* userspace better not think we'll reconnect */ + err = 0; + out: + wdev_unlock(wdev); + return err; +} + +int cfg80211_wext_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + struct cfg80211_registered_device *rdev; + int err; + + if (!wdev) + return -EOPNOTSUPP; + + rdev = wiphy_to_dev(wdev->wiphy); + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (mlme->addr.sa_family != ARPHRD_ETHER) + return -EINVAL; + + wdev_lock(wdev); + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + case IW_MLME_DISASSOC: + err = __cfg80211_disconnect(rdev, dev, mlme->reason_code, + true); + break; + default: + err = -EOPNOTSUPP; + break; + } + wdev_unlock(wdev); + + return err; +} diff --git a/net/wireless_ath/wext-spy.c b/net/wireless_ath/wext-spy.c new file mode 100644 index 00000000..5d643a54 --- /dev/null +++ b/net/wireless_ath/wext-spy.c @@ -0,0 +1,232 @@ +/* + * This file implement the Wireless Extensions spy API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +#include +#include +#include +#include +#include +#include +#include + +static inline struct iw_spy_data *get_spydata(struct net_device *dev) +{ + /* This is the new way */ + if (dev->wireless_data) + return dev->wireless_data->spy_data; + return NULL; +} + +int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Disable spy collection while we copy the addresses. + * While we copy addresses, any call to wireless_spy_update() + * will NOP. This is OK, as anyway the addresses are changing. */ + spydata->spy_number = 0; + + /* We want to operate without locking, because wireless_spy_update() + * most likely will happen in the interrupt handler, and therefore + * have its own locking constraints and needs performance. + * The rtnl_lock() make sure we don't race with the other iw_handlers. + * This make sure wireless_spy_update() "see" that the spy list + * is temporarily disabled. */ + smp_wmb(); + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + int i; + + /* Copy addresses */ + for (i = 0; i < wrqu->data.length; i++) + memcpy(spydata->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(spydata->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + } + + /* Make sure above is updated before re-enabling */ + smp_wmb(); + + /* Enable addresses */ + spydata->spy_number = wrqu->data.length; + + return 0; +} +EXPORT_SYMBOL(iw_handler_set_spy); + +int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + int i; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + wrqu->data.length = spydata->spy_number; + + /* Copy addresses. */ + for (i = 0; i < spydata->spy_number; i++) { + memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if (spydata->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), + spydata->spy_stat, + sizeof(struct iw_quality) * spydata->spy_number); + /* Reset updated flags. */ + for (i = 0; i < spydata->spy_number; i++) + spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; + return 0; +} +EXPORT_SYMBOL(iw_handler_get_spy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set spy threshold + */ +int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + memcpy(&(spydata->spy_thr_low), &(threshold->low), + 2 * sizeof(struct iw_quality)); + + /* Clear flag */ + memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); + + return 0; +} +EXPORT_SYMBOL(iw_handler_set_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get spy threshold + */ +int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + memcpy(&(threshold->low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + + return 0; +} +EXPORT_SYMBOL(iw_handler_get_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Prepare and send a Spy Threshold event + */ +static void iw_send_thrspy_event(struct net_device * dev, + struct iw_spy_data * spydata, + unsigned char * address, + struct iw_quality * wstats) +{ + union iwreq_data wrqu; + struct iw_thrspy threshold; + + /* Init */ + wrqu.data.length = 1; + wrqu.data.flags = 0; + /* Copy address */ + memcpy(threshold.addr.sa_data, address, ETH_ALEN); + threshold.addr.sa_family = ARPHRD_ETHER; + /* Copy stats */ + memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); + /* Copy also thresholds */ + memcpy(&(threshold.low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); +} + +/* ---------------------------------------------------------------- */ +/* + * Call for the driver to update the spy data. + * For now, the spy data is a simple array. As the size of the array is + * small, this is good enough. If we wanted to support larger number of + * spy addresses, we should use something more efficient... + */ +void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats) +{ + struct iw_spy_data * spydata = get_spydata(dev); + int i; + int match = -1; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return; + + /* Update all records that match */ + for (i = 0; i < spydata->spy_number; i++) + if (!compare_ether_addr(address, spydata->spy_address[i])) { + memcpy(&(spydata->spy_stat[i]), wstats, + sizeof(struct iw_quality)); + match = i; + } + + /* Generate an event if we cross the spy threshold. + * To avoid event storms, we have a simple hysteresis : we generate + * event only when we go under the low threshold or above the + * high threshold. */ + if (match >= 0) { + if (spydata->spy_thr_under[match]) { + if (wstats->level > spydata->spy_thr_high.level) { + spydata->spy_thr_under[match] = 0; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } else { + if (wstats->level < spydata->spy_thr_low.level) { + spydata->spy_thr_under[match] = 1; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } + } +} +EXPORT_SYMBOL(wireless_spy_update); diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index db2535b7..fcb471c2 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -77,8 +77,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" - echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\" - echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\" + echo \#define LINUX_COMPILE_BY \"Made_In_Russia\" + echo \#define LINUX_COMPILE_HOST \"Weritos\" echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\" ) > .tmpcompile diff --git a/security/Kconfig b/security/Kconfig old mode 100755 new mode 100644 diff --git a/security/Makefile b/security/Makefile old mode 100755 new mode 100644 diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore old mode 100755 new mode 100644 diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig old mode 100755 new mode 100644 diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile old mode 100755 new mode 100644 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c old mode 100755 new mode 100644 diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c old mode 100755 new mode 100644 diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c old mode 100755 new mode 100644 diff --git a/security/apparmor/context.c b/security/apparmor/context.c old mode 100755 new mode 100644 diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c old mode 100755 new mode 100644 diff --git a/security/apparmor/file.c b/security/apparmor/file.c old mode 100755 new mode 100644 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h old mode 100755 new mode 100644 index 40aedd9f..4a8cbfee --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -65,7 +65,6 @@ extern int apparmor_initialized __initdata; char *aa_split_fqname(char *args, char **ns_name); void aa_info_message(const char *str); void *kvmalloc(size_t size); -void kvfree(void *buffer); /** diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h old mode 100755 new mode 100644 diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/sid.h old mode 100755 new mode 100644 diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c old mode 100755 new mode 100644 diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c old mode 100755 new mode 100644 index e75829ba..2b038e96 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -104,34 +104,3 @@ void *kvmalloc(size_t size) return buffer; } -/** - * do_vfree - workqueue routine for freeing vmalloced memory - * @work: data to be freed - * - * The work_struct is overlaid to the data being freed, as at the point - * the work is scheduled the data is no longer valid, be its freeing - * needs to be delayed until safe. - */ -static void do_vfree(struct work_struct *work) -{ - vfree(work); -} - -/** - * kvfree - free an allocation do by kvmalloc - * @buffer: buffer to free (MAYBE_NULL) - * - * Free a buffer allocated by kvmalloc - */ -void kvfree(void *buffer) -{ - if (is_vmalloc_addr(buffer)) { - /* Data is no longer valid so just use the allocated space - * as the work_struct - */ - struct work_struct *work = (struct work_struct *) buffer; - INIT_WORK(work, do_vfree); - schedule_work(work); - } else - kfree(buffer); -} diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c old mode 100755 new mode 100644 diff --git a/security/apparmor/match.c b/security/apparmor/match.c old mode 100755 new mode 100644 diff --git a/security/apparmor/path.c b/security/apparmor/path.c old mode 100755 new mode 100644 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c old mode 100755 new mode 100644 diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c old mode 100755 new mode 100644 diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c old mode 100755 new mode 100644 diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c old mode 100755 new mode 100644 diff --git a/security/apparmor/sid.c b/security/apparmor/sid.c old mode 100755 new mode 100644 diff --git a/security/capability.c b/security/capability.c old mode 100755 new mode 100644 index 5bb21b1c..d0a49eec --- a/security/capability.c +++ b/security/capability.c @@ -12,6 +12,26 @@ #include +static int cap_binder_set_context_mgr(struct task_struct *mgr) +{ + return 0; +} + +static int cap_binder_transaction(struct task_struct *from, struct task_struct *to) +{ + return 0; +} + +static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to) +{ + return 0; +} + +static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) +{ + return 0; +} + static int cap_syslog(int type) { return 0; @@ -74,8 +94,8 @@ static int cap_sb_statfs(struct dentry *dentry) return 0; } -static int cap_sb_mount(char *dev_name, struct path *path, char *type, - unsigned long flags, void *data) +static int cap_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { return 0; } @@ -877,6 +897,10 @@ static void cap_audit_rule_free(void *lsmrule) void __init security_fixup_ops(struct security_operations *ops) { + set_to_cap_if_null(ops, binder_set_context_mgr); + set_to_cap_if_null(ops, binder_transaction); + set_to_cap_if_null(ops, binder_transfer_binder); + set_to_cap_if_null(ops, binder_transfer_file); set_to_cap_if_null(ops, ptrace_access_check); set_to_cap_if_null(ops, ptrace_traceme); set_to_cap_if_null(ops, capget); diff --git a/security/commoncap.c b/security/commoncap.c old mode 100755 new mode 100644 diff --git a/security/device_cgroup.c b/security/device_cgroup.c old mode 100755 new mode 100644 diff --git a/security/inode.c b/security/inode.c old mode 100755 new mode 100644 diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig old mode 100755 new mode 100644 diff --git a/security/integrity/Makefile b/security/integrity/Makefile old mode 100755 new mode 100644 diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c old mode 100755 new mode 100644 diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig old mode 100755 new mode 100644 diff --git a/security/integrity/evm/Makefile b/security/integrity/evm/Makefile old mode 100755 new mode 100644 diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h old mode 100755 new mode 100644 diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c old mode 100755 new mode 100644 diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c old mode 100755 new mode 100644 diff --git a/security/integrity/evm/evm_posix_acl.c b/security/integrity/evm/evm_posix_acl.c old mode 100755 new mode 100644 diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c old mode 100755 new mode 100644 diff --git a/security/integrity/iint.c b/security/integrity/iint.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig old mode 100755 new mode 100644 diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c old mode 100755 new mode 100644 diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c old mode 100755 new mode 100644 diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h old mode 100755 new mode 100644 diff --git a/security/keys/Makefile b/security/keys/Makefile old mode 100755 new mode 100644 diff --git a/security/keys/compat.c b/security/keys/compat.c old mode 100755 new mode 100644 index 1b0b7bfe..b7a913d4 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -135,6 +135,9 @@ asmlinkage long compat_sys_keyctl(u32 option, return compat_keyctl_instantiate_key_iov( arg2, compat_ptr(arg3), arg4, arg5); + case KEYCTL_INVALIDATE: + return keyctl_invalidate_key(arg2); + default: return -EOPNOTSUPP; } diff --git a/security/keys/encrypted-keys/Makefile b/security/keys/encrypted-keys/Makefile old mode 100755 new mode 100644 diff --git a/security/keys/encrypted-keys/ecryptfs_format.c b/security/keys/encrypted-keys/ecryptfs_format.c old mode 100755 new mode 100644 diff --git a/security/keys/encrypted-keys/ecryptfs_format.h b/security/keys/encrypted-keys/ecryptfs_format.h old mode 100755 new mode 100644 diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c old mode 100755 new mode 100644 index a02f9230..0685b15f --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -843,6 +843,8 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) const char *format = NULL; int ret = 0; + if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) + return -ENOKEY; if (datalen <= 0 || datalen > 32767 || !data) return -EINVAL; diff --git a/security/keys/encrypted-keys/encrypted.h b/security/keys/encrypted-keys/encrypted.h old mode 100755 new mode 100644 diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c old mode 100755 new mode 100644 diff --git a/security/keys/gc.c b/security/keys/gc.c old mode 100755 new mode 100644 index 87632bd1..28ea1521 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -71,6 +71,15 @@ void key_schedule_gc(time_t gc_at) } } +/* + * Schedule a dead links collection run. + */ +void key_schedule_gc_links(void) +{ + set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); + queue_work(system_nrt_wq, &key_gc_work); +} + /* * Some key's cleanup time was met after it expired, so we need to get the * reaper to go through a cycle finding expired keys. @@ -79,8 +88,7 @@ static void key_gc_timer_func(unsigned long data) { kenter(""); key_gc_next_run = LONG_MAX; - set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); - queue_work(system_nrt_wq, &key_gc_work); + key_schedule_gc_links(); } /* @@ -131,12 +139,12 @@ void key_gc_keytype(struct key_type *ktype) static void key_gc_keyring(struct key *keyring, time_t limit) { struct keyring_list *klist; - struct key *key; int loop; kenter("%x", key_serial(keyring)); - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) + if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED))) goto dont_gc; /* scan the keyring looking for dead keys */ @@ -148,9 +156,8 @@ static void key_gc_keyring(struct key *keyring, time_t limit) loop = klist->nkeys; smp_rmb(); for (loop--; loop >= 0; loop--) { - key = klist->keys[loop]; - if (test_bit(KEY_FLAG_DEAD, &key->flags) || - (key->expiry > 0 && key->expiry <= limit)) + struct key *key = rcu_dereference(klist->keys[loop]); + if (key_is_dead(key, limit)) goto do_gc; } @@ -168,38 +175,47 @@ static void key_gc_keyring(struct key *keyring, time_t limit) } /* - * Garbage collect an unreferenced, detached key + * Garbage collect a list of unreferenced, detached keys */ -static noinline void key_gc_unused_key(struct key *key) +static noinline void key_gc_unused_keys(struct list_head *keys) { - key_check(key); - - security_key_free(key); - - /* deal with the user's key tracking and quota */ - if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { - spin_lock(&key->user->lock); - key->user->qnkeys--; - key->user->qnbytes -= key->quotalen; - spin_unlock(&key->user->lock); - } - - atomic_dec(&key->user->nkeys); - if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) - atomic_dec(&key->user->nikeys); + while (!list_empty(keys)) { + struct key *key = + list_entry(keys->next, struct key, graveyard_link); + list_del(&key->graveyard_link); + + kdebug("- %u", key->serial); + key_check(key); + + /* Throw away the key data if the key is instantiated */ + if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && + !test_bit(KEY_FLAG_NEGATIVE, &key->flags) && + key->type->destroy) + key->type->destroy(key); + + security_key_free(key); + + /* deal with the user's key tracking and quota */ + if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { + spin_lock(&key->user->lock); + key->user->qnkeys--; + key->user->qnbytes -= key->quotalen; + spin_unlock(&key->user->lock); + } - /* now throw away the key memory */ - if (key->type->destroy) - key->type->destroy(key); + atomic_dec(&key->user->nkeys); + if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) + atomic_dec(&key->user->nikeys); - key_user_put(key->user); + key_user_put(key->user); - kfree(key->description); + kfree(key->description); #ifdef KEY_DEBUGGING - key->magic = KEY_DEBUG_MAGIC_X; + key->magic = KEY_DEBUG_MAGIC_X; #endif - kmem_cache_free(key_jar, key); + kmem_cache_free(key_jar, key); + } } /* @@ -211,6 +227,7 @@ static noinline void key_gc_unused_key(struct key *key) */ static void key_garbage_collector(struct work_struct *work) { + static LIST_HEAD(graveyard); static u8 gc_state; /* Internal persistent state */ #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ @@ -316,15 +333,22 @@ static void key_garbage_collector(struct work_struct *work) key_schedule_gc(new_timer); } - if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { - /* Make sure everyone revalidates their keys if we marked a - * bunch as being dead and make sure all keyring ex-payloads - * are destroyed. + if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2) || + !list_empty(&graveyard)) { + /* Make sure that all pending keyring payload destructions are + * fulfilled and that people aren't now looking at dead or + * dying keys that they don't have a reference upon or a link + * to. */ - kdebug("dead sync"); + kdebug("gc sync"); synchronize_rcu(); } + if (!list_empty(&graveyard)) { + kdebug("gc keys"); + key_gc_unused_keys(&graveyard); + } + if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2))) { if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { @@ -359,7 +383,7 @@ static void key_garbage_collector(struct work_struct *work) rb_erase(&key->serial_node, &key_serial_tree); spin_unlock(&key_serial_lock); - key_gc_unused_key(key); + list_add_tail(&key->graveyard_link, &graveyard); gc_state |= KEY_GC_REAP_AGAIN; goto maybe_resched; diff --git a/security/keys/internal.h b/security/keys/internal.h old mode 100755 new mode 100644 index 65647f82..f711b094 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -152,7 +152,8 @@ extern long join_session_keyring(const char *name); extern struct work_struct key_gc_work; extern unsigned key_gc_delay; extern void keyring_gc(struct key *keyring, time_t limit); -extern void key_schedule_gc(time_t expiry_at); +extern void key_schedule_gc(time_t gc_at); +extern void key_schedule_gc_links(void); extern void key_gc_keytype(struct key_type *ktype); extern int key_task_permission(const key_ref_t key_ref, @@ -196,6 +197,17 @@ extern struct key *request_key_auth_new(struct key *target, extern struct key *key_get_instantiation_authkey(key_serial_t target_id); +/* + * Determine whether a key is dead. + */ +static inline bool key_is_dead(struct key *key, time_t limit) +{ + return + key->flags & ((1 << KEY_FLAG_DEAD) | + (1 << KEY_FLAG_INVALIDATED)) || + (key->expiry > 0 && key->expiry <= limit); +} + /* * keyctl() functions */ @@ -225,6 +237,7 @@ extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); extern long keyctl_instantiate_key_iov(key_serial_t, const struct iovec __user *, unsigned, key_serial_t); +extern long keyctl_invalidate_key(key_serial_t); extern long keyctl_instantiate_key_common(key_serial_t, const struct iovec __user *, diff --git a/security/keys/key.c b/security/keys/key.c old mode 100755 new mode 100644 index 06783cff..91a5b4c1 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -954,6 +954,28 @@ void key_revoke(struct key *key) } EXPORT_SYMBOL(key_revoke); +/** + * key_invalidate - Invalidate a key. + * @key: The key to be invalidated. + * + * Mark a key as being invalidated and have it cleaned up immediately. The key + * is ignored by all searches and other operations from this point. + */ +void key_invalidate(struct key *key) +{ + kenter("%d", key_serial(key)); + + key_check(key); + + if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { + down_write_nested(&key->sem, 1); + if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) + key_schedule_gc_links(); + up_write(&key->sem); + } +} +EXPORT_SYMBOL(key_invalidate); + /** * register_key_type - Register a type of key. * @ktype: The new key type. diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c old mode 100755 new mode 100644 index dfc8c229..299dcd02 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -374,6 +374,37 @@ long keyctl_revoke_key(key_serial_t id) return ret; } +/* + * Invalidate a key. + * + * The key must be grant the caller Invalidate permission for this to work. + * The key and any links to the key will be automatically garbage collected + * immediately. + * + * If successful, 0 is returned. + */ +long keyctl_invalidate_key(key_serial_t id) +{ + key_ref_t key_ref; + long ret; + + kenter("%d", id); + + key_ref = lookup_user_key(id, 0, KEY_SEARCH); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); + goto error; + } + + key_invalidate(key_ref_to_ptr(key_ref)); + ret = 0; + + key_ref_put(key_ref); +error: + kleave(" = %ld", ret); + return ret; +} + /* * Clear the specified keyring, creating an empty process keyring if one of the * special keyring IDs is used. @@ -1622,6 +1653,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, (unsigned) arg4, (key_serial_t) arg5); + case KEYCTL_INVALIDATE: + return keyctl_invalidate_key((key_serial_t) arg2); + default: return -EOPNOTSUPP; } diff --git a/security/keys/keyring.c b/security/keys/keyring.c old mode 100755 new mode 100644 index d605f752..f4078a85 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -25,6 +25,11 @@ (keyring)->payload.subscriptions, \ rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) +#define rcu_deref_link_locked(klist, index, keyring) \ + (rcu_dereference_protected( \ + (klist)->keys[index], \ + rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) + #define KEY_LINK_FIXQUOTA 1UL /* @@ -138,6 +143,11 @@ static int keyring_match(const struct key *keyring, const void *description) /* * Clean up a keyring when it is destroyed. Unpublish its name if it had one * and dispose of its data. + * + * The garbage collector detects the final key_put(), removes the keyring from + * the serial number tree and then does RCU synchronisation before coming here, + * so we shouldn't need to worry about code poking around here with the RCU + * readlock held by this time. */ static void keyring_destroy(struct key *keyring) { @@ -154,11 +164,10 @@ static void keyring_destroy(struct key *keyring) write_unlock(&keyring_name_lock); } - klist = rcu_dereference_check(keyring->payload.subscriptions, - atomic_read(&keyring->usage) == 0); + klist = rcu_access_pointer(keyring->payload.subscriptions); if (klist) { for (loop = klist->nkeys - 1; loop >= 0; loop--) - key_put(klist->keys[loop]); + key_put(rcu_access_pointer(klist->keys[loop])); kfree(klist); } } @@ -214,7 +223,8 @@ static long keyring_read(const struct key *keyring, ret = -EFAULT; for (loop = 0; loop < klist->nkeys; loop++) { - key = klist->keys[loop]; + key = rcu_deref_link_locked(klist, loop, + keyring); tmp = sizeof(key_serial_t); if (tmp > buflen) @@ -366,13 +376,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, /* otherwise, the top keyring must not be revoked, expired, or * negatively instantiated if we are to search it */ key_ref = ERR_PTR(-EAGAIN); - if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || + if (kflags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_NEGATIVE)) || (keyring->expiry && now.tv_sec >= keyring->expiry)) goto error_2; /* start processing a new keyring */ descend: - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) + kflags = keyring->flags; + if (kflags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED))) goto not_this_keyring; keylist = rcu_dereference(keyring->payload.subscriptions); @@ -383,16 +397,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, nkeys = keylist->nkeys; smp_rmb(); for (kix = 0; kix < nkeys; kix++) { - key = keylist->keys[kix]; + key = rcu_dereference(keylist->keys[kix]); kflags = key->flags; /* ignore keys not of this type */ if (key->type != type) continue; - /* skip revoked keys and expired keys */ + /* skip invalidated, revoked and expired keys */ if (!no_state_check) { - if (kflags & (1 << KEY_FLAG_REVOKED)) + if (kflags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED))) continue; if (key->expiry && now.tv_sec >= key->expiry) @@ -426,7 +441,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, nkeys = keylist->nkeys; smp_rmb(); for (; kix < nkeys; kix++) { - key = keylist->keys[kix]; + key = rcu_dereference(keylist->keys[kix]); if (key->type != &key_type_keyring) continue; @@ -531,14 +546,14 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, nkeys = klist->nkeys; smp_rmb(); for (loop = 0; loop < nkeys ; loop++) { - key = klist->keys[loop]; - + key = rcu_dereference(klist->keys[loop]); if (key->type == ktype && (!key->type->match || key->type->match(key, description)) && key_permission(make_key_ref(key, possessed), perm) == 0 && - !test_bit(KEY_FLAG_REVOKED, &key->flags) + !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED))) ) goto found; } @@ -654,7 +669,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) nkeys = keylist->nkeys; smp_rmb(); for (; kix < nkeys; kix++) { - key = keylist->keys[kix]; + key = rcu_dereference(keylist->keys[kix]); if (key == A) goto cycle_detected; @@ -711,7 +726,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) container_of(rcu, struct keyring_list, rcu); if (klist->delkey != USHRT_MAX) - key_put(klist->keys[klist->delkey]); + key_put(rcu_access_pointer(klist->keys[klist->delkey])); kfree(klist); } @@ -749,24 +764,16 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, /* see if there's a matching key we can displace */ if (klist && klist->nkeys > 0) { for (loop = klist->nkeys - 1; loop >= 0; loop--) { - if (klist->keys[loop]->type == type && - strcmp(klist->keys[loop]->description, - description) == 0 - ) { - /* found a match - we'll replace this one with - * the new key */ - size = sizeof(struct key *) * klist->maxkeys; - size += sizeof(*klist); - BUG_ON(size > PAGE_SIZE); - - ret = -ENOMEM; - nklist = kmemdup(klist, size, GFP_KERNEL); - if (!nklist) - goto error_sem; - - /* note replacement slot */ - klist->delkey = nklist->delkey = loop; - prealloc = (unsigned long)nklist; + struct key *key = rcu_deref_link_locked(klist, loop, + keyring); + if (key->type == type && + strcmp(key->description, description) == 0) { + /* Found a match - we'll replace the link with + * one to the new key. We record the slot + * position. + */ + klist->delkey = loop; + prealloc = 0; goto done; } } @@ -780,7 +787,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, if (klist && klist->nkeys < klist->maxkeys) { /* there's sufficient slack space to append directly */ - nklist = NULL; + klist->delkey = klist->nkeys; prealloc = KEY_LINK_FIXQUOTA; } else { /* grow the key list */ @@ -813,10 +820,10 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, } /* add the key into the new space */ - nklist->keys[nklist->delkey] = NULL; + RCU_INIT_POINTER(nklist->keys[nklist->delkey], NULL); + prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; } - prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; done: *_prealloc = prealloc; kleave(" = 0"); @@ -862,6 +869,7 @@ void __key_link(struct key *keyring, struct key *key, unsigned long *_prealloc) { struct keyring_list *klist, *nklist; + struct key *discard; nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); *_prealloc = 0; @@ -875,10 +883,10 @@ void __key_link(struct key *keyring, struct key *key, /* there's a matching key we can displace or an empty slot in a newly * allocated list we can fill */ if (nklist) { - kdebug("replace %hu/%hu/%hu", + kdebug("reissue %hu/%hu/%hu", nklist->delkey, nklist->nkeys, nklist->maxkeys); - nklist->keys[nklist->delkey] = key; + RCU_INIT_POINTER(nklist->keys[nklist->delkey], key); rcu_assign_pointer(keyring->payload.subscriptions, nklist); @@ -889,9 +897,23 @@ void __key_link(struct key *keyring, struct key *key, klist->delkey, klist->nkeys, klist->maxkeys); call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); } + } else if (klist->delkey < klist->nkeys) { + kdebug("replace %hu/%hu/%hu", + klist->delkey, klist->nkeys, klist->maxkeys); + + discard = rcu_dereference_protected( + klist->keys[klist->delkey], + rwsem_is_locked(&keyring->sem)); + rcu_assign_pointer(klist->keys[klist->delkey], key); + /* The garbage collector will take care of RCU + * synchronisation */ + key_put(discard); } else { /* there's sufficient slack space to append directly */ - klist->keys[klist->nkeys] = key; + kdebug("append %hu/%hu/%hu", + klist->delkey, klist->nkeys, klist->maxkeys); + + RCU_INIT_POINTER(klist->keys[klist->delkey], key); smp_wmb(); klist->nkeys++; } @@ -998,7 +1020,7 @@ int key_unlink(struct key *keyring, struct key *key) if (klist) { /* search the keyring for the key */ for (loop = 0; loop < klist->nkeys; loop++) - if (klist->keys[loop] == key) + if (rcu_access_pointer(klist->keys[loop]) == key) goto key_is_present; } @@ -1061,7 +1083,7 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu) klist = container_of(rcu, struct keyring_list, rcu); for (loop = klist->nkeys - 1; loop >= 0; loop--) - key_put(klist->keys[loop]); + key_put(rcu_access_pointer(klist->keys[loop])); kfree(klist); } @@ -1127,15 +1149,6 @@ static void keyring_revoke(struct key *keyring) } } -/* - * Determine whether a key is dead. - */ -static bool key_is_dead(struct key *key, time_t limit) -{ - return test_bit(KEY_FLAG_DEAD, &key->flags) || - (key->expiry > 0 && key->expiry <= limit); -} - /* * Collect garbage from the contents of a keyring, replacing the old list with * a new one with the pointers all shuffled down. @@ -1161,7 +1174,8 @@ void keyring_gc(struct key *keyring, time_t limit) /* work out how many subscriptions we're keeping */ keep = 0; for (loop = klist->nkeys - 1; loop >= 0; loop--) - if (!key_is_dead(klist->keys[loop], limit)) + if (!key_is_dead(rcu_deref_link_locked(klist, loop, keyring), + limit)) keep++; if (keep == klist->nkeys) @@ -1182,11 +1196,11 @@ void keyring_gc(struct key *keyring, time_t limit) */ keep = 0; for (loop = klist->nkeys - 1; loop >= 0; loop--) { - key = klist->keys[loop]; + key = rcu_deref_link_locked(klist, loop, keyring); if (!key_is_dead(key, limit)) { if (keep >= max) goto discard_new; - new->keys[keep++] = key_get(key); + RCU_INIT_POINTER(new->keys[keep++], key_get(key)); } } new->nkeys = keep; diff --git a/security/keys/permission.c b/security/keys/permission.c old mode 100755 new mode 100644 index c35b5229..5f4c00c0 --- a/security/keys/permission.c +++ b/security/keys/permission.c @@ -87,20 +87,25 @@ EXPORT_SYMBOL(key_task_permission); * key_validate - Validate a key. * @key: The key to be validated. * - * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if - * the key's type has been removed or if the key has been revoked or - * -EKEYEXPIRED if the key has expired. + * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the + * key is invalidated, -EKEYREVOKED if the key's type has been removed or if + * the key has been revoked or -EKEYEXPIRED if the key has expired. */ int key_validate(struct key *key) { struct timespec now; + unsigned long flags = key->flags; int ret = 0; if (key) { + ret = -ENOKEY; + if (flags & (1 << KEY_FLAG_INVALIDATED)) + goto error; + /* check it's still accessible */ ret = -EKEYREVOKED; - if (test_bit(KEY_FLAG_REVOKED, &key->flags) || - test_bit(KEY_FLAG_DEAD, &key->flags)) + if (flags & ((1 << KEY_FLAG_REVOKED) | + (1 << KEY_FLAG_DEAD))) goto error; /* check it hasn't expired */ diff --git a/security/keys/proc.c b/security/keys/proc.c old mode 100755 new mode 100644 index 49bbc979..30d1ddfd --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -242,7 +242,7 @@ static int proc_keys_show(struct seq_file *m, void *v) #define showflag(KEY, LETTER, FLAG) \ (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') - seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", + seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", key->serial, showflag(key, 'I', KEY_FLAG_INSTANTIATED), showflag(key, 'R', KEY_FLAG_REVOKED), @@ -250,6 +250,7 @@ static int proc_keys_show(struct seq_file *m, void *v) showflag(key, 'Q', KEY_FLAG_IN_QUOTA), showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), showflag(key, 'N', KEY_FLAG_NEGATIVE), + showflag(key, 'i', KEY_FLAG_INVALIDATED), atomic_read(&key->usage), xbuf, key->perm, diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c old mode 100755 new mode 100644 diff --git a/security/keys/request_key.c b/security/keys/request_key.c old mode 100755 new mode 100644 diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c old mode 100755 new mode 100644 diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c old mode 100755 new mode 100644 diff --git a/security/keys/trusted.c b/security/keys/trusted.c old mode 100755 new mode 100644 index 2d5d041f..9614dbca --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -1013,12 +1013,15 @@ static void trusted_rcu_free(struct rcu_head *rcu) */ static int trusted_update(struct key *key, const void *data, size_t datalen) { - struct trusted_key_payload *p = key->payload.data; + struct trusted_key_payload *p; struct trusted_key_payload *new_p; struct trusted_key_options *new_o; char *datablob; int ret = 0; + if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) + return -ENOKEY; + p = key->payload.data; if (!p->migratable) return -EPERM; if (datalen <= 0 || datalen > 32767 || !data) diff --git a/security/keys/trusted.h b/security/keys/trusted.h old mode 100755 new mode 100644 diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c old mode 100755 new mode 100644 index c7660a25..f89846f6 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -117,7 +117,10 @@ int user_update(struct key *key, const void *data, size_t datalen) if (ret == 0) { /* attach the new data, displacing the old */ - zap = key->payload.data; + if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags)) + zap = key->payload.data; + else + zap = NULL; rcu_assign_keypointer(key, upayload); key->expiry = 0; } diff --git a/security/lsm_audit.c b/security/lsm_audit.c old mode 100755 new mode 100644 index 90c129b0..abacc49f --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -242,6 +242,21 @@ static void dump_common_audit_data(struct audit_buffer *ab, } break; } + case LSM_AUDIT_DATA_IOCTL_OP: { + struct inode *inode; + + audit_log_d_path(ab, " path=", &a->u.op->path); + + inode = a->u.op->path.dentry->d_inode; + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } + + audit_log_format(ab, " ioctlcmd=%hx", a->u.op->cmd); + break; + } case LSM_AUDIT_DATA_DENTRY: { struct inode *inode; diff --git a/security/min_addr.c b/security/min_addr.c old mode 100755 new mode 100644 diff --git a/security/security.c b/security/security.c old mode 100755 new mode 100644 index bf619ffc..0e1916e9 --- a/security/security.c +++ b/security/security.c @@ -130,6 +130,26 @@ int __init register_security(struct security_operations *ops) /* Security operations */ +int security_binder_set_context_mgr(struct task_struct *mgr) +{ + return security_ops->binder_set_context_mgr(mgr); +} + +int security_binder_transaction(struct task_struct *from, struct task_struct *to) +{ + return security_ops->binder_transaction(from, to); +} + +int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to) +{ + return security_ops->binder_transfer_binder(from, to); +} + +int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) +{ + return security_ops->binder_transfer_file(from, to, file); +} + int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { return security_ops->ptrace_access_check(child, mode); @@ -260,8 +280,8 @@ int security_sb_statfs(struct dentry *dentry) return security_ops->sb_statfs(dentry); } -int security_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, void *data) +int security_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { return security_ops->sb_mount(dev_name, path, type, flags, data); } diff --git a/security/selinux/.gitignore b/security/selinux/.gitignore old mode 100755 new mode 100644 diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig old mode 100755 new mode 100644 index bca1b74a..c83e48fa --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -65,6 +65,13 @@ config SECURITY_SELINUX_DEVELOP can interactively toggle the kernel between enforcing mode and permissive mode (if permitted by the policy) via /selinux/enforce. +config SECURITY_SELINUX_FORCE_PERMISSIVE + bool "NSA SELinux Permanent Permissive" + depends on SECURITY_SELINUX + default n + help + This option sets SELINUX mode as permissive permanently + config SECURITY_SELINUX_AVC_STATS bool "NSA SELinux AVC Statistics" depends on SECURITY_SELINUX diff --git a/security/selinux/Makefile b/security/selinux/Makefile old mode 100755 new mode 100644 diff --git a/security/selinux/avc.c b/security/selinux/avc.c old mode 100755 new mode 100644 index 8ee42b2a..59c831cd --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ struct avc_entry { u32 tsid; u16 tclass; struct av_decision avd; + struct avc_operation_node *ops_node; }; struct avc_node { @@ -56,6 +58,16 @@ struct avc_node { struct rcu_head rhead; }; +struct avc_operation_decision_node { + struct operation_decision od; + struct list_head od_list; +}; + +struct avc_operation_node { + struct operation ops; + struct list_head od_head; /* list of operation_decision_node */ +}; + struct avc_cache { struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ @@ -86,6 +98,9 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; static struct avc_cache avc_cache; static struct avc_callback_node *avc_callbacks; static struct kmem_cache *avc_node_cachep; +static struct kmem_cache *avc_operation_decision_node_cachep; +static struct kmem_cache *avc_operation_node_cachep; +static struct kmem_cache *avc_operation_perm_cachep; static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) { @@ -177,6 +192,16 @@ void __init avc_init(void) avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), 0, SLAB_PANIC, NULL); + avc_operation_node_cachep = kmem_cache_create("avc_operation_node", + sizeof(struct avc_operation_node), + 0, SLAB_PANIC, NULL); + avc_operation_decision_node_cachep = kmem_cache_create( + "avc_operation_decision_node", + sizeof(struct avc_operation_decision_node), + 0, SLAB_PANIC, NULL); + avc_operation_perm_cachep = kmem_cache_create("avc_operation_perm", + sizeof(struct operation_perm), + 0, SLAB_PANIC, NULL); audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } @@ -213,9 +238,255 @@ int avc_get_hash_stats(char *page) slots_used, AVC_CACHE_SLOTS, max_chain_len); } +/* + * using a linked list for operation_decision lookup because the list is + * always small. i.e. less than 5, typically 1 + */ +static struct operation_decision *avc_operation_lookup(u8 type, + struct avc_operation_node *ops_node) +{ + struct avc_operation_decision_node *od_node; + struct operation_decision *od = NULL; + + list_for_each_entry(od_node, &ops_node->od_head, od_list) { + if (od_node->od.type != type) + continue; + od = &od_node->od; + break; + } + return od; +} + +static inline unsigned int avc_operation_has_perm(struct operation_decision *od, + u16 cmd, u8 specified) +{ + unsigned int rc = 0; + u8 num = cmd & 0xff; + + if ((specified == OPERATION_ALLOWED) && + (od->specified & OPERATION_ALLOWED)) + rc = security_operation_test(od->allowed->perms, num); + else if ((specified == OPERATION_AUDITALLOW) && + (od->specified & OPERATION_AUDITALLOW)) + rc = security_operation_test(od->auditallow->perms, num); + else if ((specified == OPERATION_DONTAUDIT) && + (od->specified & OPERATION_DONTAUDIT)) + rc = security_operation_test(od->dontaudit->perms, num); + return rc; +} + +static void avc_operation_allow_perm(struct avc_operation_node *node, u16 cmd) +{ + struct operation_decision *od; + u8 type; + u8 num; + + type = cmd >> 8; + num = cmd & 0xff; + security_operation_set(node->ops.type, type); + od = avc_operation_lookup(type, node); + if (od && od->allowed) + security_operation_set(od->allowed->perms, num); +} + +static void avc_operation_decision_free( + struct avc_operation_decision_node *od_node) +{ + struct operation_decision *od; + + od = &od_node->od; + if (od->allowed) + kmem_cache_free(avc_operation_perm_cachep, od->allowed); + if (od->auditallow) + kmem_cache_free(avc_operation_perm_cachep, od->auditallow); + if (od->dontaudit) + kmem_cache_free(avc_operation_perm_cachep, od->dontaudit); + kmem_cache_free(avc_operation_decision_node_cachep, od_node); +} + +static void avc_operation_free(struct avc_operation_node *ops_node) +{ + struct avc_operation_decision_node *od_node, *tmp; + + if (!ops_node) + return; + + list_for_each_entry_safe(od_node, tmp, &ops_node->od_head, od_list) { + list_del(&od_node->od_list); + avc_operation_decision_free(od_node); + } + kmem_cache_free(avc_operation_node_cachep, ops_node); +} + +static void avc_copy_operation_decision(struct operation_decision *dest, + struct operation_decision *src) +{ + dest->type = src->type; + dest->specified = src->specified; + if (dest->specified & OPERATION_ALLOWED) + memcpy(dest->allowed->perms, src->allowed->perms, + sizeof(src->allowed->perms)); + if (dest->specified & OPERATION_AUDITALLOW) + memcpy(dest->auditallow->perms, src->auditallow->perms, + sizeof(src->auditallow->perms)); + if (dest->specified & OPERATION_DONTAUDIT) + memcpy(dest->dontaudit->perms, src->dontaudit->perms, + sizeof(src->dontaudit->perms)); +} + +/* + * similar to avc_copy_operation_decision, but only copy decision + * information relevant to this command + */ +static inline void avc_quick_copy_operation_decision(u16 cmd, + struct operation_decision *dest, + struct operation_decision *src) +{ + /* + * compute index of the u32 of the 256 bits (8 u32s) that contain this + * command permission + */ + u8 i = (0xff & cmd) >> 5; + + dest->specified = src->specified; + if (dest->specified & OPERATION_ALLOWED) + dest->allowed->perms[i] = src->allowed->perms[i]; + if (dest->specified & OPERATION_AUDITALLOW) + dest->auditallow->perms[i] = src->auditallow->perms[i]; + if (dest->specified & OPERATION_DONTAUDIT) + dest->dontaudit->perms[i] = src->dontaudit->perms[i]; +} + +static struct avc_operation_decision_node + *avc_operation_decision_alloc(u8 specified) +{ + struct avc_operation_decision_node *node; + struct operation_decision *od; + + node = kmem_cache_zalloc(avc_operation_decision_node_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!node) + return NULL; + + od = &node->od; + if (specified & OPERATION_ALLOWED) { + od->allowed = kmem_cache_zalloc(avc_operation_perm_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!od->allowed) + goto error; + } + if (specified & OPERATION_AUDITALLOW) { + od->auditallow = kmem_cache_zalloc(avc_operation_perm_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!od->auditallow) + goto error; + } + if (specified & OPERATION_DONTAUDIT) { + od->dontaudit = kmem_cache_zalloc(avc_operation_perm_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!od->dontaudit) + goto error; + } + return node; +error: + avc_operation_decision_free(node); + return NULL; +} + +static int avc_add_operation(struct avc_node *node, + struct operation_decision *od) +{ + struct avc_operation_decision_node *dest_od; + + node->ae.ops_node->ops.len++; + dest_od = avc_operation_decision_alloc(od->specified); + if (!dest_od) + return -ENOMEM; + avc_copy_operation_decision(&dest_od->od, od); + list_add(&dest_od->od_list, &node->ae.ops_node->od_head); + return 0; +} + +static struct avc_operation_node *avc_operation_alloc(void) +{ + struct avc_operation_node *ops; + + ops = kmem_cache_zalloc(avc_operation_node_cachep, + GFP_ATOMIC|__GFP_NOMEMALLOC); + if (!ops) + return ops; + INIT_LIST_HEAD(&ops->od_head); + return ops; +} + +static int avc_operation_populate(struct avc_node *node, + struct avc_operation_node *src) +{ + struct avc_operation_node *dest; + struct avc_operation_decision_node *dest_od; + struct avc_operation_decision_node *src_od; + + if (src->ops.len == 0) + return 0; + dest = avc_operation_alloc(); + if (!dest) + return -ENOMEM; + + memcpy(dest->ops.type, &src->ops.type, sizeof(dest->ops.type)); + dest->ops.len = src->ops.len; + + /* for each source od allocate a destination od and copy */ + list_for_each_entry(src_od, &src->od_head, od_list) { + dest_od = avc_operation_decision_alloc(src_od->od.specified); + if (!dest_od) + goto error; + avc_copy_operation_decision(&dest_od->od, &src_od->od); + list_add(&dest_od->od_list, &dest->od_head); + } + node->ae.ops_node = dest; + return 0; +error: + avc_operation_free(dest); + return -ENOMEM; + +} + +static inline u32 avc_operation_audit_required(u32 requested, + struct av_decision *avd, + struct operation_decision *od, + u16 cmd, + int result, + u32 *deniedp) +{ + u32 denied, audited; + + denied = requested & ~avd->allowed; + if (unlikely(denied)) { + audited = denied & avd->auditdeny; + if (audited && od) { + if (avc_operation_has_perm(od, cmd, + OPERATION_DONTAUDIT)) + audited &= ~requested; + } + } else if (result) { + audited = denied = requested; + } else { + audited = requested & avd->auditallow; + if (audited && od) { + if (!avc_operation_has_perm(od, cmd, + OPERATION_AUDITALLOW)) + audited &= ~requested; + } + } + + *deniedp = denied; + return audited; +} + static void avc_node_free(struct rcu_head *rhead) { struct avc_node *node = container_of(rhead, struct avc_node, rhead); + avc_operation_free(node->ae.ops_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); } @@ -229,6 +500,7 @@ static void avc_node_delete(struct avc_node *node) static void avc_node_kill(struct avc_node *node) { + avc_operation_free(node->ae.ops_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); atomic_dec(&avc_cache.active_nodes); @@ -377,6 +649,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) * @tsid: target security identifier * @tclass: target security class * @avd: resulting av decision + * @ops: resulting operation decisions * * Insert an AVC entry for the SID pair * (@ssid, @tsid) and class @tclass. @@ -388,7 +661,9 @@ static int avc_latest_notif_update(int seqno, int is_insert) * the access vectors into a cache entry, returns * avc_node inserted. Otherwise, this function returns NULL. */ -static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) +static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, + struct av_decision *avd, + struct avc_operation_node *ops_node) { struct avc_node *pos, *node = NULL; int hvalue; @@ -402,10 +677,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec struct hlist_head *head; struct hlist_node *next; spinlock_t *lock; + int rc = 0; hvalue = avc_hash(ssid, tsid, tclass); avc_node_populate(node, ssid, tsid, tclass, avd); - + rc = avc_operation_populate(node, ops_node); + if (rc) { + kmem_cache_free(avc_node_cachep, node); + return NULL; + } head = &avc_cache.slots[hvalue]; lock = &avc_cache.slots_lock[hvalue]; @@ -455,11 +735,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) avc_dump_query(ab, ad->selinux_audit_data->slad->ssid, ad->selinux_audit_data->slad->tsid, ad->selinux_audit_data->slad->tclass); + if (ad->selinux_audit_data->slad->denied) { + audit_log_format(ab, " permissive=%u", + ad->selinux_audit_data->slad->result ? 0 : 1); + } } /* This is the slow part of avc audit with big stack footprint */ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, - u32 requested, u32 audited, u32 denied, + u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a, unsigned flags) { @@ -490,12 +774,28 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, slad.tsid = tsid; slad.audited = audited; slad.denied = denied; + slad.result = result; a->selinux_audit_data->slad = &slad; common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); return 0; } +static inline int avc_operation_audit(u32 ssid, u32 tsid, u16 tclass, + u32 requested, struct av_decision *avd, + struct operation_decision *od, + u16 cmd, int result, + struct common_audit_data *ad) +{ + u32 audited, denied; + audited = avc_operation_audit_required( + requested, avd, od, cmd, result, &denied); + if (likely(!audited)) + return 0; + return slow_avc_audit(ssid, tsid, tclass, requested, + audited, denied, result, ad, 0); +} + /** * avc_audit - Audit the granting or denial of permissions. * @ssid: source security identifier @@ -553,7 +853,7 @@ inline int avc_audit(u32 ssid, u32 tsid, return 0; return slow_avc_audit(ssid, tsid, tclass, - requested, audited, denied, + requested, audited, denied, result, a, flags); } @@ -609,14 +909,17 @@ static inline int avc_sidcmp(u32 x, u32 y) * @perms : Permission mask bits * @ssid,@tsid,@tclass : identifier of an AVC entry * @seqno : sequence number when decision was made + * @od: operation_decision to be added to the node * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. * otherwise, this function updates the AVC entry. The original AVC-entry object * will release later by RCU. */ -static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, - u32 seqno) +static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, + u16 tclass, u32 seqno, + struct operation_decision *od, + u32 flags) { int hvalue, rc = 0; unsigned long flag; @@ -661,9 +964,19 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); + if (orig->ae.ops_node) { + rc = avc_operation_populate(node, orig->ae.ops_node); + if (rc) { + kmem_cache_free(avc_node_cachep, node); + goto out_unlock; + } + } + switch (event) { case AVC_CALLBACK_GRANT: node->ae.avd.allowed |= perms; + if (node->ae.ops_node && (flags & AVC_OPERATION_CMD)) + avc_operation_allow_perm(node->ae.ops_node, cmd); break; case AVC_CALLBACK_TRY_REVOKE: case AVC_CALLBACK_REVOKE: @@ -681,6 +994,9 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, case AVC_CALLBACK_AUDITDENY_DISABLE: node->ae.avd.auditdeny &= ~perms; break; + case AVC_CALLBACK_ADD_OPERATION: + avc_add_operation(node, od); + break; } avc_node_replace(node, orig); out_unlock: @@ -754,18 +1070,20 @@ int avc_ss_reset(u32 seqno) * results in a bigger stack frame. */ static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, - u16 tclass, struct av_decision *avd) + u16 tclass, struct av_decision *avd, + struct avc_operation_node *ops_node) { rcu_read_unlock(); - security_compute_av(ssid, tsid, tclass, avd); + INIT_LIST_HEAD(&ops_node->od_head); + security_compute_av(ssid, tsid, tclass, avd, &ops_node->ops); rcu_read_lock(); - return avc_insert(ssid, tsid, tclass, avd); + return avc_insert(ssid, tsid, tclass, avd, ops_node); } static noinline int avc_denied(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - unsigned flags, - struct av_decision *avd) + u16 tclass, u32 requested, + u16 cmd, unsigned flags, + struct av_decision *avd) { if (flags & AVC_STRICT) return -EACCES; @@ -773,11 +1091,92 @@ static noinline int avc_denied(u32 ssid, u32 tsid, if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) return -EACCES; - avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, - tsid, tclass, avd->seqno); + avc_update_node(AVC_CALLBACK_GRANT, requested, cmd, ssid, + tsid, tclass, avd->seqno, NULL, flags); return 0; } +/* + * ioctl commands are comprised of four fields, direction, size, type, and + * number. The avc operation logic filters based on two of them: + * + * type: or code, typically unique to each driver + * number: or function + * + * For example, 0x89 is a socket type, and number 0x27 is the get hardware + * address function. + */ +int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, + u16 cmd, struct common_audit_data *ad) +{ + struct avc_node *node; + struct av_decision avd; + u32 denied; + struct operation_decision *od = NULL; + struct operation_decision od_local; + struct operation_perm allowed; + struct operation_perm auditallow; + struct operation_perm dontaudit; + struct avc_operation_node local_ops_node; + struct avc_operation_node *ops_node; + u8 type = cmd >> 8; + int rc = 0, rc2; + + ops_node = &local_ops_node; + BUG_ON(!requested); + + rcu_read_lock(); + + node = avc_lookup(ssid, tsid, tclass); + if (unlikely(!node)) { + node = avc_compute_av(ssid, tsid, tclass, &avd, ops_node); + } else { + memcpy(&avd, &node->ae.avd, sizeof(avd)); + ops_node = node->ae.ops_node; + } + /* if operations are not defined, only consider av_decision */ + if (!ops_node || !ops_node->ops.len) + goto decision; + + od_local.allowed = &allowed; + od_local.auditallow = &auditallow; + od_local.dontaudit = &dontaudit; + + /* lookup operation decision */ + od = avc_operation_lookup(type, ops_node); + if (unlikely(!od)) { + /* Compute operation decision if type is flagged */ + if (!security_operation_test(ops_node->ops.type, type)) { + avd.allowed &= ~requested; + goto decision; + } + rcu_read_unlock(); + security_compute_operation(ssid, tsid, tclass, type, &od_local); + rcu_read_lock(); + avc_update_node(AVC_CALLBACK_ADD_OPERATION, requested, cmd, + ssid, tsid, tclass, avd.seqno, &od_local, 0); + } else { + avc_quick_copy_operation_decision(cmd, &od_local, od); + } + od = &od_local; + + if (!avc_operation_has_perm(od, cmd, OPERATION_ALLOWED)) + avd.allowed &= ~requested; + +decision: + denied = requested & ~(avd.allowed); + if (unlikely(denied)) + rc = avc_denied(ssid, tsid, tclass, requested, cmd, + AVC_OPERATION_CMD, &avd); + + rcu_read_unlock(); + + rc2 = avc_operation_audit(ssid, tsid, tclass, requested, + &avd, od, cmd, rc, ad); + if (rc2) + return rc2; + return rc; +} /** * avc_has_perm_noaudit - Check permissions but perform no auditing. @@ -805,6 +1204,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, struct av_decision *avd) { struct avc_node *node; + struct avc_operation_node ops_node; int rc = 0; u32 denied; @@ -813,16 +1213,14 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); - if (unlikely(!node)) { - node = avc_compute_av(ssid, tsid, tclass, avd); - } else { + if (unlikely(!node)) + node = avc_compute_av(ssid, tsid, tclass, avd, &ops_node); + else memcpy(avd, &node->ae.avd, sizeof(*avd)); - avd = &node->ae.avd; - } denied = requested & ~(avd->allowed); if (unlikely(denied)) - rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); + rc = avc_denied(ssid, tsid, tclass, requested, 0, flags, avd); rcu_read_unlock(); return rc; diff --git a/security/selinux/exports.c b/security/selinux/exports.c old mode 100755 new mode 100644 diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c old mode 100755 new mode 100644 index 4787e929..7a488e7d --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -102,6 +102,9 @@ extern struct security_operations *security_ops; static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); #ifdef CONFIG_SECURITY_SELINUX_DEVELOP +#ifdef CONFIG_SECURITY_SELINUX_FORCE_PERMISSIVE + int selinux_enforcing = 0; +#else int selinux_enforcing; static int __init enforcing_setup(char *str) @@ -113,6 +116,7 @@ static int __init enforcing_setup(char *str) } __setup("enforcing=", enforcing_setup); #endif +#endif #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; @@ -418,8 +422,18 @@ static int sb_finish_set_opts(struct super_block *sb) sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) sbsec->flags &= ~SE_SBLABELSUPP; - /* Special handling for sysfs. Is genfs but also has setxattr handler*/ - if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) + /* Special handling. Is genfs but also has in-core setxattr handler*/ + if (!strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "rootfs")) + sbsec->flags |= SE_SBLABELSUPP; + + /* + * Special handling for rootfs. Is genfs but supports + * setting SELinux context on in-core inodes. + */ + if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0) sbsec->flags |= SE_SBLABELSUPP; /* Initialize the root inode. */ @@ -1853,6 +1867,67 @@ static inline u32 open_file_to_av(struct file *file) /* Hook functions begin here. */ +static int selinux_binder_set_context_mgr(struct task_struct *mgr) +{ + u32 mysid = current_sid(); + u32 mgrsid = task_sid(mgr); + + return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL); +} + +static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to) +{ + u32 mysid = current_sid(); + u32 fromsid = task_sid(from); + u32 tosid = task_sid(to); + int rc; + + if (mysid != fromsid) { + rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL); + if (rc) + return rc; + } + + return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL); +} + +static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to) +{ + u32 fromsid = task_sid(from); + u32 tosid = task_sid(to); + return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL); +} + +static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) +{ + u32 sid = task_sid(to); + struct file_security_struct *fsec = file->f_security; + struct inode *inode = file->f_path.dentry->d_inode; + struct inode_security_struct *isec = inode->i_security; + struct common_audit_data ad; + struct selinux_audit_data sad = {0,}; + int rc; + + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path = file->f_path; + ad.selinux_audit_data = &sad; + + if (sid != fsec->sid) { + rc = avc_has_perm(sid, fsec->sid, + SECCLASS_FD, + FD__USE, + &ad); + if (rc) + return rc; + } + + if (unlikely(IS_PRIVATE(inode))) + return 0; + + return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), + &ad); +} + static int selinux_ptrace_access_check(struct task_struct *child, unsigned int mode) { @@ -2197,7 +2272,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, int fd; j++; - i = j * __NFDBITS; + i = j * BITS_PER_LONG; fdt = files_fdtable(files); if (i >= fdt->max_fds) break; @@ -2556,9 +2631,9 @@ static int selinux_sb_statfs(struct dentry *dentry) return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } -static int selinux_mount(char *dev_name, +static int selinux_mount(const char *dev_name, struct path *path, - char *type, + const char *type, unsigned long flags, void *data) { @@ -3020,6 +3095,46 @@ static void selinux_file_free_security(struct file *file) file_free_security(file); } +/* + * Check whether a task has the ioctl permission and cmd + * operation to an inode. + */ +int ioctl_has_perm(const struct cred *cred, struct file *file, + u32 requested, u16 cmd) +{ + struct common_audit_data ad; + struct file_security_struct *fsec = file->f_security; + struct inode *inode = file->f_path.dentry->d_inode; + struct inode_security_struct *isec = inode->i_security; + struct lsm_ioctlop_audit ioctl; + u32 ssid = cred_sid(cred); + struct selinux_audit_data sad = {0,}; + int rc; + + COMMON_AUDIT_DATA_INIT(&ad, IOCTL_OP); + ad.u.op = &ioctl; + ad.u.op->cmd = cmd; + ad.u.op->path = file->f_path; + ad.selinux_audit_data = &sad; + + if (ssid != fsec->sid) { + rc = avc_has_perm(ssid, fsec->sid, + SECCLASS_FD, + FD__USE, + &ad); + if (rc) + goto out; + } + + if (unlikely(IS_PRIVATE(inode))) + return 0; + + rc = avc_has_operation(ssid, isec->sid, isec->sclass, + requested, cmd, &ad); +out: + return rc; +} + static int selinux_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -3062,7 +3177,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, * to the file's ioctl() function. */ default: - error = file_has_perm(cred, file, FILE__IOCTL); + error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); } return error; } @@ -5647,6 +5762,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) static struct security_operations selinux_ops = { .name = "selinux", + .binder_set_context_mgr = selinux_binder_set_context_mgr, + .binder_transaction = selinux_binder_transaction, + .binder_transfer_binder = selinux_binder_transfer_binder, + .binder_transfer_file = selinux_binder_transfer_file, + .ptrace_access_check = selinux_ptrace_access_check, .ptrace_traceme = selinux_ptrace_traceme, .capget = selinux_capget, diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h old mode 100755 new mode 100644 index 19313702..63c3105d --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -84,11 +84,15 @@ int avc_audit(u32 ssid, u32 tsid, struct common_audit_data *a, unsigned flags); #define AVC_STRICT 1 /* Ignore permissive mode. */ +#define AVC_OPERATION_CMD 2 /* ignore command when updating operations */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, struct av_decision *avd); +int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, + u16 cmd, struct common_audit_data *ad); + int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata, @@ -111,6 +115,7 @@ u32 avc_policy_seqno(void); #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 #define AVC_CALLBACK_AUDITDENY_ENABLE 64 #define AVC_CALLBACK_AUDITDENY_DISABLE 128 +#define AVC_CALLBACK_ADD_OPERATION 256 int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, u16 tclass, u32 perms, diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h old mode 100755 new mode 100644 index b8c53723..20b00fc3 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -145,9 +145,12 @@ struct security_class_mapping secclass_map[] = { "node_bind", "name_connect", NULL } }, { "memprotect", { "mmap_zero", NULL } }, { "peer", { "recv", NULL } }, - { "capability2", { "mac_override", "mac_admin", "syslog", NULL } }, + { "capability2", + { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", + NULL } }, { "kernel_service", { "use_as_override", "create_files_as", NULL } }, { "tun_socket", { COMMON_SOCK_PERMS, NULL } }, + { "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } }, { NULL } }; diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h old mode 100755 new mode 100644 diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h old mode 100755 new mode 100644 index e277dfe2..7b1830bd --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -46,7 +46,6 @@ struct inode_security_struct { u32 sid; /* SID of this object */ u16 sclass; /* security class of this object */ unsigned char initialized; /* initialization flag */ - u32 tag; /* Per-File-Encryption tag */ struct mutex lock; }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h old mode 100755 new mode 100644 index d871e8ad..ff1a1880 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -31,13 +31,17 @@ #define POLICYDB_VERSION_BOUNDARY 24 #define POLICYDB_VERSION_FILENAME_TRANS 25 #define POLICYDB_VERSION_ROLETRANS 26 +#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 +#define POLICYDB_VERSION_DEFAULT_TYPE 28 +#define POLICYDB_VERSION_CONSTRAINT_NAMES 29 +#define POLICYDB_VERSION_IOCTL_OPERATIONS 30 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #else -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_IOCTL_OPERATIONS #endif /* Mask for just the mount related flags */ @@ -100,11 +104,40 @@ struct av_decision { u32 flags; }; +#define security_operation_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) +#define security_operation_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) + +struct operation_perm { + u32 perms[8]; +}; + +struct operation_decision { + u8 type; + u8 specified; + struct operation_perm *allowed; + struct operation_perm *auditallow; + struct operation_perm *dontaudit; +}; + +#define OPERATION_ALLOWED 1 +#define OPERATION_AUDITALLOW 2 +#define OPERATION_DONTAUDIT 4 +#define OPERATION_ALL (OPERATION_ALLOWED | OPERATION_AUDITALLOW |\ + OPERATION_DONTAUDIT) +struct operation { + u16 len; /* length of operation decision chain */ + u32 type[8]; /* 256 types */ +}; + /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 void security_compute_av(u32 ssid, u32 tsid, - u16 tclass, struct av_decision *avd); + u16 tclass, struct av_decision *avd, + struct operation *ops); + +void security_compute_operation(u32 ssid, u32 tsid, u16 tclass, + u8 type, struct operation_decision *od); void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd); diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h old mode 100755 new mode 100644 diff --git a/security/selinux/netif.c b/security/selinux/netif.c old mode 100755 new mode 100644 diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c old mode 100755 new mode 100644 diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c old mode 100755 new mode 100644 diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c old mode 100755 new mode 100644 diff --git a/security/selinux/netport.c b/security/selinux/netport.c old mode 100755 new mode 100644 diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 5776921d..f24a04e3 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "flask.h" #include "av_permissions.h" @@ -80,6 +81,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] = { { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, }; static struct nlmsg_perm nlmsg_xfrm_perms[] = diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c old mode 100755 new mode 100644 index 3bf90453..17973289 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -31,6 +31,7 @@ #include #include + /* selinuxfs pseudo filesystem for exporting the security policy API. Based on the proc code and the fs/nfsd/nfsctl.c code. */ @@ -136,6 +137,7 @@ static ssize_t sel_read_enforce(struct file *filp, char __user *buf, return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } +#ifndef CONFIG_SECURITY_SELINUX_FORCE_PERMISSIVE #ifdef CONFIG_SECURITY_SELINUX_DEVELOP static ssize_t sel_write_enforce(struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -190,10 +192,15 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, #else #define sel_write_enforce NULL #endif +#endif static const struct file_operations sel_enforce_ops = { .read = sel_read_enforce, +#ifdef CONFIG_SECURITY_SELINUX_FORCE_PERMISSIVE + .write = NULL, +#else .write = sel_write_enforce, +#endif .llseek = generic_file_llseek, }; diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c old mode 100755 new mode 100644 index a3dd9faa..dd7466cb --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -24,6 +24,7 @@ #include "policydb.h" static struct kmem_cache *avtab_node_cachep; +static struct kmem_cache *avtab_operation_cachep; static inline int avtab_hash(struct avtab_key *keyp, u16 mask) { @@ -37,11 +38,24 @@ avtab_insert_node(struct avtab *h, int hvalue, struct avtab_key *key, struct avtab_datum *datum) { struct avtab_node *newnode; + struct avtab_operation *ops; newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); if (newnode == NULL) return NULL; newnode->key = *key; - newnode->datum = *datum; + + if (key->specified & AVTAB_OP) { + ops = kmem_cache_zalloc(avtab_operation_cachep, GFP_KERNEL); + if (ops == NULL) { + kmem_cache_free(avtab_node_cachep, newnode); + return NULL; + } + *ops = *(datum->u.ops); + newnode->datum.u.ops = ops; + } else { + newnode->datum.u.data = datum->u.data; + } + if (prev) { newnode->next = prev->next; prev->next = newnode; @@ -70,8 +84,11 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && - (specified & cur->key.specified)) + (specified & cur->key.specified)) { + if (specified & AVTAB_OPNUM) + break; return -EEXIST; + } if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && @@ -232,6 +249,9 @@ void avtab_destroy(struct avtab *h) while (cur) { temp = cur; cur = cur->next; + if (temp->key.specified & AVTAB_OP) + kmem_cache_free(avtab_operation_cachep, + temp->datum.u.ops); kmem_cache_free(avtab_node_cachep, temp); } h->htable[i] = NULL; @@ -320,7 +340,13 @@ static uint16_t spec_order[] = { AVTAB_AUDITALLOW, AVTAB_TRANSITION, AVTAB_CHANGE, - AVTAB_MEMBER + AVTAB_MEMBER, + AVTAB_OPNUM_ALLOWED, + AVTAB_OPNUM_AUDITALLOW, + AVTAB_OPNUM_DONTAUDIT, + AVTAB_OPTYPE_ALLOWED, + AVTAB_OPTYPE_AUDITALLOW, + AVTAB_OPTYPE_DONTAUDIT }; int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, @@ -330,10 +356,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, { __le16 buf16[4]; u16 enabled; - __le32 buf32[7]; u32 items, items2, val, vers = pol->policyvers; struct avtab_key key; struct avtab_datum datum; + struct avtab_operation ops; + __le32 buf32[ARRAY_SIZE(ops.op.perms)]; int i, rc; unsigned set; @@ -390,11 +417,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); return -EINVAL; } + if (val & AVTAB_OP) { + printk(KERN_ERR "SELinux: avtab: entry has operations\n"); + return -EINVAL; + } for (i = 0; i < ARRAY_SIZE(spec_order); i++) { if (val & spec_order[i]) { key.specified = spec_order[i] | enabled; - datum.data = le32_to_cpu(buf32[items++]); + datum.u.data = le32_to_cpu(buf32[items++]); rc = insertf(a, &key, &datum, p); if (rc) return rc; @@ -413,7 +444,6 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } - items = 0; key.source_type = le16_to_cpu(buf16[items++]); key.target_type = le16_to_cpu(buf16[items++]); @@ -437,14 +467,32 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return -EINVAL; } - rc = next_entry(buf32, fp, sizeof(u32)); - if (rc) { - printk(KERN_ERR "SELinux: avtab: truncated entry\n"); - return rc; + if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS) + || !(key.specified & AVTAB_OP)) { + rc = next_entry(buf32, fp, sizeof(u32)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + datum.u.data = le32_to_cpu(*buf32); + } else { + memset(&ops, 0, sizeof(struct avtab_operation)); + rc = next_entry(&ops.type, fp, sizeof(u8)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(ops.op.perms)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + for (i = 0; i < ARRAY_SIZE(ops.op.perms); i++) + ops.op.perms[i] = le32_to_cpu(buf32[i]); + datum.u.ops = &ops; } - datum.data = le32_to_cpu(*buf32); if ((key.specified & AVTAB_TYPE) && - !policydb_type_isvalid(pol, datum.data)) { + !policydb_type_isvalid(pol, datum.u.data)) { printk(KERN_ERR "SELinux: avtab: invalid type\n"); return -EINVAL; } @@ -504,8 +552,9 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) { __le16 buf16[4]; - __le32 buf32[1]; + __le32 buf32[ARRAY_SIZE(cur->datum.u.ops->op.perms)]; int rc; + unsigned int i; buf16[0] = cpu_to_le16(cur->key.source_type); buf16[1] = cpu_to_le16(cur->key.target_type); @@ -514,8 +563,19 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) rc = put_entry(buf16, sizeof(u16), 4, fp); if (rc) return rc; - buf32[0] = cpu_to_le32(cur->datum.data); - rc = put_entry(buf32, sizeof(u32), 1, fp); + + if (cur->key.specified & AVTAB_OP) { + rc = put_entry(&cur->datum.u.ops->type, sizeof(u8), 1, fp); + if (rc) + return rc; + for (i = 0; i < ARRAY_SIZE(cur->datum.u.ops->op.perms); i++) + buf32[i] = cpu_to_le32(cur->datum.u.ops->op.perms[i]); + rc = put_entry(buf32, sizeof(u32), + ARRAY_SIZE(cur->datum.u.ops->op.perms), fp); + } else { + buf32[0] = cpu_to_le32(cur->datum.u.data); + rc = put_entry(buf32, sizeof(u32), 1, fp); + } if (rc) return rc; return 0; @@ -548,9 +608,13 @@ void avtab_cache_init(void) avtab_node_cachep = kmem_cache_create("avtab_node", sizeof(struct avtab_node), 0, SLAB_PANIC, NULL); + avtab_operation_cachep = kmem_cache_create("avtab_operation", + sizeof(struct avtab_operation), + 0, SLAB_PANIC, NULL); } void avtab_cache_destroy(void) { kmem_cache_destroy(avtab_node_cachep); + kmem_cache_destroy(avtab_operation_cachep); } diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h old mode 100755 new mode 100644 index 63ce2f9e..97acd6fa --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -23,6 +23,8 @@ #ifndef _SS_AVTAB_H_ #define _SS_AVTAB_H_ +#include "security.h" + struct avtab_key { u16 source_type; /* source type */ u16 target_type; /* target type */ @@ -35,13 +37,34 @@ struct avtab_key { #define AVTAB_MEMBER 0x0020 #define AVTAB_CHANGE 0x0040 #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) +#define AVTAB_OPNUM_ALLOWED 0x0100 +#define AVTAB_OPNUM_AUDITALLOW 0x0200 +#define AVTAB_OPNUM_DONTAUDIT 0x0400 +#define AVTAB_OPNUM (AVTAB_OPNUM_ALLOWED | \ + AVTAB_OPNUM_AUDITALLOW | \ + AVTAB_OPNUM_DONTAUDIT) +#define AVTAB_OPTYPE_ALLOWED 0x1000 +#define AVTAB_OPTYPE_AUDITALLOW 0x2000 +#define AVTAB_OPTYPE_DONTAUDIT 0x4000 +#define AVTAB_OPTYPE (AVTAB_OPTYPE_ALLOWED | \ + AVTAB_OPTYPE_AUDITALLOW | \ + AVTAB_OPTYPE_DONTAUDIT) +#define AVTAB_OP (AVTAB_OPNUM | AVTAB_OPTYPE) #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ u16 specified; /* what field is specified */ }; +struct avtab_operation { + u8 type; + struct operation_perm op; +}; + struct avtab_datum { - u32 data; /* access vector or type value */ + union { + u32 data; /* access vector or type value */ + struct avtab_operation *ops; /* ioctl operations */ + } u; }; struct avtab_node { diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c old mode 100755 new mode 100644 index 377d148e..16651c7a --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -15,6 +15,7 @@ #include "security.h" #include "conditional.h" +#include "services.h" /* * cond_evaluate_expr evaluates a conditional expr @@ -617,21 +618,39 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) return 0; } + +void cond_compute_operation(struct avtab *ctab, struct avtab_key *key, + struct operation_decision *od) +{ + struct avtab_node *node; + + if (!ctab || !key || !od) + return; + + for (node = avtab_search_node(ctab, key); node; + node = avtab_search_node_next(node, key->specified)) { + if (node->key.specified & AVTAB_ENABLED) + services_compute_operation_num(od, node); + } + return; + +} /* Determine whether additional permissions are granted by the conditional * av table, and if so, add them to the result */ -void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) +void cond_compute_av(struct avtab *ctab, struct avtab_key *key, + struct av_decision *avd, struct operation *ops) { struct avtab_node *node; - if (!ctab || !key || !avd) + if (!ctab || !key || !avd || !ops) return; for (node = avtab_search_node(ctab, key); node; node = avtab_search_node_next(node, key->specified)) { if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) - avd->allowed |= node->datum.data; + avd->allowed |= node->datum.u.data; if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) /* Since a '0' in an auditdeny mask represents a @@ -639,10 +658,13 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi * the '&' operand to ensure that all '0's in the mask * are retained (much unlike the allow and auditallow cases). */ - avd->auditdeny &= node->datum.data; + avd->auditdeny &= node->datum.u.data; if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) - avd->auditallow |= node->datum.data; + avd->auditallow |= node->datum.u.data; + if ((node->key.specified & AVTAB_ENABLED) && + (node->key.specified & AVTAB_OP)) + services_compute_operation_type(ops, node); } return; } diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h old mode 100755 new mode 100644 index 4d1f8746..80ee2bb2 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -73,8 +73,10 @@ int cond_read_list(struct policydb *p, void *fp); int cond_write_bool(void *key, void *datum, void *ptr); int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); -void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); - +void cond_compute_av(struct avtab *ctab, struct avtab_key *key, + struct av_decision *avd, struct operation *ops); +void cond_compute_operation(struct avtab *ctab, struct avtab_key *key, + struct operation_decision *od); int evaluate_cond_node(struct policydb *p, struct cond_node *node); #endif /* _CONDITIONAL_H_ */ diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h old mode 100755 new mode 100644 index 149dda73..96fd947c --- a/security/selinux/ss/constraint.h +++ b/security/selinux/ss/constraint.h @@ -48,6 +48,7 @@ struct constraint_expr { u32 op; /* operator */ struct ebitmap names; /* names */ + struct type_set *type_names; struct constraint_expr *next; /* next expression */ }; diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h old mode 100755 new mode 100644 index 45e8fb05..212e3479 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -74,6 +74,26 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) return rc; } +/* + * Sets both levels in the MLS range of 'dst' to the high level of 'src'. + */ +static inline int mls_context_cpy_high(struct context *dst, struct context *src) +{ + int rc; + + dst->range.level[0].sens = src->range.level[1].sens; + rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[1].cat); + if (rc) + goto out; + + dst->range.level[1].sens = src->range.level[1].sens; + rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat); + if (rc) + ebitmap_destroy(&dst->range.level[0].cat); +out: + return rc; +} + static inline int mls_context_cmp(struct context *c1, struct context *c2) { return ((c1->range.level[0].sens == c2->range.level[0].sens) && diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c old mode 100755 new mode 100644 diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h old mode 100755 new mode 100644 diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c old mode 100755 new mode 100644 diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h old mode 100755 new mode 100644 diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c old mode 100755 new mode 100644 index fbf9c581..40de8d3f --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -517,6 +517,8 @@ int mls_compute_sid(struct context *scontext, { struct range_trans rtr; struct mls_range *r; + struct class_datum *cladatum; + int default_range = 0; if (!policydb.mls_enabled) return 0; @@ -530,6 +532,28 @@ int mls_compute_sid(struct context *scontext, r = hashtab_search(policydb.range_tr, &rtr); if (r) return mls_range_set(newcontext, r); + + if (tclass && tclass <= policydb.p_classes.nprim) { + cladatum = policydb.class_val_to_struct[tclass - 1]; + if (cladatum) + default_range = cladatum->default_range; + } + + switch (default_range) { + case DEFAULT_SOURCE_LOW: + return mls_context_cpy_low(newcontext, scontext); + case DEFAULT_SOURCE_HIGH: + return mls_context_cpy_high(newcontext, scontext); + case DEFAULT_SOURCE_LOW_HIGH: + return mls_context_cpy(newcontext, scontext); + case DEFAULT_TARGET_LOW: + return mls_context_cpy_low(newcontext, tcontext); + case DEFAULT_TARGET_HIGH: + return mls_context_cpy_high(newcontext, tcontext); + case DEFAULT_TARGET_LOW_HIGH: + return mls_context_cpy(newcontext, tcontext); + } + /* Fallthrough */ case AVTAB_CHANGE: if ((tclass == policydb.process_class) || (sock == true)) diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h old mode 100755 new mode 100644 diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h old mode 100755 new mode 100644 diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c old mode 100755 new mode 100644 index 23e9cba8..a683475e --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -133,6 +133,26 @@ static struct policydb_compat_info policydb_compat[] = { .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, + { + .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, + { + .version = POLICYDB_VERSION_DEFAULT_TYPE, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, + { + .version = POLICYDB_VERSION_CONSTRAINT_NAMES, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, + { + .version = POLICYDB_VERSION_IOCTL_OPERATIONS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, }; static struct policydb_compat_info *policydb_lookup_compat(int version) @@ -603,6 +623,19 @@ static int common_destroy(void *key, void *datum, void *p) return 0; } +static void constraint_expr_destroy(struct constraint_expr *expr) +{ + if (expr) { + ebitmap_destroy(&expr->names); + if (expr->type_names) { + ebitmap_destroy(&expr->type_names->types); + ebitmap_destroy(&expr->type_names->negset); + kfree(expr->type_names); + } + kfree(expr); + } +} + static int cls_destroy(void *key, void *datum, void *p) { struct class_datum *cladatum; @@ -618,10 +651,9 @@ static int cls_destroy(void *key, void *datum, void *p) while (constraint) { e = constraint->expr; while (e) { - ebitmap_destroy(&e->names); etmp = e; e = e->next; - kfree(etmp); + constraint_expr_destroy(etmp); } ctemp = constraint; constraint = constraint->next; @@ -632,16 +664,14 @@ static int cls_destroy(void *key, void *datum, void *p) while (constraint) { e = constraint->expr; while (e) { - ebitmap_destroy(&e->names); etmp = e; e = e->next; - kfree(etmp); + constraint_expr_destroy(etmp); } ctemp = constraint; constraint = constraint->next; kfree(ctemp); } - kfree(cladatum->comkey); } kfree(datum); @@ -1146,8 +1176,34 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) return rc; } -static int read_cons_helper(struct constraint_node **nodep, int ncons, - int allowxtarget, void *fp) +static void type_set_init(struct type_set *t) +{ + ebitmap_init(&t->types); + ebitmap_init(&t->negset); +} + +static int type_set_read(struct type_set *t, void *fp) +{ + __le32 buf[1]; + int rc; + + if (ebitmap_read(&t->types, fp)) + return -EINVAL; + if (ebitmap_read(&t->negset, fp)) + return -EINVAL; + + rc = next_entry(buf, fp, sizeof(u32)); + if (rc < 0) + return -EINVAL; + t->flags = le32_to_cpu(buf[0]); + + return 0; +} + + +static int read_cons_helper(struct policydb *p, + struct constraint_node **nodep, + int ncons, int allowxtarget, void *fp) { struct constraint_node *c, *lc; struct constraint_expr *e, *le; @@ -1215,6 +1271,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, rc = ebitmap_read(&e->names, fp); if (rc) return rc; + if (p->policyvers >= + POLICYDB_VERSION_CONSTRAINT_NAMES) { + e->type_names = kzalloc(sizeof + (*e->type_names), + GFP_KERNEL); + if (!e->type_names) + return -ENOMEM; + type_set_init(e->type_names); + rc = type_set_read(e->type_names, fp); + if (rc) + return rc; + } break; default: return -EINVAL; @@ -1291,7 +1359,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) goto bad; } - rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); + rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp); if (rc) goto bad; @@ -1301,9 +1369,27 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) if (rc) goto bad; ncons = le32_to_cpu(buf[0]); - rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); + rc = read_cons_helper(p, &cladatum->validatetrans, + ncons, 1, fp); + if (rc) + goto bad; + } + + if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { + rc = next_entry(buf, fp, sizeof(u32) * 3); + if (rc) + goto bad; + + cladatum->default_user = le32_to_cpu(buf[0]); + cladatum->default_role = le32_to_cpu(buf[1]); + cladatum->default_range = le32_to_cpu(buf[2]); + } + + if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { + rc = next_entry(buf, fp, sizeof(u32) * 1); if (rc) goto bad; + cladatum->default_type = le32_to_cpu(buf[0]); } rc = hashtab_insert(h, key, cladatum); @@ -2735,6 +2821,24 @@ static int common_write(void *vkey, void *datum, void *ptr) return 0; } +static int type_set_write(struct type_set *t, void *fp) +{ + int rc; + __le32 buf[1]; + + if (ebitmap_write(&t->types, fp)) + return -EINVAL; + if (ebitmap_write(&t->negset, fp)) + return -EINVAL; + + buf[0] = cpu_to_le32(t->flags); + rc = put_entry(buf, sizeof(u32), 1, fp); + if (rc) + return -EINVAL; + + return 0; +} + static int write_cons_helper(struct policydb *p, struct constraint_node *node, void *fp) { @@ -2766,6 +2870,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node, rc = ebitmap_write(&e->names, fp); if (rc) return rc; + if (p->policyvers >= + POLICYDB_VERSION_CONSTRAINT_NAMES) { + rc = type_set_write(e->type_names, fp); + if (rc) + return rc; + } break; default: break; @@ -2844,6 +2954,23 @@ static int class_write(void *vkey, void *datum, void *ptr) if (rc) return rc; + if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { + buf[0] = cpu_to_le32(cladatum->default_user); + buf[1] = cpu_to_le32(cladatum->default_role); + buf[2] = cpu_to_le32(cladatum->default_range); + + rc = put_entry(buf, sizeof(uint32_t), 3, fp); + if (rc) + return rc; + } + + if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { + buf[0] = cpu_to_le32(cladatum->default_type); + rc = put_entry(buf, sizeof(uint32_t), 1, fp); + if (rc) + return rc; + } + return 0; } diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h old mode 100755 new mode 100644 index b846c038..725d5945 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -60,6 +60,20 @@ struct class_datum { struct symtab permissions; /* class-specific permission symbol table */ struct constraint_node *constraints; /* constraints on class permissions */ struct constraint_node *validatetrans; /* special transition rules */ +/* Options how a new object user, role, and type should be decided */ +#define DEFAULT_SOURCE 1 +#define DEFAULT_TARGET 2 + char default_user; + char default_role; + char default_type; +/* Options how a new object range should be decided */ +#define DEFAULT_SOURCE_LOW 1 +#define DEFAULT_SOURCE_HIGH 2 +#define DEFAULT_SOURCE_LOW_HIGH 3 +#define DEFAULT_TARGET_LOW 4 +#define DEFAULT_TARGET_HIGH 5 +#define DEFAULT_TARGET_LOW_HIGH 6 + char default_range; }; /* Role attributes */ @@ -139,6 +153,17 @@ struct cond_bool_datum { struct cond_node; +/* + * type set preserves data needed to determine constraint info from + * policy source. This is not used by the kernel policy but allows + * utilities such as audit2allow to determine constraint denials. + */ +struct type_set { + struct ebitmap types; + struct ebitmap negset; + u32 flags; +}; + /* * The configuration data includes security contexts for * initial SIDs, unlabeled file systems, TCP and UDP port numbers, diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c old mode 100755 new mode 100644 index 72b20b10..e8b9b9fc --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -92,9 +92,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len); static void context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - struct av_decision *avd); + struct context *tcontext, + u16 tclass, + struct av_decision *avd, + struct operation *ops); struct selinux_mapping { u16 value; /* policy value */ @@ -564,7 +565,8 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, tcontext, tclass, - &lo_avd); + &lo_avd, + NULL); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; @@ -579,7 +581,8 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(scontext, &lo_tcontext, tclass, - &lo_avd); + &lo_avd, + NULL); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; @@ -595,7 +598,8 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, &lo_tcontext, tclass, - &lo_avd); + &lo_avd, + NULL); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; @@ -611,14 +615,39 @@ static void type_attribute_bounds_av(struct context *scontext, } } +/* flag ioctl types that have operation permissions */ +void services_compute_operation_type( + struct operation *ops, + struct avtab_node *node) +{ + u8 type; + unsigned int i; + + if (node->key.specified & AVTAB_OPTYPE) { + /* if allowing one or more complete types */ + for (i = 0; i < ARRAY_SIZE(ops->type); i++) + ops->type[i] |= node->datum.u.ops->op.perms[i]; + } else { + /* if allowing operations within a type */ + type = node->datum.u.ops->type; + security_operation_set(ops->type, type); + } + + /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ + if (node->key.specified & AVTAB_OPTYPE_ALLOWED || + node->key.specified & AVTAB_OPNUM_ALLOWED) + ops->len = 1; +} + /* - * Compute access vectors based on a context structure pair for - * the permissions in a particular class. + * Compute access vectors and operations ranges based on a context + * structure pair for the permissions in a particular class. */ static void context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - struct av_decision *avd) + struct context *tcontext, + u16 tclass, + struct av_decision *avd, + struct operation *ops) { struct constraint_node *constraint; struct role_allow *ra; @@ -632,6 +661,10 @@ static void context_struct_compute_av(struct context *scontext, avd->allowed = 0; avd->auditallow = 0; avd->auditdeny = 0xffffffff; + if (ops) { + memset(&ops->type, 0, sizeof(ops->type)); + ops->len = 0; + } if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { if (printk_ratelimit()) @@ -646,7 +679,7 @@ static void context_struct_compute_av(struct context *scontext, * this permission check, then use it. */ avkey.target_class = tclass; - avkey.specified = AVTAB_AV; + avkey.specified = AVTAB_AV | AVTAB_OP; sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); BUG_ON(!sattr); tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); @@ -659,15 +692,17 @@ static void context_struct_compute_av(struct context *scontext, node; node = avtab_search_node_next(node, avkey.specified)) { if (node->key.specified == AVTAB_ALLOWED) - avd->allowed |= node->datum.data; + avd->allowed |= node->datum.u.data; else if (node->key.specified == AVTAB_AUDITALLOW) - avd->auditallow |= node->datum.data; + avd->auditallow |= node->datum.u.data; else if (node->key.specified == AVTAB_AUDITDENY) - avd->auditdeny &= node->datum.data; + avd->auditdeny &= node->datum.u.data; + else if (ops && (node->key.specified & AVTAB_OP)) + services_compute_operation_type(ops, node); } /* Check conditional av table for additional permissions */ - cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); + cond_compute_av(&policydb.te_cond_avtab, &avkey, avd, ops); } } @@ -898,13 +933,139 @@ static void avd_init(struct av_decision *avd) avd->flags = 0; } +void services_compute_operation_num(struct operation_decision *od, + struct avtab_node *node) +{ + unsigned int i; + + if (node->key.specified & AVTAB_OPNUM) { + if (od->type != node->datum.u.ops->type) + return; + } else { + if (!security_operation_test(node->datum.u.ops->op.perms, + od->type)) + return; + } + + if (node->key.specified == AVTAB_OPTYPE_ALLOWED) { + od->specified |= OPERATION_ALLOWED; + memset(od->allowed->perms, 0xff, + sizeof(od->allowed->perms)); + } else if (node->key.specified == AVTAB_OPTYPE_AUDITALLOW) { + od->specified |= OPERATION_AUDITALLOW; + memset(od->auditallow->perms, 0xff, + sizeof(od->auditallow->perms)); + } else if (node->key.specified == AVTAB_OPTYPE_DONTAUDIT) { + od->specified |= OPERATION_DONTAUDIT; + memset(od->dontaudit->perms, 0xff, + sizeof(od->dontaudit->perms)); + } else if (node->key.specified == AVTAB_OPNUM_ALLOWED) { + od->specified |= OPERATION_ALLOWED; + for (i = 0; i < ARRAY_SIZE(od->allowed->perms); i++) + od->allowed->perms[i] |= + node->datum.u.ops->op.perms[i]; + } else if (node->key.specified == AVTAB_OPNUM_AUDITALLOW) { + od->specified |= OPERATION_AUDITALLOW; + for (i = 0; i < ARRAY_SIZE(od->auditallow->perms); i++) + od->auditallow->perms[i] |= + node->datum.u.ops->op.perms[i]; + } else if (node->key.specified == AVTAB_OPNUM_DONTAUDIT) { + od->specified |= OPERATION_DONTAUDIT; + for (i = 0; i < ARRAY_SIZE(od->dontaudit->perms); i++) + od->dontaudit->perms[i] |= + node->datum.u.ops->op.perms[i]; + } else { + BUG(); + } +} + +void security_compute_operation(u32 ssid, + u32 tsid, + u16 orig_tclass, + u8 type, + struct operation_decision *od) +{ + u16 tclass; + struct context *scontext, *tcontext; + struct avtab_key avkey; + struct avtab_node *node; + struct ebitmap *sattr, *tattr; + struct ebitmap_node *snode, *tnode; + unsigned int i, j; + + od->type = type; + od->specified = 0; + memset(od->allowed->perms, 0, sizeof(od->allowed->perms)); + memset(od->auditallow->perms, 0, sizeof(od->auditallow->perms)); + memset(od->dontaudit->perms, 0, sizeof(od->dontaudit->perms)); + + read_lock(&policy_rwlock); + if (!ss_initialized) + goto allow; + + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; + } + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + + tclass = unmap_class(orig_tclass); + if (unlikely(orig_tclass && !tclass)) { + if (policydb.allow_unknown) + goto allow; + goto out; + } + + + if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { + if (printk_ratelimit()) + printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); + goto out; + } + + avkey.target_class = tclass; + avkey.specified = AVTAB_OP; + sattr = flex_array_get(policydb.type_attr_map_array, + scontext->type - 1); + BUG_ON(!sattr); + tattr = flex_array_get(policydb.type_attr_map_array, + tcontext->type - 1); + BUG_ON(!tattr); + ebitmap_for_each_positive_bit(sattr, snode, i) { + ebitmap_for_each_positive_bit(tattr, tnode, j) { + avkey.source_type = i + 1; + avkey.target_type = j + 1; + for (node = avtab_search_node(&policydb.te_avtab, &avkey); + node; + node = avtab_search_node_next(node, avkey.specified)) + services_compute_operation_num(od, node); + cond_compute_operation(&policydb.te_cond_avtab, + &avkey, od); + } + } +out: + read_unlock(&policy_rwlock); + return; +allow: + memset(od->allowed->perms, 0xff, sizeof(od->allowed->perms)); + goto out; +} /** * security_compute_av - Compute access vector decisions. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @avd: access vector decisions + * @od: operation decisions * * Compute a set of access vector decisions based on the * SID pair (@ssid, @tsid) for the permissions in @tclass. @@ -912,13 +1073,15 @@ static void avd_init(struct av_decision *avd) void security_compute_av(u32 ssid, u32 tsid, u16 orig_tclass, - struct av_decision *avd) + struct av_decision *avd, + struct operation *ops) { u16 tclass; struct context *scontext = NULL, *tcontext = NULL; read_lock(&policy_rwlock); avd_init(avd); + ops->len = 0; if (!ss_initialized) goto allow; @@ -946,7 +1109,7 @@ void security_compute_av(u32 ssid, goto allow; goto out; } - context_struct_compute_av(scontext, tcontext, tclass, avd); + context_struct_compute_av(scontext, tcontext, tclass, avd, ops); map_decision(orig_tclass, avd, policydb.allow_unknown); out: read_unlock(&policy_rwlock); @@ -992,7 +1155,7 @@ void security_compute_av_user(u32 ssid, goto out; } - context_struct_compute_av(scontext, tcontext, tclass, avd); + context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); out: read_unlock(&policy_rwlock); return; @@ -1229,10 +1392,6 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, struct context context; int rc = 0; - /* An empty security context is never valid. */ - if (!scontext_len) - return -EINVAL; - if (!ss_initialized) { int i; @@ -1393,6 +1552,7 @@ static int security_compute_sid(u32 ssid, u32 *out_sid, bool kern) { + struct class_datum *cladatum = NULL; struct context *scontext = NULL, *tcontext = NULL, newcontext; struct role_trans *roletr = NULL; struct avtab_key avkey; @@ -1441,12 +1601,20 @@ static int security_compute_sid(u32 ssid, goto out_unlock; } + if (tclass && tclass <= policydb.p_classes.nprim) + cladatum = policydb.class_val_to_struct[tclass - 1]; + /* Set the user identity. */ switch (specified) { case AVTAB_TRANSITION: case AVTAB_CHANGE: - /* Use the process user identity. */ - newcontext.user = scontext->user; + if (cladatum && cladatum->default_user == DEFAULT_TARGET) { + newcontext.user = tcontext->user; + } else { + /* notice this gets both DEFAULT_SOURCE and unset */ + /* Use the process user identity. */ + newcontext.user = scontext->user; + } break; case AVTAB_MEMBER: /* Use the related object owner. */ @@ -1454,16 +1622,31 @@ static int security_compute_sid(u32 ssid, break; } - /* Set the role and type to default values. */ - if ((tclass == policydb.process_class) || (sock == true)) { - /* Use the current role and type of process. */ + /* Set the role to default values. */ + if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { newcontext.role = scontext->role; - newcontext.type = scontext->type; + } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { + newcontext.role = tcontext->role; } else { - /* Use the well-defined object role. */ - newcontext.role = OBJECT_R_VAL; - /* Use the type of the related object. */ + if ((tclass == policydb.process_class) || (sock == true)) + newcontext.role = scontext->role; + else + newcontext.role = OBJECT_R_VAL; + } + + /* Set the type to default values. */ + if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { + newcontext.type = scontext->type; + } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { newcontext.type = tcontext->type; + } else { + if ((tclass == policydb.process_class) || (sock == true)) { + /* Use the type of process. */ + newcontext.type = scontext->type; + } else { + /* Use the type of the related object. */ + newcontext.type = tcontext->type; + } } /* Look for a type transition/member/change rule. */ @@ -1486,7 +1669,7 @@ static int security_compute_sid(u32 ssid, if (avdatum) { /* Use the type from the type transition/member/change rule. */ - newcontext.type = avdatum->data; + newcontext.type = avdatum->u.data; } /* if we have a objname this is a file trans check so check those rules */ diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h old mode 100755 new mode 100644 index e8d907e9..56975748 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h @@ -11,5 +11,11 @@ extern struct policydb policydb; +void services_compute_operation_type(struct operation *ops, + struct avtab_node *node); + +void services_compute_operation_num(struct operation_decision *od, + struct avtab_node *node); + #endif /* _SS_SERVICES_H_ */ diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c old mode 100755 new mode 100644 diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h old mode 100755 new mode 100644 diff --git a/security/selinux/ss/status.c b/security/selinux/ss/status.c old mode 100755 new mode 100644 diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c old mode 100755 new mode 100644 diff --git a/security/selinux/ss/symtab.h b/security/selinux/ss/symtab.h old mode 100755 new mode 100644 diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c old mode 100755 new mode 100644 diff --git a/security/smack/Kconfig b/security/smack/Kconfig old mode 100755 new mode 100644 diff --git a/security/smack/Makefile b/security/smack/Makefile old mode 100755 new mode 100644 diff --git a/security/smack/smack.h b/security/smack/smack.h old mode 100755 new mode 100644 diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c old mode 100755 new mode 100644 diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c old mode 100755 new mode 100644 index 82df24d1..401b5847 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -404,8 +404,8 @@ static int smack_sb_statfs(struct dentry *dentry) * Returns 0 if current can write the floor of the filesystem * being mounted on, an error code otherwise. */ -static int smack_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, void *data) +static int smack_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { struct superblock_smack *sbp = path->dentry->d_sb->s_security; struct smk_audit_info ad; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/.gitignore b/security/tomoyo/.gitignore old mode 100755 new mode 100644 diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig old mode 100755 new mode 100644 diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile old mode 100755 new mode 100644 diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h old mode 100755 new mode 100644 index 30fd9836..997aa5bf --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -971,7 +971,7 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, const u8 index); int tomoyo_mkdev_perm(const u8 operation, struct path *path, const unsigned int mode, unsigned int dev); -int tomoyo_mount_permission(char *dev_name, struct path *path, +int tomoyo_mount_permission(const char *dev_name, struct path *path, const char *type, unsigned long flags, void *data_page); int tomoyo_open_control(const u8 type, struct file *file); diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/environ.c b/security/tomoyo/environ.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c old mode 100755 new mode 100644 index fe00cdfd..390c6460 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -71,7 +71,8 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, +static int tomoyo_mount_acl(struct tomoyo_request_info *r, + const char *dev_name, struct path *dir, const char *type, unsigned long flags) { @@ -183,7 +184,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, * * Returns 0 on success, negative value otherwise. */ -int tomoyo_mount_permission(char *dev_name, struct path *path, +int tomoyo_mount_permission(const char *dev_name, struct path *path, const char *type, unsigned long flags, void *data_page) { diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c old mode 100755 new mode 100644 diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c old mode 100755 new mode 100644 index 620d37c1..43d3f97a --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -406,8 +406,8 @@ static int tomoyo_path_chroot(struct path *path) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_sb_mount(char *dev_name, struct path *path, - char *type, unsigned long flags, void *data) +static int tomoyo_sb_mount(const char *dev_name, struct path *path, + const char *type, unsigned long flags, void *data) { return tomoyo_mount_permission(dev_name, path, type, flags, data); } diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c old mode 100755 new mode 100644 diff --git a/security/yama/Kconfig b/security/yama/Kconfig old mode 100755 new mode 100644 diff --git a/security/yama/Makefile b/security/yama/Makefile old mode 100755 new mode 100644 diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c old mode 100755 new mode 100644 diff --git a/weritos_defconfig b/weritos_defconfig new file mode 100644 index 00000000..998599a8 --- /dev/null +++ b/weritos_defconfig @@ -0,0 +1,3484 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.4.110 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_LOCKBREAK=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_IO_H=y +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_PHYS_OFFSET=0x00200000 +CONFIG_GENERIC_BUG=y +# CONFIG_ARCH_RANDOM is not set +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-WERITOS-MM" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_MEM_RES_CTLR=y +# CONFIG_CGROUP_MEM_RES_CTLR_SWAP is not set +# CONFIG_CGROUP_MEM_RES_CTLR_KMEM is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_MM_OWNER=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +# CONFIG_OPTIMIZE_INLINING is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_PERF_COUNTERS is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_LOAD_ATH6KL is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_BFQ=y +# CONFIG_CGROUP_BFQIO is not set +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_FIOPS=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_ROW=y +CONFIG_IOSCHED_SIO=y +CONFIG_IOSCHED_SIOPLUS=y +CONFIG_IOSCHED_TEST=m +CONFIG_IOSCHED_VR=y +CONFIG_IOSCHED_ZEN=y +# CONFIG_DEFAULT_BFQ is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_FIOPS is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_ROW=y +# CONFIG_DEFAULT_SIO is not set +# CONFIG_DEFAULT_SIOPLUS is not set +# CONFIG_DEFAULT_VR is not set +# CONFIG_DEFAULT_ZEN is not set +CONFIG_DEFAULT_IOSCHED="row" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_UNINLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +CONFIG_ARCH_MSM=y +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_GPIO_PCA953X is not set + +# +# MSM SoC Type +# +# CONFIG_ARCH_MSM7X01A is not set +# CONFIG_ARCH_MSM7X25 is not set +CONFIG_ARCH_MSM7X27=y +# CONFIG_ARCH_MSM7X30 is not set +# CONFIG_ARCH_QSD8X50 is not set +# CONFIG_ARCH_MSM8X60 is not set +# CONFIG_ARCH_MSM8960 is not set +# CONFIG_ARCH_MSM8930 is not set +# CONFIG_ARCH_APQ8064 is not set +# CONFIG_ARCH_MSM8974 is not set +# CONFIG_ARCH_FSM9XXX is not set +# CONFIG_ARCH_MSM9615 is not set +CONFIG_ARCH_MSM8625=y +# CONFIG_ARCH_MSM9625 is not set +# CONFIG_ARCH_MSM8910 is not set +# CONFIG_MSM_SOC_REV_NONE is not set +CONFIG_MSM_SOC_REV_A=y +CONFIG_MSM_SMP=y +CONFIG_ARCH_MSM_CORTEXMP=y +CONFIG_ARCH_MSM_CORTEX_A5=y +CONFIG_ARCH_MSM7X27A=y +CONFIG_MSM_VIC=y +# CONFIG_MSM_RPM is not set +# CONFIG_MSM_RPM_SMD is not set +# CONFIG_MSM_MPM is not set + +# +# MSM Board Selection +# +# CONFIG_MACH_MSM7X27_SURF is not set +# CONFIG_MACH_MSM7X27_FFA is not set +CONFIG_MACH_MSM7X27A_RUMI3=y +CONFIG_MACH_MSM7X27A_SURF=y +CONFIG_MACH_MSM7X27A_FFA=y +CONFIG_WERITOS_KERNEL=y +CONFIG_MACH_MSM7625A_SURF=y +CONFIG_MACH_MSM7625A_FFA=y +CONFIG_MACH_MSM7627A_QRD1=y +CONFIG_MACH_MSM7627A_QRD3=y +CONFIG_MACH_MSM7627A_EVB=y +CONFIG_MACH_MSM8625_RUMI3=y +CONFIG_MACH_MSM8625_SURF=y +CONFIG_MACH_MSM8625_FFA=y +CONFIG_MACH_MSM8625_EVB=y +CONFIG_MACH_MSM7X27A_QRD5A=y +CONFIG_MACH_MSM8625_QRD7=y +CONFIG_MACH_MSM8625_QRD5=y +CONFIG_MACH_MSM8625Q_EVBD=y +CONFIG_MACH_MSM8625Q_SKUD=y +CONFIG_MACH_MSM8625Q_SKUE=y +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_MSM_AMSS_VERSION=6225 +# CONFIG_MSM_AMSS_VERSION_6210 is not set +# CONFIG_MSM_AMSS_VERSION_6220 is not set +CONFIG_MSM_AMSS_VERSION_6225=y +# CONFIG_MSM7X00A_USE_GP_TIMER is not set +CONFIG_MSM7X00A_USE_DG_TIMER=y +CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y +# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set +# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_SLEEP_MODE=0 +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE=y +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set +# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set +CONFIG_MSM7X00A_IDLE_SLEEP_MODE=1 +CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000 +CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000 +CONFIG_MSM_IDLE_STATS=y +CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500 +CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2 +CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10 +CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET=1000000000 +CONFIG_CPU_HAS_L2_PMU=y +# CONFIG_HTC_HEADSET is not set +# CONFIG_HTC_PWRSINK is not set +CONFIG_MSM_FIQ_SUPPORT=y +# CONFIG_MSM_SERIAL_DEBUGGER is not set +CONFIG_MSM_PROC_COMM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_AMSS_ENHANCE_DEBUG=y +# CONFIG_MSM_SMD_PKG3 is not set +CONFIG_MSM_SMD_PKG4=y +CONFIG_MSM_FUSE_INFO_DEBUG=y +# CONFIG_MSM_SMD_DEBUG is not set +CONFIG_MSM_FAST_BOOT=y +CONFIG_MSM_N_WAY_SMD=y +CONFIG_MSM_N_WAY_SMSM=y +# CONFIG_MSM_RESET_MODEM is not set +CONFIG_MSM_SMD_LOGGING=y +# CONFIG_MSM_IPC_LOGGING is not set +# CONFIG_MSM_SMD_NMEA is not set +CONFIG_MSM_SMD_TTY=y +# CONFIG_MSM_SMD_QMI is not set +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ONCRPCROUTER=y +CONFIG_MSM_IPC_ROUTER=y +# CONFIG_MSM_IPC_ROUTER_SMD_XPRT is not set +CONFIG_MSM_ONCRPCROUTER_DEBUG=y +# CONFIG_MSM_RPC_LOOPBACK_XPRT is not set +# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set +CONFIG_MSM_RPCSERVER_WATCHDOG=y +# CONFIG_MSM_RPC_WATCHDOG is not set +CONFIG_MSM_RPC_PING=y +CONFIG_MSM_RPC_PROC_COMM_TEST=y +CONFIG_MSM_RPC_OEM_RAPI=y +CONFIG_MSM_RPCSERVER_HANDSET=y +CONFIG_MSM_RMT_STORAGE_CLIENT=y +# CONFIG_MSM_RMT_STORAGE_CLIENT_STATS is not set +CONFIG_MSM_DALRPC=y +CONFIG_MSM_DALRPC_TEST=m +# CONFIG_MSM_CPU_FREQ_SET_MIN_MAX is not set +# CONFIG_MSM_AVS_HW is not set +# CONFIG_MSM_HW3D is not set +CONFIG_MSM_ADSP=y +CONFIG_ADSP_RPC_VER=0x30002 +CONFIG_AMSS_7X25_VERSION_2009=y +# CONFIG_AMSS_7X25_VERSION_2008 is not set +CONFIG_MSM_ADSP_REPORT_EVENTS=y +CONFIG_RTAC=y +CONFIG_MSM7X27A_AUDIO=y +CONFIG_MSM_PROC_COMM_REGULATOR=y +# CONFIG_MSM_VREG_SWITCH_INVERTED is not set +CONFIG_MSM_DMA_TEST=y +# CONFIG_WIFI_CONTROL_FUNC is not set +CONFIG_AUDIO_AAC_PLUS=y +CONFIG_AUDIO_ENHANCED_AAC_PLUS=y +CONFIG_SURF_FFA_GPIO_KEYPAD=y +CONFIG_MSM_SLEEP_TIME_OVERRIDE=y +# CONFIG_MSM_MEMORY_LOW_POWER_MODE is not set +CONFIG_MSM_PM_TIMEOUT_HALT=y +# CONFIG_MSM_PM_TIMEOUT_RESET_MODEM is not set +# CONFIG_MSM_PM_TIMEOUT_RESET_CHIP is not set +CONFIG_MSM_IDLE_WAIT_ON_MODEM=0 +# CONFIG_MSM_PIL is not set +# CONFIG_MSM_SCM is not set +# CONFIG_MSM_TZ_LOG is not set +# CONFIG_MSM_DIRECT_SCLK_ACCESS is not set +CONFIG_MSM_GPIOMUX=y +CONFIG_MSM_MODEM_RESTART=y +CONFIG_MSM_PM2=y +CONFIG_MSM_EVENT_TIMER=y +# CONFIG_MSM_BUS_SCALING is not set +# CONFIG_MSM_WATCHDOG_V2 is not set +# CONFIG_MSM_JTAG is not set +CONFIG_MSM_SLEEP_STATS_DEVICE=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SM_EVENT=y +CONFIG_MSM_SM_EVENT_LOG=m +CONFIG_UNCACHED_BUF=y +CONFIG_MSM_SLEEP_MONITOR=m +# CONFIG_MSM_STANDALONE_POWER_COLLAPSE is not set +# CONFIG_MSM_GSBI9_UART is not set +CONFIG_MSM_SHOW_RESUME_IRQ=y +CONFIG_BT_MSM_PINTEST=y +# CONFIG_MSM_FAKE_BATTERY is not set +# CONFIG_MSM_QDSP6_APR is not set +# CONFIG_MSM_QDSP6_CODECS is not set +# CONFIG_MSM_QDSP6V2_CODECS is not set +# CONFIG_MSM_AUDIO_QDSP6 is not set +# CONFIG_MSM_AUDIO_QDSP6V2 is not set +CONFIG_MSM_RPC_VIBRATOR=y +CONFIG_PM8XXX_RPC_VIBRATOR=y +# CONFIG_MSM_SPM_V1 is not set +CONFIG_MSM_SPM_V2=y +# CONFIG_MSM_L2_SPM is not set +CONFIG_MSM_MULTIMEDIA_USE_ION=y +# CONFIG_MSM_OCMEM is not set +# CONFIG_MSM_RTB is not set +# CONFIG_MSM_EBI_ERP is not set +CONFIG_MSM_CPR=y +CONFIG_MSM_VP_REGULATOR=y +# CONFIG_MSM_CACHE_DUMP is not set +# CONFIG_MSM_HSIC_SYSMON is not set +# CONFIG_MSM_8X60_FUSION_GPIO_GLITCH is not set +CONFIG_MSM_FIQ=y +CONFIG_MSM_PBUS=y +CONFIG_HAS_MACH_MEMUTILS=y +# CONFIG_MSM_OVERCLOCK_GPU is not set +# CONFIG_INTELLI_PLUG is not set +# CONFIG_BRICKED_HOTPLUG is not set + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +# CONFIG_CACHE_PL310_ERP is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARCH_HAS_BARRIERS=y +# CONFIG_VCM is not set +# CONFIG_STRICT_MEMORY_RWX is not set +CONFIG_ARM_NR_BANKS=8 +# CONFIG_RESERVE_FIRST_PAGE is not set +CONFIG_CPU_HAS_PMU=y +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set +CONFIG_ARM_GIC=y +CONFIG_GIC_SECURE=y +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_ARM_ARCH_TIMER is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=300 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_VMALLOC_RESERVE=0xC800000 +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=999999 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CLEANCACHE=y +# CONFIG_DYNAMIC_PAGE_WRITEBACK is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_USE_USER_ACCESSIBLE_TIMERS is not set +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set +# CONFIG_ARCH_MEMORY_PROBE is not set +# CONFIG_ARCH_MEMORY_REMOVE is not set +# CONFIG_ARCH_POPULATES_NODE_MAP is not set +# CONFIG_ENABLE_DMM is not set +# CONFIG_FIX_MOVABLE_ZONE is not set +CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0=y +# CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG is not set +# CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set +CONFIG_CP_ACCESS=y + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASSH3 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIACTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIMM is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_STOCKDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_YANKDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTELLIDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_LIONHEART is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_HYPER is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMANDX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVEX is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SMARTASS2=y +# CONFIG_CPU_FREQ_GOV_SMARTASSH3 is not set +# CONFIG_CPU_FREQ_GOV_INTELLIACTIVE is not set +# CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set +# CONFIG_CPU_FREQ_GOV_INTELLIMM is not set +# CONFIG_CPU_FREQ_GOV_STOCKDEMAND is not set +# CONFIG_CPU_FREQ_GOV_YANKDEMAND is not set +# CONFIG_CPU_FREQ_GOV_INTELLIDEMAND is not set +CONFIG_CPU_FREQ_GOV_LIONHEART=y +# CONFIG_CPU_FREQ_GOV_HYPER is not set +# CONFIG_CPU_FREQ_GOV_ONDEMANDX is not set +# CONFIG_CPU_FREQ_GOV_INTERACTIVEX is not set +CONFIG_CPU_FREQ_GOV_ALUCARD=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_CPU_IDLE is not set +CONFIG_CPU_FREQ_MSM=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_RUNTIME=y +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_CAN_PM_TRACE=y +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=y +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +CONFIG_TCP_CONG_VEGAS=y +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +CONFIG_TCP_CONG_VENO=y +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_VENO is not set +CONFIG_DEFAULT_WESTWOOD=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="westwood" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_REJECT_SKERR is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_NF_NAT_SIP=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +# CONFIG_IP6_NF_TARGET_REJECT_SKERR is not set +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_IP6_NF_SECURITY=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +CONFIG_HAVE_BPF_JIT=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCISMD is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_IBS=y +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +CONFIG_BT_MSM_SLEEP=y +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_MSM_BT_POWER=y +CONFIG_HUAWEI_BT_WCN2243=y +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +# CONFIG_WIRELESS_EXT_SYSFS is not set +# CONFIG_LIB80211 is not set +# CONFIG_CFG80211_ALLOW_RECONNECT is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_GENLOCK=y +CONFIG_GENLOCK_MISCDEVICE=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +CONFIG_SW_SYNC_USER=y +# CONFIG_CMA is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +CONFIG_ANDROID_PMEM=y +# CONFIG_ATMEL_PWM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +CONFIG_APANIC_MMC=y +CONFIG_APANIC_PLABEL="kpanic" +# CONFIG_TSIF is not set +CONFIG_GLANCEVIEW=y +# CONFIG_TSPP is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_QSEECOM is not set +# CONFIG_QFP_FUSE is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_TGT=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set + +# +# CAIF transport drivers +# +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851_MLL is not set +CONFIG_MSM_RMNET=y +# CONFIG_MSM_RMNET_DEBUG is not set +# CONFIG_QFEC is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +# CONFIG_SEEQ8005 is not set +CONFIG_NET_VENDOR_SMSC=y +CONFIG_SMC91X=y +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_MSM_RMNET_USB is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +CONFIG_LIBRA_SDIOIF=m +# CONFIG_ATH6K_LEGACY_EXT is not set +CONFIG_ATH_COMMON=m +# CONFIG_ATH_DEBUG is not set +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +# CONFIG_WIFI_MAC_FROM_NV is not set +# CONFIG_ATH6KL_USB is not set +# CONFIG_ATH6KL_DEBUG is not set +# CONFIG_ATH6KL_REGDOMAIN is not set +# CONFIG_BCMDHD is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_KEYRESET=y + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +# CONFIG_TOUCHDISC_VTD518_SHINETSU is not set +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_TABLET_USB_WACOM=y +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_FOCAL is not set +# CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y +CONFIG_SYNA_MULTI_TOUCH=y +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_MSM_LEGACY is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_CY8C_TS is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC is not set +# CONFIG_TOUCHSCREEN_FT5X06 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +CONFIG_TOUCHSCREEN_FT6306=y +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_ISA1200_FF_MEMLESS is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_BOSCH_BMA150 is not set +# CONFIG_INPUT_LTR502 is not set +# CONFIG_INPUT_LTR558 is not set +# CONFIG_BOSCH_BMA250 is not set +# CONFIG_AVAGO_APDS990X is not set +# CONFIG_INPUT_ISL29028 is not set +# CONFIG_INPUT_LIS3DH is not set +# CONFIG_SENSORS_TMD2771X is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_N_SMUX is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set +# CONFIG_SERIAL_MSM_HSL is not set +# CONFIG_SERIAL_BCM_BT_LPM is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_MSM_SMD is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set + +# +# Diag Support +# +CONFIG_DIAG_CHAR=y + +# +# DIAG traffic over USB +# +CONFIG_DIAG_OVER_USB=y + +# +# SDIO support for DIAG +# + +# +# HSIC support for DIAG +# +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +# CONFIG_MMC_GENERIC_CSDIO is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_MSM is not set +CONFIG_I2C_QUP=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_SLIMBUS is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +CONFIG_GPIO_MSM_V1=y +# CONFIG_GPIO_MSM_V2 is not set +# CONFIG_GPIO_MSM_V3 is not set +# CONFIG_GPIO_FSM9XXX is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_SX150X=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_GPIO_PM8XXX_RPC is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +CONFIG_BATTERY_MSM=y +# CONFIG_BATTERY_MSM_DEBUG is not set +# CONFIG_BATTERY_MSM8X60 is not set +# CONFIG_SMB137B_CHARGER is not set +# CONFIG_SMB349_CHARGER is not set +# CONFIG_BATTERY_EARLYSUSPEND is not set +# CONFIG_BATTERY_MSM_FAKE is not set +# CONFIG_BATTERY_BQ27520 is not set +# CONFIG_BATTERY_BQ27541 is not set +# CONFIG_LTC4088_CHARGER is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_FORCE_FAST_CHARGE is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +CONFIG_SENSORS_MSM_ADC=y +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_LTR559=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +CONFIG_MARIMBA_CORE=y +# CONFIG_MARIMBA_CODEC is not set +# CONFIG_TIMPANI_CODEC is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_PM8821_IRQ is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_WCD9304_CODEC is not set +# CONFIG_WCD9310_CODEC is not set +# CONFIG_WCD9320_CODEC is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_FAN53555=y +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +CONFIG_REGULATOR_ONSEMI_NCP6335D=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +CONFIG_REGULATOR_MSM_GPIO=y +# CONFIG_REGULATOR_STUB is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_TUNER is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEOBUF2_VMALLOC=y +CONFIG_VIDEOBUF2_DMA_SG=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_AK881X is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_S5K6AA is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_AS3645A is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set +CONFIG_MSM_VCAP=y +CONFIG_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set + +# +# Qualcomm MSM Camera And Video +# +CONFIG_MSM_CAMERA=y +# CONFIG_MSM_CAMERA_DEBUG is not set +CONFIG_MSM_CAMERA_V4L2=y + +# +# Camera Sensor Selection +# +# CONFIG_IMX074 is not set +CONFIG_S5K5CA=y +CONFIG_S5K5CA_DARLING=y +# CONFIG_HI351_SUNNY_Q3H01B is not set +# CONFIG_OV5647 is not set +# CONFIG_OV5647_TRULY_CM6868 is not set +# CONFIG_OV5648_TRULY_CM8352 is not set +# CONFIG_WEBCAM_OV7692_QRD is not set +# CONFIG_MT9M114 is not set +# CONFIG_WEBCAM_OV9726 is not set +# CONFIG_MT9E013 is not set +# CONFIG_IMX074_ACT is not set +# CONFIG_S5K4E1 is not set +# CONFIG_AR0543 is not set +# CONFIG_A8140 is not set +# CONFIG_S5K3H2_SUNNY_Q8S02E is not set +CONFIG_AR0542=y +# CONFIG_MSM_CAMERA_FLASH_SC628A is not set +# CONFIG_MSM_CAMERA_FLASH_TPS61310 is not set +# CONFIG_IMX072 is not set +# CONFIG_OV2720 is not set +CONFIG_OV8825=y +CONFIG_MSM_CAMERA_FLASH=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_ACTUATOR=y +# CONFIG_MSM_EEPROM is not set +# CONFIG_IMX074_EEPROM is not set +# CONFIG_IMX091_EEPROM is not set +CONFIG_QUP_EXCLUSIVE_TO_CAMERA=y +# CONFIG_S5K3L1YX is not set +# CONFIG_IMX091 is not set +# CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE is not set +# CONFIG_OV7692 is not set +# CONFIG_OV7695 is not set +# CONFIG_OV7695_RAW is not set +# CONFIG_MT9V115 is not set +# CONFIG_OV5647_DALING_OVBD631AC is not set +# CONFIG_OV5647_PARTRON_CM500 is not set +# CONFIG_OV5647_HQ_O9B5_DG806T is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_KEENE is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +# CONFIG_RADIO_WL128X is not set +CONFIG_RADIO_TAVARUA=y +# CONFIG_RADIO_IRIS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_MSM_KGSL=y +# CONFIG_MSM_KGSL_CFF_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP is not set +# CONFIG_MSM_KGSL_PSTMRTMDMP_RB_HEX is not set +# CONFIG_KGSL_PER_PROCESS_PAGE_TABLE is not set +CONFIG_MSM_KGSL_PAGE_TABLE_SIZE=0xFFF0000 +CONFIG_MSM_KGSL_MMU_PAGE_FAULT=y +CONFIG_MSM_KGSL_DISABLE_SHADOW_WRITES=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_MSM_VIDC_CONTENT_PROTECTION is not set +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MIPI_OTM9608A_PT=y +# CONFIG_FB_MSM_BACKLIGHT is not set +# CONFIG_FB_MSM_LOGO is not set +CONFIG_FB_MSM_LCDC_HW=y +CONFIG_FB_MSM_TRIPLE_BUFFER=y +CONFIG_FB_MSM_MDP_HW=y +# CONFIG_FB_MSM_MDP22 is not set +CONFIG_FB_MSM_MDP30=y +CONFIG_FB_MSM_MDP303=y +# CONFIG_FB_MSM_MDP31 is not set +# CONFIG_FB_MSM_MDP40 is not set +# CONFIG_FB_MSM_MDSS is not set +# CONFIG_FB_MSM_MDP_NONE is not set +# CONFIG_FB_MSM_EBI2 is not set +# CONFIG_FB_MSM_MDDI is not set +CONFIG_FB_MSM_MIPI_DSI=y +CONFIG_FB_MSM_LCDC=y +# CONFIG_FB_MSM_LVDS is not set +# CONFIG_FB_MSM_EXTMDDI is not set +# CONFIG_FB_MSM_TVOUT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA is not set +# CONFIG_FB_MSM_MDDI_ORISE is not set +# CONFIG_FB_MSM_MDDI_QUICKVX is not set +# CONFIG_FB_MSM_MDDI_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_AUTO_DETECT is not set +CONFIG_FB_MSM_LCDC_PANEL=y +CONFIG_FB_MSM_MIPI_DSI_TOSHIBA=y +CONFIG_FB_MSM_MIPI_DSI_RENESAS=y +CONFIG_FB_MSM_MIPI_DSI_TRULY=y +CONFIG_FB_MSM_MIPI_DSI_SIMULATOR=y +CONFIG_FB_MSM_MIPI_DSI_NOVATEK=y +CONFIG_FB_MSM_MIPI_DSI_NT35510=y +CONFIG_FB_MSM_MIPI_DSI_HX8389B=y +CONFIG_FB_MSM_MIPI_DSI_HX8392A=y +CONFIG_FB_MSM_MIPI_DSI_OTM9605A=y +CONFIG_FB_MSM_MIPI_DSI_ORISE=y +CONFIG_FB_MSM_MIPI_DSI_NT35516=y +CONFIG_FB_MSM_MIPI_DSI_NT35590=y +CONFIG_FB_MSM_MIPI_DSI_TC358764_DSI2LVDS=y +# CONFIG_FB_MSM_LCDC_ST15_WXGA is not set +# CONFIG_FB_MSM_LCDC_ST15_PANEL is not set +# CONFIG_FB_MSM_LCDC_PRISM_WVGA is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA is not set +CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335=y +CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL=y +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT is not set +# CONFIG_FB_MSM_LCDC_NT35582_WVGA is not set +# CONFIG_FB_MSM_LCDC_WXGA is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD is not set +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT=y +CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA=y +CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT=y +CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT=y +CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT=y +CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT=y +CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT=y +CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT=y +CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_HX8392A_VIDEO_720P_PT=y +CONFIG_FB_MSM_MIPI_OTM9605A_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT=y +CONFIG_FB_MSM_MIPI_NT35590_CMD_720P_PT=y +CONFIG_FB_MSM_MIPI_NT35590_VIDEO_720P_PT=y +# CONFIG_FB_MSM_MIPI_DIV4_WVGA_NT35510_PANEL is not set +CONFIG_FB_MSM_MIPI_CHIMEI_WXGA=y +CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA=y +CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT=y +CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO=y +# CONFIG_FB_MSM_LCDC_PRISM_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_GORDON_VGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_LCDC_AUO_WVGA_PANEL is not set +# CONFIG_FB_MSM_LCDC_NT35582_PANEL is not set +# CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL is not set +# CONFIG_FB_MSM_LVDS_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_LVDS_FRC_FHD_PANEL is not set +# CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM is not set +CONFIG_FB_MSM_MIPI_PANEL_DETECT=y +# CONFIG_FB_MSM_MDDI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT is not set +# CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT is not set +# CONFIG_FB_MSM_MDDI_PRISM_WVGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_VGA is not set +# CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA is not set +# CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128 is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA_PANEL is not set +# CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_HX8389B_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_HX8392A_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_OTM9605A_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35590_CMD_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_NT35590_VIDEO_720P_PT_PANEL is not set +# CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL is not set +# CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF is not set +# CONFIG_FB_MSM_PANEL_NONE is not set +# CONFIG_FB_MSM_EXT_INTERFACE_COMMON is not set +# CONFIG_FB_MSM_HDMI_COMMON is not set +# CONFIG_FB_MSM_HDMI_3D is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565 is not set +# CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888 is not set +CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888=y +# CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL is not set +# CONFIG_FB_MSM_EBI2_PANEL_DETECT is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y + +# +# MSM SoC Audio support +# +CONFIG_SND_MSM_DAI_SOC=y +CONFIG_SND_MSM_SOC_MSM7K=y +CONFIG_SND_MSM_SOC=y +# CONFIG_SND_SOC_QDSP6 is not set +# CONFIG_SND_SOC_QDSP6V2 is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +# CONFIG_HOLTEK_FF is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LEDS is not set +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WACOM_POWER_SUPPLY is not set +CONFIG_HID_WIIMOTE=y +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_SUPPORT_NON_STANDARD_WALL_CHARGER=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MSM_HSIC is not set +# CONFIG_USB_OXU210HP_HCD is not set +CONFIG_USB_EHCI_MSM_72K=y +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_PEHCI_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +CONFIG_USB_EHSET_TEST_FIXTURE=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_CI13XXX_MSM is not set +# CONFIG_USB_CI13XXX_MSM_HSIC is not set +# CONFIG_USB_DWC3_MSM is not set +CONFIG_USB_MSM_72K=y +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_SUPERSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_CSW_HACK=y +# CONFIG_USB_MSC_PROFILING is not set +CONFIG_MODEM_SUPPORT=y +CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL" +CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40" +# CONFIG_USB_ANDROID_RMNET_CTRL_SMD is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +CONFIG_USB_OTG_WAKELOCK=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_MSM_OTG_72K=y +# CONFIG_MSM_OTG_ENABLE_A_WAIT_BCON_TIMEOUT is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MSM_ACA is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +# CONFIG_MMC_EMBEDDED_SDIO is not set +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +CONFIG_MMC_TEST=m +CONFIG_MMC_BLOCK_TEST=m + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_MSM=y +CONFIG_MMC_MSM_RAW=y +CONFIG_MMC_MSM_SDC1_SUPPORT=y +# CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC2_SUPPORT=y +# CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT is not set +CONFIG_MMC_MSM_SDC3_SUPPORT=y +CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y +# CONFIG_MMC_MSM_SDC3_WP_SUPPORT is not set +# CONFIG_MMC_MSM_SDC4_SUPPORT is not set +# CONFIG_MMC_MSM_SDC5_SUPPORT is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_MSM_PDM=y +CONFIG_LEDS_PMIC_MPP=y +CONFIG_LEDS_MSM_TRICOLOR=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_CPLD is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_MSM_PMIC is not set +CONFIG_LEDS_TRICOLOR_FLAHSLIGHT=y +# CONFIG_LEDS_PMIC8029 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_TRIGGERS is not set + +# +# LED Triggers +# +CONFIG_SWITCH=y +CONFIG_SWITCH_GPIO=y +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_MSM=y +CONFIG_RTC_SECURE_TIME_SUPPORT=y +# CONFIG_RTC_DRV_MSM7X00A is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +# CONFIG_SNAPPY_COMPRESS is not set +# CONFIG_SNAPPY_DECOMPRESS is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_ZCACHE is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +# CONFIG_ANDROID_LOGGER_SYSFS is not set +CONFIG_ANDROID_PERSISTENT_RAM=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +# CONFIG_ANDROID_SWITCH is not set +# CONFIG_ANDROID_INTF_ALARM_DEV is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set + +# +# Qualcomm MSM specific device drivers +# +# CONFIG_MSM_SSBI is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y + +# +# Hardware Spinlock drivers +# +CONFIG_IOMMU_SUPPORT=y + +# +# Remoteproc drivers (EXPERIMENTAL) +# + +# +# Rpmsg drivers (EXPERIMENTAL) +# +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_MOBICORE_SUPPORT is not set +# CONFIG_MSM_QDSS is not set + +# +# NVBK share memory +# +CONFIG_NVBK_SHARE_MEM=y + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DYNAMIC_FSYNC is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_PRINTK_RTC_TIME=y +CONFIG_PRINTK_CPU_ID=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_SCHED_TRACER=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_KPROBE_EVENT=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=32768 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_FORCE_PERMISSIVE=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA1_ARM is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_QCRYPTO is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_QCEDEV is not set +# CONFIG_CRYPTO_DEV_OTA_CRYPTO is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set

    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�$To=k5x5e@n*2gJY+?>4PR^~?(n*7|1))t+1 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